/**** * * This file defines a tree-generating parser for EJay programming language * being studied in CSC 330. * */ import java_cup.runtime.*; parser code {: public void syntax_error(Symbol cur_token) { report_error("Sytax error at line " + (cur_token.left+1) + ", column " + cur_token.right, null); } public void initSymbolTable(int size) { symtab = new SymbolTable(size); } public SymbolTable getSymbolTable() { return symtab; } /** Reference to current symbol table. This value changes as the program * is parsed, such that symtab points to the symbol table for the scope in * which the parse is currently active. */ public SymbolTable symtab; /** Reference to the current function entry. It is assigned each time a * function entry is created. */ public FunctionEntry entry; /** Reasonable size for a function symbol table. */ public final int FUNC_SYMTAB_SIZE = 25; /** Reasonable size for a block symbol table. */ public final int BLOCK_SYMTAB_SIZE = 25; /** Incrementing counter for declared structs. This number is used to * create a unique name for each struct, so it can be entered and * subsequently retrieved from a symbol table. */ public int structNum; /** Incrementing counter for nested blocks. This number is used to create * a unique name for each block, so it can be entered and subsequently * retrieved from a symbol table. */ public int blockNum; /** Enter the vars in the given tree node list in the current symtab. The * type of each var entry is the given type. */ public void enterVars(TypeNode type, TreeNodeList vars) { TreeNode node; TreeNodeList rest; boolean done = false; for (node = vars.node, rest = vars.siblings; !done; ) { symtab.enter(new VariableEntry( (String) (((LeafNode) node).value), type, false, 0, symtab.level)); if (rest == null) { done = true; } else { node = rest.node; rest = rest.siblings; } } } /** Enter an inner block by allocating a symtab for it, entering a * unique-named BlockEntry for it in the current symtab, and descending * into the new block symtab. This function is used both for inner * statement blocks and struct types; the String-valued blockType parameter * is "block" or "struct" depending on the caller. * * NOTE: An acceptable solution to CSC 330 Assignment 3 does not need to * generate the unique entry name. */ public void enterBlock(String blockType) { SymbolTable blockTab = new SymbolTable(BLOCK_SYMTAB_SIZE); BlockEntry blockEntry = new BlockEntry(blockTab); blockEntry.name = blockType + Integer.toString( blockType.equals("block") ? blockNum++ : structNum++); symtab.enter(blockEntry); blockTab.parent = symtab; symtab = blockTab; } :} terminal BOOLEAN; terminal ELSE; terminal IF; terminal INT; terminal VOID; terminal WHILE; terminal TRUE; terminal FALSE; terminal FLOAT; terminal STRING; terminal STRUCT; terminal RETURN; terminal PRINT; terminal REF; terminal LEFT_PAREN; // "(" terminal RT_PAREN; // ")" terminal LEFT_BRACE; // "{" terminal RT_BRACE; // "}" terminal SEMI; // ";" terminal COMMA; // "," terminal LEFT_BRKT; // "[" terminal RT_BRKT; // "]" terminal EQ; // "=" terminal PLUS; // "+" terminal MINUS; // "-" terminal TIMES; // "*" terminal DIVIDE; // "/" terminal LESS; // "<" terminal LESS_EQ; // "<=" terminal GTR; // ">" terminal GTR_EQ; // ">=" terminal EQ_EQ; // "==" terminal NOT_EQ; // "!=" terminal AND; // "&&" terminal OR; // "||" terminal NOT; // "!" terminal DOT; // "." terminal UNY_PLUS; // unary "+" terminal UNY_MINUS; // unary "-" terminal IDENT; // identifier terminal INTEGER; // decimal, hex, or octal integer terminal FLOATING_PT;// floating point terminal STRING_LIT; // floating point nonterminal TreeNodeList Program; nonterminal TreeNodeList Declarations; nonterminal TreeNode Declaration; nonterminal TreeNode DataDeclaration; nonterminal TreeNodeList DataDeclarations; nonterminal TreeNode FunctionDeclaration; nonterminal TreeNode4 FunctionHeader; nonterminal TreeNode FunctionBlock; nonterminal TypeNode Type; nonterminal TreeNodeList Identifiers; nonterminal TypeNode ArrayType; nonterminal TypeNode StructType; nonterminal TreeNode StructHeader; nonterminal TreeNodeList Dimensions; nonterminal LeafNode Identifier; nonterminal TreeNode Integer; nonterminal TreeNodeList Fields; nonterminal TreeNode Field; nonterminal TreeNodeList Formals; nonterminal TreeNode Block; nonterminal TreeNode BlockHeader; nonterminal TreeNode FormalDeclaration; nonterminal TreeNodeList Statements; nonterminal TreeNode Statement; nonterminal TreeNode Assignment; nonterminal TreeNode IfStatement; nonterminal TreeNode WhileStatement; nonterminal TreeNode CallStatement; nonterminal TreeNode ReturnStatement; nonterminal TreeNode PrintStatement; nonterminal TreeNode Designator; nonterminal TreeNode Expression; nonterminal TreeNode ArraySelection; nonterminal TreeNode StructSelection; nonterminal TreeNodeList Expressions; nonterminal TreeNode2 RelationalOp; nonterminal TreeNode2 AdditiveOp; nonterminal TreeNode2 MultiplicativeOp; nonterminal TreeNode1 UnaryOp; nonterminal TreeNode Literal; nonterminal TreeNode Float; nonterminal TreeNode String; nonterminal TreeNode Boolean; precedence right RT_PAREN; precedence right RT_BRKT; precedence left OR; precedence left AND; precedence left LESS, LESS_EQ, GTR, GTR_EQ, EQ_EQ, NOT_EQ; precedence left PLUS, MINUS; precedence left TIMES, DIVIDE; precedence left DOT; precedence left LEFT_BRKT; precedence left UNY_PLUS, UNY_MINUS; precedence left LEFT_PAREN; precedence left ELSE; Program ::= Declarations:ds {: RESULT = ds; :} ; Declarations ::= Declaration:d {: RESULT = new TreeNodeList(d, null); :} | Declaration:d Declarations:ds {: RESULT = new TreeNodeList(d, ds); :} ; Declaration ::= DataDeclaration:dd SEMI {: RESULT = dd; :} | FunctionDeclaration:fd {: RESULT = fd; :} ; DataDeclaration ::= Type:t Identifiers:is {: RESULT = new TreeNode2( sym.SEMI, t, is, tleft, tright); parser.enterVars(t, is); :} ; Type ::= INT:i {: RESULT = new TypeNode(sym.INT, ileft, iright); :} | FLOAT:f {: RESULT = new TypeNode(sym.FLOAT, fleft, fright); :} | STRING:s {: RESULT = new TypeNode(sym.STRING, sleft, sright); :} | BOOLEAN:b {: RESULT = new TypeNode(sym.BOOLEAN, bleft, bright); :} | VOID:v {: RESULT = new TypeNode(sym.VOID, vleft, vright); :} | ArrayType:at {: RESULT = at; :} | StructType:st {: RESULT = st; :} ; ArrayType ::= Type:t LEFT_BRKT Dimensions:ds RT_BRKT {: RESULT = new TypeNode( sym.LEFT_BRKT, t, ds, tleft, tright); :} ; Dimensions ::= | Integer:i {: RESULT = new TreeNodeList(i, null); :} | Integer:i COMMA Dimensions:ds {: RESULT = new TreeNodeList(i, ds); :} ; StructType ::= StructHeader:s LEFT_BRACE Fields:fs RT_BRACE {: RESULT = new TypeNode(sym.LEFT_BRACE, fs, sleft, sright); RESULT.symtab = parser.symtab; parser.symtab = parser.symtab.ascend(); :} ; StructHeader ::= STRUCT {: parser.enterBlock("struct"); :} ; Fields ::= Field:f SEMI {: RESULT = new TreeNodeList(f, null); :} | Field:f SEMI Fields:fs {: RESULT = new TreeNodeList(f, fs); :} ; Field ::= DataDeclaration:dd {: RESULT = dd; :} ; FunctionDeclaration ::= FunctionHeader:fh LEFT_PAREN Formals:fs RT_PAREN FunctionBlock:b {: RESULT = fh; fh.child3 = fs; fh.child4 = b; parser.entry.formals = fs; parser.entry.body = b; parser.symtab = parser.symtab.ascend(); :} ; FunctionHeader ::= Type:t Identifier:i {: RESULT = new TreeNode4(sym.LEFT_PAREN, t, i, null, null, tleft, tright); parser.symtab = parser.symtab.newLevel(parser.entry = new FunctionEntry((String) i.value, t, null, null, null), parser.FUNC_SYMTAB_SIZE); :} ; FunctionBlock ::= LEFT_BRACE:l RT_BRACE {: RESULT = new TreeNode2(sym.LEFT_BRACE, null, null, lleft, lright); :} | LEFT_BRACE:l Statements:ss RT_BRACE {: RESULT = new TreeNode2(sym.LEFT_BRACE, null, ss, lleft, lright); :} | LEFT_BRACE:l DataDeclarations:dds Statements:ss RT_BRACE {: RESULT = new TreeNode2(sym.LEFT_BRACE, dds, ss, lleft, lright); :} ; Formals ::= | FormalDeclaration:fd {: RESULT = new TreeNodeList(fd, null); :} | FormalDeclaration:fd COMMA Formals:fs {: RESULT = new TreeNodeList(fd, fs); :} ; FormalDeclaration ::= Type:t Identifier:i {: RESULT = new TreeNode3(sym.COMMA, t, i, null, tleft, tright); parser.symtab.enter(new VariableEntry( (String) i.value, t, false, 0, parser.symtab.level)); :} | REF:r Type:t Identifier:i {: RESULT = new TreeNode3(sym.COMMA, t, i, new LeafNode(sym.REF, null, rleft, rright), tleft, tright); parser.symtab.enter(new VariableEntry( (String) i.value, t, true, 0, parser.symtab.level)); :} ; Block ::= LEFT_BRACE:l RT_BRACE {: RESULT = new TreeNode2(sym.LEFT_BRACE, null, null, lleft, lright); :} | LEFT_BRACE:l Statements:ss RT_BRACE {: RESULT = new TreeNode2(sym.LEFT_BRACE, null, ss, lleft, lright); :} | BlockHeader:b DataDeclarations:dds Statements:ss RT_BRACE {: RESULT = new TreeNode2(sym.LEFT_BRACE, dds, ss, bleft, bright); parser.symtab = parser.symtab.ascend(); :} ; BlockHeader ::= LEFT_BRACE {: parser.enterBlock("block"); :} ; DataDeclarations ::= DataDeclaration:dd SEMI {: RESULT = new TreeNodeList(dd, null); :} | DataDeclaration:dd SEMI DataDeclarations:dds {: RESULT = new TreeNodeList(dd, dds); :} ; Statements ::= Statement:s {: RESULT = new TreeNodeList(s, null);:} | Statement:s Statements:ss {: RESULT = new TreeNodeList(s, ss); :} ; Statement ::= SEMI:s {: RESULT = new LeafNode(sym.SEMI, null, sleft, sright); :} | Block:b {: RESULT = b; :} | Assignment:a {: RESULT = a; :} | IfStatement:is {: RESULT = is; :} | WhileStatement:ws {: RESULT = ws; :} | CallStatement:cs {: RESULT = cs; :} | ReturnStatement:rs {: RESULT = rs; :} | PrintStatement:ps {: RESULT = ps; :} ; Assignment ::= Designator:d EQ Expression:e SEMI {: RESULT = new TreeNode2(sym.EQ, d, e, dleft, dright); :} ; Designator ::= Identifier:i {: RESULT = i; :} | ArraySelection:as {: RESULT = as; :} | StructSelection:ss {: RESULT = ss; :} ; ArraySelection ::= Designator:d LEFT_BRKT Expressions:es RT_BRKT {: RESULT = new TreeNode2(sym.LEFT_BRKT, d, es, dleft, dright); :} ; StructSelection ::= Designator:d DOT Identifier:i {: RESULT = new TreeNode2(sym.DOT, d, i, dleft, dright); :} ; IfStatement ::= IF:i LEFT_PAREN Expression:e RT_PAREN Statement:s {: RESULT = new TreeNode3(sym.IF, e, s, null, ileft, iright); :} | IF:i LEFT_PAREN Expression:e RT_PAREN Statement:s1 ELSE Statement:s2 {: RESULT = new TreeNode3(sym.IF, e, s1, s2, ileft, iright); :} ; WhileStatement ::= WHILE:w LEFT_PAREN Expression:e RT_PAREN Statement:s {: RESULT = new TreeNode2(sym.WHILE, e, s, wleft, wright); :} ; CallStatement ::= Identifier:i LEFT_PAREN RT_PAREN SEMI {: RESULT = new TreeNode2(sym.LEFT_PAREN, i, null, ileft, iright); :} | Identifier:i LEFT_PAREN Expressions:es RT_PAREN SEMI {: RESULT = new TreeNode2(sym.LEFT_PAREN, i, es, ileft, iright); :} ; ReturnStatement ::= RETURN:r Expression:e SEMI {: RESULT = new TreeNode1(sym.RETURN, e, rleft, rright); :} ; PrintStatement ::= PRINT:p Expressions:es SEMI {: RESULT = new TreeNode1(sym.PRINT, es, pleft, pright); :} ; Expression ::= Expression:e1 OR:op Expression:e2 {: RESULT = new TreeNode2(sym.OR, e1, e2, opleft, opright); :} | Expression:e1 AND:op Expression:e2 {: RESULT = new TreeNode2(sym.AND, e1, e2, opleft, opright); :} | Expression:e1 RelationalOp:op Expression:e2 {: RESULT = op; op.child1 = e1; op.child2 = e2; :} %prec LESS | Expression:e1 AdditiveOp:op Expression:e2 {: RESULT = op; op.child1 = e1; op.child2 = e2; :} %prec PLUS | Expression:e1 MultiplicativeOp:op Expression:e2 {: RESULT = op; op.child1 = e1; op.child2 = e2; :} %prec TIMES | UnaryOp:op Expression:e {: RESULT = op; op.child = e; :} %prec UNY_MINUS | Identifier:i LEFT_PAREN RT_PAREN {: RESULT = new TreeNode2(sym.RT_PAREN, i, null, ileft, iright); :} | Identifier:i LEFT_PAREN Expressions:es RT_PAREN {: RESULT = new TreeNode2(sym.RT_PAREN, i, es, ileft, iright); :} | Designator:d {: RESULT = d; :} %prec DOT | Literal:l {: RESULT = l; :} | LEFT_PAREN Expression:e RT_PAREN {: RESULT = e; :} ; RelationalOp ::= LESS:op {: RESULT = new TreeNode2(sym.LESS, null, null, opleft, opright); :} | LESS_EQ:op {: RESULT = new TreeNode2(sym.LESS_EQ, null, null, opleft, opright); :} | GTR:op {: RESULT = new TreeNode2(sym.GTR, null, null, opleft, opright); :} | GTR_EQ:op {: RESULT = new TreeNode2(sym.GTR_EQ, null, null, opleft, opright); :} | EQ_EQ:op {: RESULT = new TreeNode2(sym.EQ_EQ, null, null, opleft, opright); :} | NOT_EQ:op {: RESULT = new TreeNode2(sym.NOT_EQ, null, null, opleft, opright); :} ; AdditiveOp ::= PLUS:op {: RESULT = new TreeNode2(sym.PLUS, null, null, opleft, opright); :} | MINUS:op {: RESULT = new TreeNode2(sym.MINUS, null, null, opleft, opright); :} ; MultiplicativeOp ::= TIMES:op {: RESULT = new TreeNode2(sym.TIMES, null, null, opleft, opright); :} | DIVIDE:op {: RESULT = new TreeNode2(sym.DIVIDE, null, null, opleft, opright); :} ; UnaryOp ::= UNY_PLUS:op {: RESULT = new TreeNode1(sym.UNY_PLUS, null, opleft, opright); :} | UNY_MINUS:op {: RESULT = new TreeNode1(sym.UNY_MINUS, null, opleft, opright); :} | NOT:op {: RESULT = new TreeNode1(sym.NOT, null, opleft, opright); :} ; Expressions ::= Expression:e {: RESULT = new TreeNodeList(e, null); :} | Expression:e COMMA Expressions:es {: RESULT = new TreeNodeList(e, es); :} ; Identifiers ::= Identifier:i {: RESULT = new TreeNodeList(i, null); :} | Identifier:i COMMA Identifiers:is {: RESULT = new TreeNodeList(i, is); :} ; Literal ::= Integer:i {: RESULT = i; :} | Float:f {: RESULT = f; :} | String:s {: RESULT = s; :} | Boolean:b {: RESULT = b; :} ; Identifier ::= IDENT:i {: RESULT = new LeafNode(sym.IDENT, i, ileft, iright); :} ; Integer ::= INTEGER:i {: RESULT = new LeafNode(sym.INTEGER, i, ileft, iright); :} ; Float ::= FLOATING_PT:fp {: RESULT = new LeafNode(sym.FLOATING_PT, fp, fpleft, fpright); :} ; String ::= STRING_LIT:sl {: RESULT = new LeafNode(sym.STRING_LIT, sl, slleft, slright); :} ; Boolean ::= TRUE:t {: RESULT = new LeafNode(sym.IDENT, null, tleft, tright); :} | FALSE:f {: RESULT = new LeafNode(sym.IDENT, null, fleft, fright); :} ;