aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-11 12:09:25 +0900
committernsfisis <nsfisis@gmail.com>2025-08-15 10:06:21 +0900
commit9807d9905be951e83fa20642d3c7695f5d6c9e04 (patch)
tree73af5bdd7f8b89fc9e63e8347fd3fd022f7f52c8
parentb0d39831d7fa34fd47dd710d6635e5401f2d07de (diff)
downloadducc-9807d9905be951e83fa20642d3c7695f5d6c9e04.tar.gz
ducc-9807d9905be951e83fa20642d3c7695f5d6c9e04.tar.zst
ducc-9807d9905be951e83fa20642d3c7695f5d6c9e04.zip
feat: support non-extern global variables
-rw-r--r--ast.c1
-rw-r--r--codegen.c17
-rw-r--r--parse.c50
-rw-r--r--tests/085.sh40
4 files changed, 99 insertions, 9 deletions
diff --git a/ast.c b/ast.c
index 8f474ac..a4cab7a 100644
--- a/ast.c
+++ b/ast.c
@@ -231,6 +231,7 @@ typedef struct AstNode AstNode;
struct Program {
AstNode* funcs;
+ AstNode* vars;
char** str_literals;
};
typedef struct Program Program;
diff --git a/codegen.c b/codegen.c
index 941d69c..a72779a 100644
--- a/codegen.c
+++ b/codegen.c
@@ -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");
diff --git a/parse.c b/parse.c
index d55d599..2f17225 100644
--- a/parse.c
+++ b/parse.c
@@ -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