summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-07-30 00:20:30 -0400
committerCarson Fleming <cflems@cflems.net>2026-07-30 00:20:52 -0400
commit61531e58066e4d803624ab2c6dac84445fb75e59 (patch)
treec4ed43fdfdbd94c461e7429bbfa6cd46e4e78992
parent3445947c072a4cd533f5f3a53178f77361859123 (diff)
downloadccc-61531e58066e4d803624ab2c6dac84445fb75e59.tar.gz
casting
-rw-r--r--ast.c8
-rw-r--r--ast.h7
-rw-r--r--codegen.c12
-rw-r--r--parser.c46
-rw-r--r--type_checker.c27
5 files changed, 75 insertions, 25 deletions
diff --git a/ast.c b/ast.c
index 22d3181..9fa4f82 100644
--- a/ast.c
+++ b/ast.c
@@ -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;
}
}
diff --git a/ast.h b/ast.h
index e77c779..8611aaa 100644
--- a/ast.h
+++ b/ast.h
@@ -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;
diff --git a/codegen.c b/codegen.c
index 6d55d2c..5cba20f 100644
--- a/codegen.c
+++ b/codegen.c
@@ -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;
}
}
diff --git a/parser.c b/parser.c
index b92ff8b..29aea36 100644
--- a/parser.c
+++ b/parser.c
@@ -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;
}
}