From 8e19cadfd6de3db6b4cd025be8a6028071a83dd6 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 27 Aug 2020 22:05:29 +0900 Subject: [PATCH] Allow to call a variadic function --- chibicc.h | 1 + parse.c | 11 ++++++++++- test/common | 10 ++++++++++ test/function.c | 7 +++++++ test/test.h | 4 ++-- tokenize.c | 3 ++- 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/chibicc.h b/chibicc.h index fa3cec2..cffbf5f 100644 --- a/chibicc.h +++ b/chibicc.h @@ -243,6 +243,7 @@ struct Type { // Function type Type *return_ty; Type *params; + bool is_variadic; Type *next; }; diff --git a/parse.c b/parse.c index 5ee3228..6d87145 100644 --- a/parse.c +++ b/parse.c @@ -485,7 +485,7 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { return ty; } -// func-params = ("void" | param ("," param)*?)? ")" +// func-params = ("void" | param ("," param)* ("," "...")?)? ")" // param = typespec declarator static Type *func_params(Token **rest, Token *tok, Type *ty) { if (equal(tok, "void") && equal(tok->next, ")")) { @@ -495,11 +495,19 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) { Type head = {}; Type *cur = &head; + bool is_variadic = false; while (!equal(tok, ")")) { if (cur != &head) tok = skip(tok, ","); + if (equal(tok, "...")) { + is_variadic = true; + tok = tok->next; + skip(tok, ")"); + break; + } + Type *ty2 = typespec(&tok, tok, NULL); ty2 = declarator(&tok, tok, ty2); @@ -516,6 +524,7 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) { ty = func_type(ty); ty->params = head.next; + ty->is_variadic = is_variadic; *rest = tok->next; return ty; } diff --git a/test/common b/test/common index d488bdd..74065f7 100644 --- a/test/common +++ b/test/common @@ -22,3 +22,13 @@ int false_fn() { return 512; } int true_fn() { return 513; } int char_fn() { return (2<<8)+3; } int short_fn() { return (2<<16)+5; } + +int add_all(int n, ...) { + va_list ap; + va_start(ap, n); + + int sum = 0; + for (int i = 0; i < n; i++) + sum += va_arg(ap, int); + return sum; +} diff --git a/test/function.c b/test/function.c index df09ddd..0c0d36d 100644 --- a/test/function.c +++ b/test/function.c @@ -70,6 +70,8 @@ _Bool false_fn(); char char_fn(); short short_fn(); +int add_all(int n, ...); + int main() { ASSERT(3, ret3()); ASSERT(8, add2(3, 5)); @@ -116,6 +118,11 @@ int main() { ASSERT(3, char_fn()); ASSERT(5, short_fn()); + ASSERT(6, add_all(3,1,2,3)); + ASSERT(5, add_all(4,1,2,3,-1)); + + ASSERT(0, ({ char buf[100]; sprintf(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); })); + printf("OK\n"); return 0; } diff --git a/test/test.h b/test/test.h index 380607a..de46a32 100644 --- a/test/test.h +++ b/test/test.h @@ -1,7 +1,7 @@ #define ASSERT(x, y) assert(x, y, #y) int assert(int expected, int actual, char *code); -int printf(); -int sprintf(); +int printf(char *fmt, ...); +int sprintf(char *buf, char *fmt, ...); int strcmp(char *p, char *q); int memcmp(char *p, char *q, long n); diff --git a/tokenize.c b/tokenize.c index 577b760..373eb1e 100644 --- a/tokenize.c +++ b/tokenize.c @@ -333,7 +333,8 @@ static Token *tokenize(char *filename, char *p) { } // Three-letter punctuators - if (startswith(p, "<<=") || startswith(p, ">>=")) { + if (startswith(p, "<<=") || startswith(p, ">>=") || + startswith(p, "...")) { cur = new_token(TK_RESERVED, cur, p, 3); p += 3; continue; -- GitLab