aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--codegen.c25
-rw-r--r--common.c8
-rw-r--r--justfile2
-rw-r--r--parse.c9
-rw-r--r--preprocess.c88
-rw-r--r--std.h31
-rw-r--r--tests/063.sh52
-rw-r--r--tokenize.c7
8 files changed, 175 insertions, 47 deletions
diff --git a/codegen.c b/codegen.c
index 26e7604..c8d6e5b 100644
--- a/codegen.c
+++ b/codegen.c
@@ -209,8 +209,31 @@ void codegen_assign_expr(CodeGen* g, AstNode* ast) {
void codegen_func_call(CodeGen* g, AstNode* ast) {
String* func_name = &ast->name;
- AstNode* args = ast->node_args;
int i;
+
+ if (string_equals_cstr(func_name, "va_start")) {
+ printf(" # va_start BEGIN\n");
+ for (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);
+ }
+ AstNode* va_list_args = ast->node_args->node_items;
+ codegen_expr(g, va_list_args, GenMode_lval);
+ printf(" pop rdi\n");
+ printf(" mov rax, rbp\n");
+ printf(" sub rax, %d\n", 8 + (LVAR_MAX - 1) * 8);
+ printf(" mov [rdi], rax\n");
+ printf(" mov DWORD PTR [rax], 8\n");
+ printf(" mov DWORD PTR [rax+4], 0\n");
+ printf(" mov QWORD PTR [rax+8], 0\n");
+ printf(" mov rdi, rbp\n");
+ printf(" sub rdi, %d\n", 8 + (LVAR_MAX - 4) * 8);
+ printf(" mov QWORD PTR [rax+16], rdi\n");
+ printf(" # va_start END\n");
+ return;
+ }
+
+ AstNode* args = ast->node_args;
for (i = 0; i < args->node_len; ++i) {
AstNode* arg = args->node_items + i;
codegen_expr(g, arg, GenMode_rval);
diff --git a/common.c b/common.c
index fcc0790..678065a 100644
--- a/common.c
+++ b/common.c
@@ -1,5 +1,9 @@
-void fatal_error(const char* msg) {
- fprintf(stderr, "%s\n", msg);
+void fatal_error(const char* msg, ...) {
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, "\n");
exit(1);
}
diff --git a/justfile b/justfile
index 016fa19..bb945aa 100644
--- a/justfile
+++ b/justfile
@@ -3,7 +3,7 @@ all: build
build N="1":
#!/usr/bin/env bash
if [[ {{N}} = 1 ]]; then
- gcc -g -O0 -o ducc main.c
+ gcc -Wno-builtin-declaration-mismatch -g -O0 -o ducc main.c
else
if [[ {{N}} = 2 ]]; then
prev=""
diff --git a/parse.c b/parse.c
index b056077..b0f6892 100644
--- a/parse.c
+++ b/parse.c
@@ -47,6 +47,13 @@ Parser* parser_new(Token* tokens) {
p->enums = calloc(16, sizeof(AstNode));
p->typedefs = calloc(64, sizeof(AstNode));
p->str_literals = calloc(1024, sizeof(char*));
+
+ p->funcs[p->n_funcs].name.data = "va_start";
+ p->funcs[p->n_funcs].name.len = strlen("va_start");
+ p->funcs[p->n_funcs].ty = calloc(1, sizeof(Type));
+ p->funcs[p->n_funcs].ty->kind = TypeKind_void;
+ ++p->n_funcs;
+
return p;
}
@@ -174,7 +181,7 @@ AstNode* parse_primary_expr(Parser* p) {
e = parse_expr(p);
expect(p, TokenKind_paren_r);
return e;
- } else if (t->kind == TokenKind_ident) {
+ } else if (t->kind == TokenKind_ident || t->kind == TokenKind_va_start) {
String* name = &t->raw;
if (peek_token(p)->kind == TokenKind_paren_l) {
diff --git a/preprocess.c b/preprocess.c
index 205e2bd..0a577a2 100644
--- a/preprocess.c
+++ b/preprocess.c
@@ -346,35 +346,48 @@ void process_pp_directives(Preprocessor* pp) {
PpToken* tok2 = tok + 1;
while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace)
++tok2;
- if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "define")) {
+ if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "endif")) {
+ ++tok2;
+ pp->skip_pp_tokens = 0;
+ // Remove #endif directive.
+ while (tok != tok2) {
+ tok->kind = PpTokenKind_whitespace;
+ tok->raw.len = 0;
+ tok->raw.data = NULL;
+ ++tok;
+ }
+ } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "else")) {
+ ++tok2;
+ pp->skip_pp_tokens = 1 - pp->skip_pp_tokens;
+ // Remove #else directive.
+ while (tok != tok2) {
+ tok->kind = PpTokenKind_whitespace;
+ tok->raw.len = 0;
+ tok->raw.data = NULL;
+ ++tok;
+ }
+ } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "ifdef")) {
++tok2;
while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace)
++tok2;
if (tok2->kind == PpTokenKind_identifier) {
- PpToken* define_name = tok2;
+ // Process #ifdef directive.
+ PpToken* name = tok2;
++tok2;
- while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace)
- ++tok2;
- if (tok2->kind == PpTokenKind_identifier || tok2->kind == PpTokenKind_pp_number) {
- define_dest = tok2;
- PpDefine* pp_define = pp->pp_defines->data + pp->pp_defines->len;
- pp_define->name.len = define_name->raw.len;
- pp_define->name.data = define_name->raw.data;
- pp_define->tokens = calloc(1, sizeof(PpToken));
- pp_define->tokens[0].kind = define_dest->kind;
- pp_define->tokens[0].raw.len = define_dest->raw.len;
- pp_define->tokens[0].raw.data = define_dest->raw.data;
- ++pp->pp_defines->len;
- }
+ pp->skip_pp_tokens = find_pp_define(pp, &name->raw) == -1;
}
- // Remove #define directive.
- while (tok != tok2 + 1) {
+ // Remove #ifdef directive.
+ while (tok != tok2) {
tok->kind = PpTokenKind_whitespace;
tok->raw.len = 0;
tok->raw.data = NULL;
++tok;
}
+ } else if (skip_pp_tokens(pp)) {
+ tok->kind = PpTokenKind_whitespace;
+ tok->raw.len = 0;
+ tok->raw.data = NULL;
} else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "include")) {
++tok2;
while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace)
@@ -422,38 +435,29 @@ void process_pp_directives(Preprocessor* pp) {
pp->n_pp_tokens += n_include_pp_tokens;
}
- } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "ifdef")) {
+ } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "define")) {
++tok2;
while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace)
++tok2;
if (tok2->kind == PpTokenKind_identifier) {
- // Process #ifdef directive.
- PpToken* name = tok2;
+ PpToken* define_name = tok2;
++tok2;
+ while (tok2->kind != PpTokenKind_eof && tok2->kind == PpTokenKind_whitespace)
+ ++tok2;
+ if (tok2->kind == PpTokenKind_identifier || tok2->kind == PpTokenKind_pp_number) {
+ define_dest = tok2;
- pp->skip_pp_tokens = find_pp_define(pp, &name->raw) == -1;
- }
- // Remove #ifdef directive.
- while (tok != tok2 + 1) {
- tok->kind = PpTokenKind_whitespace;
- tok->raw.len = 0;
- tok->raw.data = NULL;
- ++tok;
- }
- } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "endif")) {
- ++tok2;
- pp->skip_pp_tokens = 0;
- // Remove #endif directive.
- while (tok != tok2 + 1) {
- tok->kind = PpTokenKind_whitespace;
- tok->raw.len = 0;
- tok->raw.data = NULL;
- ++tok;
+ PpDefine* pp_define = pp->pp_defines->data + pp->pp_defines->len;
+ pp_define->name.len = define_name->raw.len;
+ pp_define->name.data = define_name->raw.data;
+ pp_define->tokens = calloc(1, sizeof(PpToken));
+ pp_define->tokens[0].kind = define_dest->kind;
+ pp_define->tokens[0].raw.len = define_dest->raw.len;
+ pp_define->tokens[0].raw.data = define_dest->raw.data;
+ ++pp->pp_defines->len;
+ }
}
- } else if (tok2->kind == PpTokenKind_identifier && string_equals_cstr(&tok2->raw, "else")) {
- ++tok2;
- pp->skip_pp_tokens = 1 - pp->skip_pp_tokens;
- // Remove #else directive.
+ // Remove #define directive.
while (tok != tok2 + 1) {
tok->kind = PpTokenKind_whitespace;
tok->raw.len = 0;
diff --git a/std.h b/std.h
index 23a2e9a..86c86f5 100644
--- a/std.h
+++ b/std.h
@@ -29,3 +29,34 @@ int strncmp(const char*, const char*, size_t);
char* strstr(const char*, const char*);
#define NULL 0
+
+#ifdef __ducc__
+
+// System V Application Binary Interface
+// AMD64 Architecture Processor Supplement
+// (With LP64 and ILP32 Programming Models)
+// Version 1.0
+// Figure 3.34: va_list Type Declaration
+struct __va_list__ {
+ // unsigned int gp_offset;
+ // unsigned int fp_offset;
+ int gp_offset;
+ int fp_offset;
+ void* overflow_arg_area;
+ void* reg_save_area;
+};
+// ducc currently does not support array type.
+// typedef struct __va_list__ va_list[1];
+typedef struct __va_list__* va_list;
+
+// va_start() is currently implemented as a special form due to the limitation of #define macro.
+void va_end(va_list args) {
+}
+
+#else
+
+#include <stdarg.h>
+
+#endif
+
+int vfprintf(FILE*, const char*, va_list);
diff --git a/tests/063.sh b/tests/063.sh
new file mode 100644
index 0000000..f5f9505
--- /dev/null
+++ b/tests/063.sh
@@ -0,0 +1,52 @@
+set -e
+
+cat <<'EOF' > expected
+123
+456 789
+EOF
+
+bash ../../test_diff.sh <<'EOF'
+int fprintf();
+
+// System V Application Binary Interface
+// AMD64 Architecture Processor Supplement
+// (With LP64 and ILP32 Programming Models)
+// Version 1.0
+// Figure 3.34: va_list Type Declaration
+struct __va_list__ {
+ // unsigned int gp_offset;
+ // unsigned int fp_offset;
+ int gp_offset;
+ int fp_offset;
+ void* overflow_arg_area;
+ void* reg_save_area;
+};
+// ducc currently does not support array type.
+// typedef struct __va_list__ va_list[1];
+typedef struct __va_list__* va_list;
+
+// va_start() is currently implemented as a special form due to the limitation of #define macro.
+void va_end(va_list args) {
+}
+
+struct FILE;
+typedef struct FILE FILE;
+
+extern FILE* stdout;
+
+int vfprintf(FILE*, const char*, va_list);
+
+void fatal_error(const char* msg, ...) {
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stdout, msg, args);
+ va_end(args);
+ fprintf(stdout, "\n");
+}
+
+int main() {
+ fatal_error("%d", 123);
+ fatal_error("%d %d", 456, 789);
+ return 0;
+}
+EOF
diff --git a/tokenize.c b/tokenize.c
index 71427d0..f177d82 100644
--- a/tokenize.c
+++ b/tokenize.c
@@ -53,6 +53,9 @@ enum TokenKind {
TokenKind_semicolon,
TokenKind_slash,
TokenKind_star,
+
+ // va_start() is currently implemented as a special form due to the current limitation of #define macro.
+ TokenKind_va_start,
};
typedef enum TokenKind TokenKind;
@@ -169,6 +172,8 @@ const char* token_kind_stringify(TokenKind k) {
return "/";
else if (k == TokenKind_star)
return "*";
+ else if (k == TokenKind_va_start)
+ return "va_start";
else
unreachable();
}
@@ -247,6 +252,8 @@ void tokenize_all(Lexer* l) {
tok->kind = TokenKind_keyword_void;
} else if (string_equals_cstr(&pp_tok->raw, "while")) {
tok->kind = TokenKind_keyword_while;
+ } else if (string_equals_cstr(&pp_tok->raw, "va_start")) {
+ tok->kind = TokenKind_va_start;
} else {
tok->kind = TokenKind_ident;
}