3
\$\begingroup\$

I wrote this program for an assignment, thus I had some requirements as far as the format of the cfg.txt file and some basic other classes that we had to use. Other than that, I am curious if there is a way to drastically simplify this code. Although the program runs fine and produces the desired output, is there a better way to go about writing this? (What initially spurred my concern was the iterateData method. I did not like the code repetition and thought it may be convenient to "reuse" some of it. However, in doing so, I then introduced numerous class variables to prevent from having to pass in 7 instance variables to the method. I can't say that I'm all too thrilled about this...) Regardless, advice and suggestions appreciated.

Thank you.

import java.util.Scanner; 
import java.io.*;
import java.util.Random;
public class ContextFreeGrammar {
 private static String nt, useExp = "";
 private static int totalWeight = 0, randomNum;
 private static ArrayUnsortedList<Production> data = new ArrayUnsortedList<Production>();
 private static Production pObj;
 public static void main(String[] args) throws IOException {
 String result = "<S>";
 File myFile = new File("cfg.txt");
 Scanner fileScan = new Scanner(myFile);
 // Read and process each line of the file
 while (fileScan.hasNext()) {
 Production p = new Production(fileScan.nextLine());
 data.add(p);
 }
 // If the result string still contains non-terminals
 while (result.contains("<")) {
 // Get the non-terminal
 nt = result.substring(result.indexOf('<')+1, result.indexOf('>'));
 // Cannot condense because we have an ambiguous
 // totalWeight. Hence, we need to iterate twice:
 // 1. To generate appropriate random number from totalWeight
 // 2. To determine when the totalWeight exceeds that random number.
 iterateData(false);
 Random rand = new Random(); // Generate a random number object
 randomNum = rand.nextInt(totalWeight - 1) + 1; // Generate actual random number
 // Resets
 totalWeight = 0;
 data.reset();
 iterateData(true);
 // Replace the non-terminal with the expression to use
 result = result.replaceFirst("<" + nt + ">", useExp);
 totalWeight = 0; // Reset totalWeight;
 }
 System.out.println(result);
 }
 public static void iterateData(boolean GETEXP) {
 // Iterate through list again
 for (int i = 0; i < data.size(); i++) {
 // Get the current value
 pObj = data.getNext();
 // Keep track of weight
 if (nt.equalsIgnoreCase(pObj.getNonTerminal())) {
 totalWeight += pObj.getWeight();
 if (GETEXP) {
 if (totalWeight > randomNum) {
 useExp = pObj.getExpression(); // This is expression to use
 break;
 }
 }
 }
 }
 }
}

My cfg.txt file is as such:

80 <S> = My homework is late because <reason>.
20 <S> = I want to <action> instead of writing this program.
40 <reason> = <who> ate it
40 <reason> = I set it on fire because I was cold
20 <reason> = I didn't feel like doing it
30 <who> = Deep Shah
70 <who> = my pet <animal>
10 <animal> = dog
20 <animal> = narwhal
50 <animal> = python
20 <animal> = velociraptor
30 <action> = go on a vacation
30 <action> = indulge in a giant feast
40 <action> = frolic in the snow
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Dec 10, 2013 at 17:16
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$
  • It is said that "a method should do one thing, and it should do that one thing well". Your iterateData method is being used to do two separate things, depending on the parameter you send it.

  • If your ArrayUnsortedList is this class (which really could use a code review itself) then I don't really understand why you are using it. The way I see it is that you could use a regular ArrayList.

  • What you are referring to as "class variables" are static variables. It would be better to use them as instance variables. Currently you can't have two ContextFreeGrammar objects at once, each with it's own state. Remove the static keyword and *create an instance of ContextFreeGrammar to properly use it as an instance (which is a lot better practice, although you might not have learned about such things yet. If you haven't learned about it yet, you should ask your teacher about it)

  • Only create a new Random object once. Random objects are meant to be re-used. When they are initialized, they get a random seed set depending on the system clock time. Repeatedly creating a Random object gives a loss in randomness.

  • Instead of your current iterateData method, consider using one method such as int calculateTotalWeight(List<Production> list, String nonTerminal) and one String determineExpression(List<Production> list, String nonTerminal, int weightRandom). Determining such an important behavior of your method by sending it a true/false value makes your code harder to understand. You don't need to pass seven variables to the method when it only uses two or three.

answered Dec 10, 2013 at 17:44
\$\endgroup\$
5
  • \$\begingroup\$ To address your second point, this is quite true; however, for my course, I must use this class because it comes from my professor's textbook...and he wants us to use it...Anyway, I appreciate the feedback and will make the necessary changes. You make some very good points. Thanks. \$\endgroup\$ Commented Dec 10, 2013 at 19:20
  • \$\begingroup\$ @JohnZ Send your professor and his textbook over here and we would gladly review him! \$\endgroup\$ Commented Dec 10, 2013 at 21:01
  • \$\begingroup\$ You have no idea how much I would love that. To be honest, considering I've only ever learned Java in his particular class, I'm very interested to know what I'm being taught versus what I should be being taught. Makes me wonder. \$\endgroup\$ Commented Dec 10, 2013 at 21:04
  • 1
    \$\begingroup\$ @JohnZ It all depends on how much you're ready to learn at once I think. Whenever you create something you'd like a second opinion on, Code Review is your friend. \$\endgroup\$ Commented Dec 10, 2013 at 21:06
  • \$\begingroup\$ Well for what it's worth, your review was far more helpful than any other feedback I've received in class. I will definitely be using CodeReview more often. \$\endgroup\$ Commented Dec 10, 2013 at 21:13

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.