#include "parser.h" #include "lexer.h" #include "scope.h" #include #include #include #define PARSER_PANIC(format, ...) {\ fprintf(\ stderr,\ "ccc: parse error: %s: line %lu, column %lu: " format "\n",\ tok.PATH,\ tok.LINE,\ tok.COL __VA_OPT__(,)\ __VA_ARGS__);\ exit(1);\ } static struct token tok; static struct scope* scope; static void* protected_alloc(size_t sz) { void* ptr = calloc(1, sz); if (ptr == NULL) { fprintf(stderr, "ccc: out of memory\n"); exit(1); } return ptr; } static void unexpected_token(enum token_type expected) { /* TODO: print what token was expected */ PARSER_PANIC("unexpected token; expected %d", expected); } static void peek_or_panic() { if (!lexer_peek(&tok)) PARSER_PANIC("unexpected EOF"); } static void expect(enum token_type expected) { if (!lexer_pop(&tok)) PARSER_PANIC("unexpected EOF"); if (tok.type != expected) unexpected_token(expected); } static void expect_kw(const char* kw) { if (!lexer_pop(&tok)) PARSER_PANIC("unexpected EOF, expected %s", kw); if (tok.type != TK_IDENT) PARSER_PANIC("unexpected token, expected %s", kw); if (strcmp(kw, tok.data.ident) != 0) PARSER_PANIC( "unexpected identifier %s, expected %s", tok.data.ident, kw); /* string won't go in the AST, discard it */ free(tok.data.ident); tok.data.ident = NULL; } static void parse_type_ref(struct type_ref_node* p_node) { /* TODO: modifiers, void rules, arrays, etc. */ /* TODO: struct, union, enum */ expect(TK_IDENT); const struct type_def* type_def; if (!scope_get_type( scope, &type_def, &(struct type_key) { .name = tok.data.ident, /* TODO: parse modifiers */ .how_long = 0, .marked_signed = 0, .marked_unsigned = 0, })) PARSER_PANIC("unknown type name: %s", tok.data.ident); free(tok.data.ident); p_node->type = (struct type_ref) { .raw_type = type_def, .ptr_level = 0, }; peek_or_panic(); while (tok.type == TK_STAR) { expect(TK_STAR); p_node->type.ptr_level++; peek_or_panic(); } } static void parse_expr(struct expr_node* p_node); static void parse_literal(struct expr_node* p_node) { peek_or_panic(); switch (tok.type) { case TK_INT_LIT: expect(TK_INT_LIT); p_node->type = EXPR_INT_LIT; p_node->inner.int_lit.val = tok.data.int_lit; break; case TK_CHAR_LIT: expect(TK_CHAR_LIT); p_node->type = EXPR_CHAR_LIT; p_node->inner.char_lit.val = tok.data.char_lit; break; default: PARSER_PANIC("invalid literal type"); } } static void parse_var_ref(struct var_ref_node* p_node) { expect(TK_IDENT); struct var_def* var_def; if (!scope_get_var(scope, &var_def, tok.data.ident)) PARSER_PANIC("use of undeclared identifier: '%s'", tok.data.ident); free(tok.data.ident); p_node->def_ref = var_def; } static void parse_expr_assign(struct expr_node* p_node) { switch (p_node->type) { case EXPR_VAR_REF: p_node->inner.assign.lval = (struct lval_node) { .type = LVAL_VAR_REF, .inner.var_ref = p_node->inner.var_ref, }; break; default: PARSER_PANIC("expression is not assignable"); } p_node->type = EXPR_ASSIGN; p_node->inner.assign.rval = protected_alloc(sizeof(struct expr_node)); expect(TK_ASSIGN); parse_expr(p_node->inner.assign.rval); } static void parse_args_eval(struct args_eval_node** pp_arg) { for (;;) { *pp_arg = protected_alloc(sizeof(struct args_eval_node)); (*pp_arg)->expr = protected_alloc(sizeof(struct expr_node)); parse_expr((*pp_arg)->expr); pp_arg = &((*pp_arg)->next); peek_or_panic(); if (tok.type == TK_RPAREN) break; expect(TK_COMMA); } } static void parse_expr_call(struct expr_node* p_node) { switch (p_node->type) { case EXPR_VAR_REF: struct var_def* var_def = p_node->inner.var_ref.def_ref; /* TODO: I would like to include functions in the type model rather than checking storage */ if (var_def->loc.type != STO_FN) PARSER_PANIC("called object is not a function"); p_node->inner.call.called_fn_ref = var_def->loc.decl; break; default: PARSER_PANIC("expression is not callable"); } p_node->type = EXPR_CALL; p_node->inner.call.args = NULL; expect(TK_LPAREN); peek_or_panic(); if (tok.type != TK_RPAREN) parse_args_eval(&p_node->inner.call.args); expect(TK_RPAREN); } static void parse_unary(struct unary_node* p_node) { peek_or_panic(); switch (tok.type) { case TK_NEG: expect(TK_NEG); p_node->op = UNARY_NEG; break; default: PARSER_PANIC("expected unary operator"); } p_node->expr = protected_alloc(sizeof(struct expr_node)); parse_expr(p_node->expr); } static void parse_expr_binary(struct expr_node* p_node) { struct expr_node* lhs = protected_alloc(sizeof(struct expr_node)); struct expr_node* rhs = protected_alloc(sizeof(struct expr_node)); *lhs = *p_node; *p_node = (struct expr_node) { .type = EXPR_BINARY, .inner.binary = { .lhs = lhs, .rhs = rhs, }, }; peek_or_panic(); switch (tok.type) { case TK_PLUS: expect(TK_PLUS); p_node->inner.binary.op = BINARY_ADD; break; case TK_NEG: expect(TK_NEG); p_node->inner.binary.op = BINARY_SUB; break; case TK_STAR: expect(TK_STAR); p_node->inner.binary.op = BINARY_MUL; break; case TK_DIV: expect(TK_DIV); p_node->inner.binary.op = BINARY_DIV; break; default: PARSER_PANIC("expected binary operator"); } parse_expr(rhs); } static void parse_expr(struct expr_node* p_node) { peek_or_panic(); switch (tok.type) { case TK_LPAREN: expect(TK_LPAREN); parse_expr(p_node); expect(TK_RPAREN); break; case TK_NEG: p_node->type = EXPR_UNARY; parse_unary(&p_node->inner.unary); break; case TK_INT_LIT: case TK_CHAR_LIT: case TK_FLOAT_LIT: case TK_STR_LIT: parse_literal(p_node); break; case TK_IDENT: p_node->type = EXPR_VAR_REF; parse_var_ref(&p_node->inner.var_ref); break; default: PARSER_PANIC("expected expression"); } peek_or_panic(); switch (tok.type) { case TK_ASSIGN: parse_expr_assign(p_node); break; case TK_LPAREN: parse_expr_call(p_node); break; case TK_PLUS: case TK_NEG: case TK_STAR: case TK_DIV: parse_expr_binary(p_node); break; default: } } static void parse_var_decl(struct var_decl_node* p_node) { parse_type_ref(&p_node->type); expect(TK_IDENT); p_node->def_ref = scope_define_var(scope, (struct var_def) { .type = &p_node->type.type, .name = tok.data.ident, .loc.type = STO_UNRESOLVED, }); if (p_node->def_ref == NULL) PARSER_PANIC("redefinition of '%s'", tok.data.ident); } static void parse_stmt(struct stmt_node* p_node); static void parse_return(struct return_node* p_node) { expect_kw("return"); peek_or_panic(); if (tok.type == TK_SEMI) { p_node->ret_val = NULL; return; } p_node->ret_val = protected_alloc(sizeof(struct expr_node)); parse_expr(p_node->ret_val); } static void parse_group(struct group_node* p_node) { expect(TK_LCURLY); scope_push(&scope); p_node->scope = scope; struct stmt_node** pp_node = &p_node->head; for (;;) { peek_or_panic(); if (tok.type == TK_RCURLY) break; *pp_node = protected_alloc(sizeof(struct stmt_node)); parse_stmt(*pp_node); pp_node = &((*pp_node)->next); } scope_pop(&scope); expect(TK_RCURLY); } static void parse_if(struct if_node* p_node) { expect_kw("if"); scope_push(&scope); p_node->scope = scope; expect(TK_LPAREN); p_node->cond = protected_alloc(sizeof(struct expr_node)); parse_expr(p_node->cond); expect(TK_RPAREN); p_node->true_branch = protected_alloc(sizeof(struct stmt_node)); parse_stmt(p_node->true_branch); peek_or_panic(); if (tok.type == TK_IDENT && strcmp(tok.data.ident, "else") == 0) { expect_kw("else"); p_node->false_branch = protected_alloc(sizeof(struct stmt_node)); parse_stmt(p_node->false_branch); } scope_pop(&scope); } static void parse_while(struct loop_node* p_node) { expect_kw("while"); scope_push(&scope); p_node->scope = scope; expect(TK_LPAREN); p_node->cond = protected_alloc(sizeof(struct expr_node)); parse_expr(p_node->cond); expect(TK_RPAREN); p_node->body = protected_alloc(sizeof(struct stmt_node)); parse_stmt(p_node->body); scope_pop(&scope); } static void parse_for(struct loop_node* p_node) { expect_kw("for"); scope_push(&scope); p_node->scope = scope; expect(TK_LPAREN); peek_or_panic(); if (tok.type != TK_SEMI) { p_node->init = protected_alloc(sizeof(struct expr_node)); parse_expr(p_node->init); } expect(TK_SEMI); peek_or_panic(); if (tok.type != TK_SEMI) { p_node->cond = protected_alloc(sizeof(struct expr_node)); parse_expr(p_node->cond); } expect(TK_SEMI); peek_or_panic(); if (tok.type != TK_RPAREN) { p_node->incr = protected_alloc(sizeof(struct expr_node)); parse_expr(p_node->incr); } expect(TK_RPAREN); p_node->body = protected_alloc(sizeof(struct stmt_node)); parse_stmt(p_node->body); scope_pop(&scope); } static void parse_stmt_assign(struct stmt_node* p_node) { peek_or_panic(); if (tok.type != TK_ASSIGN) return; switch (p_node->type) { case STMT_VAR_DECL: p_node->inner.expr.inner.assign.lval = (struct lval_node) { .type = LVAL_VAR_DECL, .inner.var_decl = p_node->inner.var_decl, }; break; default: return; } p_node->type = STMT_EXPR; p_node->inner.expr.type = EXPR_ASSIGN; p_node->inner.expr.inner.assign.rval = protected_alloc(sizeof(struct expr_node)); expect(TK_ASSIGN); parse_expr(p_node->inner.expr.inner.assign.rval); } static void parse_stmt(struct stmt_node* p_node) { peek_or_panic(); switch (tok.type) { case TK_SEMI: p_node->type = STMT_EMPTY; break; case TK_LCURLY: p_node->type = STMT_GROUP; parse_group(&p_node->inner.group); return; case TK_IDENT: if (strcmp(tok.data.ident, "if") == 0) { p_node->type = STMT_IF; parse_if(&p_node->inner.if_); return; } else if (strcmp(tok.data.ident, "while") == 0) { p_node->type = STMT_LOOP; parse_while(&p_node->inner.loop); return; } else if (strcmp(tok.data.ident, "for") == 0) { p_node->type = STMT_LOOP; parse_for(&p_node->inner.loop); return; } else if (strcmp(tok.data.ident, "return") == 0) { p_node->type = STMT_RETURN; parse_return(&p_node->inner.return_); break; } else if (scope_get_type( scope, NULL, &(struct type_key) { .name = tok.data.ident, .how_long = 0, .marked_signed = false, .marked_unsigned = false, })) { p_node->type = STMT_VAR_DECL; parse_var_decl(&p_node->inner.var_decl); break; } default: p_node->type = STMT_EXPR; parse_expr(&p_node->inner.expr); } parse_stmt_assign(p_node); expect(TK_SEMI); } static void parse_args_decl(struct args_decl_node** pp_decl) { for (;;) { *pp_decl = protected_alloc(sizeof(struct args_decl_node)); (*pp_decl)->decl = protected_alloc(sizeof(struct var_decl_node)); parse_var_decl((*pp_decl)->decl); pp_decl = &((*pp_decl)->next); peek_or_panic(); if (tok.type == TK_RPAREN) break; expect(TK_COMMA); } } static void parse_fn_decl(struct fn_decl_node* p_node) { if (scope->next_out != NULL) PARSER_PANIC("functions can only be define in the root scope"); parse_type_ref(&p_node->return_type); expect(TK_IDENT); if (scope_define_var(scope, (struct var_def) { .name = tok.data.ident, .loc = { .type = STO_FN, .decl = p_node, }, }) == NULL) PARSER_PANIC("redefinition of '%s'", tok.data.ident) p_node->name = tok.data.ident; expect(TK_LPAREN); scope_push(&scope); p_node->scope = scope; peek_or_panic(); if (tok.type != TK_RPAREN) parse_args_decl(&p_node->args); expect(TK_RPAREN); parse_group(&p_node->body); scope_pop(&scope); } static bool parse_root(struct root_node* p_node) { if (!lexer_peek(&tok)) return false; p_node->type = ROOT_FN_DECL; parse_fn_decl(&p_node->inner.fn_decl); return true; } void parse(const char* path, struct ast* ast) { lexer_load(path); scope_push(&scope); ast->root_scope = scope; scope_install_default_types(ast); struct root_node** p_node = &ast->root_node; for (;;) { *p_node = protected_alloc(sizeof(struct root_node)); if (!parse_root(*p_node)) { free(*p_node); *p_node = NULL; break; } p_node = &((*p_node)->next); } scope_pop(&scope); lexer_close(); }