You can create an arithmetic parser by translating the arithmetic grammar into a parser class and plugging in the assemblers. Section 3.6, "Translating a Grammar to Code," gives a set of rules for creating a parser from a grammar. The only remaining problem is to prevent looping in the subparser definitions. Section 6.5, "Eliminating Parser Class Loops," explains how to address loops in a grammar. The arithmetic grammar has two cycles. expression = term (plusTerm minusTerm)*; term = factor (timesFactor divideFactor)*; plusTerm = '+' term; minusTerm = '-' term; factor = phrase expFactor phrase; timesFactor = '*' factor; divideFactor = '/' factor; expFactor = '^' factor; phrase = '(' expression ')' Num; One cycle is in factor . This definition depends on expFactor , which depends on factor . The other cycle in the grammar begins with expression . The expression rule depends on term , which depends on factor , which depends on phrase , which depends on expression . To avoid loops in the code, use instance variables to hold the expression and factor parsers. Figure 7.3 shows the ArithmeticParser class. Figure 7.3. The ArithmeticParser class. This class holds a collection of methods that can be composed into a parser for arithmetic. To use this class, you can apply the parser ArithmeticParser.start() to match a token assembly. Alternatively, you can use this class's value() method, which takes a String and returns a double value. The following class shows this approach: package sjm.examples.arithmetic; /** * Show how to use the <code>ArithmeticParser</code> class. */ public class ShowArithmeticParser { /* * Help out the main() method. */ private static void eval(String s, double d) throws ArithmeticExpressionException { System.out.println( "Given: " + s + " Expected: " + d + "\tFound: " + ArithmeticParser.value(s)); } /** * Show a few examples of arithmetic. */ public static void main(String args[]) throws ArithmeticExpressionException { eval("9^2 - 81 ", 0); // exponentiation eval("7 - 3 - 1 ", 3); // minus associativity eval("2 ^ 1 ^ 4 ", 2); // exp associativity eval("100 - 25*3 ", 25); // precedence eval("100 - 5^2*3 ", 25); // precedence eval("(100 - 5^2) * 3", 225); // parentheses } } Running this class prints the following: Given: 9^2 - 81 Expected: 0.0 Found: 0.0 Given: 7 - 3 - 1 Expected: 3.0 Found: 3.0 Given: 2 ^ 1 ^ 4 Expected: 2.0 Found: 2.0 Given: 100 - 25*3 Expected: 25.0 Found: 25.0 Given: 100 - 5^2*3 Expected: 25.0 Found: 25.0 Given: (100 - 5^2) * 3 Expected: 225.0 Found: 225.0 The display shows various expected results that demonstrate associativity, precedence, and the use of parentheses. |