diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-02 17:50:56 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-02 18:29:51 +0900 |
| commit | 2509637fb653cc8f5987736c1485a35245baa9b7 (patch) | |
| tree | 18f5cbc7d750b90d916f4d1db5dc5c823178bb54 | |
| parent | d81d087caf4fdb9a6ce482133d5c50c3113d13cc (diff) | |
| download | ducc-2509637fb653cc8f5987736c1485a35245baa9b7.tar.gz ducc-2509637fb653cc8f5987736c1485a35245baa9b7.tar.zst ducc-2509637fb653cc8f5987736c1485a35245baa9b7.zip | |
feat: generate .file and .loc directives
| -rw-r--r-- | src/ast.h | 3 | ||||
| -rw-r--r-- | src/cli.c | 4 | ||||
| -rw-r--r-- | src/cli.h | 1 | ||||
| -rw-r--r-- | src/codegen.c | 8 | ||||
| -rw-r--r-- | src/codegen.h | 2 | ||||
| -rw-r--r-- | src/main.c | 2 | ||||
| -rw-r--r-- | src/parse.c | 73 |
7 files changed, 76 insertions, 17 deletions
@@ -2,6 +2,7 @@ #define DUCC_AST_H #include "ducc.h" +#include "io.h" typedef enum { StorageClass_unspecified, @@ -328,6 +329,8 @@ typedef struct { struct AstNode { AstNodeKind kind; + // TODO: currently only limited set of ast nodes have loc field. + SourceLocation loc; Type* ty; union { IntExprNode* int_expr; @@ -17,6 +17,7 @@ CliArgs* parse_cli_args(int argc, char** argv) { bool opt_wasm = false; bool opt_MD = false; bool opt_MMD = false; + bool opt_g = false; StrArray include_dirs; strings_init(&include_dirs); StrArray defines; @@ -76,6 +77,8 @@ CliArgs* parse_cli_args(int argc, char** argv) { opt_c = true; } else if (c == 'E') { opt_E = true; + } else if (c == 'g') { + opt_g = true; } else if (strcmp(argv[i], "-MD") == 0) { opt_MD = true; } else if (strcmp(argv[i], "-MMD") == 0) { @@ -106,6 +109,7 @@ CliArgs* parse_cli_args(int argc, char** argv) { a->gcc_command = NULL; a->generate_system_deps = opt_MD; a->generate_user_deps = opt_MD || opt_MMD; + a->generate_debug_info = opt_g; a->include_dirs = include_dirs; a->defines = defines; @@ -11,6 +11,7 @@ typedef struct { bool preprocess_only; bool generate_system_deps; bool generate_user_deps; + bool generate_debug_info; bool totally_deligate_to_gcc; bool wasm; const char* gcc_command; diff --git a/src/codegen.c b/src/codegen.c index bc1e3d3..7f85fbd 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -777,6 +777,9 @@ static void codegen_block_stmt(CodeGen* g, AstNode* ast) { } static void codegen_stmt(CodeGen* g, AstNode* ast) { + // TODO: support multiple files. + fprintf(g->out, " .loc 1 %d 0\n", ast->loc.line); + if (ast->kind == AstNodeKind_list) { codegen_block_stmt(g, ast); } else if (ast->kind == AstNodeKind_return_stmt) { @@ -864,11 +867,14 @@ static void codegen_global_var(CodeGen* g, AstNode* var) { } } -void codegen(Program* prog, FILE* out) { +void codegen(Program* prog, const char* input_filename, FILE* out) { CodeGen* g = codegen_new(prog, out); fprintf(g->out, ".intel_syntax noprefix\n\n"); + // TODO: support multiple files. + fprintf(g->out, ".file 1 \"%s\"\n\n", input_filename); + // For GNU ld: // https://sourceware.org/binutils/docs/ld/Options.html fprintf(g->out, ".section .note.GNU-stack,\"\",@progbits\n\n"); diff --git a/src/codegen.h b/src/codegen.h index 95ec069..2c1d7b3 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -3,6 +3,6 @@ #include "ast.h" -void codegen(Program* prog, FILE* out); +void codegen(Program* prog, const char* input_filename, FILE* out); #endif @@ -50,7 +50,7 @@ int main(int argc, char** argv) { if (cli_args->wasm) { codegen_wasm(prog, assembly_file); } else { - codegen(prog, assembly_file); + codegen(prog, cli_args->input_filename, assembly_file); } fclose(assembly_file); diff --git a/src/parse.c b/src/parse.c index 5601ee8..12d4fbf 100644 --- a/src/parse.c +++ b/src/parse.c @@ -182,6 +182,10 @@ static Token* peek_token2(Parser* p) { return &p->tokens->data[p->pos + 1]; } +static SourceLocation current_location(Parser* p) { + return peek_token(p)->loc; +} + static Token* next_token(Parser* p) { return &p->tokens->data[p->pos++]; } @@ -2417,8 +2421,10 @@ static AstNode* parse_unlabaled_stmt(Parser* p) { // TODO attribute-specifier-sequence? 'case' constant-expr ':' // TODO attribute-specifier-sequence? 'default' ':' static AstNode* parse_label(Parser* p) { + SourceLocation loc = current_location(p); Token* t = peek_token(p); + AstNode* node; if (t->kind == TokenKind_keyword_case) { if (!p->current_switch) { fatal_error("%s:%d: 'case' label not within a switch statement", t->loc.filename, t->loc.line); @@ -2426,20 +2432,22 @@ static AstNode* parse_label(Parser* p) { expect(p, TokenKind_keyword_case); AstNode* value = parse_constant_expr(p); expect(p, TokenKind_colon); - return ast_new_case_label(eval(value), ast_new_nop()); + node = ast_new_case_label(eval(value), ast_new_nop()); } else if (t->kind == TokenKind_keyword_default) { if (!p->current_switch) { fatal_error("%s:%d: 'default' label not within a switch statement", t->loc.filename, t->loc.line); } expect(p, TokenKind_keyword_default); expect(p, TokenKind_colon); - return ast_new_default_label(ast_new_nop()); + node = ast_new_default_label(ast_new_nop()); } else { // identifier ':' Token* label_token = expect(p, TokenKind_ident); expect(p, TokenKind_colon); - return ast_new_label_stmt(label_token->value.string, ast_new_nop()); + node = ast_new_label_stmt(label_token->value.string, ast_new_nop()); } + node->loc = loc; + return node; } static bool is_label_token(Parser* p) { @@ -2477,6 +2485,7 @@ static AstNode* parse_stmt(Parser* p) { // compound-stmt: // '{' { block-item }* '}' static AstNode* parse_compound_stmt(Parser* p) { + SourceLocation loc = current_location(p); AstNode* list = ast_new_list(4); expect(p, TokenKind_brace_l); enter_scope(p); @@ -2486,6 +2495,7 @@ static AstNode* parse_compound_stmt(Parser* p) { } leave_scope(p); expect(p, TokenKind_brace_r); + list->loc = loc; return list; } @@ -2508,18 +2518,24 @@ static AstNode* parse_block_item(Parser* p) { // expr-stmt: // TODO attribute-specifier-sequence? expr? ';' static AstNode* parse_expr_stmt(Parser* p) { + SourceLocation loc = current_location(p); if (consume_token_if(p, TokenKind_semicolon)) { - return ast_new_nop(); + AstNode* node = ast_new_nop(); + node->loc = loc; + return node; } AstNode* e = parse_expr(p); expect(p, TokenKind_semicolon); - return ast_new_expr_stmt(e); + AstNode* node = ast_new_expr_stmt(e); + node->loc = loc; + return node; } // if-stmt: // 'if' '(' expr ')' stmt ( 'else' stmt )? static AstNode* parse_if_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_if); expect(p, TokenKind_paren_l); AstNode* cond = parse_expr(p); @@ -2530,12 +2546,15 @@ static AstNode* parse_if_stmt(Parser* p) { else_body = parse_stmt(p); } - return ast_new_if_stmt(cond, then_body, else_body); + AstNode* node = ast_new_if_stmt(cond, then_body, else_body); + node->loc = loc; + return node; } // switch-stmt: // 'switch' '(' expr ')' stmt static AstNode* parse_switch_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_switch); expect(p, TokenKind_paren_l); AstNode* expr = parse_expr(p); @@ -2544,8 +2563,10 @@ static AstNode* parse_switch_stmt(Parser* p) { AstNode* tmp_var = generate_temporary_lvar(p, expr->ty); AstNode* assignment = ast_new_assign_expr(TokenKind_assign, tmp_var, expr); AstNode* assign_stmt = ast_new_expr_stmt(assignment); + assign_stmt->loc = loc; AstNode* switch_stmt = ast_new_switch_stmt(tmp_var); + switch_stmt->loc = loc; AstNode* prev_switch = p->current_switch; p->current_switch = switch_stmt; @@ -2553,6 +2574,7 @@ static AstNode* parse_switch_stmt(Parser* p) { p->current_switch = prev_switch; AstNode* list = ast_new_list(2); + list->loc = loc; ast_append(list, assign_stmt); ast_append(list, switch_stmt); return list; @@ -2561,17 +2583,21 @@ static AstNode* parse_switch_stmt(Parser* p) { // while-stmt: // 'while' '(' expr ')' stmt static AstNode* parse_while_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_while); expect(p, TokenKind_paren_l); AstNode* cond = parse_expr(p); expect(p, TokenKind_paren_r); AstNode* body = parse_stmt(p); - return ast_new_for_stmt(NULL, cond, NULL, body); + AstNode* node = ast_new_for_stmt(NULL, cond, NULL, body); + node->loc = loc; + return node; } // do-while-stmt: // 'do' stmt 'while' '(' expr ')' ';' static AstNode* parse_do_while_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_do); AstNode* body = parse_stmt(p); expect(p, TokenKind_keyword_while); @@ -2580,13 +2606,16 @@ static AstNode* parse_do_while_stmt(Parser* p) { expect(p, TokenKind_paren_r); expect(p, TokenKind_semicolon); - return ast_new_do_while_stmt(cond, body); + AstNode* node = ast_new_do_while_stmt(cond, body); + node->loc = loc; + return node; } // for-stmt: // 'for' '(' expr? ';' expr? ';' expr? ')' stmt // 'for' '(' declaration expr? ';' expr? ')' stmt static AstNode* parse_for_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_for); expect(p, TokenKind_paren_l); AstNode* init = NULL; @@ -2623,45 +2652,61 @@ static AstNode* parse_for_stmt(Parser* p) { expect(p, TokenKind_paren_r); AstNode* body = parse_stmt(p); leave_scope(p); - return ast_new_for_stmt(init, cond, update, body); + AstNode* node = ast_new_for_stmt(init, cond, update, body); + node->loc = loc; + return node; } // goto-stmt: // 'goto' identifier ';' static AstNode* parse_goto_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_goto); Token* label_token = expect(p, TokenKind_ident); expect(p, TokenKind_semicolon); - return ast_new_goto_stmt(label_token->value.string); + AstNode* node = ast_new_goto_stmt(label_token->value.string); + node->loc = loc; + return node; } // continue-stmt: // 'continue' ';' static AstNode* parse_continue_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_continue); expect(p, TokenKind_semicolon); - return ast_new_continue_stmt(); + AstNode* node = ast_new_continue_stmt(); + node->loc = loc; + return node; } // break-stmt: // 'break' ';' static AstNode* parse_break_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_break); expect(p, TokenKind_semicolon); - return ast_new_break_stmt(); + AstNode* node = ast_new_break_stmt(); + node->loc = loc; + return node; } // return-stmt: // 'return' expr? ';' static AstNode* parse_return_stmt(Parser* p) { + SourceLocation loc = current_location(p); expect(p, TokenKind_keyword_return); if (consume_token_if(p, TokenKind_semicolon)) { - return ast_new_return_stmt(NULL); + AstNode* node = ast_new_return_stmt(NULL); + node->loc = loc; + return node; } AstNode* expr = parse_expr(p); expect(p, TokenKind_semicolon); - return ast_new_return_stmt(expr); + AstNode* node = ast_new_return_stmt(expr); + node->loc = loc; + return node; } // static_assert-declaration: |
