/* File: parser.y * -------------- * Yacc input file to generate the parser for the compiler. * * pp2: your job is to write a parser that will construct the parse tree * and if no parse errors were found, print it. The parser should * accept the language as described in specification, and as augmented * in the pp2 handout. */ %{ /* Just like lex, the text within this first region delimited by %{ and %} * is assumed to be C/C++ code and will be copied verbatim to the y.tab.c * file ahead of the definitions of the yyparse() function. Add other header * file inclusions or C++ variable declarations/prototypes that are needed * by your code here. */ #include "scanner.h" // for yylex #include "parser.h" #include "errors.h" #include using namespace std; void yyerror(const char *msg); // standard error-handling routine %} /* The section before the first %% is the Definitions section of the yacc * input file. Here is where you declare tokens and types, add precedence * and associativity options, and so on. */ /* yylval * ------ * Here we define the type of the yylval global variable that is used by * the scanner to store attibute information about the token just scanned * and thus communicate that information to the parser. * * pp2: You will need to add new fields to this union as you add different * attributes to your non-terminal symbols. */ %union { int integerConstant; bool boolConstant; char *stringConstant; double doubleConstant; char identifier[MaxIdentLen+1]; // +1 for terminating null Decl *decl; VarDecl *varDecl; Case *caseNode; Default *defaultNode; List *declList; Stmt *stmt; List *stmtList; List *varDeclList; List *caseList; Expr *expr; Type *type; List *exprList; List *typeList; } /* Tokens * ------ * Here we tell yacc about all the token types that we are using. * Yacc will assign unique numbers to these and export the #define * in the generated y.tab.h header file. */ %token T_Void T_Bool T_Int T_Double T_String T_Class %token T_LessEqual T_GreaterEqual T_Equal T_NotEqual T_Dims %token T_And T_Or T_Null T_Extends T_This T_Interface T_Implements %token T_While T_For T_If T_Else T_Return T_Break %token T_New T_NewArray T_Print T_ReadInteger T_ReadLine %token T_Identifier %token T_StringConstant %token T_IntConstant %token T_DoubleConstant %token T_BoolConstant %token T_Increm T_Decrem T_Switch T_Case T_Default %nonassoc NON_ELSE %nonassoc T_Else %nonassoc '=' %left T_Or %left T_And %left T_Equal T_NotEqual %nonassoc '<' T_LessEqual T_GreaterEqual '>' %left '+' '-' %left '*' '/' '%' %left NEG '!' INCRDECR %left '[' '.' /* Non-terminal types * ------------------ * In order for yacc to assign/access the correct field of $$, $1, we * must to declare which field is appropriate for the non-terminal. * As an example, this first type declaration establishes that the DeclList * non-terminal uses the field named "declList" in the yylval union. This * means that when we are setting $$ for a reduction for DeclList ore reading * $n which corresponds to a DeclList nonterminal we are accessing the field * of the union named "declList" which is of type List. * pp2: You'll need to add many of these of your own. */ %type DeclList %type VarDeclList %type Formals %type Decl %type FnDecl %type VarDecl %type Variable %type Stmt %type WhileStmt %type IfStmt %type ForStmt %type BreakStmt %type ReturnStmt %type PrintStmt %type StmtBlock %type StmtList %type Expr %type EmptyExpr %type Type %type Field %type FieldList %type ClassDecl %type InterfaceDecl %type InterfaceList %type Prototype %type PrototypeList %type ExprList %type Actuals %type LValue %type Constant %type Call %type SwitchStmt %type CaseList %type Case %type Default %% /* Rules * ----- * All productions and actions should be placed between the start and stop * %% markers which delimit the Rules section. */ Program : DeclList { Program *program = new Program($1); // if no errors, advance to next phase if (ReportError::NumErrors() == 0) program->Print(0); } ; DeclList : DeclList Decl { ($$=$1)->Append($2); } | Decl { ($$ = new List)->Append($1); } ; Decl : VarDecl { $$ = $1; } | FnDecl {$$ = $1;} | ClassDecl {$$ = $1;} | InterfaceDecl {$$ = $1;} ; VarDeclList : VarDeclList VarDecl { ($$=$1)->Append($2); } | VarDecl { ($$ = new List)->Append($1); } ; VarDecl : Variable ';' {$$ = $1;}; Variable : Type T_Identifier {$$ = new VarDecl(new Identifier(@2, $2), $1); }; ClassDecl : T_Class T_Identifier '{' FieldList '}' {$$ = new ClassDecl(new Identifier(@2, $2), 0, new List, $4);} | T_Class T_Identifier T_Extends T_Identifier '{' FieldList '}' {$$ = new ClassDecl(new Identifier(@2, $2), new NamedType(new Identifier(@4, $4)), new List, $6);} | T_Class T_Identifier T_Extends T_Identifier T_Implements InterfaceList '{' FieldList '}' {$$ = new ClassDecl(new Identifier(@2, $2), new NamedType(new Identifier(@4, $4)), $6, $8);} | T_Class T_Identifier T_Implements InterfaceList '{' FieldList '}' {$$ = new ClassDecl(new Identifier(@2, $2), 0, $4, $6);} ; InterfaceList: T_Identifier ',' InterfaceList {($$=$3)->Append(new NamedType(new Identifier(@1, $1)));} | T_Identifier {($$=new List)->Append(new NamedType(new Identifier(@1, $1)));} FieldList : FieldList Field {($$ = $1)->Append($2);} | /* empty */ {$$ = new List;} ; Type: T_Int {$$ = Type::intType; } | T_Double {$$ = Type::doubleType; } |T_Bool {$$ = Type::boolType; } |T_String {$$ = Type::stringType; } |T_Identifier {$$ = new NamedType(new Identifier(@1, $1)); } |Type T_Dims {$$ = new ArrayType(@1, $1); } ; FnDecl : Type T_Identifier '(' Formals ')' StmtBlock {$$ = new FnDecl(new Identifier(@2, $2), $1, $4); ((FnDecl *)$$)->SetFunctionBody($6); } | T_Void T_Identifier '(' Formals ')' StmtBlock {$$ = new FnDecl(new Identifier(@2, $2), Type::voidType, $4); ((FnDecl *)$$)->SetFunctionBody($6); } ; Formals : Variable {($$ = new List)->Append($1);} | Formals ',' Variable {($$ = $1)->Append($3);} | {$$ = new List;} ; Field : VarDecl {$$ = $1;} | FnDecl {$$ = $1;} ; InterfaceDecl : T_Interface T_Identifier '{' PrototypeList '}' {$$ = new InterfaceDecl(new Identifier(@2, $2), $4);}; PrototypeList : PrototypeList Prototype {($$=$1)->Append($2);} | {$$ = new List;} ; Prototype : Type T_Identifier '(' Formals ')' ';' {$$ = new FnDecl(new Identifier(@2, $2), $1, $4);} | T_Void T_Identifier '(' Formals ')' ';' {$$ = new FnDecl(new Identifier(@2, $2), Type::voidType, $4);} ; StmtBlock : '{' VarDeclList StmtList '}' { $$ = new StmtBlock($2, $3);} | '{' VarDeclList '}' { $$ = new StmtBlock($2, new List);} | '{' StmtList '}' { $$ = new StmtBlock(new List, $2);} | '{' '}' { $$ = new StmtBlock(new List, new List);} ; StmtList : StmtList Stmt { ($$=$1)->Append($2);} | Stmt { ($$ = new List)->Append($1); } ; Stmt : EmptyExpr ';' {$$ = $1; } | IfStmt {$$ = $1; } | WhileStmt {$$ = $1; } | ForStmt {$$ = $1; } | BreakStmt {$$ = $1; } | ReturnStmt {$$ = $1; } | PrintStmt {$$ = $1; } | StmtBlock {$$ = $1; } | SwitchStmt {$$ = $1; } ; IfStmt : T_If '(' Expr ')' Stmt %prec NON_ELSE {$$ = new IfStmt($3, $5, 0); } | T_If '(' Expr ')' Stmt T_Else Stmt { $$ = new IfStmt($3, $5, $7); } ; SwitchStmt : T_Switch '(' Expr ')' '{' CaseList Default '}' { $$ = new SwitchStmt($3, $6, $7);} | T_Switch '(' Expr ')' '{' CaseList '}' { $$ = new SwitchStmt($3, $6, 0);}; CaseList : CaseList Case {($$ = $1)->Append($2);} | Case {($$ = new List)->Append($1);} ; Case : T_Case T_IntConstant ':' StmtList {$$ = new Case(new IntConstant(@2, $2), $4);} | T_Case T_IntConstant ':' {$$ = new Case(new IntConstant(@2, $2), new List);}; Default : T_Default ':' StmtList {$$ = new Default($3);} | T_Default ':' {$$ = new Default(new List);}; WhileStmt : T_While '(' Expr ')' Stmt {$$ = new WhileStmt($3, $5); } ; ForStmt : T_For '(' EmptyExpr ';' Expr ';' EmptyExpr ')' Stmt {$$ = new ForStmt($3, $5, $7, $9); } ; ReturnStmt : T_Return EmptyExpr ';' { $$ = new ReturnStmt(@1, $2); }; BreakStmt : T_Break ';' {$$ = new BreakStmt(@1); }; PrintStmt : T_Print '(' ExprList ')' ';' {$$ = new PrintStmt($3);}; ExprList : Expr {($$ = new List)->Append($1);} | ExprList ',' Expr {($$ = $1)->Append($3);} ; EmptyExpr : Expr {$$ = $1; } | {$$ = new EmptyExpr; } ; Expr : LValue '=' Expr {$$ = new AssignExpr($1, new Operator(@2, "=") , $3); }; | Constant {$$ = $1;} | LValue {$$ = $1; } | T_This {$$ = new This(@1);} | Call {$$ = $1;} |'(' Expr ')' {$$ = $2;} | Expr '+' Expr {$$ = new ArithmeticExpr($1, new Operator(@2, "+"), $3);} | Expr '-' Expr {$$ = new ArithmeticExpr($1, new Operator(@2, "-"), $3);} | Expr '*' Expr {$$ = new ArithmeticExpr($1, new Operator(@2, "*"), $3);} | Expr '/' Expr {$$ = new ArithmeticExpr($1, new Operator(@2, "/"), $3);} | Expr '%' Expr {$$ = new ArithmeticExpr($1, new Operator(@2, "%"), $3);} | '-' Expr %prec NEG {$$ = new ArithmeticExpr(new Operator(@2, "-"), $2);} | Expr '<' Expr {$$ = new RelationalExpr($1, new Operator(@2, "<"), $3);} | Expr T_LessEqual Expr {$$ = new RelationalExpr($1, new Operator(@2, "<="), $3);} | Expr '>' Expr {$$ = new RelationalExpr($1, new Operator(@2, ">"), $3);} | Expr T_GreaterEqual Expr {$$ = new RelationalExpr($1, new Operator(@2, ">="), $3);} | Expr T_Equal Expr {$$ = new EqualityExpr($1, new Operator(@2, "=="), $3);} | Expr T_NotEqual Expr {$$ = new EqualityExpr($1, new Operator(@2, "!="), $3);} | Expr T_And Expr {$$ = new LogicalExpr($1, new Operator(@2, "&&"), $3);} | Expr T_Or Expr {$$ = new LogicalExpr($1, new Operator(@2, "||"), $3);} | '!' Expr {$$ = new LogicalExpr(new Operator(@1, "!"), $2);} | T_ReadInteger '(' ')' {$$ = new ReadIntegerExpr(@1);} | T_ReadLine '(' ')' {$$ = new ReadLineExpr(@1);} | T_New '(' T_Identifier ')' {$$ = new NewExpr(@1, new NamedType(new Identifier(@3, $3)) );} | T_NewArray '('Expr ',' Type')' {$$ = new NewArrayExpr(@1, $3, $5);} | LValue T_Increm %prec INCRDECR {$$ = new PostfixExpr($1, new Operator(@2, "++"));} | LValue T_Decrem %prec INCRDECR {$$ = new PostfixExpr($1, new Operator(@2, "--"));} ; LValue : T_Identifier {$$ = new FieldAccess(0, new Identifier(@1, $1)); } | Expr '.' T_Identifier {$$ = new FieldAccess($1, new Identifier(@3, $3));} | Expr '[' Expr ']' {$$ = new ArrayAccess(@1, $1, $3);} ; Call : T_Identifier '(' Actuals ')' {$$ = new Call(@1, 0, new Identifier(@1, $1), $3);} | Expr '.' T_Identifier '(' Actuals ')' {$$ = new Call(@1, $1, new Identifier(@3, $3), $5);} ; Actuals: ExprList {$$ = $1;} | {$$ = new List;} ; Constant: T_IntConstant {$$ = new IntConstant(@1, $1);} | T_DoubleConstant {$$ = new DoubleConstant(@1, $1);} | T_BoolConstant {$$ = new BoolConstant(@1, $1);} | T_StringConstant {$$ = new StringConstant(@1, $1);} | T_Null {$$ = new NullConstant(@1); } ; %% /* The closing %% above marks the end of the Rules section and the beginning * of the User Subroutines section. All text from here to the end of the * file is copied verbatim to the end of the generated y.tab.c file. * This section is where you put definitions of helper functions. */ /* Function: InitParser * -------------------- * This function will be called before any calls to yyparse(). It is designed * to give you an opportunity to do anything that must be done to initialize * the parser (set global variables, configure starting state, etc.). One * thing it already does for you is assign the value of the global variable * yydebug that controls whether yacc prints debugging information about * parser actions (shift/reduce) and contents of state stack during parser. * If set to false, no information is printed. Setting it to true will give * you a running trail that might be helpful when debugging your parser. * Please be sure the variable is set to false when submitting your final * version. */ void InitParser() { PrintDebug("parser", "Initializing parser"); yydebug = false; }