diff options
| -rw-r--r-- | ast.c | 8 | ||||
| -rw-r--r-- | ast.h | 7 | ||||
| -rw-r--r-- | codegen.c | 12 | ||||
| -rw-r--r-- | parser.c | 46 | ||||
| -rw-r--r-- | type_checker.c | 27 |
5 files changed, 75 insertions, 25 deletions
@@ -107,6 +107,11 @@ static void paren_destroy(struct paren_node* node) { free(node->expr_list); } +static void cast_destroy(struct cast_node* node) { + expr_destroy(node->expr); + free(node->expr); +} + static void expr_destroy(struct expr_node* node) { switch (node->type) { case EXPR_INT_LIT: @@ -133,6 +138,9 @@ static void expr_destroy(struct expr_node* node) { case EXPR_PAREN: paren_destroy(&node->inner.paren); break; + case EXPR_CAST: + cast_destroy(&node->inner.cast); + break; } } @@ -78,6 +78,11 @@ struct paren_node { struct expr_list_node* expr_list; }; +struct cast_node { + struct type type; + struct expr_node* expr; +}; + struct expr_node { enum { EXPR_INT_LIT, @@ -90,6 +95,7 @@ struct expr_node { EXPR_UNARY, EXPR_BINARY, EXPR_PAREN, + EXPR_CAST, } type; union { struct int_lit_node int_lit; @@ -102,6 +108,7 @@ struct expr_node { struct unary_node unary; struct binary_node binary; struct paren_node paren; + struct cast_node cast; } inner; const struct type* resolved_type; @@ -515,12 +515,13 @@ static void emit_expr_list( emit_expr(outfile, node->expr, node->next == NULL ? dst : NULL); } -static void emit_paren( +static void emit_cast( FILE* outfile, - const struct paren_node* node, + const struct cast_node* node, const struct lval_def* dst ) { - emit_expr_list(outfile, node->expr_list, dst); + /* TODO: for anything but a reinterpret cast this is garbage */ + emit_expr(outfile, node->expr, dst); } static void emit_expr( @@ -557,7 +558,10 @@ static void emit_expr( emit_binary(outfile, &node->inner.binary, dst); break; case EXPR_PAREN: - emit_paren(outfile, &node->inner.paren, dst); + emit_expr_list(outfile, node->inner.paren.expr_list, dst); + break; + case EXPR_CAST: + emit_cast(outfile, &node->inner.cast, dst); break; } } @@ -269,11 +269,35 @@ static void parse_expr_binary(struct expr_node* p_node) { parse_expr(rhs); } -static void parse_paren(struct paren_node* p_node) { +static bool is_type_token() { + if (tok.type != TK_IDENT) return false; + + /* check primitive types */ + for (integral_t i = 0; primitive_types[i] != NULL; i++) { + if (strcmp(tok.data.ident, primitive_types[i]->name) == 0) return true; + } + + /* check type aliases */ + return scope_get_type(scope, NULL, tok.data.ident); +} + +static void parse_paren(struct expr_node* p_node) { expect(TK_LPAREN); - p_node->expr_list = ccc_alloc(sizeof(struct expr_list_node)); - parse_expr_list(p_node->expr_list); - expect(TK_RPAREN); + peek_or_panic(); + if (is_type_token()) { + p_node->type = EXPR_CAST; + struct cast_node* cast_node = &p_node->inner.cast; + parse_type_ref(&cast_node->type); + expect(TK_RPAREN); + cast_node->expr = ccc_alloc(sizeof(struct expr_node)); + parse_expr(cast_node->expr); + } else { + p_node->type = EXPR_PAREN; + struct paren_node* paren_node = &p_node->inner.paren; + paren_node->expr_list = ccc_alloc(sizeof(struct expr_list_node)); + parse_expr_list(paren_node->expr_list); + expect(TK_RPAREN); + } } static void parse_expr(struct expr_node* p_node) { @@ -281,7 +305,7 @@ static void parse_expr(struct expr_node* p_node) { switch (tok.type) { case TK_LPAREN: p_node->type = EXPR_PAREN; - parse_paren(&p_node->inner.paren); + parse_paren(p_node); break; case TK_NEG: p_node->type = EXPR_UNARY; @@ -432,18 +456,6 @@ static void parse_while(struct loop_node* p_node) { scope_pop(&scope); } -static bool is_type_token() { - if (tok.type != TK_IDENT) return false; - - /* check primitive types */ - for (integral_t i = 0; primitive_types[i] != NULL; i++) { - if (strcmp(tok.data.ident, primitive_types[i]->name) == 0) return true; - } - - /* check type aliases */ - return scope_get_type(scope, NULL, tok.data.ident); -} - static void parse_loop_init(struct loop_init_node* p_node) { peek_or_panic(); if (is_type_token()) { diff --git a/type_checker.c b/type_checker.c index 86fe63a..0aaa584 100644 --- a/type_checker.c +++ b/type_checker.c @@ -81,13 +81,23 @@ static void type_check_decl_list(struct decl_list_node* node) { type_check_decl(&node->type, cur); } -static const struct type* resolve_assign(struct assign_node* node) { - switch (node->lval->type) { +static bool is_expr_assignable(struct expr_node* node) { + switch (node->type) { case EXPR_VAR_REF: - break; + return true; + case EXPR_PAREN: + const struct expr_list_node* expr_list = + node->inner.paren.expr_list; + return expr_list->next == NULL + && is_expr_assignable(expr_list->expr); default: - TYPE_PANIC("expression is not assignable"); + return false; } +} + +static const struct type* resolve_assign(struct assign_node* node) { + if (!is_expr_assignable(node->lval)) + TYPE_PANIC("expression is not assignable"); type_check_expr(node->lval); type_check_expr(node->rval); @@ -146,6 +156,12 @@ static const struct type* resolve_paren(struct paren_node* node) { return node->expr_list->resolved_type; } +static const struct type* resolve_cast(struct cast_node* node) { + type_check_expr(node->expr); + assert_cast_compatible(&node->type, node->expr->resolved_type); + return &node->type; +} + static void type_check_expr(struct expr_node* node) { switch (node->type) { case EXPR_INT_LIT: @@ -178,6 +194,9 @@ static void type_check_expr(struct expr_node* node) { case EXPR_PAREN: node->resolved_type = resolve_paren(&node->inner.paren); break; + case EXPR_CAST: + node->resolved_type = resolve_cast(&node->inner.cast); + break; } } |
