%{ #include #include #include #include #include "syntax_tree.h" // external functions from lex extern int yylex(); extern int yyparse(); extern int yyrestart(); extern FILE * yyin; // external variables from lexical_analyzer module extern int lines; extern char *yytext; extern int pos_end; extern int pos_start; // Global syntax tree syntax_tree *gt; // Error reporting void yyerror(const char *s); // Helper functions written for you with love syntax_tree_node *node(const char *node_name, int children_num, ...); %} /* TODO: Complete this definition. Hint: See pass_node(), node(), and syntax_tree.h. Use forward declaring. */ %union { struct _syntax_tree_node *node; } /* TODO: Your tokens here. */ /* alias: - SPEC: SPECIFIER - DEC:DECLARATION - COM: COMPOUND - STMT: STATEMENT - EXPR: EXPRESSION - ITER: ITERATION - SELC: SELCTION - RET: RETURN - Tokens starting with '_' is the terminator */ %token ERROR %type TYPE_SPEC RELOP ADDOP MULOP %type DEC_LIST DEC VAR_DEC FUN_DEC LOCAL_DEC %type COM_STMT STMT_LIST STMT EXPR_STMT ITER_STMT SELC_STMT RET_STMT %type EXPR SIMPLE_EXPR VAR ADD_EXPR TERM FACTOR INTEGER FLOAT CALL %type PARAM PARAMS PARAM_LIST ARGS ARG_LIST /* These are for flex to return NOTE: Though combining _LE _LT _BT _BE _EQ _NEQ to _RELOP makes the program simpler, it may not satisfy the subsequent requirements. */ %token _IF _ELSE _WHILE _RETURN _INT _FLOAT _VOID %token _ASSIGN _RELOP _ADD_OP _MUL_OP %token _L_SQUARE _R_SQUARE _L_PARE _R_PARE _L_BRACKET _R_BRACKET %token _SEMI _COMMA _ID _INTEGER _FLOATPOINT %type program %start program /* TODO: Your rules here. */ %% program: DEC_LIST {$$ = node("program", 1, $1); gt->root = $$;} ; DEC_LIST: DEC_LIST DEC {$$ = node("declaration-list", 2, $1, $2); } | DEC {$$ = node("declaration-list", 1, $1);} ; DEC: VAR_DEC {$$ = node("declaration", 1, $1); } | FUN_DEC {$$ = node("declaration", 1, $1); } ; VAR_DEC: TYPE_SPEC _ID _SEMI {$$ = node("var-declaration", 3, $1, $2, $3); } | TYPE_SPEC _ID _L_SQUARE _INTEGER _R_SQUARE _SEMI {$$ = node("var-declaration", 6, $1, $2, $3, $4, $5, $6); } ; TYPE_SPEC: _INT {$$ = node("type-specifier", 1, $1); } | _FLOAT {$$ = node("type-specifier", 1, $1); } | _VOID {$$ = node("type-specifier", 1, $1); } ; FUN_DEC: TYPE_SPEC _ID _L_PARE PARAMS _R_PARE COM_STMT {$$ = node("fun-declaration", 6, $1, $2, $3, $4, $5, $6); } ; PARAMS: PARAM_LIST {$$ = node("params", 1, $1); } | _VOID {$$ = node("params", 1, $1); } ; PARAM_LIST: PARAM_LIST _COMMA PARAM {$$ = node("param-list", 3, $1, $2, $3); } | PARAM {$$ = node("param-list", 1, $1); } ; PARAM: TYPE_SPEC _ID {$$ = node("param", 2, $1, $2); } | TYPE_SPEC _ID _L_SQUARE _R_SQUARE {$$ = node("param", 4, $1, $2, $3, $4);} ; COM_STMT: _L_BRACKET LOCAL_DEC STMT_LIST _R_BRACKET {$$ = node("compound-stmt", 4, $1, $2, $3, $4);} ; LOCAL_DEC: LOCAL_DEC VAR_DEC {$$ = node("local-declarations", 2, $1, $2);} | {$$ = node("local-declarations", 0);} ; STMT_LIST: STMT_LIST STMT {$$ = node("statement-list", 2, $1, $2);} | {$$ = node("statement-list", 0);} ; STMT: EXPR_STMT {$$ = node("statement", 1, $1);} | COM_STMT {$$ = node("statement", 1, $1);} | SELC_STMT {$$ = node("statement", 1, $1);} | ITER_STMT {$$ = node("statement", 1, $1);} | RET_STMT {$$ = node("statement", 1, $1);} ; EXPR_STMT: EXPR _SEMI {$$ = node("expression-stmt", 2, $1, $2);} | _SEMI {$$ = node("expression-stmt", 1, $1);} ; SELC_STMT: _IF _L_PARE EXPR _R_PARE STMT {$$ = node("selection-stmt", 5, $1, $2, $3, $4, $5);} | _IF _L_PARE EXPR _R_PARE STMT _ELSE STMT {$$ = node("selection-stmt", 7, $1, $2, $3, $4, $5, $6, $7);} ; ITER_STMT: _WHILE _L_PARE EXPR _R_PARE STMT {$$ = node("iteration-stmt", 5, $1, $2, $3, $4, $5);} ; RET_STMT: _RETURN _SEMI {$$ = node("return-stmt", 2, $1, $2);} | _RETURN EXPR _SEMI {$$ = node("return-stmt", 3, $1, $2, $3);} ; EXPR: VAR _ASSIGN EXPR {$$ = node("expression", 3, $1, $2, $3);} | SIMPLE_EXPR {$$ = node("expression", 1, $1);} ; VAR: _ID {$$ = node("var", 1, $1);} | _ID _L_SQUARE EXPR _R_SQUARE {$$ = node("var", 4, $1, $2, $3, $4);} ; SIMPLE_EXPR: ADD_EXPR RELOP ADD_EXPR {$$ = node("simple-expression", 3, $1, $2, $3);} | ADD_EXPR {$$ = node("simple-expression", 1, $1);} ; RELOP: _RELOP {$$ = node("relop", 1, $1);} ; /* RELOP: _LE {$$ = node("relop", 1, $1);} | _LT {$$ = node("relop", 1, $1);} | _GT {$$ = node("relop", 1, $1);} | _GE {$$ = node("relop", 1, $1);} | _EQ {$$ = node("relop", 1, $1);} | _NEQ {$$ = node("relop", 1, $1);} ; */ ADD_EXPR: ADD_EXPR ADDOP TERM {$$ = node("additive-expression", 3, $1, $2, $3);} | TERM {$$ = node("additive-expression", 1, $1);} ; ADDOP: _ADD_OP {$$ = node("addop", 1, $1);} ; TERM: TERM MULOP FACTOR {$$ = node("term", 3, $1, $2, $3);} | FACTOR {$$ = node("term", 1, $1);} ; MULOP: _MUL_OP {$$ = node("mulop", 1, $1);} ; FACTOR: _L_PARE EXPR _R_PARE {$$ = node("factor", 3, $1, $2, $3);} | VAR {$$ = node("factor", 1, $1);} | CALL {$$ = node("factor", 1, $1);} | INTEGER {$$ = node("factor", 1, $1);} | FLOAT {$$ = node("factor", 1, $1);} ; INTEGER: _INTEGER {$$ = node("integer", 1, $1);} ; FLOAT: _FLOATPOINT {$$ = node("float", 1, $1);} ; CALL: _ID _L_PARE ARGS _R_PARE {$$ = node("call", 4, $1, $2, $3, $4);} ; ARGS: ARG_LIST {$$ = node("args", 1, $1);} | {$$ = node("args", 0);} ; ARG_LIST: ARG_LIST _COMMA EXPR {$$ = node("arg-list", 3, $1, $2, $3);} | EXPR {$$ = node("arg-list", 1, $1);} ; %% /// The error reporting function. void yyerror(const char * s) { // TO STUDENTS: This is just an example. // You can customize it as you like. fprintf(stderr, "error at line %d column %d: %s\n", lines, pos_start, s); } /// Parse input from file `input_path`, and prints the parsing results /// to stdout. If input_path is NULL, read from stdin. /// /// This function initializes essential states before running yyparse(). syntax_tree *parse(const char *input_path) { if (input_path != NULL) { if (!(yyin = fopen(input_path, "r"))) { fprintf(stderr, "[ERR] Open input file %s failed.\n", input_path); exit(1); } } else { yyin = stdin; } lines = pos_start = pos_end = 1; gt = new_syntax_tree(); yyrestart(yyin); yyparse(); return gt; } /// A helper function to quickly construct a tree node. /// /// e.g. $$ = node("program", 1, $1); syntax_tree_node *node(const char *name, int children_num, ...) { syntax_tree_node *p = new_syntax_tree_node(name); syntax_tree_node *child; if (children_num == 0) { child = new_syntax_tree_node("epsilon"); syntax_tree_add_child(p, child); } else { va_list ap; va_start(ap, children_num); for (int i = 0; i < children_num; ++i) { child = va_arg(ap, syntax_tree_node *); syntax_tree_add_child(p, child); } va_end(ap); } return p; }