From 0ac870511569b57410860f0f3c788afdd5ca1d14 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sun, 11 Aug 2019 09:53:31 +0900 Subject: [PATCH] Add a return type to a function --- chibi.h | 4 ++++ parse.c | 34 ++++++++++++++++++++++++++-------- tests | 6 ++++++ tokenize.c | 11 +++++++++-- type.c | 7 ++++++- 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/chibi.h b/chibi.h index e405dc5..6c81688 100644 --- a/chibi.h +++ b/chibi.h @@ -41,6 +41,7 @@ struct Token { void error(char *fmt, ...); void error_at(char *loc, char *fmt, ...); void error_tok(Token *tok, char *fmt, ...); +void warn_tok(Token *tok, char *fmt, ...); Token *peek(char *s); Token *consume(char *op); Token *consume_ident(void); @@ -171,6 +172,7 @@ typedef enum { TY_PTR, TY_ARRAY, TY_STRUCT, + TY_FUNC, } TypeKind; struct Type { @@ -180,6 +182,7 @@ struct Type { Type *base; // pointer or array int array_len; // array Member *members; // struct + Type *return_ty; // function }; // Struct member @@ -199,6 +202,7 @@ bool is_integer(Type *ty); int align_to(int n, int align); Type *pointer_to(Type *base); Type *array_of(Type *base, int size); +Type *func_type(Type *return_ty); void add_type(Node *node); // diff --git a/parse.c b/parse.c index b35d0d4..e9b68c5 100644 --- a/parse.c +++ b/parse.c @@ -122,14 +122,16 @@ static Var *new_lvar(char *name, Type *ty) { return var; } -static Var *new_gvar(char *name, Type *ty) { +static Var *new_gvar(char *name, Type *ty, bool emit) { Var *var = new_var(name, ty, false); push_scope(name)->var = var; - VarList *vl = calloc(1, sizeof(VarList)); - vl->var = var; - vl->next = globals; - globals = vl; + if (emit) { + VarList *vl = calloc(1, sizeof(VarList)); + vl->var = var; + vl->next = globals; + globals = vl; + } return var; } @@ -357,8 +359,12 @@ static Function *function(void) { Type *ty = basetype(); char *name = NULL; - declarator(ty, &name); + ty = declarator(ty, &name); + // Add a function type to the scope + new_gvar(name, func_type(ty), false); + + // Construct a function object Function *fn = calloc(1, sizeof(Function)); fn->name = name; expect("("); @@ -371,6 +377,7 @@ static Function *function(void) { return NULL; } + // Read function body Node head = {}; Node *cur = &head; expect("{"); @@ -392,7 +399,7 @@ static void global_var(void) { ty = declarator(ty, &name); ty = type_suffix(ty); expect(";"); - new_gvar(name, ty); + new_gvar(name, ty, true); } // declaration = basetype declarator type-suffix ("=" expr)? ";" @@ -764,6 +771,17 @@ static Node *primary(void) { Node *node = new_node(ND_FUNCALL, tok); node->funcname = strndup(tok->str, tok->len); node->args = func_args(); + add_type(node); + + VarScope *sc = find_var(tok); + if (sc) { + if (!sc->var || sc->var->ty->kind != TY_FUNC) + error_tok(tok, "not a function"); + node->ty = sc->var->ty->return_ty; + } else { + warn_tok(node->tok, "implicit declaration of a function"); + node->ty = int_type; + } return node; } @@ -779,7 +797,7 @@ static Node *primary(void) { token = token->next; Type *ty = array_of(char_type, tok->cont_len); - Var *var = new_gvar(new_label(), ty); + Var *var = new_gvar(new_label(), ty, true); var->contents = tok->contents; var->cont_len = tok->cont_len; return new_var_node(var, tok); diff --git a/tests b/tests index 8954226..0696eb9 100644 --- a/tests +++ b/tests @@ -54,6 +54,10 @@ int sub_long(long a, long b, long c) { return a - b - c; } +int *g1_ptr() { + return &g1; +} + int fib(int x) { if (x<=1) return 1; @@ -274,6 +278,8 @@ int main() { assert(3, ({ int *x[3]; int y; x[0]=&y; y=3; x[0][0]; }), "int *x[3]; int y; x[0]=&y; y=3; x[0][0];"); assert(4, ({ int x[3]; int (*y)[3]=x; y[0][0]=4; y[0][0]; }), "int x[3]; int (*y)[3]=x; y[0][0]=4; y[0][0];"); + assert(3, *g1_ptr(), "*g1_ptr()"); + printf("OK\n"); return 0; } diff --git a/tokenize.c b/tokenize.c index 9e21dd9..7ca4f80 100644 --- a/tokenize.c +++ b/tokenize.c @@ -13,7 +13,7 @@ void error(char *fmt, ...) { exit(1); } -// Reports an error message in the following format and exit. +// Reports an error message in the following format. // // foo.c:10: x = y + 1; // ^ @@ -43,7 +43,6 @@ static void verror_at(char *loc, char *fmt, va_list ap) { fprintf(stderr, "^ "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); - exit(1); } // Reports an error location and exit. @@ -51,6 +50,7 @@ void error_at(char *loc, char *fmt, ...) { va_list ap; va_start(ap, fmt); verror_at(loc, fmt, ap); + exit(1); } // Reports an error location and exit. @@ -58,6 +58,13 @@ void error_tok(Token *tok, char *fmt, ...) { va_list ap; va_start(ap, fmt); verror_at(tok->str, fmt, ap); + exit(1); +} + +void warn_tok(Token *tok, char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + verror_at(tok->str, fmt, ap); } // Consumes the current token if it matches `op`. diff --git a/type.c b/type.c index a5991d3..0efe975 100644 --- a/type.c +++ b/type.c @@ -36,6 +36,12 @@ Type *array_of(Type *base, int len) { return ty; } +Type *func_type(Type *return_ty) { + Type *ty = new_type(TY_FUNC, 1, 1); + ty->return_ty = return_ty; + return ty; +} + void add_type(Node *node) { if (!node || node->ty) return; @@ -63,7 +69,6 @@ void add_type(Node *node) { case ND_NE: case ND_LT: case ND_LE: - case ND_FUNCALL: case ND_NUM: node->ty = long_type; return;