/* * In this second modification to the Calc grammar, we now add * "Identifiers" to the token list so that we can parse functions. * Functions are specified in the function() production. * * Further, we've added some logical operations, &, |, and ^ to the * existing mathematical ones. * * The grammar now supports the plus (+), minus (-) * multiply (*), divide (/) and exponentiation operations. * * See Calc3.jack for the bare grammar (without embedded Java code) * * Example grammar written 11/1/96 by Chuck McManis (cmcmanis@netcom.com) */ options { LOOKAHEAD=1; } PARSER_BEGIN(Calc3i) public class Calc3i { static double total; static java.util.Stack argStack = new java.util.Stack(); public static void main(String args[]) throws ParseError { Calc3i parser = new Calc3i(System.in); while (true) { System.out.print("Enter Expression: "); System.out.flush(); try { switch (parser.one_line()) { case -1: System.exit(0); case 0: break; case 1: double x = ((Double) argStack.pop()).doubleValue(); System.out.println("Total = " + x); break; } } catch (ParseError x) { System.out.println("Exiting."); throw x; } } } } PARSER_END(Calc3i) IGNORE_IN_BNF : {} { " " | "\r" | "\t" } TOKEN : { } { < EOL: "\n" > } TOKEN : /* OPERATORS */ { } { < PLUS: "+" > | < MINUS: "-" > | < MULTIPLY: "*" > | < DIVIDE: "/" > | < EXP: "**" > | < AND: "&" > | < OR: "|" > | < XOR: "^" > } TOKEN : /* numeric constants */ { } { < CONSTANT: | ( ["e","E"] ([ "-","+"])? )? > | < #FLOAT: | ( "." )? | "." > | < #INTEGER: ( )+ > | < #DIGIT: ["0" - "9"] > } TOKEN : /* Function names */ { } { < ID: ( )+ ( | )* > | < #LETTER: ["a"-"z", "A"-"Z"] > } int one_line() : {} { logical() { return 1; } | { return 0; } | { return -1; } } void logical() : {Token x;} { sum() ( ( x = | x = | x = ) sum() { long a = ((Double) argStack.pop()).longValue(); long b = ((Double) argStack.pop()).longValue(); switch (x.kind) { case AND: argStack.push(new Double(a & b)); break; case OR: argStack.push(new Double(a | b)); break; case XOR: argStack.push(new Double(a ^ b)); break; } } )* } void sum() : {Token x;} { term() ( ( x = | x = ) term() { double a = ((Double) argStack.pop()).doubleValue(); double b = ((Double) argStack.pop()).doubleValue(); if ( x.kind == PLUS ) argStack.push(new Double(b + a)); else argStack.push(new Double(b - a)); } )* } void term() : {Token x;} { exp() ( ( x = | x = ) exp() { double a = ((Double) argStack.pop()).doubleValue(); double b = ((Double) argStack.pop()).doubleValue(); if ( x.kind == MULTIPLY ) argStack.push(new Double(b * a)); else argStack.push(new Double(b / a)); } )* } void exp() : { } { unary() ( LOOKAHEAD( ) exp() { double a = ((Double) argStack.pop()).doubleValue(); double b = ((Double) argStack.pop()).doubleValue(); argStack.push(new Double(Math.pow(b, a))); } )* } void unary() : { } { element() { double a = ((Double) argStack.pop()).doubleValue(); argStack.push(new Double(- a)); } | element() } void element() : {} { { try { argStack.push(Double.valueOf(token.image)); } catch (NumberFormatException ee) { argStack.push(new Double(Double.NaN)); } } | function() | "(" logical() ")" } void function() : { String funcname; double args = 0; } { {funcname = token.image;} "(" [ logical() {args++;} ( "," logical() {args++;})* ] ")" { double a, b; if (funcname.equalsIgnoreCase("sin")) { if (args != 1) { System.err.println("Too many arguments to sin()"); throw new ParseError(); } a = ((Double) argStack.pop()).doubleValue(); argStack.push(new Double(Math.sin(a))); } else if (funcname.equalsIgnoreCase("cos")) { if (args != 1) { System.err.println("Too many arguments to cos()"); throw new ParseError(); } a = ((Double) argStack.pop()).doubleValue(); argStack.push(new Double(Math.cos(a))); } else if (funcname.equalsIgnoreCase("tan")) { if (args != 1) { System.err.println("Too many arguments to tan()"); throw new ParseError(); } a = ((Double) argStack.pop()).doubleValue(); argStack.push(new Double(Math.tan(a))); } else if (funcname.equalsIgnoreCase("min")) { if (args != 2) { System.err.println("Wrong number of arguments to min()"); throw new ParseError(); } a = ((Double) argStack.pop()).doubleValue(); b = ((Double) argStack.pop()).doubleValue(); argStack.push(new Double(Math.min(a, b))); } else if (funcname.equalsIgnoreCase("max")) { if (args != 2) { System.err.println("Wrong number of arguments to max()"); throw new ParseError(); } a = ((Double) argStack.pop()).doubleValue(); b = ((Double) argStack.pop()).doubleValue(); argStack.push(new Double(Math.max(a, b))); } else { /* Note we have to reverse the order of the arguments */ StringBuffer sb = new StringBuffer(); System.out.print("Function "+funcname+"( "); for (int i = 0; i < args; i++) { a = ((Double) argStack.pop()).doubleValue(); if (i == 0) { sb.insert(0, " "+a); } else { sb.insert(0, " "+a+","); } } System.out.println(sb+")"); /* push back a bogus value */ argStack.push(new Double(-1)); } } }