From 8afaa51e92d954dd4d264656b091b85661c4a19a Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Fri, 25 Oct 2013 20:32:42 -0700 Subject: [PATCH] Global variables. --- src/compiler.c | 100 ++++++++++++++++++++++++++++++++++--------------- src/vm.c | 20 ++++++++++ src/vm.h | 11 ++++++ 3 files changed, 100 insertions(+), 31 deletions(-) diff --git a/src/compiler.c b/src/compiler.c index 39d64557..5b0e8969 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -134,6 +134,17 @@ static void makeToken(Parser* parser, TokenType type); // Utility: static void initCompiler(Compiler* compiler, Parser* parser, Compiler* parent); + +// Parses a name token and defines a variable in the current scope with that +// name. Returns its symbol. +static int defineName(Compiler* compiler); + +// Stores a variable with the previously defined symbol in the current scope. +static void storeVariable(Compiler* compiler, int symbol); + +// Adds the previous token's text to the symbol table and returns its index. +static int internSymbol(Compiler* compiler); + static void emit(Compiler* compiler, Code code); static void error(Compiler* compiler, const char* format, ...); @@ -197,24 +208,13 @@ void statement(Compiler* compiler) { if (match(compiler, TOKEN_CLASS)) { - consume(compiler, TOKEN_NAME); - - // TODO(bob): Copied from below. Unify. - int local = addSymbol(&compiler->locals, - compiler->parser->source + compiler->parser->previous.start, - compiler->parser->previous.end - compiler->parser->previous.start); - - if (local == -1) - { - error(compiler, "Local variable is already defined."); - } + int symbol = defineName(compiler); // Create the empty class. emit(compiler, CODE_CLASS); // Store it in its name. - emit(compiler, CODE_STORE_LOCAL); - emit(compiler, local); + storeVariable(compiler, symbol); // Compile the method definitions. consume(compiler, TOKEN_LEFT_BRACE); @@ -244,15 +244,7 @@ void statement(Compiler* compiler) if (match(compiler, TOKEN_VAR)) { - consume(compiler, TOKEN_NAME); - int local = addSymbol(&compiler->locals, - compiler->parser->source + compiler->parser->previous.start, - compiler->parser->previous.end - compiler->parser->previous.start); - - if (local == -1) - { - error(compiler, "Local variable is already defined."); - } + int symbol = defineName(compiler); // TODO(bob): Allow uninitialized vars? consume(compiler, TOKEN_EQ); @@ -260,8 +252,7 @@ void statement(Compiler* compiler) // Compile the initializer. expression(compiler); - emit(compiler, CODE_STORE_LOCAL); - emit(compiler, local); + storeVariable(compiler, symbol); return; } @@ -314,18 +305,32 @@ void primary(Compiler* compiler) // Variable name. if (match(compiler, TOKEN_NAME)) { + // See if it's a local in this scope. int local = findSymbol(&compiler->locals, compiler->parser->source + compiler->parser->previous.start, compiler->parser->previous.end - compiler->parser->previous.start); - if (local == -1) + if (local != -1) { - // TODO(bob): Look for globals or names in outer scopes. - error(compiler, "Unknown variable."); + emit(compiler, CODE_LOAD_LOCAL); + emit(compiler, local); + return; } - emit(compiler, CODE_LOAD_LOCAL); - emit(compiler, local); - return; + // TODO(bob): Look up names in outer local scopes. + + // See if it's a global variable. + int global = findSymbol(&compiler->parser->vm->globalSymbols, + compiler->parser->source + compiler->parser->previous.start, + compiler->parser->previous.end - compiler->parser->previous.start); + if (global != -1) + { + emit(compiler, CODE_LOAD_GLOBAL); + emit(compiler, global); + return; + } + + // TODO(bob): Look for globals or names in outer scopes. + error(compiler, "Unknown variable."); } // Number. @@ -667,7 +672,40 @@ void emit(Compiler* compiler, Code code) compiler->block->bytecode[compiler->numCodes++] = code; } -// Adds the previous token's text to the symbol table and returns its index. +int defineName(Compiler* compiler) +{ + consume(compiler, TOKEN_NAME); + + SymbolTable* symbols; + if (compiler->parent) + { + // Nested block, so this is a local variable. + symbols = &compiler->locals; + } + else + { + // Top level global variable. + symbols = &compiler->parser->vm->globalSymbols; + } + + int symbol = addSymbol(symbols, + compiler->parser->source + compiler->parser->previous.start, + compiler->parser->previous.end - compiler->parser->previous.start); + + if (symbol == -1) + { + error(compiler, "Variable is already defined."); + } + + return symbol; +} + +void storeVariable(Compiler* compiler, int symbol) +{ + emit(compiler, compiler->parent ? CODE_STORE_LOCAL : CODE_STORE_GLOBAL); + emit(compiler, symbol); +} + int internSymbol(Compiler* compiler) { return ensureSymbol(&compiler->parser->vm->symbols, diff --git a/src/vm.c b/src/vm.c index 6702f787..606143c9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -44,6 +44,10 @@ VM* newVM() VM* vm = malloc(sizeof(VM)); initSymbolTable(&vm->symbols); + initSymbolTable(&vm->globalSymbols); + vm->numGlobals = 0; + + // Define the built-in classes and their methods. vm->blockClass = makeClass(); // The call method is special: neither a primitive nor a user-defined one. @@ -251,6 +255,22 @@ Value interpret(VM* vm, ObjBlock* block) break; } + case CODE_LOAD_GLOBAL: + { + int global = frame->block->bytecode[frame->ip++]; + push(&fiber, vm->globals[global]); + printf("load global %d to %d\n", global, fiber.stackSize - 1); + break; + } + + case CODE_STORE_GLOBAL: + { + int global = frame->block->bytecode[frame->ip++]; + printf("store global %d from %d\n", global, fiber.stackSize - 1); + vm->globals[global] = fiber.stack[fiber.stackSize - 1]; + break; + } + case CODE_DUP: push(&fiber, fiber.stack[fiber.stackSize - 1]); printf("dup %d\n", fiber.stackSize - 1); diff --git a/src/vm.h b/src/vm.h index c1aeae6e..8ba25d0f 100644 --- a/src/vm.h +++ b/src/vm.h @@ -101,6 +101,12 @@ typedef enum CODE_STORE_LOCAL, // Stores the top of stack in local slot [arg]. Does not pop it. + CODE_LOAD_GLOBAL, + // Pushes the value in global slot [arg]. + + CODE_STORE_GLOBAL, + // Stores the top of stack in global slot [arg]. Does not pop it. + CODE_CALL, // Invoke the method with symbol [arg]. @@ -123,6 +129,11 @@ typedef struct ObjClass* blockClass; ObjClass* classClass; ObjClass* numClass; + + SymbolTable globalSymbols; + // TODO(bob): Using a fixed array is gross here. + Value globals[MAX_SYMBOLS]; + int numGlobals; } VM; VM* newVM();