diff options
Diffstat (limited to 'c.y')
-rw-r--r-- | c.y | 248 |
1 files changed, 248 insertions, 0 deletions
@@ -0,0 +1,248 @@ +%{ + +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#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> ID NUM ADDOP MULOP RELOP BOOLOP +%type <node> toplevel toplevel_decl var_decl func_decl parameter_list parameter block +%type <node> statement statement_list open_statement matched_statement other_statement +%type <node> expression atom_expr expression_list +%type <type> type INT VOID + +%union { + char *id; + struct node *node; + struct type *type; +} + +%destructor { free($$); } <id> +%destructor { node_delete_recursive($$); } <node> + +%% + +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: parameter { + $$ = node_make_2(N_LIST, $1, node_make_0(N_LIST_END)); + } + | parameter ',' parameter_list { + $$ = node_make_2(N_LIST, $1, $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 expression ';' { + $$ = node_make_1(N_RETURN, $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 +*/ |