aboutsummaryrefslogtreecommitdiff
path: root/c.y
diff options
context:
space:
mode:
Diffstat (limited to 'c.y')
-rw-r--r--c.y248
1 files changed, 248 insertions, 0 deletions
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 <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
+*/