/* * This is based on: * Example grammar written 11/1/96 by Chuck McManis options { MULTI=true; VISITOR=true; NODE_DEFAULT_VOID=true; } /* MULTI=true; */ /* #LOOKAHEAD=1; */ PARSER_BEGIN(PRM) public class PRM { public static void main(String args[]) { PRM parser = new PRM(System.in); ASTProgram n = null; try { n = parser.program(); n.dump(""); System.out.println("Successfully parsed!\n"); } catch (Exception e) { System.out.println("Error."); System.out.println(e.getMessage()); e.printStackTrace(); } /* Check variable declarations */ System.out.println("\nChecking variable declarations"); PRMDeclarationCheckVisitor dcv = new PRMDeclarationCheckVisitor(); dcv.visit(n, null); } } PARSER_END(PRM) SKIP : /* WHITESPACE */ { " " | "\t" | "\r" | "\n" | < "//" (~["\n","\r"])* ("\n" | "\r" | "\r\n") > } /* The next few TOKEN definitions are the binary operators of our language in decreasing order of precedence */ TOKEN : /* The end of line token (a semicolon) */ { < EOL: ";" > } TOKEN : /* Block begin and block end markers */ { < BB: "{" > | < BE: "}" > } TOKEN : /* The left subscript and right subscript operators */ { < LSUB: "[" > | < RSUB: "]" > } TOKEN : /* Left and right parentheses */ { < LPAREN: "(" > | < RPAREN: ")" > } TOKEN : /* The list separator */ { < LISTSEP: "," > } TOKEN : /* Exponentiation operator */ { < EXP: "^" > } TOKEN : /* Multiplication and division */ { < MULTIPLY: "*" > | < DIVIDE: "/"> | < MOD: "%" > } TOKEN : /* Addition and subtraction */ { < PLUS: "+" > | < MINUS: "-"> } TOKEN : /* Comparison operators */ { < EQ: "=" > | < GT: ">" > | < GE: ">=" > | < LT: "<" > | < LE: "<=" > | < NE: "<>" | "!=" > } TOKEN : /* Logical operators (AND/OR) */ { < AND: "&" > | < OR: "|" > } TOKEN : /* The assignment operator */ { < GETS: ":=" > } TOKEN : /* Keywords */ { < DO: "do" > | < WHILE: "while" > | < IF: "if" > | < ELSIF: "elsif" > | < ELSE: "else" > | < NUMBER_TYPE: "number" > | < STRING_TYPE: "string" > | < BOOLEAN_TYPE: "boolean" > | < RETURN: "return" > } TOKEN : /* Numeric Constants */ { < NUMBER: | "r" | ( ["e","E"] ([ "-","+"])? )? > | < #FLOAT: | ( "." )? | "." > | < #INTEGER: ( )+ > | < #SPECINTEGER: (["a"-"t", "A"-"T", "0"-"9"])+ | < #DIGIT: ["0" - "9"] > } TOKEN : /* String constants */ { < STRING: "\"" ( )* "\"" > | < #CHAR: ["!", "#"-"~", " ", "\t"] > } TOKEN : /* Boolean constants */ { < BOOLEAN: "true" | "false" > } TOKEN : /* Identifiers (variables and function calls) */ { < ID: ( )+ ( | )* > | < #LETTER: ["a"-"z", "A"-"Z", "_"] > } /* That's it for TOKEN definitions, now we start with the grammar */ ASTProgram program() #Program : { } { (( functionDefinition() )* ) { return jjtThis; } } void functionDefinition() : { } { ( type() identifier() parameterList() block() ) #Function } void parameterList() : { } { ( ( parameter() ( parameter() )* )? ) #ParameterList } void parameter() : { } { ( type() identifier() ) #Parameter } void block() : { } { ( expressionList() ) #Block } void expressionList() : { } { ( statement() )* } void statement() : { } { declaration() | returnStatement() | whileLoop() | doLoop() | ifStatement() | simpleStatement() } void declaration() : { } { ( type() identifier() ( identifier())* ) #Declaration } void type() #MyType : { Token t; } { ( | | ) { t = getToken(0); jjtThis.setName(t.image); } } void identifier() #MyIdentifier : { Token t; } { t= { jjtThis.setName(t.image); } } void returnStatement() : { } { ( logical() ) #Return } void whileLoop() : { } { ( condition() block() ) #WhileLoop } void doLoop() : { } { ( block() condition() ) #DoLoop } void ifStatement() : { } { ( condition() block() ( condition() block() )* ( block() )? ) #IfStatement } void condition() : { } { ( assignment() ) #Condition } void simpleStatement() : { } { ( assignment() ) #SimpleStatement } void assignment() : { } { // The first solution requires a lookahead, but spots invalid // assignments during parsing. The second solution doesn't require // lookahead, but allows invalid assignments during parsing // LOOKAHEAD( ) logical() | logical() ( logical() ( logical() )* ) #Assign(>1) } void logical() : { } { ( comparison() (logicalOp() comparison())* ) #OperatorList(>1) } void logicalOp() #MyOperator : { Token t; } { ( | ) { t = getToken(0); jjtThis.setName(t.image); } } void comparison() : { } { ( sum() (comparisonOp() sum())* ) #OperatorList(>1) } void comparisonOp() #MyOperator : { Token t; } { ( | | | | | ) { t = getToken(0); jjtThis.setName(t.image); } } void sum() : { } { ( term() (sumOp() term())* ) #OperatorList(>1) } void sumOp() #MyOperator : { Token t; } { ( | ) { t = getToken(0); jjtThis.setName(t.image); } } void term() : { } { ( exp() (termOp() exp())* ) #OperatorList(>1) } void termOp() #MyOperator : { Token t; } { ( | | ) { t = getToken(0); jjtThis.setName(t.image); } } void exp() : { } { // Notice: x^x^x^x = x^(x^(x^(x))) ( unary() ( expOp() exp() )? ) #OperatorList(>1) } void expOp() #MyOperator : { Token t; } { t= { jjtThis.setName(t.image); } } void unary() : { } { negation() | element() } void negation() #MyUnaryOp : { Token t; } { t= element() { jjtThis.setName(t.image); } } void element() : { } { constant() | idOrFunctionCall() | assignment() } void idOrFunctionCall() : { } { ( identifier() (argumentList())? ) #IDOrFunctionCall } void constant() : { } { ( stringConstant() | booleanConstant() | numberConstant() ) } void stringConstant() #MyStringConstant : { Token t; } { t= { jjtThis.setValue(t.image.substring(1,t.image.length()-1)); } } void booleanConstant() #MyBooleanConstant : { Token t; } { t= { jjtThis.setValue(t.image.compareTo("true")==0); } } void numberConstant() #MyNumberConstant : { Token t; } { t= { String parsed[]; if ((t.image.indexOf("r") == 1)||(t.image.indexOf("r") == 2)) { parsed = t.image.split("r"); jjtThis.setValue(new Double(Integer.valueOf(parsed[1], (new Integer(parsed[0])).intValue())).doubleValue()); } else { jjtThis.setValue(new Double(t.image).doubleValue()); } } } void variableOrFunctionCall() #MyIdentifier : { Token t; } { t= ( argumentList() )? { jjtThis.setName(t.image); } } void argumentList() : { } { ( assignment() ( assignment() )* ) #ArgumentList }