From 9911f9a73c7dc46069199e52f2bc54082d10366c Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Wed, 3 Jan 2018 23:10:59 +0100 Subject: Initial --- c.y | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 c.y (limited to 'c.y') diff --git a/c.y b/c.y new file mode 100644 index 0000000..5aafe26 --- /dev/null +++ b/c.y @@ -0,0 +1,248 @@ +%{ + +#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 block +%type statement statement_list open_statement matched_statement other_statement +%type 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: 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 +*/ -- cgit v1.2.3-54-g00ecf