diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-08-11 12:09:25 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-08-15 10:06:21 +0900 |
| commit | 9807d9905be951e83fa20642d3c7695f5d6c9e04 (patch) | |
| tree | 73af5bdd7f8b89fc9e63e8347fd3fd022f7f52c8 | |
| parent | b0d39831d7fa34fd47dd710d6635e5401f2d07de (diff) | |
| download | ducc-9807d9905be951e83fa20642d3c7695f5d6c9e04.tar.gz ducc-9807d9905be951e83fa20642d3c7695f5d6c9e04.tar.zst ducc-9807d9905be951e83fa20642d3c7695f5d6c9e04.zip | |
feat: support non-extern global variables
| -rw-r--r-- | ast.c | 1 | ||||
| -rw-r--r-- | codegen.c | 17 | ||||
| -rw-r--r-- | parse.c | 50 | ||||
| -rw-r--r-- | tests/085.sh | 40 |
4 files changed, 99 insertions, 9 deletions
@@ -231,6 +231,7 @@ typedef struct AstNode AstNode; struct Program { AstNode* funcs; + AstNode* vars; char** str_literals; }; typedef struct Program Program; @@ -331,14 +331,11 @@ void codegen_lvar(CodeGen* g, AstNode* ast, GenMode gen_mode) { } void codegen_gvar(CodeGen* g, AstNode* ast, GenMode gen_mode) { - if (gen_mode == GenMode_lval) { - unimplemented(); - } - if (ast->ty->kind != TypeKind_ptr) { - unimplemented(); - } - printf(" mov rax, QWORD PTR %.*s[rip]\n", ast->name.len, ast->name.data); + printf(" lea rax, %.*s[rip]\n", ast->name.len, ast->name.data); printf(" push rax\n"); + if (gen_mode == GenMode_rval) { + codegen_lval2rval(ast->ty); + } } void codegen_composite_expr(CodeGen* g, AstNode* ast) { @@ -534,6 +531,12 @@ void codegen(Program* prog) { printf(" .string \"%s\"\n\n", prog->str_literals[i]); } + printf(".bss\n\n"); + for (i = 0; i < prog->vars->node_len; ++i) { + AstNode* var = prog->vars->node_items + i; + printf(" .lcomm %.*s, %d\n", var->name.len, var->name.data, type_sizeof(var->ty)); + } + printf(".globl main\n\n"); printf(".text\n\n"); @@ -392,7 +392,7 @@ Type* parse_type(Parser* p) { t = next_token(p); } if (!is_type_token(p, t)) { - fatal_error("parse_type: expected type, but got '%s'", token_stringify(t)); + fatal_error("%s:%d: parse_type: expected type, but got '%s'", t->loc.filename, t->loc.line, token_stringify(t)); } Type* ty; if (t->kind == TokenKind_ident) { @@ -490,6 +490,11 @@ AstNode* parse_prefix_expr(Parser* p) { next_token(p); ty = p->lvars[lvar_idx].ty; } + int gvar_idx = find_gvar(p, &next_tok->raw); + if (gvar_idx != -1) { + next_token(p); + ty = p->gvars[gvar_idx].ty; + } } if (!ty) { ty = parse_type(p); @@ -941,11 +946,48 @@ AstNode* parse_param_list(Parser* p) { return list; } +AstNode* parse_global_var_decl(Parser* p, Type* ty, String* name) { + if (type_is_unsized(ty)) { + fatal_error("parse_global_var_decl: invalid type for variable"); + } + + if (peek_token(p)->kind == TokenKind_bracket_l) { + next_token(p); + AstNode* size_expr = parse_expr(p); + if (size_expr->kind != AstNodeKind_int_expr) { + fatal_error("parse_global_var_decl: invalid array size"); + } + int size = size_expr->node_int_value; + expect(p, TokenKind_bracket_r); + ty = type_new_array(ty, size); + } + + expect(p, TokenKind_semicolon); + + if (find_gvar(p, name) != -1) { + fatal_error("parse_global_var_decl: %.*s redeclared", name->len, name->data); + } + + p->gvars[p->n_gvars].name = *name; + p->gvars[p->n_gvars].ty = ty; + ++p->n_gvars; + + AstNode* ret = ast_new(AstNodeKind_gvar_decl); + ret->name = *name; + ret->ty = ty; + return ret; +} + AstNode* parse_func_decl_or_def(Parser* p) { Type* ty = parse_type(p); String* name = parse_ident(p); - register_func(p, name, ty); + + if (peek_token(p)->kind != TokenKind_paren_l) { + return parse_global_var_decl(p, ty, name); + } + expect(p, TokenKind_paren_l); + register_func(p, name, ty); AstNode* params = parse_param_list(p); expect(p, TokenKind_paren_r); if (peek_token(p)->kind == TokenKind_semicolon) { @@ -1165,14 +1207,18 @@ AstNode* parse_toplevel(Parser* p) { Program* parse(Token* tokens) { Parser* p = parser_new(tokens); AstNode* funcs = ast_new_list(1024); + AstNode* vars = ast_new_list(1024); while (eof(p)) { AstNode* n = parse_toplevel(p); if (n->kind == AstNodeKind_func_def) { ast_append(funcs, n); + } else if (n->kind == AstNodeKind_gvar_decl && n->ty) { + ast_append(vars, n); } } Program* prog = calloc(1, sizeof(Program)); prog->funcs = funcs; + prog->vars = vars; prog->str_literals = p->str_literals; return prog; } diff --git a/tests/085.sh b/tests/085.sh new file mode 100644 index 0000000..10ab24c --- /dev/null +++ b/tests/085.sh @@ -0,0 +1,40 @@ +set -e + +cat <<'EOF' > expected +0 +42 +48 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +123 +EOF + +bash ../../test_diff.sh <<'EOF' +int printf(); + +int a; +int b[12]; + +int main() { + printf("%d\n", a); + a = 42; + printf("%d\n", a); + printf("%zu\n", sizeof(b)); + int i; + for (i = 0; i < 12; ++i) { + printf("%d\n", b[i]); + } + b[11] = 123; + printf("%d\n", b[11]); +} +EOF |
