aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-13 01:14:35 +0900
committernsfisis <nsfisis@gmail.com>2025-08-15 10:06:21 +0900
commit15c8a2f45b3916f840665b317afb344cbc08f5a4 (patch)
tree77cfd6866c5100f836adfee8603c122aefaf21b0
parent9c12de31ab03385cea3b7bc78582ef4fdb9b22cc (diff)
downloadducc-15c8a2f45b3916f840665b317afb344cbc08f5a4.tar.gz
ducc-15c8a2f45b3916f840665b317afb344cbc08f5a4.tar.zst
ducc-15c8a2f45b3916f840665b317afb344cbc08f5a4.zip
feat: implement block-based variable scope
-rw-r--r--codegen.c14
-rw-r--r--parse.c76
-rw-r--r--preprocess.c10
-rw-r--r--tests/088.sh35
4 files changed, 109 insertions, 26 deletions
diff --git a/codegen.c b/codegen.c
index f3790d2..59cee04 100644
--- a/codegen.c
+++ b/codegen.c
@@ -275,11 +275,10 @@ void codegen_assign_expr(CodeGen* g, AstNode* ast) {
void codegen_func_call(CodeGen* g, AstNode* ast) {
String* func_name = &ast->name;
- int i;
if (string_equals_cstr(func_name, "va_start")) {
printf(" # va_start BEGIN\n");
- for (i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; ++i) {
printf(" mov rax, %s\n", param_reg(i));
printf(" mov [rbp-%d], rax\n", 8 + (LVAR_MAX - 4 - i) * 8);
}
@@ -300,11 +299,11 @@ void codegen_func_call(CodeGen* g, AstNode* ast) {
}
AstNode* args = ast->node_args;
- for (i = 0; i < args->node_len; ++i) {
+ for (int i = 0; i < args->node_len; ++i) {
AstNode* arg = args->node_items + i;
codegen_expr(g, arg, GenMode_rval);
}
- for (i = args->node_len - 1; i >= 0; --i) {
+ for (int i = args->node_len - 1; i >= 0; --i) {
printf(" pop %s\n", param_reg(i));
}
@@ -529,18 +528,17 @@ void codegen_func(CodeGen* g, AstNode* ast) {
void codegen(Program* prog) {
CodeGen* g = codegen_new();
- int i;
printf(".intel_syntax noprefix\n\n");
printf(".section .rodata\n\n");
- for (i = 0; prog->str_literals[i]; ++i) {
+ for (int i = 0; prog->str_literals[i]; ++i) {
printf(".Lstr__%d:\n", i + 1);
printf(" .string \"%s\"\n\n", prog->str_literals[i]);
}
printf(".bss\n\n");
- for (i = 0; i < prog->vars->node_len; ++i) {
+ for (int 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));
}
@@ -548,7 +546,7 @@ void codegen(Program* prog) {
printf(".globl main\n\n");
printf(".text\n\n");
- for (i = 0; i < prog->funcs->node_len; ++i) {
+ for (int i = 0; i < prog->funcs->node_len; ++i) {
AstNode* func = prog->funcs->node_items + i;
codegen_func(g, func);
}
diff --git a/parse.c b/parse.c
index c0d60dc..a1d4aa8 100644
--- a/parse.c
+++ b/parse.c
@@ -7,6 +7,13 @@ struct LocalVar {
};
typedef struct LocalVar LocalVar;
+struct Scope {
+ struct Scope* outer;
+ String* lvar_names;
+ int* lvar_indices;
+};
+typedef struct Scope Scope;
+
struct GlobalVar {
String name;
Type* ty;
@@ -24,6 +31,7 @@ struct Parser {
int pos;
LocalVar* lvars;
int n_lvars;
+ Scope* scope;
GlobalVar* gvars;
int n_gvars;
Func* funcs;
@@ -83,15 +91,30 @@ Token* expect(Parser* p, TokenKind expected) {
token_stringify(t));
}
-int find_lvar(Parser* p, const String* name) {
- for (int i = 0; i < p->n_lvars; ++i) {
- if (string_equals(&p->lvars[i].name, name)) {
- return i;
+int find_lvar_in_scope(Parser* p, Scope* scope, const String* name) {
+ for (int i = 0; i < LVAR_MAX; ++i) {
+ if (string_equals(&scope->lvar_names[i], name)) {
+ return scope->lvar_indices[i];
}
}
return -1;
}
+int find_lvar_in_current_scope(Parser* p, const String* name) {
+ return find_lvar_in_scope(p, p->scope, name);
+}
+
+int find_lvar(Parser* p, const String* name) {
+ Scope* scope = p->scope;
+ while (scope) {
+ int idx = find_lvar_in_scope(p, scope, name);
+ if (idx != -1)
+ return idx;
+ scope = scope->outer;
+ }
+ return -1;
+}
+
int calc_stack_offset(Parser* p, Type* ty, BOOL is_param) {
int align;
if (is_param) {
@@ -119,6 +142,13 @@ int add_lvar(Parser* p, String* name, Type* ty, BOOL is_param) {
p->lvars[p->n_lvars].name = *name;
p->lvars[p->n_lvars].ty = ty;
p->lvars[p->n_lvars].stack_offset = stack_offset;
+ for (int i = 0; i < LVAR_MAX; ++i) {
+ if (p->scope->lvar_names[i].len == 0) {
+ p->scope->lvar_names[i] = *name;
+ p->scope->lvar_indices[i] = p->n_lvars;
+ break;
+ }
+ }
++p->n_lvars;
return stack_offset;
}
@@ -209,6 +239,28 @@ int find_typedef(Parser* p, const String* name) {
return -1;
}
+void enter_scope(Parser* p) {
+ Scope* outer_scope = p->scope;
+ p->scope = calloc(1, sizeof(Scope));
+ p->scope->outer = outer_scope;
+ p->scope->lvar_names = calloc(LVAR_MAX, sizeof(String));
+ p->scope->lvar_indices = calloc(LVAR_MAX, sizeof(int));
+}
+
+void leave_scope(Parser* p) {
+ p->scope = p->scope->outer;
+}
+
+void enter_func(Parser* p) {
+ p->lvars = calloc(LVAR_MAX, sizeof(LocalVar));
+ p->n_lvars = 0;
+ enter_scope(p);
+}
+
+void leave_func(Parser* p) {
+ leave_scope(p);
+}
+
AstNode* parse_expr(Parser* p);
AstNode* parse_stmt(Parser* p);
@@ -734,10 +786,10 @@ AstNode* parse_var_decl(Parser* p) {
}
expect(p, TokenKind_semicolon);
- if (find_lvar(p, name) != -1 || find_gvar(p, name) != -1) {
+ if (find_lvar_in_current_scope(p, name) != -1) {
// TODO: use name's location.
- fatal_error("%s:%d: parse_var_decl: %.*s redeclared", peek_token(p)->loc.filename, peek_token(p)->loc.line,
- name->len, name->data);
+ fatal_error("%s:%d: '%.*s' redeclared", peek_token(p)->loc.filename, peek_token(p)->loc.line, name->len,
+ name->data);
}
int stack_offset = add_lvar(p, name, ty, FALSE);
@@ -762,6 +814,7 @@ AstNode* parse_for_stmt(Parser* p) {
AstNode* init = NULL;
AstNode* cond = NULL;
AstNode* update = NULL;
+ enter_scope(p);
if (peek_token(p)->kind != TokenKind_semicolon) {
if (is_type_token(p, peek_token(p))) {
init = parse_var_decl(p)->node_expr;
@@ -783,6 +836,7 @@ AstNode* parse_for_stmt(Parser* p) {
}
expect(p, TokenKind_paren_r);
AstNode* body = parse_stmt(p);
+ leave_scope(p);
AstNode* stmt = ast_new(AstNodeKind_for_stmt);
stmt->node_cond = cond;
@@ -843,10 +897,12 @@ AstNode* parse_expr_stmt(Parser* p) {
AstNode* parse_block_stmt(Parser* p) {
AstNode* list = ast_new_list(4);
expect(p, TokenKind_brace_l);
+ enter_scope(p);
while (peek_token(p)->kind != TokenKind_brace_r) {
AstNode* stmt = parse_stmt(p);
ast_append(list, stmt);
}
+ leave_scope(p);
expect(p, TokenKind_brace_r);
return list;
}
@@ -883,11 +939,6 @@ AstNode* parse_stmt(Parser* p) {
}
}
-void enter_func(Parser* p) {
- p->lvars = calloc(LVAR_MAX, sizeof(LocalVar));
- p->n_lvars = 0;
-}
-
void register_params(Parser* p, AstNode* params) {
for (int i = 0; i < params->node_len; ++i) {
AstNode* param = params->node_items + i;
@@ -996,6 +1047,7 @@ AstNode* parse_func_decl_or_def(Parser* p) {
enter_func(p);
register_params(p, params);
AstNode* body = parse_block_stmt(p);
+ leave_func(p);
AstNode* func = ast_new(AstNodeKind_func_def);
func->ty = ty;
func->name = *name;
diff --git a/preprocess.c b/preprocess.c
index b097bfb..f11bde2 100644
--- a/preprocess.c
+++ b/preprocess.c
@@ -922,7 +922,6 @@ Token* process_include_directive(Preprocessor* pp, Token* tok, Token* tok2) {
Token* process_define_directive(Preprocessor* pp, Token* tok, Token* tok2) {
Token* tok3 = NULL;
PpMacro* pp_macro;
- int i;
++tok2;
tok2 = skip_whitespace(tok2);
if (tok2->kind != TokenKind_ident) {
@@ -948,7 +947,7 @@ Token* process_define_directive(Preprocessor* pp, Token* tok, Token* tok2) {
pp_macro->name = macro_name->raw;
pp_macro->n_replacements = tok3 - tok2;
pp_macro->replacements = calloc(pp_macro->n_replacements, sizeof(Token));
- for (i = 0; i < pp_macro->n_replacements; ++i) {
+ for (int i = 0; i < pp_macro->n_replacements; ++i) {
pp_macro->replacements[i] = tok2[i];
}
} else {
@@ -961,7 +960,7 @@ Token* process_define_directive(Preprocessor* pp, Token* tok, Token* tok2) {
pp_macro->name = macro_name->raw;
pp_macro->n_replacements = tok3 - tok2;
pp_macro->replacements = calloc(pp_macro->n_replacements, sizeof(Token));
- for (i = 0; i < pp_macro->n_replacements; ++i) {
+ for (int i = 0; i < pp_macro->n_replacements; ++i) {
pp_macro->replacements[i] = tok2[i];
}
}
@@ -1001,20 +1000,19 @@ BOOL expand_macro(Preprocessor* pp, Token* tok) {
return FALSE;
}
- int i;
SourceLocation original_loc = tok->loc;
PpMacro* pp_macro = pp->pp_macros->data + pp_macro_idx;
if (pp_macro->kind == PpMacroKind_func) {
// also consume '(' and ')'
replace_pp_tokens(pp, tok, tok + 3, pp_macro->n_replacements, pp_macro->replacements);
// Inherit a source location from the original macro token.
- for (i = 0; i < pp_macro->n_replacements; ++i) {
+ for (int i = 0; i < pp_macro->n_replacements; ++i) {
tok[i].loc = original_loc;
}
} else if (pp_macro->kind == PpMacroKind_obj) {
replace_pp_tokens(pp, tok, tok + 1, pp_macro->n_replacements, pp_macro->replacements);
// Inherit a source location from the original macro token.
- for (i = 0; i < pp_macro->n_replacements; ++i) {
+ for (int i = 0; i < pp_macro->n_replacements; ++i) {
tok[i].loc = original_loc;
}
} else if (pp_macro->kind == PpMacroKind_builtin_file) {
diff --git a/tests/088.sh b/tests/088.sh
new file mode 100644
index 0000000..6630cf0
--- /dev/null
+++ b/tests/088.sh
@@ -0,0 +1,35 @@
+set -e
+
+cat <<'EOF' > expected
+0
+1
+2
+3
+4
+0
+1
+2
+3
+4
+43
+42
+EOF
+
+bash ../../test_diff.sh <<'EOF'
+int printf();
+
+int main() {
+ for (int i = 0; i < 5; i++) {
+ printf("%d\n", i);
+ }
+ for (int i = 0; i < 5; i++) {
+ printf("%d\n", i);
+ }
+ int x = 42;
+ {
+ int x = 43;
+ printf("%d\n", x);
+ }
+ printf("%d\n", x);
+}
+EOF