diff --git a/parse.c b/parse.c index d7ee3fe..1f099fc 100644 --- a/parse.c +++ b/parse.c @@ -18,11 +18,28 @@ #include "chibicc.h" +// Scope for local or global variables. +typedef struct VarScope VarScope; +struct VarScope { + VarScope *next; + char *name; + Obj *var; +}; + +// Represents a block scope. +typedef struct Scope Scope; +struct Scope { + Scope *next; + VarScope *vars; +}; + // All local variable instances created during parsing are // accumulated to this list. static Obj *locals; static Obj *globals; +static Scope *scope = &(Scope){}; + static Type *declspec(Token **rest, Token *tok); static Type *declarator(Token **rest, Token *tok, Type *ty); static Node *declaration(Token **rest, Token *tok); @@ -39,16 +56,22 @@ static Node *postfix(Token **rest, Token *tok); static Node *unary(Token **rest, Token *tok); static Node *primary(Token **rest, Token *tok); -// Find a local variable by name. +static void enter_scope(void) { + Scope *sc = calloc(1, sizeof(Scope)); + sc->next = scope; + scope = sc; +} + +static void leave_scope(void) { + scope = scope->next; +} + +// Find a variable by name. static Obj *find_var(Token *tok) { - for (Obj *var = locals; var; var = var->next) - if (strlen(var->name) == tok->len && !strncmp(tok->loc, var->name, tok->len)) - return var; - - for (Obj *var = globals; var; var = var->next) - if (strlen(var->name) == tok->len && !strncmp(tok->loc, var->name, tok->len)) - return var; - + for (Scope *sc = scope; sc; sc = sc->next) + for (VarScope *sc2 = sc->vars; sc2; sc2 = sc2->next) + if (equal(tok, sc2->name)) + return sc2->var; return NULL; } @@ -84,10 +107,20 @@ static Node *new_var_node(Obj *var, Token *tok) { return node; } +static VarScope *push_scope(char *name, Obj *var) { + VarScope *sc = calloc(1, sizeof(VarScope)); + sc->name = name; + sc->var = var; + sc->next = scope->vars; + scope->vars = sc; + return sc; +} + static Obj *new_var(char *name, Type *ty) { Obj *var = calloc(1, sizeof(Obj)); var->name = name; var->ty = ty; + push_scope(name, var); return var; } @@ -291,9 +324,11 @@ static Node *stmt(Token **rest, Token *tok) { // compound-stmt = (declaration | stmt)* "}" static Node *compound_stmt(Token **rest, Token *tok) { Node *node = new_node(ND_BLOCK, tok); - Node head = {}; Node *cur = &head; + + enter_scope(); + while (!equal(tok, "}")) { if (is_typename(tok)) cur = cur->next = declaration(&tok, tok); @@ -302,6 +337,8 @@ static Node *compound_stmt(Token **rest, Token *tok) { add_type(cur); } + leave_scope(); + node->body = head.next; *rest = tok->next; return node; @@ -614,12 +651,14 @@ static Token *function(Token *tok, Type *basety) { fn->is_function = true; locals = NULL; + enter_scope(); create_param_lvars(ty->params); fn->params = locals; tok = skip(tok, "{"); fn->body = compound_stmt(&tok, tok); fn->locals = locals; + leave_scope(); return tok; } diff --git a/test.sh b/test.sh index 1575ed9..bb09ebb 100755 --- a/test.sh +++ b/test.sh @@ -217,4 +217,8 @@ assert 2 'int main() { /* return 1; */ return 2; }' assert 2 'int main() { // return 1; return 2; }' +assert 2 'int main() { int x=2; { int x=3; } return x; }' +assert 2 'int main() { int x=2; { int x=3; } { int y=4; return x; }}' +assert 3 'int main() { int x=2; { x=3; } return x; }' + echo OK