/**** * * This file defines a simple tree-generating parser for a subset of the Pascal * programming language, with the following features: * * -- declarations for variables, types, and procedures * -- built-in types for identifiers and 1-dimensional arrays * -- statements for assignment, if-then-else, and procedure call * -- expressions for arithmetic, boolean relations, array reference, and * function call * * Semantic action methods are defined in the companion files Tree*.java. * */ 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; } public SymbolTable symtab; public FunctionEntry entry; public final int PROC_SYMTAB_SIZE = 25; public void enterVars(TreeNodeList vars, TreeNode type) { 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)); if (rest == null) { done = true; } else { node = rest.node; rest = rest.siblings; } } } public void enterFormals(TreeNodeList formals) { TreeNode2 node; TreeNodeList rest; boolean done = false; if (formals == null) return; for (node = (TreeNode2)formals.node, rest = formals.siblings; !done; ) { symtab.enter(new VariableEntry( (String) (((LeafNode) node.child1).value), node.child2, false, 0)); if (rest == null) { done = true; } else { node = (TreeNode2) rest.node; rest = rest.siblings; } } } :} /*-* * SYMBOL DEFINITIONS */ /*-* Terminal symbols */ terminal AND; terminal ARRAY; terminal BEGIN; terminal ELSE; terminal END; terminal IF; terminal NOT; terminal OF; terminal OR; terminal PROGRAM; terminal PROCEDURE; terminal THEN; terminal TYPE; terminal VAR; terminal TIMES; terminal PLUS; terminal MINUS; terminal DIVIDE; terminal UNY_PLUS; terminal UNY_MINUS; terminal SEMI; terminal COMMA; terminal LEFT_PAREN; terminal RT_PAREN; terminal LEFT_BRKT; terminal RT_BRKT; terminal EQ; terminal GTR; terminal LESS; terminal LESS_EQ; terminal GTR_EQ; terminal NOT_EQ; terminal COLON; terminal ASSMNT; terminal DOT; terminal IDENT; terminal INT; terminal REAL; terminal CHAR; /*-* Non-non terminal symbols **/ nonterminal TreeNode program; nonterminal TreeNode block; nonterminal TreeNodeList decls; nonterminal TreeNode decl; nonterminal TreeNode typedecl; nonterminal TreeNode vardecl; nonterminal TreeNode procdecl; nonterminal TreeNode type; nonterminal TreeNode identtype; nonterminal TreeNode arraytype; nonterminal TreeNodeList vars; nonterminal TreeNode var; nonterminal LeafNode identifier; nonterminal TreeNode prochdr; nonterminal TreeNodeList formals; nonterminal TreeNode formal; nonterminal TreeNodeList stmts; nonterminal TreeNode stmt; nonterminal TreeNode assmntstmt; nonterminal TreeNode designator; nonterminal TreeNode ifstmt; nonterminal TreeNode proccallstmt; nonterminal TreeNode compoundstmt; nonterminal TreeNodeList exprlist; nonterminal TreeNode expr; nonterminal TreeNode2 relop; nonterminal TreeNode2 addop; nonterminal TreeNode2 multop; nonterminal TreeNode1 unyop; nonterminal TreeNode real; nonterminal TreeNode integer; nonterminal TreeNode character; /*-* Operator Precedences **/ precedence right ASSMNT; precedence left EQ, LESS, GTR, LESS_EQ, GTR_EQ, NOT_EQ; /* RelOperator */ precedence left PLUS, MINUS, OR; /* AddOperator */ precedence left TIMES, DIVIDE, AND; /* MultOperator */ /*-* * GRAMMAR RULES */ program ::= PROGRAM block:b DOT {: RESULT = new TreeNode1(sym.PROGRAM, b); :} ; block ::= decls:d BEGIN stmts:s END {: RESULT = new TreeNode2(sym.BEGIN, d, s); :} ; decls ::= /* empty */ {: RESULT = null; :} | decl:d {: RESULT = new TreeNodeList(d, null); :} | decl:d SEMI decls:ds {: RESULT = new TreeNodeList(d, ds); :} ; decl ::= typedecl:td {: RESULT = td; :} | vardecl:vd {: RESULT = vd; :} | procdecl:pd {: RESULT = pd; :} ; typedecl ::= TYPE identifier:i EQ type:t {: RESULT = new TreeNode2(sym.TYPE, i, t); :} ; type ::= identtype:it {: RESULT = it; :} | arraytype:at {: RESULT = at; :} ; identtype ::= identifier:i {: RESULT = new TreeNode1(sym.IDENT, i); :} ; arraytype ::= ARRAY LEFT_BRKT integer:i RT_BRKT OF type:t {: RESULT = new TreeNode2(sym.ARRAY, i, t); :} ; vardecl ::= VAR vars:vs COLON type:t {: RESULT = new TreeNode2(sym.VAR, vs, t); parser.enterVars(vs, t); :} ; vars ::= var:v {: RESULT = new TreeNodeList(v, null); :} | var:v COMMA vars:vs {: RESULT = new TreeNodeList(v, vs); :} ; var ::= identifier:i {: RESULT = i; :} ; procdecl ::= prochdr:ph SEMI block:b {: RESULT = ph; ((TreeNode4) RESULT).child4 = b; parser.entry.body = b; parser.symtab = parser.symtab.ascend(); :} ; prochdr ::= PROCEDURE identifier:i LEFT_PAREN formals:fs RT_PAREN {: RESULT = new TreeNode4(sym.PROCEDURE, i, fs, null, null); // NOTE: the parent procdecl rule sets child4 to the // procedure block parser.symtab = parser.symtab.newLevel(parser.entry = new FunctionEntry((String) i.value, null, fs, null, null), parser.PROC_SYMTAB_SIZE); parser.enterFormals(fs); :} | PROCEDURE identifier:i LEFT_PAREN formals:fs RT_PAREN COLON identtype:it {: RESULT = new TreeNode4(sym.PROCEDURE, i, fs, it, null); parser.symtab = parser.symtab.newLevel(parser.entry = new FunctionEntry((String) i.value, it, fs, null, null), parser.PROC_SYMTAB_SIZE); parser.enterFormals(fs); :} ; formals ::= /* empty */ {: RESULT = null; :} | formal:f {: RESULT = new TreeNodeList(f, null); :} | formal:f SEMI formals:fs {: RESULT = new TreeNodeList(f, fs); :} ; formal ::= var:v COLON identtype:it {: RESULT = new TreeNode2(sym.COLON, v, it); :} ; stmts ::= stmt:s {: RESULT = new TreeNodeList(s, null); :} | stmt:s SEMI stmts:ss {: RESULT = new TreeNodeList(s, ss); :} ; stmt ::= /* empty */ {: RESULT = new LeafNode(0, null); :} | assmntstmt:as {: RESULT = as; :} | ifstmt:is {: RESULT = is; :} | proccallstmt:ps {: RESULT = ps; :} | compoundstmt:cs {: RESULT = cs; :} ; assmntstmt ::= designator:d ASSMNT expr:e {: RESULT = new TreeNode2(sym.ASSMNT, d, e); :} ; ifstmt ::= IF expr:e THEN stmt:s {: RESULT = new TreeNode3(sym.IF, e, s, null); :} | IF expr:e THEN stmt:s1 ELSE stmt:s2 {: RESULT = new TreeNode3(sym.IF, e, s1, s2); :} ; proccallstmt ::= identifier:i LEFT_PAREN exprlist:el RT_PAREN {: RESULT = new TreeNode2(sym.PROCEDURE, i, el); :} ; compoundstmt ::= BEGIN stmts:ss END {: RESULT = ss; :} ; expr ::= integer:i {: RESULT = i; :} | real:r {: RESULT = r; :} | character:c {: RESULT = c; :} | designator:d {: RESULT = d; :} | var:v LEFT_PAREN exprlist:el RT_PAREN {: RESULT = new TreeNode2(sym.PROCEDURE, v, el); :} | expr:e1 relop:op expr:e2 {: RESULT = op; op.child1 = e1; op.child2 = e2; :} %prec EQ | expr:e1 addop:op expr:e2 {: RESULT = op; op.child1 = e1; op.child2 = e2; :} %prec PLUS | expr:e1 multop:op expr:e2 {: RESULT = op; op.child1 = e1; op.child2 = e2; :} %prec TIMES | unyop:op expr:e {: RESULT = op; op.child = e; :} %prec NOT | LEFT_PAREN expr:e RT_PAREN {: RESULT = e; :} ; designator ::= var:v {: RESULT = v; :} | designator:d LEFT_BRKT expr:e RT_BRKT {: RESULT = new TreeNode2(sym.LEFT_BRKT, d, e); :} ; exprlist ::= expr:e {: RESULT = new TreeNodeList(e, null); :} | expr:e COMMA exprlist:el {: RESULT = new TreeNodeList(e, el); :} ; relop ::= LESS {: RESULT = new TreeNode2(sym.LESS, null, null); :} // NOTE: the parent expr rule sets child1 and child2 // to the operand values | GTR {: RESULT = new TreeNode2(sym.GTR, null, null); :} | EQ {: RESULT = new TreeNode2(sym.EQ, null, null); :} | LESS_EQ {: RESULT = new TreeNode2(sym.LESS, null, null); :} | GTR_EQ {: RESULT = new TreeNode2(sym.GTR, null, null); :} | NOT_EQ {: RESULT = new TreeNode2(sym.NOT, null, null); :} ; addop ::= PLUS {: RESULT = new TreeNode2(sym.PLUS, null, null); :} | MINUS {: RESULT = new TreeNode2(sym.MINUS, null, null); :} | OR {: RESULT = new TreeNode2(sym.OR, null, null); :} ; multop ::= TIMES {: RESULT = new TreeNode2(sym.TIMES, null, null); :} | DIVIDE {: RESULT = new TreeNode2(sym.DIVIDE, null, null); :} | AND {: RESULT = new TreeNode2(sym.AND, null, null); :} ; unyop ::= PLUS {: RESULT = new TreeNode1(sym.UNY_PLUS, null); :} | MINUS {: RESULT = new TreeNode1(sym.UNY_MINUS, null); :} | NOT {: RESULT = new TreeNode1(sym.NOT, null); :} ; identifier ::= IDENT:i {: RESULT = new LeafNode(sym.IDENT, i); :} ; real ::= REAL:r {: RESULT = new LeafNode(sym.REAL, r); :} ; integer ::= INT:i {: RESULT = new LeafNode(sym.INT, i); :} ; character ::= CHAR:c {: RESULT = new LeafNode(sym.CHAR, c); :} ;