浏览代码

add If statement

runningwater 2 年之前
父节点
当前提交
2a87b676ba
共有 4 个文件被更改,包括 62 次插入4 次删除
  1. 5 3
      chunk.h
  2. 34 0
      compiler.c
  3. 8 0
      debug.c
  4. 15 1
      vm.c

+ 5 - 3
chunk.h

@@ -26,8 +26,8 @@ typedef enum {
   OP_SET_GLOBAL,/// \brief setter
   OP_GET_LOCAL,
   OP_SET_LOCAL,/// \brief setter
-  OP_NOT,       /// \brief print !true; // "false"
-  OP_NEGATE,    /// \brief prefix -
+  OP_NOT,      /// \brief print !true; // "false"
+  OP_NEGATE,   /// \brief prefix -
   OP_EQUAL,
   OP_GREATER,
   OP_LESS,
@@ -36,7 +36,9 @@ typedef enum {
   OP_MULTIPLY,/// \brief *
   OP_DIVIDE,  /// \brief /
   OP_PRINT,
-  OP_RETURN,///<OP_RETURN>
+  OP_JUMP_IF_FALSE,/// <OP_JUMP_IF_FALSE + +>
+  OP_JUMP,         /// <OP_JUMP + +>
+  OP_RETURN,       ///<OP_RETURN>
 } OpCode;
 
 //============================================================================

+ 34 - 0
compiler.c

@@ -129,6 +129,12 @@ static void emitBytes(uint8_t byte1, uint8_t byte2) {
   emitByte(byte1);
   emitByte(byte2);
 }
+static int emitJump(uint8_t instruction) {
+  emitByte(instruction);
+  emitByte(0xff);// 占位字节,后面填入需要跳转的 offset
+  emitByte(0xff);//
+  return currentChunk()->count - 2;
+}
 static void emitReturn() {
   emitByte(OP_RETURN);
 }
@@ -163,6 +169,32 @@ static void expressionStatement() {
   consume(TOKEN_SEMICOLON, "Expect ';' after expression.");
   emitByte(OP_POP);
 }
+static void patchJump(int offset) {
+  // -2 to adjust for the bytecode for the jump offset itself.
+  int jump = currentChunk()->count - offset - 2;
+
+  if (jump > UINT16_MAX) error("Too much code to jump over.");
+
+  currentChunk()->code[offset] = (jump >> 8) & 0xFF;
+  currentChunk()->code[offset + 1] = jump & 0xFF;
+}
+static void ifStatement() {
+  consume(TOKEN_LEFT_PAREN, "Expect '(' after 'if'.");
+  expression();
+  consume(TOKEN_RIGHT_PAREN, "Expect ')' after condition.");
+
+  int thenJump = emitJump(OP_JUMP_IF_FALSE);
+  emitByte(OP_POP);
+  statement();// then branch statement
+
+  int elseJump = emitJump(OP_JUMP);
+
+  patchJump(thenJump);
+  emitByte(OP_POP);
+
+  if (match(TOKEN_ELSE)) statement();// else branch statement
+  patchJump(elseJump);
+}
 static void printStatement() {
   expression();
   consume(TOKEN_SEMICOLON, "Expect ';' after value.");
@@ -218,6 +250,8 @@ static void block() {
 static void statement() {
   if (match(TOKEN_PRINT)) {
     printStatement();
+  } else if (match(TOKEN_IF)) {
+    ifStatement();
   } else if (match(TOKEN_LEFT_BRACE)) {
     ///! block → "{" declaration* "}" ;
     beginScope();

+ 8 - 0
debug.c

@@ -16,6 +16,12 @@ void disassembleChunk(Chunk *chunk, const char *name) {
   }
   printf("== %s END ==\n", name);
 }
+static int jumpInstruction(const char *name, int sign, Chunk *chunk, int offset) {
+  uint16_t jump = (uint16_t) (chunk->code[offset + 1] << 8);
+  jump |= chunk->code[offset + 2];
+  printf("%-16s %4d -> %d\n", name, offset, offset + 3 + sign * jump);
+  return offset + 3;
+}
 int disassembleInstruction(Chunk *chunk, int offset) {
   printf("%04d ", offset);
 
@@ -47,6 +53,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
     case OP_GREATER: return simpleInstruction("OP_GREATER", offset);
     case OP_LESS: return simpleInstruction("OP_LESS", offset);
     case OP_PRINT: return simpleInstruction("OP_PRINT", offset);
+    case OP_JUMP: return jumpInstruction("OP_JUMP", 1, chunk, offset);
+    case OP_JUMP_IF_FALSE: return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset);
     case OP_RETURN: return simpleInstruction("OP_RETURN", offset);
     default:
       printf("Unknown opcode %d\n", instruction);

+ 15 - 1
vm.c

@@ -68,6 +68,8 @@ static InterpretResult run() {
 //! reads the next byte from the bytecode
 //! treats the resulting number as an index
 #define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
+#define READ_SHORT() \
+  (vm.ip += 2, (uint16_t) ((vm.ip[-2] << 8) | vm.ip[-1]))
 #define READ_STRING() AS_STRING(READ_CONSTANT())
 #define BINARY_OP(valueType, op)                      \
   do {                                                \
@@ -195,10 +197,21 @@ static InterpretResult run() {
       case OP_LESS:
         BINARY_OP(BOOL_VAL, <);
         break;
-      case OP_PRINT:
+      case OP_PRINT: {
         printValue(pop());
         printf("\n");
         break;
+      }
+      case OP_JUMP_IF_FALSE: {
+        uint16_t offset = READ_SHORT();
+        if (isFalse(peek(0))) vm.ip += offset;
+        break;
+      }
+      case OP_JUMP: {
+        uint16_t offset = READ_SHORT();
+        vm.ip += offset;
+        break;
+      }
       case OP_RETURN: {
         // Exit interpreter.
         return INTERPRET_OK;
@@ -211,6 +224,7 @@ static InterpretResult run() {
 
 #undef READ_BYTE
 #undef READ_CONSTANT
+#undef READ_SHORT
 #undef READ_STRING
 #undef BINARY_OP
 }