aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-11 12:44:40 +0900
committernsfisis <nsfisis@gmail.com>2025-08-15 10:06:21 +0900
commitfc55b5f89b5974f627657c730bfd6b7d01609eae (patch)
treeb594b55bc00a71a0fb83b8e15bf959c1dfdeeb6f
parentcf38ecdd3611efe138e24ea6b5b91c1861f36f31 (diff)
downloadducc-fc55b5f89b5974f627657c730bfd6b7d01609eae.tar.gz
ducc-fc55b5f89b5974f627657c730bfd6b7d01609eae.tar.zst
ducc-fc55b5f89b5974f627657c730bfd6b7d01609eae.zip
feat: allow variable declaration in for loop's init
-rw-r--r--ast.c18
-rw-r--r--codegen.c17
-rw-r--r--parse.c137
-rw-r--r--preprocess.c12
-rw-r--r--tests/087.sh24
5 files changed, 107 insertions, 101 deletions
diff --git a/ast.c b/ast.c
index a4cab7a..a6fb722 100644
--- a/ast.c
+++ b/ast.c
@@ -357,8 +357,7 @@ int type_sizeof_struct(Type* ty) {
int next_offset = 0;
int struct_align = 0;
- int i;
- for (i = 0; i < ty->def->node_members->node_len; ++i) {
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
AstNode* member = ty->def->node_members->node_items + i;
int size = type_sizeof(member->ty);
int align = type_alignof(member->ty);
@@ -376,8 +375,7 @@ int type_sizeof_union(Type* ty) {
int union_size = 0;
int union_align = 0;
- int i;
- for (i = 0; i < ty->def->node_members->node_len; ++i) {
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
AstNode* member = ty->def->node_members->node_items + i;
int size = type_sizeof(member->ty);
int align = type_alignof(member->ty);
@@ -396,8 +394,7 @@ int type_sizeof_union(Type* ty) {
int type_alignof_struct(Type* ty) {
int struct_align = 0;
- int i;
- for (i = 0; i < ty->def->node_members->node_len; ++i) {
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
AstNode* member = ty->def->node_members->node_items + i;
int align = type_alignof(member->ty);
@@ -411,8 +408,7 @@ int type_alignof_struct(Type* ty) {
int type_alignof_union(Type* ty) {
int union_align = 0;
- int i;
- for (i = 0; i < ty->def->node_members->node_len; ++i) {
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
AstNode* member = ty->def->node_members->node_items + i;
int align = type_alignof(member->ty);
@@ -433,8 +429,7 @@ int type_offsetof(Type* ty, const String* name) {
int next_offset = 0;
- int i;
- for (i = 0; i < ty->def->node_members->node_len; ++i) {
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
AstNode* member = ty->def->node_members->node_items + i;
int size = type_sizeof(member->ty);
int align = type_alignof(member->ty);
@@ -454,8 +449,7 @@ Type* type_member_typeof(Type* ty, const String* name) {
fatal_error("type_member_typeof: type is neither a struct nor a union");
}
- int i;
- for (i = 0; i < ty->def->node_members->node_len; ++i) {
+ for (int i = 0; i < ty->def->node_members->node_len; ++i) {
AstNode* member = ty->def->node_members->node_items + i;
if (string_equals(&member->name, name)) {
return member->ty;
diff --git a/codegen.c b/codegen.c
index a72779a..796dd14 100644
--- a/codegen.c
+++ b/codegen.c
@@ -47,8 +47,7 @@ const char* param_reg(int n) {
void codegen_func_prologue(CodeGen* g, AstNode* ast) {
printf(" push rbp\n");
printf(" mov rbp, rsp\n");
- int i;
- for (i = 0; i < ast->node_params->node_len; ++i) {
+ for (int i = 0; i < ast->node_params->node_len; ++i) {
printf(" push %s\n", param_reg(i));
}
printf(" sub rsp, %d\n", 8 * LVAR_MAX);
@@ -105,8 +104,7 @@ void codegen_push_expr(const char* reg, int size) {
// Perform bitwise copy. Use r10 register as temporary space.
// Note: rsp must be aligned to 8.
printf(" sub rsp, %d\n", to_aligned(size, 8));
- int i;
- for (i = 0; i < size; ++i) {
+ for (int i = 0; i < size; ++i) {
// Copy a sinle byte from the address that "reg" points to to the stack via r10 register.
printf(" mov r10b, [%s+%d]\n", reg, i);
printf(" mov [rsp+%d], r10b\n", i);
@@ -250,8 +248,7 @@ void codegen_assign_expr(CodeGen* g, AstNode* ast) {
int aligned_size = to_aligned(sizeof_lhs, 8);
printf(" mov rax, [rsp+%d]\n", aligned_size);
// Perform bitwise copy. Use r10 register as temporary space.
- int i;
- for (i = 0; i < aligned_size; ++i) {
+ for (int i = 0; i < aligned_size; ++i) {
// Copy a sinle byte from the stack to the address that rax points to via r10 register.
printf(" mov r10b, [rsp+%d]\n", i);
printf(" mov [rax+%d], r10b\n", i);
@@ -340,8 +337,7 @@ void codegen_gvar(CodeGen* g, AstNode* ast, GenMode gen_mode) {
void codegen_composite_expr(CodeGen* g, AstNode* ast) {
// Standard C does not have composite expression, but ducc internally has.
- int i;
- for (i = 0; i < ast->node_len; ++i) {
+ for (int i = 0; i < ast->node_len; ++i) {
AstNode* expr = ast->node_items + i;
codegen_expr(g, expr, GenMode_rval);
if (i != ast->node_len - 1) {
@@ -472,8 +468,7 @@ void codegen_nop(CodeGen* g, AstNode* ast) {
}
void codegen_block_stmt(CodeGen* g, AstNode* ast) {
- int i;
- for (i = 0; i < ast->node_len; ++i) {
+ for (int i = 0; i < ast->node_len; ++i) {
AstNode* stmt = ast->node_items + i;
codegen_stmt(g, stmt);
}
@@ -521,11 +516,11 @@ 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");
- int i;
for (i = 0; prog->str_literals[i]; ++i) {
printf(".Lstr__%d:\n", i + 1);
printf(" .string \"%s\"\n\n", prog->str_literals[i]);
diff --git a/parse.c b/parse.c
index 60fde56..67103c7 100644
--- a/parse.c
+++ b/parse.c
@@ -84,8 +84,7 @@ Token* expect(Parser* p, TokenKind expected) {
}
int find_lvar(Parser* p, const String* name) {
- int i;
- for (i = 0; i < p->n_lvars; ++i) {
+ for (int i = 0; i < p->n_lvars; ++i) {
if (string_equals(&p->lvars[i].name, name)) {
return i;
}
@@ -127,8 +126,7 @@ int add_lvar(Parser* p, String* name, Type* ty, BOOL is_param) {
String* generate_temporary_lvar_name(Parser* p) {
String* ret = calloc(1, sizeof(String));
ret->data = calloc(256, sizeof(char));
- int i;
- for (i = 1;; ++i) {
+ for (int i = 1;; ++i) {
ret->len = sprintf(ret->data, "__%d", i);
if (find_lvar(p, ret) == -1) {
return ret;
@@ -147,8 +145,7 @@ AstNode* generate_temporary_lvar(Parser* p, Type* ty) {
}
int find_gvar(Parser* p, const String* name) {
- int i;
- for (i = 0; i < p->n_gvars; ++i) {
+ for (int i = 0; i < p->n_gvars; ++i) {
if (string_equals(&p->gvars[i].name, name)) {
return i;
}
@@ -157,8 +154,7 @@ int find_gvar(Parser* p, const String* name) {
}
int find_func(Parser* p, const String* name) {
- int i;
- for (i = 0; i < p->n_funcs; ++i) {
+ for (int i = 0; i < p->n_funcs; ++i) {
if (string_equals(&p->funcs[i].name, name)) {
return i;
}
@@ -167,8 +163,7 @@ int find_func(Parser* p, const String* name) {
}
int find_struct(Parser* p, const String* name) {
- int i;
- for (i = 0; i < p->n_structs; ++i) {
+ for (int i = 0; i < p->n_structs; ++i) {
if (string_equals(&p->structs[i].name, name)) {
return i;
}
@@ -177,8 +172,7 @@ int find_struct(Parser* p, const String* name) {
}
int find_union(Parser* p, const String* name) {
- int i;
- for (i = 0; i < p->n_unions; ++i) {
+ for (int i = 0; i < p->n_unions; ++i) {
if (string_equals(&p->unions[i].name, name)) {
return i;
}
@@ -187,8 +181,7 @@ int find_union(Parser* p, const String* name) {
}
int find_enum(Parser* p, const String* name) {
- int i;
- for (i = 0; i < p->n_enums; ++i) {
+ for (int i = 0; i < p->n_enums; ++i) {
if (string_equals(&p->enums[i].name, name)) {
return i;
}
@@ -197,10 +190,8 @@ int find_enum(Parser* p, const String* name) {
}
int find_enum_member(Parser* p, const String* name) {
- int i;
- int j;
- for (i = 0; i < p->n_enums; ++i) {
- for (j = 0; j < p->enums[i].node_members->node_len; ++j) {
+ for (int i = 0; i < p->n_enums; ++i) {
+ for (int j = 0; j < p->enums[i].node_members->node_len; ++j) {
if (string_equals(&p->enums[i].node_members->node_items[j].name, name)) {
return i * 1000 + j;
}
@@ -210,8 +201,7 @@ int find_enum_member(Parser* p, const String* name) {
}
int find_typedef(Parser* p, const String* name) {
- int i;
- for (i = 0; i < p->n_typedefs; ++i) {
+ for (int i = 0; i < p->n_typedefs; ++i) {
if (string_equals(&p->typedefs[i].name, name)) {
return i;
}
@@ -287,7 +277,7 @@ AstNode* parse_primary_expr(Parser* p) {
e->ty = p->lvars[lvar_idx].ty;
return e;
} else {
- fatal_error("expected primary expression, but got '%s'", token_stringify(t));
+ fatal_error("%s:%d: expected an expression, but got '%s'", t->loc.filename, t->loc.line, token_stringify(t));
}
}
@@ -718,6 +708,53 @@ AstNode* parse_if_stmt(Parser* p) {
return stmt;
}
+AstNode* parse_var_decl(Parser* p) {
+ Type* ty = parse_type(p);
+ if (type_is_unsized(ty)) {
+ fatal_error("parse_var_decl: invalid type for variable");
+ }
+ String* name = parse_ident(p);
+
+ 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_var_decl: invalid array size");
+ }
+ int size = size_expr->node_int_value;
+ expect(p, TokenKind_bracket_r);
+ ty = type_new_array(ty, size);
+ }
+
+ AstNode* init = NULL;
+ if (peek_token(p)->kind == TokenKind_assign) {
+ next_token(p);
+ init = parse_expr(p);
+ }
+ expect(p, TokenKind_semicolon);
+
+ if (find_lvar(p, name) != -1 || find_gvar(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);
+ }
+ int stack_offset = add_lvar(p, name, ty, FALSE);
+
+ AstNode* ret;
+ if (init) {
+ AstNode* lhs = ast_new(AstNodeKind_lvar);
+ lhs->name = *name;
+ lhs->node_stack_offset = stack_offset;
+ lhs->ty = ty;
+ AstNode* assign = ast_new_assign_expr(TokenKind_assign, lhs, init);
+ ret = ast_new(AstNodeKind_expr_stmt);
+ ret->node_expr = assign;
+ } else {
+ ret = ast_new(AstNodeKind_lvar_decl);
+ }
+ return ret;
+}
+
AstNode* parse_for_stmt(Parser* p) {
expect(p, TokenKind_keyword_for);
expect(p, TokenKind_paren_l);
@@ -725,9 +762,15 @@ AstNode* parse_for_stmt(Parser* p) {
AstNode* cond = NULL;
AstNode* update = NULL;
if (peek_token(p)->kind != TokenKind_semicolon) {
- init = parse_expr(p);
+ if (is_type_token(p, peek_token(p))) {
+ init = parse_var_decl(p)->node_expr;
+ } else {
+ init = parse_expr(p);
+ expect(p, TokenKind_semicolon);
+ }
+ } else {
+ expect(p, TokenKind_semicolon);
}
- expect(p, TokenKind_semicolon);
if (peek_token(p)->kind != TokenKind_semicolon) {
cond = parse_expr(p);
} else {
@@ -788,51 +831,6 @@ AstNode* parse_continue_stmt(Parser* p) {
return ast_new(AstNodeKind_continue_stmt);
}
-AstNode* parse_var_decl(Parser* p) {
- Type* ty = parse_type(p);
- if (type_is_unsized(ty)) {
- fatal_error("parse_var_decl: invalid type for variable");
- }
- String* name = parse_ident(p);
-
- 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_var_decl: invalid array size");
- }
- int size = size_expr->node_int_value;
- expect(p, TokenKind_bracket_r);
- ty = type_new_array(ty, size);
- }
-
- AstNode* init = NULL;
- if (peek_token(p)->kind == TokenKind_assign) {
- next_token(p);
- init = parse_expr(p);
- }
- expect(p, TokenKind_semicolon);
-
- if (find_lvar(p, name) != -1 || find_gvar(p, name) != -1) {
- fatal_error("parse_var_decl: %.*s redeclared", name->len, name->data);
- }
- int stack_offset = add_lvar(p, name, ty, FALSE);
-
- AstNode* ret;
- if (init) {
- AstNode* lhs = ast_new(AstNodeKind_lvar);
- lhs->name = *name;
- lhs->node_stack_offset = stack_offset;
- lhs->ty = ty;
- AstNode* assign = ast_new_assign_expr(TokenKind_assign, lhs, init);
- ret = ast_new(AstNodeKind_expr_stmt);
- ret->node_expr = assign;
- } else {
- ret = ast_new(AstNodeKind_lvar_decl);
- }
- return ret;
-}
-
AstNode* parse_expr_stmt(Parser* p) {
AstNode* e = parse_expr(p);
expect(p, TokenKind_semicolon);
@@ -890,8 +888,7 @@ void enter_func(Parser* p) {
}
void register_params(Parser* p, AstNode* params) {
- int i;
- for (i = 0; i < params->node_len; ++i) {
+ for (int i = 0; i < params->node_len; ++i) {
AstNode* param = params->node_items + i;
add_lvar(p, &param->name, param->ty, TRUE);
}
diff --git a/preprocess.c b/preprocess.c
index 7ba7c7c..b7e52bf 100644
--- a/preprocess.c
+++ b/preprocess.c
@@ -336,11 +336,10 @@ PpMacros* pp_macros_new() {
}
void pp_macros_dump(PpMacros* pp_macros) {
- int i;
fprintf(stderr, "PpMacros {\n");
fprintf(stderr, " len = %zu\n", pp_macros->len);
fprintf(stderr, " data = [\n");
- for (i = 0; i < pp_macros->len; ++i) {
+ for (int i = 0; i < pp_macros->len; ++i) {
PpMacro* m = &pp_macros->data[i];
fprintf(stderr, " PpMacro {\n");
fprintf(stderr, " kind = %s\n", pp_macro_kind_stringify(m->kind));
@@ -406,8 +405,7 @@ Preprocessor* preprocessor_new(InFile* src, int include_depth, PpMacros* pp_macr
}
int find_pp_macro(Preprocessor* pp, String* name) {
- int i;
- for (i = 0; i < pp->pp_macros->len; ++i) {
+ for (int i = 0; i < pp->pp_macros->len; ++i) {
if (string_equals(&pp->pp_macros->data[i].name, name)) {
return i;
}
@@ -722,8 +720,7 @@ Token* skip_whitespace(Token* tok) {
}
BOOL string_contains_newline(String* s) {
- int i;
- for (i = 0; i < s->len; ++i) {
+ for (int i = 0; i < s->len; ++i) {
if (s->data[i] == '\n') {
return TRUE;
}
@@ -834,8 +831,7 @@ const char* resolve_include_name(Preprocessor* pp, String* include_name) {
sprintf(buf, "%.*s", include_name->len - 2, include_name->data + 1);
return buf;
} else {
- int i;
- for (i = 0; i < pp->n_include_paths; ++i) {
+ for (int i = 0; i < pp->n_include_paths; ++i) {
buf = calloc(include_name->len + 1 + pp->include_paths[i].len, sizeof(char));
sprintf(buf, "%s/%.*s", pp->include_paths[i].data, include_name->len, include_name->data);
if (access(buf, F_OK | R_OK) == 0) {
diff --git a/tests/087.sh b/tests/087.sh
new file mode 100644
index 0000000..e662687
--- /dev/null
+++ b/tests/087.sh
@@ -0,0 +1,24 @@
+set -e
+
+cat <<'EOF' > expected
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+EOF
+
+bash ../../test_diff.sh <<'EOF'
+int printf();
+
+int main() {
+ for (int i = 0; i < 10; i++) {
+ printf("%d\n", i);
+ }
+}
+EOF