summaryrefslogtreecommitdiff
path: root/parser.c
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-07-17 00:38:51 -0400
committerCarson Fleming <cflems@cflems.net>2026-07-17 00:38:51 -0400
commita5c12fd6f4438fc172f28b722e54908b575c6ce1 (patch)
tree5f9b2d48681e02d392567eb8798ba614cb96bfbd /parser.c
parent1dfa2971999b4adf36a33866b0b07af07188da08 (diff)
downloadccc-a5c12fd6f4438fc172f28b722e54908b575c6ce1.tar.gz
before I do something crazy
Diffstat (limited to 'parser.c')
-rw-r--r--parser.c100
1 files changed, 57 insertions, 43 deletions
diff --git a/parser.c b/parser.c
index 6a8ad31..42a7f49 100644
--- a/parser.c
+++ b/parser.c
@@ -66,8 +66,8 @@ static void parse_type(struct type_node* p_node) {
/* TODO: modifiers, void rules, arrays, etc. */
/* TODO: struct, union, enum */
expect(TK_IDENT);
- struct type_def type_def;
- if (!scope_get_type(scope, &type_def, tok.data.ident))
+ struct type_def* type_def = protected_alloc(sizeof(struct type_def));
+ if (!scope_get_type(scope, type_def, tok.data.ident))
PARSER_PANIC("unknown type name: %s", tok.data.ident);
p_node->def = type_def;
@@ -90,12 +90,12 @@ static void parse_literal(struct expr_node* p_node) {
case TK_INT_LIT:
expect(TK_INT_LIT);
p_node->type = EXPR_INT_LIT;
- p_node->as._int_lit.val = tok.data.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->as._char_lit.val = tok.data.char_lit;
+ p_node->inner.char_lit.val = tok.data.char_lit;
break;
default:
PARSER_PANIC("invalid literal type");
@@ -105,14 +105,16 @@ static void parse_literal(struct expr_node* p_node) {
static void parse_var_ref(struct var_ref_node* p_node) {
expect(TK_IDENT);
p_node->ident = tok.data.ident;
+ if (!scope_get_var(scope, NULL, p_node->ident))
+ PARSER_PANIC("use of undeclared identifier: '%s'", p_node->ident);
}
static void parse_expr_assign(struct expr_node* p_node) {
switch (p_node->type) {
case EXPR_VAR_REF:
- p_node->as._assign.lval = (struct lval_node) {
+ p_node->inner.assign.lval = (struct lval_node) {
.type = LVAL_VAR_REF,
- .as._var_ref = p_node->as._var_ref,
+ .inner.var_ref = p_node->inner.var_ref,
};
return;
default:
@@ -120,16 +122,17 @@ static void parse_expr_assign(struct expr_node* p_node) {
}
p_node->type = EXPR_ASSIGN;
- p_node->as._assign.rval = protected_alloc(sizeof(struct expr_node));
+ p_node->inner.assign.rval = protected_alloc(sizeof(struct expr_node));
expect(TK_ASSIGN);
- parse_expr(p_node->as._assign.rval);
+ parse_expr(p_node->inner.assign.rval);
}
-static void parse_arg_evals(struct expr_node** pp_arg) {
+static void parse_args_eval(struct args_eval_node** pp_arg) {
for (;;) {
- *pp_arg = protected_alloc(sizeof(struct expr_node));
- parse_expr(*pp_arg);
+ *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();
@@ -142,25 +145,25 @@ static void parse_expr_call(struct expr_node* p_node) {
switch (p_node->type) {
case EXPR_VAR_REF:
struct var_def var_def;
- if (!scope_get_var(scope, &var_def, p_node->as._var_ref.ident))
+ if (!scope_get_var(scope, &var_def, p_node->inner.var_ref.ident))
PARSER_PANIC(
- "%s is not a known function", p_node->as._var_ref.ident);
+ "%s is not a known function", p_node->inner.var_ref.ident);
if (var_def.loc.type != STO_FN)
PARSER_PANIC("called object is not a function");
- p_node->as._call.called_fn = var_def.loc.decl;
+ 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->as._call.args_head = NULL;
+ p_node->inner.call.args = NULL;
expect(TK_LPAREN);
peek_or_panic();
- if (tok.type != TK_RPAREN) parse_arg_evals(&p_node->as._call.args_head);
+ if (tok.type != TK_RPAREN) parse_args_eval(&p_node->inner.call.args);
expect(TK_RPAREN);
}
@@ -186,7 +189,7 @@ static void parse_expr_binary(struct expr_node* p_node) {
*lhs = *p_node;
*p_node = (struct expr_node) {
.type = EXPR_BINARY,
- .as._binary = {
+ .inner.binary = {
.lhs = lhs,
.rhs = rhs,
},
@@ -196,19 +199,19 @@ static void parse_expr_binary(struct expr_node* p_node) {
switch (tok.type) {
case TK_PLUS:
expect(TK_PLUS);
- p_node->as._binary.op = BINARY_ADD;
+ p_node->inner.binary.op = BINARY_ADD;
break;
case TK_NEG:
expect(TK_NEG);
- p_node->as._binary.op = BINARY_SUB;
+ p_node->inner.binary.op = BINARY_SUB;
break;
case TK_STAR:
expect(TK_STAR);
- p_node->as._binary.op = BINARY_MUL;
+ p_node->inner.binary.op = BINARY_MUL;
break;
case TK_DIV:
expect(TK_DIV);
- p_node->as._binary.op = BINARY_DIV;
+ p_node->inner.binary.op = BINARY_DIV;
break;
default:
PARSER_PANIC("expected binary operator");
@@ -227,7 +230,7 @@ static void parse_expr(struct expr_node* p_node) {
break;
case TK_NEG:
p_node->type = EXPR_UNARY;
- parse_unary(&p_node->as._unary);
+ parse_unary(&p_node->inner.unary);
break;
case TK_INT_LIT:
case TK_CHAR_LIT:
@@ -237,7 +240,7 @@ static void parse_expr(struct expr_node* p_node) {
break;
case TK_IDENT:
p_node->type = EXPR_VAR_REF;
- parse_var_ref(&p_node->as._var_ref);
+ parse_var_ref(&p_node->inner.var_ref);
break;
default:
PARSER_PANIC("expected expression");
@@ -265,6 +268,7 @@ static void parse_var_decl(struct var_decl_node* p_node) {
parse_type(&p_node->type);
expect(TK_IDENT);
p_node->ident = tok.data.ident;
+ scope_define_var(scope, (struct var_def) { .name = p_node->ident });
}
static void parse_stmt(struct stmt_node* p_node);
@@ -285,7 +289,10 @@ static void parse_return(struct return_node* p_node) {
static void parse_group(struct group_node* p_node) {
expect(TK_LCURLY);
- struct stmt_node** pp_node = &p_node->body_head;
+ 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;
@@ -295,6 +302,8 @@ static void parse_group(struct group_node* p_node) {
pp_node = &((*pp_node)->next);
}
+ scope_pop(&scope);
+
expect(TK_RCURLY);
}
@@ -304,9 +313,9 @@ static void parse_stmt_assign(struct stmt_node* p_node) {
switch (p_node->type) {
case STMT_VAR_DECL:
- p_node->as._expr.as._assign.lval = (struct lval_node) {
+ p_node->inner.expr.inner.assign.lval = (struct lval_node) {
.type = LVAL_VAR_DECL,
- .as._var_decl = p_node->as._var_decl,
+ .inner.var_decl = p_node->inner.var_decl,
};
break;
default:
@@ -314,12 +323,12 @@ static void parse_stmt_assign(struct stmt_node* p_node) {
}
p_node->type = STMT_EXPR;
- p_node->as._expr.type = EXPR_ASSIGN;
- p_node->as._expr.as._assign.rval =
+ 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->as._expr.as._assign.rval);
+ parse_expr(p_node->inner.expr.inner.assign.rval);
}
static void parse_stmt(struct stmt_node* p_node) {
@@ -330,32 +339,33 @@ static void parse_stmt(struct stmt_node* p_node) {
break;
case TK_LCURLY:
p_node->type = STMT_GROUP;
- parse_group(&p_node->as._group);
+ parse_group(&p_node->inner.group);
return;
case TK_IDENT:
if (strcmp(tok.data.ident, "return") == 0) {
p_node->type = STMT_RETURN;
- parse_return(&p_node->as._return);
+ parse_return(&p_node->inner.return_);
break;
} else if (scope_get_type(scope, NULL, tok.data.ident)) {
p_node->type = STMT_VAR_DECL;
- parse_var_decl(&p_node->as._var_decl);
+ parse_var_decl(&p_node->inner.var_decl);
break;
}
default:
p_node->type = STMT_EXPR;
- parse_expr(&p_node->as._expr);
+ parse_expr(&p_node->inner.expr);
}
parse_stmt_assign(p_node);
expect(TK_SEMI);
}
-static void parse_arg_decls(struct var_decl_node** pp_arg) {
+static void parse_args_decl(struct args_decl_node** pp_decl) {
for (;;) {
- *pp_arg = protected_alloc(sizeof(struct var_decl_node));
- parse_var_decl(*pp_arg);
- pp_arg = &((*pp_arg)->next);
+ *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;
@@ -371,13 +381,18 @@ static void parse_fn_decl(struct fn_decl_node* p_node) {
expect(TK_LPAREN);
+ scope_push(&scope);
+ p_node->scope = scope;
+
peek_or_panic();
- if (tok.type != TK_RPAREN) parse_arg_decls(&p_node->args_head);
+ if (tok.type != TK_RPAREN) parse_args_decl(&p_node->args);
expect(TK_RPAREN);
parse_group(&p_node->body);
+ scope_pop(&scope);
+
scope_define_var(scope, (struct var_def) {
.name = p_node->name,
.loc = {
@@ -391,17 +406,17 @@ 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->as._fn_decl);
+ parse_fn_decl(&p_node->inner.fn_decl);
return true;
}
-struct root_node* parse(const char* path) {
+void parse(const char* path, struct ast* ast) {
lexer_load(path);
scope_push(&scope);
scope_install_default_types(scope);
- struct root_node* root;
- struct root_node** p_node = &root;
+ ast->root_scope = scope;
+ struct root_node** p_node = &ast->root_node;
for (;;) {
*p_node = protected_alloc(sizeof(struct root_node));
@@ -415,5 +430,4 @@ struct root_node* parse(const char* path) {
scope_pop(&scope);
lexer_close();
- return root;
}