Handle block scope

This commit is contained in:
Rui Ueyama 2020-09-04 18:00:26 +09:00
parent 6c0a42926a
commit ca8b2434c9
2 changed files with 53 additions and 10 deletions

59
parse.c
View File

@ -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;
}

View File

@ -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