%{ #include #include #include #include #include #include "node.h" static void yyerror(const char*); int yylex(void); static enum operator addop_to_oper(const char *op); static enum operator mulop_to_oper(const char *op); static enum operator relop_to_oper(const char *op); static enum operator boolop_to_oper(const char *op); extern int lineno; struct node *root_node; %} %start start %token ID NUM INT VOID IF ELSE WHILE FOR RETURN PTR %token DEREF ADDROF NEGATE NOT ADDOP MULOP RELOP BOOLOP ASSIGN %left ASSIGN %left BOOLOP %left RELOP %left ADDOP %left MULOP %left NOT NEGATE DEREF ADDROF %type ID NUM ADDOP MULOP RELOP BOOLOP %type toplevel toplevel_decl var_decl func_decl parameter_list parameter_list_rest %type parameter block statement statement_list open_statement matched_statement %type other_statement expression atom_expr expression_list %type type INT VOID %union { char *id; struct node *node; struct type *type; } %destructor { free($$); } %destructor { node_delete_recursive($$); } %% start: toplevel { root_node = $1; } ; toplevel: toplevel_decl toplevel { $$ = node_make_2(N_LIST, $1, $2); } | toplevel_decl { $$ = $1; } ; toplevel_decl: var_decl | func_decl ; var_decl: type ID ASSIGN expression ';' { $$ = node_make_1(N_VAR_DECL_INIT, $4); $$->rtype = $1; $$->name = $2; } | type ID ';' { $$ = node_make_0(N_VAR_DECL); $$->rtype = $1; $$->name = $2; } ; func_decl: type ID '(' parameter_list ')' block { $$ = node_make_2(N_FUNC_DECL, $4, $6); $$->rtype = $1; $$->name = $2; } ; type: type PTR { $$ = type_ptr($1); } | INT { $$ = type_int(16); } | VOID { $$ = type_void(); } ; parameter_list: { $$ = node_make_0(N_LIST_END); } | parameter parameter_list_rest { $$ = node_make_2(N_LIST, $1, $2); } ; parameter_list_rest: { $$ = node_make_0(N_LIST_END); } | ',' parameter parameter_list_rest { $$ = node_make_2(N_LIST, $2, $3); } ; parameter: type ID { $$ = node_make_0(N_VAR_DECL); $$->rtype = $1; $$->name = $2; } ; block: '{' statement_list '}' { $$ = node_make_1(N_BLOCK, $2); } ; statement_list: statement { $$ = node_make_2(N_LIST, $1, node_make_0(N_LIST_END)); } | statement statement_list { $$ = node_make_2(N_LIST, $1, $2); } ; statement: open_statement | matched_statement ; open_statement: IF '(' expression ')' statement { $$ = node_make_3(N_IF, $3, $5, node_make_0(N_LIST_END)); } | IF '(' expression ')' matched_statement ELSE open_statement { $$ = node_make_3(N_IF, $3, $5, $7); } | WHILE '(' expression ')' open_statement { $$ = node_make_2(N_WHILE, $3, $5); } /*| FOR '(' statement ';' expression ';' statement ')' open_statement { $$ = node_make_1(N_BLOCK, node_make_list( $3, node_make_2(N_WHILE, $5, node_make_list($9, $7)))); }*/ ; matched_statement: IF '(' expression ')' matched_statement ELSE matched_statement { $$ = node_make_3(N_IF, $3, $5, $7); } | WHILE '(' expression ')' matched_statement { $$ = node_make_2(N_WHILE, $3, $5); } /*| FOR '(' statement ';' expression ';' statement ')' matched_statement { $$ = node_make_1(N_BLOCK, node_make_list( $3, node_make_2(N_WHILE, $5, node_make_list($9, $7)))); }*/ | other_statement ; other_statement: var_decl | expression ';' | block | RETURN ';' { $$ = node_make_0(N_RETURN); } | RETURN expression ';' { $$ = node_make_1(N_RETURNV, $2); } ; expression: atom_expr | NOT expression { $$ = node_make_1(N_UNOP, $2); $$->oper = OP_NOT; } | NEGATE expression { $$ = node_make_1(N_UNOP, $2); $$->oper = OP_NEG; } | DEREF expression { $$ = node_make_1(N_UNOP, $2); $$->oper = OP_DEREF; } | ADDROF expression { $$ = node_make_1(N_UNOP, $2); $$->oper = OP_ADDROF; } | expression ADDOP expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = addop_to_oper($2); free($2); } | expression MULOP expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = mulop_to_oper($2); free($2); } | expression RELOP expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = relop_to_oper($2); free($2); } | expression BOOLOP expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = boolop_to_oper($2); free($2); } | atom_expr ASSIGN expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = OP_ASSIGN; } ; atom_expr: NUM { $$ = node_make_0(N_NUM); $$->value = strtol($1, NULL, 10); free($1); } | ID { $$ = node_make_0(N_VAR); $$->name = $1; } | '(' expression ')' { $$ = $2; } | ID '(' expression_list ')' { $$ = node_make_1(N_CALL, $3); $$->name = $1; } | atom_expr '[' expression ']' { $$ = node_make_1(N_UNOP, node_make_2(N_BINOP, $1, $3)); $$->child2->oper = OP_ADD; $$->oper = OP_DEREF; } ; expression_list: expression { $$ = node_make_2(N_LIST, $1, node_make_0(N_LIST_END)); } | expression ',' expression_list { $$ = node_make_2(N_LIST, $1, $3); } ; %% static void yyerror(const char *s) { fprintf(stderr, "Parse error: %s\n", s); exit(1); } static enum operator addop_to_oper(const char *op) { if (strcmp(op, "+") == 0) return OP_ADD; else if (strcmp(op, "-") == 0) return OP_SUB; else assert(false); } static enum operator mulop_to_oper(const char *op) { if (strcmp(op, "*") == 0) return OP_MUL; else if (strcmp(op, "/") == 0) return OP_DIV; else if (strcmp(op, "%") == 0) return OP_MOD; else assert(false); } static enum operator relop_to_oper(const char *op) { if (strcmp(op, "==") == 0) return OP_EQ; else if (strcmp(op, "!=") == 0) return OP_NEQ; else if (strcmp(op, "<") == 0) return OP_LT; else if (strcmp(op, ">") == 0) return OP_GT; else if (strcmp(op, "<=") == 0) return OP_LEQ; else if (strcmp(op, ">=") == 0) return OP_GEQ; else assert(false); } static enum operator boolop_to_oper(const char *op) { if (strcmp(op, "&&") == 0) return OP_AND; else if (strcmp(op, "||") == 0) return OP_OR; else assert(false); } /* vim:et:ts=4:sw=4 */