runningwater преди 2 години
родител
ревизия
499b5785f3
променени са 5 файла, в които са добавени 138 реда и са изтрити 3 реда
  1. 2 0
      chunk.h
  2. 2 0
      common.h
  3. 122 3
      compiler.c
  4. 2 0
      debug.c
  5. 10 0
      vm.c

+ 2 - 0
chunk.h

@@ -24,6 +24,8 @@ typedef enum {
   OP_DEFINE_GLOBAL,
   OP_GET_GLOBAL,
   OP_SET_GLOBAL,/// \brief setter
+  OP_GET_LOCAL,
+  OP_SET_LOCAL,/// \brief setter
   OP_NOT,       /// \brief print !true; // "false"
   OP_NEGATE,    /// \brief prefix -
   OP_EQUAL,

+ 2 - 0
common.h

@@ -15,4 +15,6 @@
 #define DEBUG_PRINT_CODE
 #define DEBUG_TRACE_EXECUTION
 
+#define UINT8_COUNT (UINT8_MAX + 1)
+
 #endif//CLOX__COMMON_H_

+ 122 - 3
compiler.c

@@ -43,17 +43,33 @@ typedef struct {
   Precedence precedence;
 } ParseRule;
 
+typedef struct {
+  Token name;
+  int depth;
+} Local;
+
+typedef struct {
+  Local locals[UINT8_COUNT];
+  int localCount;/// how many locals are in scope
+  int scopeDepth;
+} Compiler;
+
 Parser parser;
+Compiler *current = NULL;
 Chunk *compilingChunk;
 
 static void parsePrecedence(Precedence);
 static uint8_t parseVariable(const char *);
 static void defineVariable(uint8_t);
 static uint8_t identifierConstant(Token *name);
+static bool identifiersEqual(Token *a, Token *b);
 static ParseRule *getRule(TokenType);
 static void statement();
 static void declaration();
 
+static void beginScope();
+static void endScope();
+
 static Chunk *currentChunk() {
   return compilingChunk;
 }
@@ -131,6 +147,7 @@ static void expression() {
 static void varDeclaration() {
   uint8_t global = parseVariable("Expect variable name.");
 
+  // 变量初始化
   if (match(TOKEN_EQUAL)) {
     expression();
   } else {
@@ -184,6 +201,13 @@ static void declaration() {
 
   if (parser.panicMode) synchronize();
 }
+static void block() {
+  while (!check(TOKEN_RIGHT_BRACE) && !check(TOKEN_EOF)) {
+    declaration();
+  }
+
+  consume(TOKEN_RIGHT_BRACE, "Expect '}' after block.");
+}
 ///statement      → exprStmt
 ///               | forStmt
 ///               | ifStmt
@@ -194,13 +218,35 @@ static void declaration() {
 static void statement() {
   if (match(TOKEN_PRINT)) {
     printStatement();
+  } else if (match(TOKEN_LEFT_BRACE)) {
+    ///! block → "{" declaration* "}" ;
+    beginScope();
+    block();
+    endScope();
   } else {
     expressionStatement();
   }
 }
+static void beginScope() {
+  current->scopeDepth++;
+}
+static void endScope() {
+  current->scopeDepth--;
+
+  while (current->localCount > 0
+         && current->locals[current->localCount - 1].depth > current->scopeDepth) {
+    emitByte(OP_POP);
+    current->localCount--;
+  }
+}
 static void emitConstant(Value value) {
   emitBytes(OP_CONSTANT, makeConstant(value));
 }
+static void initCompiler(Compiler *compiler) {
+  compiler->localCount = 0;
+  compiler->scopeDepth = 0;
+  current = compiler;
+}
 static void endCompiler() {
   emitReturn();
 #ifdef DEBUG_PRINT_CODE
@@ -223,15 +269,36 @@ static void string(__attribute__((unused)) bool canAssign) {
   emitConstant(OBJ_VAL(copyString(parser.previous.start + 1,
                                   parser.previous.length - 2)));
 }
+static int resolveLocal(Compiler *compile, Token *name) {
+  for (int i = compile->localCount - 1; i >= 0; i--) {
+    Local *local = &compile->locals[i];
+    if (identifiersEqual(name, &local->name)) {
+      if (local->depth == -1) {
+        error("Can't read local variable in ints own initializer.");
+      }
+      return i;
+    }
+  }
+  return -1;
+}
 static void namedVariable(Token name, bool canAssign) {
-  uint8_t arg = identifierConstant(&name);
+  uint8_t getOp, setOp;
+  int arg = resolveLocal(current, &name);
+  if (arg != -1) {
+    getOp = OP_GET_LOCAL;
+    setOp = OP_SET_LOCAL;
+  } else {
+    arg = identifierConstant(&name);
+    getOp = OP_GET_GLOBAL;
+    setOp = OP_SET_GLOBAL;
+  }
 
   if (canAssign && match(TOKEN_EQUAL)) {
     // 如 menu.brunch(sunday).beverage = "mimosa";
     expression();
-    emitBytes(OP_SET_GLOBAL, arg);
+    emitBytes(setOp, (uint8_t) arg);
   } else {
-    emitBytes(OP_GET_GLOBAL, arg);
+    emitBytes(getOp, (uint8_t) arg);
   }
 }
 static void variable(bool canAssign) {
@@ -378,11 +445,60 @@ static void parsePrecedence(Precedence precedence) {
 static uint8_t identifierConstant(Token *name) {
   return makeConstant(OBJ_VAL(copyString(name->start, name->length)));
 }
+static bool identifiersEqual(Token *a, Token *b) {
+  if (a->length != b->length) return false;
+  return memcmp(a->start, b->start, a->length) == 0;
+}
+static void addLocal(Token name) {
+  if (current->localCount == UINT8_COUNT) {
+    error("Too many local variables in function.");
+    return;
+  }
+
+  Local *local = &current->locals[current->localCount++];
+  local->name = name;
+  local->depth = -1;// 未初始化
+}
+static void declareVariable() {
+  if (current->scopeDepth == 0) return;
+
+  Token *name = &parser.previous;
+
+  // we detect the error like:
+  // {
+  //   var a = "first";
+  //   var a = "second";
+  // }
+  for (int i = current->localCount - 1; i >= 0; i--) {
+    Local *local = &current->locals[i];
+    if (local->depth != -1 && local->depth < current->scopeDepth) {
+      break;
+    }
+
+    if (identifiersEqual(name, &local->name)) {
+      error("Already a variable with the name in this scope.");
+    }
+  }
+
+  addLocal(*name);
+}
 static uint8_t parseVariable(const char *errorMessage) {
   consume(TOKEN_IDENTIFIER, errorMessage);
+
+  declareVariable();// 处理本地变量
+  if (current->scopeDepth > 0) return 0;
+
   return identifierConstant(&parser.previous);
 }
 static void defineVariable(uint8_t global) {
+
+  if (current->scopeDepth > 0) {
+    // markInitialized 未初始化时值 为 -1
+    current->locals[current->localCount - 1].depth = current->scopeDepth;
+    // 本地变量,直接退出
+    return;
+  }
+
   emitBytes(OP_DEFINE_GLOBAL, global);
 }
 static ParseRule *getRule(TokenType type) {
@@ -398,6 +514,7 @@ static ParseRule *getRule(TokenType type) {
                       | returnStmt
                       | whileStmt
                       | block ;
+    block          → "{" declaration* "}" ;
 
     declaration    → classDecl
                    | funDecl
@@ -406,7 +523,9 @@ static ParseRule *getRule(TokenType type) {
   ******************************************************************************
   */
 bool compile(const char *source, Chunk *chunk) {
+  Compiler compiler;
   initScanner(source);
+  initCompiler(&compiler);
   compilingChunk = chunk;
 
   parser.hadError = false;

+ 2 - 0
debug.c

@@ -35,6 +35,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
     case OP_DEFINE_GLOBAL: return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset);
     case OP_GET_GLOBAL: return constantInstruction("OP_GET_GLOBAL", chunk, offset);
     case OP_SET_GLOBAL: return constantInstruction("OP_SET_GLOBAL", chunk, offset);
+    case OP_GET_LOCAL: return constantInstruction("OP_GET_LOCAL", chunk, offset);
+    case OP_SET_LOCAL: return constantInstruction("OP_SET_LOCAL", chunk, offset);
     case OP_ADD: return simpleInstruction("OP_ADD", offset);
     case OP_SUBTRACT: return simpleInstruction("OP_SUBTRACT", offset);
     case OP_MULTIPLY: return simpleInstruction("OP_MULTIPLY", offset);

+ 10 - 0
vm.c

@@ -140,6 +140,16 @@ static InterpretResult run() {
         }
         break;
       }
+      case OP_GET_LOCAL: {
+        uint8_t slot = READ_BYTE();
+        push(vm.stack[slot]);
+        break;
+      }
+      case OP_SET_LOCAL: {
+        uint8_t slot = READ_BYTE();
+        vm.stack[slot] = peek(0);
+        break;
+      }
       case OP_ADD: {
         if (IS_STRING(peek(0)) && IS_STRING(peek(1))) {
           // 字串拼接