/* * espresso.y * Parser source code file (bison input file) * */ %{ #include #include "StringTab.h" #include "printToken.h" #include "ast.h" /* Note: the base class for the AST nodes (called TreeNode) initializes its local linenum field from this global variable. Thus it doesn't need to be explicitly passed to all the node constructors */ extern int linenum; StringTab stringtab; void yyerror(char *s); /* defined below; called for each parse error */ extern int yylex(); extern void initLexer(); /************************************************************************/ /* DONT CHANGE ANYTHING IN THIS SECTION */ Program *ast; /* save the root of the AST we build */ %} /* A union of all the types that can be the result of parsing actions. */ %union { int intLiteral; bool boolLiteral; Symbol * id; char * errorMsg; Program *program; ClassList *classList; Class *class_; MemberList *memberList; Member *member; FormalList *formalList; Formal *formal; LocalList *localList; Local *local; Expr *expr; ExprList *exprList; StmtList *stmtList; Stmt *stmt; } /* The terminals. A few of them have types. If the lexical analyzer returns ERROR, it will trigger a parse error. We don't use ERROR in any of our rules below. Note: for "true" or "false" we return BOOL_LITERAL, with an associated value in the boolLiteral field. */ %token BOOLEAN CLASS ELSE IF INT MAIN NEW NULLTOK OUT PRINTLN PUBLIC %token RETURN STATIC THIS VOID WHILE STRING SYSTEM %token INT_LITERAL %token BOOL_LITERAL %token ID /* the following tokens are for two-character lexemes that use punctuation symbols. For single-char punctuation, we just return the char itself as the token from the lexer */ %token EQUALS NOTEQUALS AND /* to be returned if there is a lexical error */ %token ERROR /* END of DO-NOT-CHANGE SECTION */ /************************************************************************/ /* Add precedence decls here. */ /* they go from low to high */ /* Types for the nonterminals. You will be adding more nonterminals * The part in parens indicates the type of its semantic value * by giving the field name from the %union above */ %type program %type mainClass %type mainMethod /* dummy*List are just place-holders; please change the name of these * non-terminal when you write the real grammar */ %type dummyClassList %type dummyLocalList %type dummyStmtList %% /* save the root of the tree in a global variable */ program : mainClass dummyClassList { ast = new Program($1, $2); } ; mainClass: CLASS ID '{' mainMethod '}' { MemberList *ml = new MemberList(); ml->push_back($4); $$ = new Class($2,ml); } ; dummyClassList : /* empty */ { $$ = new ClassList(); } ; dummyLocalList : /* empty */ { $$ = new LocalList(); } ; dummyStmtList : /* empty */ { $$ = new StmtList(); } ; mainMethod: PUBLIC STATIC VOID MAIN '(' STRING '[' ']' ID ')' '{' dummyLocalList dummyStmtList '}' { FormalList *fl = new FormalList(); fl->push_back(new Formal(stringtab.addString("String[]"),$9)); $$ = new MainMethod(fl, $12, $13); } ; %% void initParser() { initLexer(); // You may add code here that will get called before yyparse from test driver // e.g., if you have an Espresso parse error you don't think you should // be getting you can temporarily turn on tracing info by putting in: // yydebug = 1; // (but be sure to take the yydebug stmt out again before submitting) } // prints out the correct token value based on the token type // note: most tokens do not have a value void printTokenValue(ostream &o, int token, YYSTYPE yylval) { switch (token) { case INT_LITERAL: o << yylval.intLiteral; break; case BOOL_LITERAL: o << yylval.boolLiteral; break; case ID: o << yylval.id; break; case ERROR: o << yylval.errorMsg; break; default: ; // has no token value } } /* This function is called automatically when Bison detects a parse error. */ void yyerror(char *s) { cerr << "line " << linenum << ": " << s << " at or near "; printToken(cerr, yychar); cerr << " "; printTokenValue(cerr, yychar, yylval); cerr << endl; }