Handle block scope

This commit is contained in:
Rui Ueyama 2020-09-04 18:00:26 +09:00
parent 5617cca877
commit d7b0a41a5d
2 changed files with 52 additions and 10 deletions

58
parse.c
View File

@ -18,11 +18,26 @@
#include "chibicc.h"
// Scope for local or global variables.
typedef struct VarScope VarScope;
struct VarScope {
VarScope *next;
char *name;
int depth;
Var *var;
};
// All local variable instances created during parsing are
// accumulated to this list.
static Var *locals;
static Var *globals;
static VarScope *var_scope;
// scope_depth is incremented by one at the beginning of a block
// scope and decremented by one at the end of a block scope.
static int scope_depth;
static Type *typespec(Token **rest, Token *tok);
static Type *declarator(Token **rest, Token *tok, Type *ty);
static Node *declaration(Token **rest, Token *tok);
@ -39,16 +54,21 @@ 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_depth++;
}
static void leave_scope(void) {
scope_depth--;
while (var_scope && var_scope->depth > scope_depth)
var_scope = var_scope->next;
}
// Find a variable by name.
static Var *find_var(Token *tok) {
for (Var *var = locals; var; var = var->next)
if (strlen(var->name) == tok->len && !strncmp(tok->loc, var->name, tok->len))
return var;
for (Var *var = globals; var; var = var->next)
if (strlen(var->name) == tok->len && !strncmp(tok->loc, var->name, tok->len))
return var;
for (VarScope *sc = var_scope; sc; sc = sc->next)
if (equal(tok, sc->name))
return sc->var;
return NULL;
}
@ -84,10 +104,22 @@ static Node *new_var_node(Var *var, Token *tok) {
return node;
}
static VarScope *push_scope(char *name, Var *var) {
VarScope *sc = calloc(1, sizeof(VarScope));
sc->name = name;
sc->var = var;
sc->depth = scope_depth;
sc->next = var_scope;
var_scope = sc;
return sc;
}
static Var *new_var(char *name, Type *ty) {
Var *var = calloc(1, sizeof(Var));
var->name = name;
var->ty = ty;
push_scope(name, var);
return var;
}
@ -293,9 +325,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);
@ -304,6 +338,8 @@ static Node *compound_stmt(Token **rest, Token *tok) {
add_type(cur);
}
leave_scope();
node->body = head.next;
*rest = tok->next;
return node;
@ -616,12 +652,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

@ -216,4 +216,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