diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-05-03 20:02:07 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-05-03 20:02:07 +0900 |
| commit | 7570e8a0af6b4d8ea28d422cd8e4645fb23300af (patch) | |
| tree | e131c5cf1ebdc7516c4e86587bb88b174090779f | |
| parent | 2783653dd95c2e4acb69151aee9350926204493a (diff) | |
| download | P4Dcc-7570e8a0af6b4d8ea28d422cd8e4645fb23300af.tar.gz P4Dcc-7570e8a0af6b4d8ea28d422cd8e4645fb23300af.tar.zst P4Dcc-7570e8a0af6b4d8ea28d422cd8e4645fb23300af.zip | |
string literals
| -rw-r--r-- | main.c | 70 | ||||
| -rw-r--r-- | tests/018.sh | 22 | ||||
| -rw-r--r-- | tests/019.sh | 28 | ||||
| -rw-r--r-- | tests/test_output.sh | 2 |
4 files changed, 116 insertions, 6 deletions
@@ -177,6 +177,23 @@ TOKEN* tokenize(char* src, int len) { tok->kind = TK_GT; tok += 1; } + } else if (c == '"') { + pos += 1; + int start = pos; + while (1) { + int ch = src[pos]; + if (ch == '\\') { + pos += 1; + } else if (ch == '"') { + break; + } + pos += 1; + } + tok->kind = TK_L_STR; + tok->value = calloc(pos - start + 1, sizeof(char)); + memcpy(tok->value, src + start, pos - start); + pos += 1; + tok += 1; } else if (isdigit(c)) { int start = pos; while (isdigit(src[pos])) { @@ -268,9 +285,10 @@ TYPE* type_new(int kind) { #define AST_PARAM_LIST 16 #define AST_PROGRAM 17 #define AST_RETURN_STMT 18 -#define AST_TYPE 19 -#define AST_UNARY_EXPR 20 -#define AST_VAR_DECL 21 +#define AST_STR_LIT_EXPR 19 +#define AST_TYPE 20 +#define AST_UNARY_EXPR 21 +#define AST_VAR_DECL 22 typedef struct AstNode { int kind; @@ -288,6 +306,7 @@ typedef struct AstNode { int var_index; struct AstNode* node1; struct AstNode* node2; + char** str_literals; } AST; AST* ast_new(int kind) { @@ -339,11 +358,14 @@ typedef struct Parser { int pos; LVAR* locals; int n_locals; + char** str_literals; + int n_str_literals; } PARSER; PARSER* parser_new(TOKEN* tokens) { PARSER* p = calloc(1, sizeof(PARSER)); p->tokens = tokens; + p->str_literals = calloc(1024, sizeof(char*)); return p; } @@ -388,12 +410,23 @@ char* parse_ident(PARSER* p) { return expect(p, TK_IDENT)->value; } +int parse_register_str_lit(PARSER* p, char* s) { + p->str_literals[p->n_str_literals] = s; + p->n_str_literals += 1; + return p->n_str_literals; +} + AST* parse_primary_expr(PARSER* p) { TOKEN* t = next_token(p); if (t->kind == TK_L_INT) { AST* e = ast_new(AST_INT_LIT_EXPR); e->int_value = atoi(t->value); return e; + } else if (t->kind == TK_L_STR) { + int str_lit_index = parse_register_str_lit(p, t->value); + AST* e = ast_new(AST_STR_LIT_EXPR); + e->int_value = str_lit_index; + return e; } else if (t->kind == TK_PAREN_L) { AST* e = parse_expr(p); expect(p, TK_PAREN_R); @@ -729,11 +762,15 @@ AST* parse_func_decl_or_def(PARSER* p) { TOKEN* t = peek_token(p); if (t->kind == TK_K_INT) { next_token(p); - parse_enter_func(p); TOKEN* name = expect(p, TK_IDENT); expect(p, TK_PAREN_L); AST* params = parse_param_list(p); expect(p, TK_PAREN_R); + if (peek_token(p)->kind == TK_SEMICOLON) { + next_token(p); + return ast_new(AST_FUNC_DECL); + } + parse_enter_func(p); parse_register_params(p, params); AST* body = parse_block_stmt(p); AST* func = ast_new(AST_FUNC_DEF); @@ -757,6 +794,7 @@ AST* parse(PARSER* p) { list->last->next = n; list->last = n; } + list->str_literals = p->str_literals; return list; } @@ -836,6 +874,14 @@ void gen_int_lit_expr(CODEGEN* g, AST* ast) { printf(" push %d\n", ast->int_value); } +void gen_str_lit_expr(CODEGEN* g, AST* ast) { + assert_ast_kind(ast, AST_STR_LIT_EXPR); + printf(" # gen_str_lit_expr\n"); + + printf(" mov rax, OFFSET FLAG:.Lstr__%d\n", ast->int_value); + printf(" push rax\n"); +} + void gen_unary_expr(CODEGEN* g, AST* ast) { assert_ast_kind(ast, AST_UNARY_EXPR); printf(" # gen_unary_expr\n"); @@ -954,6 +1000,8 @@ void gen_lvar(CODEGEN* g, AST* ast, int gen_mode) { void gen_expr(CODEGEN* g, AST* ast, int gen_mode) { if (ast->kind == AST_INT_LIT_EXPR) { gen_int_lit_expr(g, ast); + } else if (ast->kind == AST_STR_LIT_EXPR) { + gen_str_lit_expr(g, ast); } else if (ast->kind == AST_UNARY_EXPR) { gen_unary_expr(g, ast); } else if (ast->kind == AST_BINARY_EXPR) { @@ -1090,12 +1138,24 @@ void gen_func(CODEGEN* g, AST* ast) { void gen(CODEGEN* g, AST* ast) { assert_ast_kind(ast, AST_PROGRAM); + printf(".intel_syntax noprefix\n\n"); + + int str_index = 1; + char** str_lit = ast->str_literals; + while (*str_lit) { + printf(".Lstr__%d:\n", str_index); + printf(" .string \"%s\"\n\n", *str_lit); + str_lit += 1; + } + printf(".globl main\n\n"); AST* func = ast->next; while (func) { - gen_func(g, func); + if (func->kind == AST_FUNC_DEF) { + gen_func(g, func); + } func = func->next; } } diff --git a/tests/018.sh b/tests/018.sh new file mode 100644 index 0000000..eb86a5e --- /dev/null +++ b/tests/018.sh @@ -0,0 +1,22 @@ +set -e + +bash ../../test_output.sh "" <<'EOF' +int main() { + ""; + return 0; +} +EOF + +bash ../../test_output.sh "" <<'EOF' +int main() { + "abc"; + return 0; +} +EOF + +bash ../../test_output.sh "" <<'EOF' +int main() { + "\"foo\"bar\\\n\""; + return 0; +} +EOF diff --git a/tests/019.sh b/tests/019.sh new file mode 100644 index 0000000..d31f154 --- /dev/null +++ b/tests/019.sh @@ -0,0 +1,28 @@ +set -e + +bash ../../test_output.sh "" <<'EOF' +int printf(); + +int main() { + printf(""); + return 0; +} +EOF + +bash ../../test_output.sh "Hello, World!" <<'EOF' +int printf(); + +int main() { + printf("Hello, World!\n"); + return 0; +} +EOF + +bash ../../test_output.sh '"Hello, World!"' <<'EOF' +int printf(); + +int main() { + printf("\"Hello, World!\"\n"); + return 0; +} +EOF diff --git a/tests/test_output.sh b/tests/test_output.sh index f4a4a20..2c8fb29 100644 --- a/tests/test_output.sh +++ b/tests/test_output.sh @@ -16,7 +16,7 @@ fi expected="$1" -if [[ "$output" -ne "$expected" ]]; then +if [[ "$output" != "$expected" ]]; then echo "invalid output: expected '$expected', but got '$output'" >&2 exit 1 fi |
