The objectives for this assignment are to use associative arrays (HashMaps in this case), a queue, and an extended finite state machine to parse a String containing an arithmetic expression into tokens and place those tokens into a queue for further processing. The next assignment translates the expression from the current infix notation into postfix notation, and then evaluates the postfix expression. Tests should be done to make sure your program works properly before submitting it for grading. Notice that output from a sample run has been provided.
This is a new assignment and it would not be surprising if it contained some errors. Let me know if you find any errors, and I'll be available to check out your code as it develops to help debug it and get it running.
There are four user-defined classes that make up this assignment.
Finite state machines are a concept that is often used in computer programming. You may even have done something equivalent or similar without even realizing it. The basic idea is that there are a finite number of states. You begin in one particular state and start processing input. Each state has rules for what it will do with different types of input. As input is read, the appropriate rule is looked up based on the current state and the input that was read. The rule describes what actions should be taken and the next state to move into. This assignment uses an extended finite state machine (a finite state machine with memory) to parse tokens in an input stream and output them to a queue. The basic diagram for this state machine, without the associated actions, is shown below.
A template is available so you can start with the Token, FSM, and FSMRule classes. It is located at infix.txt.
This is the class that you have to write to do all the work. It uses HashMaps, a LinkedList operating as a queue, and implements a finite state machine. There are five static variables and seven static methods.
Note: In the pseudocode below, you may see something like: if rule.actions includes FSM.ERROR. That means that you are actually checking a bit in rule.actions to see if it is set. Fortunately, there are constants already set up in the FSM class to make this easy. Here's the code that would check rule.actions to see if it includes FSM.ERROR:
if ((rule.actions & FSM.ERROR) != 0) { ... }
All of the fields should be static and initialized.
This is the method that does most of the work. It has two main loops, one nested inside the other. The outer loop keeps getting one line of input at a time from the user. The inner loop processes one character at a time from the input data.
for (String s : args) { s = s.toUpperCase(); if (s.charAt(0) == '-') s = s.substring(1); if (s.equals("DEBUG") || s.equals("D")) DEBUG = true; } System.out.println("Enter an expression to evaluate (or QUIT to exit)"); if (DEBUG) System.out.println("Program is in DEBUG mode");
System.out.print("\nEnter expression: "); String expr = in.nextLine().toUpperCase(); if (expr.equals("QUIT") || expr.equals("Q")) done = true;
error = true; System.out.println("Error: " + expr); System.out.print(" "); for (int j=0; j<pos; j++) System.out.print(" "); System.out.println("^");
error = true; System.out.println("Error: " + expr); System.out.print(" "); for (int j=0; j<pos; j++) System.out.print(" "); System.out.println("^");
error = true; System.out.println("Error: " + expr); System.out.print(" "); for (int j=0; j<pos; j++) System.out.print(" "); System.out.println("^");
System.out.println("Infix queue:"); for (int i=0; i<infixQueue.size(); i++) System.out.printf("%2d: %s\n", (i+1), infixQueue.get(i));
This is a pretty simple static method whose job is to return true if an operator is left associative, and false if it isn't. The associativities are already stored in the leftAssociative HashMap, which makes this routine rather short.
This is a pretty simple static method whose job is to return the integer precedence value of an operator. The precedences are already stored in the precedences HashMap, which makes this routine rather short.
This is a pretty straight-forward method. It is a static method which adds the associations in the following list into the precedences HashMap.
This is a pretty straight-forward method. It is a static method which adds the associations in the following list into the leftAssociative HashMap.
This method is simple. Print "Error: " followed by the msg passed in. Then end the program.
A static method named initFSM. It should add the rules in the list below to the finite state machine. The rules in the list below are in the following format: state, character type, actions, next state. Check out the FSM class for the appropriate method to be used to enter a rule into the finite state machine. You should already have a reference variable to a FSM.
C:\>java Infix Enter an expression to evaluate (or QUIT to exit) Program is in DEBUG mode Enter expression: (5+2) * (.3 - -3.3) Infix queue: 1: open parenthesis 2: operand (5) 3: operator (+), 1, true 4: operand (2) 5: close parenthesis 6: operator (*), 2, true 7: open parenthesis 8: operand (.3) 9: operator (-), 1, true 10: operand (-3.3) 11: close parenthesis Enter expression: ( 6 + 2.3) ) -1 Error: ( 6 + 2.3) ) -1 ^ Enter expression: ( 6 + 2.3) -1 Infix queue: 1: open parenthesis 2: operand (6) 3: operator (+), 1, true 4: operand (2.3) 5: close parenthesis 6: operator (-), 1, true 7: operand (1) Enter expression: 3 +-.78*((2++14.9 * 3.)^(3+(2*5))) Infix queue: 1: operand (3) 2: operator (+), 1, true 3: operand (-.78) 4: operator (*), 2, true 5: open parenthesis 6: open parenthesis 7: operand (2) 8: operator (+), 1, true 9: operand (+14.9) 10: operator (*), 2, true 11: operand (3.) 12: close parenthesis 13: operator (^), 3, false 14: open parenthesis 15: operand (3) 16: operator (+), 1, true 17: open parenthesis 18: operand (2) 19: operator (*), 2, true 20: operand (5) 21: close parenthesis 22: close parenthesis 23: close parenthesis Enter expression: 7.8 + -3.0001 Infix queue: 1: operand (7.8) 2: operator (+), 1, true 3: operand (-3.0001) Enter expression: quit C:\>