diff --git a/chibi.h b/chibi.h index 33d95fc..b5eed65 100644 --- a/chibi.h +++ b/chibi.h @@ -212,6 +212,7 @@ struct Function { char *name; VarList *params; bool is_static; + bool has_varargs; Node *node; VarList *locals; diff --git a/parse.c b/parse.c index 6d53623..3114c4e 100644 --- a/parse.c +++ b/parse.c @@ -609,25 +609,30 @@ static VarList *read_func_param(void) { return vl; } -static VarList *read_func_params(void) { +static void read_func_params(Function *fn) { if (consume(")")) - return NULL; + return; Token *tok = token; if (consume("void") && consume(")")) - return NULL; + return; token = tok; - VarList *head = read_func_param(); - VarList *cur = head; + fn->params = read_func_param(); + VarList *cur = fn->params; while (!consume(")")) { expect(","); + + if (consume("...")) { + fn->has_varargs = true; + expect(")"); + return; + } + cur->next = read_func_param(); cur = cur->next; } - - return head; } // function = basetype declarator "(" params? ")" ("{" stmt* "}" | ";") @@ -651,7 +656,7 @@ static Function *function(void) { expect("("); Scope *sc = enter_scope(); - fn->params = read_func_params(); + read_func_params(fn); if (consume(";")) { leave_scope(sc); diff --git a/self.sh b/self.sh index ac833cf..7f71715 100755 --- a/self.sh +++ b/self.sh @@ -36,7 +36,6 @@ EOF sed -i 's/\berrno\b/*__errno_location()/g' $TMP/$1 sed -i 's/\btrue\b/1/g; s/\bfalse\b/0/g;' $TMP/$1 sed -i 's/\bNULL\b/0/g' $TMP/$1 - sed -i 's/, \.\.\.//g' $TMP/$1 sed -i 's/INT_MAX/2147483647/g' $TMP/$1 ./chibicc $TMP/$1 > $TMP/${1%.c}.s diff --git a/tests b/tests index e46b41d..0f95681 100644 --- a/tests +++ b/tests @@ -137,6 +137,9 @@ int counter() { _Bool true_fn(); _Bool false_fn(); +int add_all1(int x, ...); +int add_all3(int z, int b, int c, ...); + int main() { assert(8, ({ int a=3; int z=5; a+z; }), "int a=3; int z=5; a+z;"); @@ -700,6 +703,12 @@ int main() { assert(1, true_fn(), "true_fn()"); assert(0, false_fn(), "false_fn()"); + assert(6, add_all1(1,2,3,0), "add_all1(1,2,3,0)"); + assert(5, add_all1(1,2,3,-1,0), "add_all1(1,2,3,-1,0)"); + + assert(6, add_all3(1,2,3,0), "add_all3(1,2,3,0)"); + assert(5, add_all3(1,2,3,-1,0), "add_all3(1,2,3,-1,0)"); + printf("OK\n"); return 0; } diff --git a/tests-extern b/tests-extern index 192b1cf..9dd6b98 100644 --- a/tests-extern +++ b/tests-extern @@ -1,7 +1,34 @@ // -*- c -*- +#include + int ext1; int *ext2; int false_fn() { return 512; } int true_fn() { return 513; } int static_fn() { return 5; } + +int add_all1(int x, ...) { + va_list ap; + va_start(ap, x); + + for (;;) { + int y = va_arg(ap, int); + if (y == 0) + return x; + x += y; + } +} + +int add_all3(int x, int y, int z, ...) { + va_list ap; + va_start(ap, z); + x = x + y + z; + + for (;;) { + int y = va_arg(ap, int); + if (y == 0) + return x; + x += y; + } +} diff --git a/tokenize.c b/tokenize.c index 7f809bd..aa7c641 100644 --- a/tokenize.c +++ b/tokenize.c @@ -160,8 +160,8 @@ static char *starts_with_reserved(char *p) { } // Multi-letter punctuator - static char *ops[] = {"<<=", ">>=", "==", "!=", "<=", ">=", "->", - "++", "--", "<<", ">>", "+=", "-=", "*=", + static char *ops[] = {"<<=", ">>=", "...", "==", "!=", "<=", ">=", + "->", "++", "--", "<<", ">>", "+=", "-=", "*=", "/=", "&&", "||", "&=", "|=", "^="}; for (int i = 0; i < sizeof(ops) / sizeof(*ops); i++)