zmap-freebsd/filter_sandbox/parser.y

348 lines
13 KiB
Plaintext

/* 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 <iostream>
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<Decl*> *declList;
Stmt *stmt;
List<Stmt*> *stmtList;
List<VarDecl*> *varDeclList;
List<Case*> *caseList;
Expr *expr;
Type *type;
List<Expr*> *exprList;
List<NamedType*> *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 <identifier> T_Identifier
%token <stringConstant> T_StringConstant
%token <integerConstant> T_IntConstant
%token <doubleConstant> T_DoubleConstant
%token <boolConstant> 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<Decl*>.
* pp2: You'll need to add many of these of your own.
*/
%type <declList> DeclList
%type <varDeclList> VarDeclList
%type <varDeclList> Formals
%type <decl> Decl
%type <decl> FnDecl
%type <varDecl> VarDecl
%type <varDecl> Variable
%type <stmt> Stmt
%type <stmt> WhileStmt
%type <stmt> IfStmt
%type <stmt> ForStmt
%type <stmt> BreakStmt
%type <stmt> ReturnStmt
%type <stmt> PrintStmt
%type <stmt> StmtBlock
%type <stmtList> StmtList
%type <expr> Expr
%type <expr> EmptyExpr
%type <type> Type
%type <decl> Field
%type <declList> FieldList
%type <decl> ClassDecl
%type <decl> InterfaceDecl
%type <typeList> InterfaceList
%type <decl> Prototype
%type <declList> PrototypeList
%type <exprList> ExprList
%type <exprList> Actuals
%type <expr> LValue
%type <expr> Constant
%type <expr> Call
%type <stmt> SwitchStmt
%type <caseList> CaseList
%type <caseNode> Case
%type <defaultNode> 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<Decl*>)->Append($1); }
;
Decl : VarDecl { $$ = $1; }
| FnDecl {$$ = $1;}
| ClassDecl {$$ = $1;}
| InterfaceDecl {$$ = $1;}
;
VarDeclList : VarDeclList VarDecl { ($$=$1)->Append($2); }
| VarDecl { ($$ = new List<VarDecl*>)->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<NamedType*>, $4);}
| T_Class T_Identifier T_Extends T_Identifier '{' FieldList '}' {$$ = new ClassDecl(new Identifier(@2, $2), new NamedType(new Identifier(@4, $4)), new List<NamedType*>, $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<NamedType*>)->Append(new NamedType(new Identifier(@1, $1)));}
FieldList : FieldList Field {($$ = $1)->Append($2);}
| /* empty */ {$$ = new List<Decl*>;}
;
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<VarDecl*>)->Append($1);}
| Formals ',' Variable {($$ = $1)->Append($3);}
| {$$ = new List<VarDecl*>;}
;
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<Decl*>;}
;
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<Stmt*>);}
| '{' StmtList '}' { $$ = new StmtBlock(new List<VarDecl*>, $2);}
| '{' '}' { $$ = new StmtBlock(new List<VarDecl*>, new List<Stmt*>);}
;
StmtList : StmtList Stmt { ($$=$1)->Append($2);}
| Stmt { ($$ = new List<Stmt*>)->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<Case*>)->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<Stmt*>);};
Default : T_Default ':' StmtList {$$ = new Default($3);}
| T_Default ':' {$$ = new Default(new List<Stmt*>);};
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<Expr*>)->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<Expr*>;}
;
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;
}