From 095bbbec20876a1901ea8602ed293605680714bd Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sun, 11 Aug 2019 20:40:48 +0900 Subject: [PATCH] Support file-scope functions --- Makefile | 3 ++- chibi.h | 1 + codegen.c | 3 ++- parse.c | 53 ++++++++++++++++++++++++++++++++++------------------- tests | 4 ++++ tokenize.c | 2 +- 6 files changed, 44 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 621fa73..c962533 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ $(OBJS): chibi.h test: chibicc ./chibicc tests > tmp.s - echo 'int char_fn() { return 257; }' | gcc -xc -c -o tmp2.o - + echo 'int char_fn() { return 257; } int static_fn() { return 5; }' | \ + gcc -xc -c -o tmp2.o - gcc -static -o tmp tmp.s tmp2.o ./tmp diff --git a/chibi.h b/chibi.h index 2fdec6d..8c2ea96 100644 --- a/chibi.h +++ b/chibi.h @@ -148,6 +148,7 @@ struct Function { Function *next; char *name; VarList *params; + bool is_static; Node *node; VarList *locals; diff --git a/codegen.c b/codegen.c index 7bbab28..912d6ae 100644 --- a/codegen.c +++ b/codegen.c @@ -329,7 +329,8 @@ static void emit_text(Program *prog) { printf(".text\n"); for (Function *fn = prog->fns; fn; fn = fn->next) { - printf(".global %s\n", fn->name); + if (!fn->is_static) + printf(".global %s\n", fn->name); printf("%s:\n", fn->name); funcname = fn->name; diff --git a/parse.c b/parse.c index a2ee539..4dd870d 100644 --- a/parse.c +++ b/parse.c @@ -155,8 +155,13 @@ static char *new_label(void) { return strndup(buf, 20); } +typedef enum { + TYPEDEF = 1 << 0, + STATIC = 1 << 1, +} StorageClass; + static Function *function(void); -static Type *basetype(bool *is_typedef); +static Type *basetype(StorageClass *sclass); static Type *declarator(Type *ty, char **name); static Type *abstract_declarator(Type *ty); static Type *type_suffix(Type *ty); @@ -185,8 +190,8 @@ static Node *primary(void); static bool is_function(void) { Token *tok = token; - bool is_typedef; - Type *ty = basetype(&is_typedef); + StorageClass sclass; + Type *ty = basetype(&sclass); char *name = NULL; declarator(ty, &name); bool isfunc = name && consume("("); @@ -225,9 +230,9 @@ Program *program(void) { // builtin-type = "void" | "_Bool" | "char" | "short" | "int" // | "long" | "long" "long" // -// Note that "typedef" can appear anywhere in a basetype. +// Note that "typedef" and "static" can appear anywhere in a basetype. // "int" can appear anywhere if type is short, long or long long. -static Type *basetype(bool *is_typedef) { +static Type *basetype(StorageClass *sclass) { if (!is_typename()) error_tok(token, "typename expected"); @@ -244,17 +249,24 @@ static Type *basetype(bool *is_typedef) { Type *ty = int_type; int counter = 0; - if (is_typedef) - *is_typedef = false; + if (sclass) + *sclass = 0; while (is_typename()) { Token *tok = token; // Handle storage class specifiers. - if (consume("typedef")) { - if (!is_typedef) - error_tok(tok, "invalid storage class specifier"); - *is_typedef = true; + if (peek("typedef") || peek("static")) { + if (!sclass) + error_tok(tok, "storage class specifier is not allowed"); + + if (consume("typedef")) + *sclass |= TYPEDEF; + else if (consume("static")) + *sclass |= STATIC; + + if (*sclass & (*sclass - 1)) + error_tok(tok, "typedef and static may not be used together"); continue; } @@ -528,7 +540,8 @@ static VarList *read_func_params(void) { static Function *function(void) { locals = NULL; - Type *ty = basetype(NULL); + StorageClass sclass; + Type *ty = basetype(&sclass); char *name = NULL; ty = declarator(ty, &name); @@ -538,6 +551,7 @@ static Function *function(void) { // Construct a function object Function *fn = calloc(1, sizeof(Function)); fn->name = name; + fn->is_static = (sclass == STATIC); expect("("); Scope *sc = enter_scope(); @@ -565,14 +579,14 @@ static Function *function(void) { // global-var = basetype declarator type-suffix ";" static void global_var(void) { - bool is_typedef; - Type *ty = basetype(&is_typedef); + StorageClass sclass; + Type *ty = basetype(&sclass); char *name = NULL; ty = declarator(ty, &name); ty = type_suffix(ty); expect(";"); - if (is_typedef) + if (sclass == TYPEDEF) push_scope(name)->type_def = ty; else new_gvar(name, ty, true); @@ -582,8 +596,8 @@ static void global_var(void) { // | basetype ";" static Node *declaration(void) { Token *tok = token; - bool is_typedef; - Type *ty = basetype(&is_typedef); + StorageClass sclass; + Type *ty = basetype(&sclass); if (consume(";")) return new_node(ND_NULL, tok); @@ -591,7 +605,7 @@ static Node *declaration(void) { ty = declarator(ty, &name); ty = type_suffix(ty); - if (is_typedef) { + if (sclass == TYPEDEF) { expect(";"); push_scope(name)->type_def = ty; return new_node(ND_NULL, tok); @@ -605,6 +619,7 @@ static Node *declaration(void) { return new_node(ND_NULL, tok); expect("="); + Node *lhs = new_var_node(var, tok); Node *rhs = expr(); expect(";"); @@ -621,7 +636,7 @@ static Node *read_expr_stmt(void) { static bool is_typename(void) { return peek("void") || peek("_Bool") || peek("char") || peek("short") || peek("int") || peek("long") || peek("enum") || peek("struct") || - peek("typedef") || find_typedef(token); + peek("typedef") || peek("static") || find_typedef(token); } static Node *stmt(void) { diff --git a/tests b/tests index a0855c1..9a5fbed 100644 --- a/tests +++ b/tests @@ -66,6 +66,8 @@ int fib(int x) { return fib(x-1) + fib(x-2); } +static int static_fn() { return 3; } + int main() { assert(8, ({ int a=3; int z=5; a+z; }), "int a=3; int z=5; a+z;"); @@ -344,6 +346,8 @@ int main() { assert(4, ({ enum { zero, one, two } x; sizeof(x); }), "enum { zero, one, two } x; sizeof(x);"); assert(4, ({ enum t { zero, one, two }; enum t y; sizeof(y); }), "enum t { zero, one, two }; enum t y; sizeof(y);"); + assert(3, static_fn(), "static_fn()"); + printf("OK\n"); return 0; } diff --git a/tokenize.c b/tokenize.c index ff3bb2d..5b67955 100644 --- a/tokenize.c +++ b/tokenize.c @@ -149,7 +149,7 @@ static char *starts_with_reserved(char *p) { // Keyword static char *kw[] = {"return", "if", "else", "while", "for", "int", "char", "sizeof", "struct", "typedef", "short", - "long", "void", "_Bool", "enum"}; + "long", "void", "_Bool", "enum", "static"}; for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) { int len = strlen(kw[i]); -- GitLab