Răsfoiți Sursa

Support and test for if

Kajetan Johannes Hammerle 2 săptămâni în urmă
părinte
comite
5965027d76
8 a modificat fișierele cu 118 adăugiri și 0 ștergeri
  1. 18 0
      src/Code.c
  2. 6 0
      src/Code.h
  3. 10 0
      src/CodeRunner.c
  4. 54 0
      src/Compiler.c
  5. 2 0
      test/Add.basic
  6. 2 0
      test/Add.basic_result
  7. 22 0
      test/If.basic
  8. 4 0
      test/If.basic_result

+ 18 - 0
src/Code.c

@@ -1,5 +1,6 @@
 #include "Code.h"
 
+#include <assert.h>
 #include <string.h>
 
 static u8 code[MAX_CODE];
@@ -78,3 +79,20 @@ const char* codeReadConstantString() {
     }
     return "";
 }
+
+size_t codeGetWritePosition() {
+    return codeIndex;
+}
+
+void codeSetWritePosition(size_t pos) {
+    codeIndex = pos;
+}
+
+size_t codeGetPosition() {
+    return codeExecutionIndex;
+}
+
+void codeSetPosition(size_t pos) {
+    assert(pos < codeIndex);
+    codeExecutionIndex = pos;
+}

+ 6 - 0
src/Code.h

@@ -9,6 +9,7 @@ typedef enum : u8 {
     PUSH_INT64,
     PRINT,
     PRINT_NEWLINE,
+    JUMP_ON_0,
     STOP
 } Instruction;
 
@@ -25,4 +26,9 @@ i64 codeReadI64();
 size_t codeReadSize();
 const char* codeReadConstantString();
 
+size_t codeGetWritePosition();
+void codeSetWritePosition(size_t pos);
+size_t codeGetPosition();
+void codeSetPosition(size_t pos);
+
 #endif

+ 10 - 0
src/CodeRunner.c

@@ -36,6 +36,15 @@ static bool iPrintNewline() {
     return false;
 }
 
+static bool iJumpIf() {
+    POP_VALUE(a);
+    size_t jumpPos = codeReadSize();
+    if(a.intValue == 0) {
+        codeSetPosition(jumpPos);
+    }
+    return false;
+}
+
 static bool execute(Instruction command) {
     switch(command) {
         case ADD: return iAdd();
@@ -43,6 +52,7 @@ static bool execute(Instruction command) {
         case PUSH_INT64: return iPushInt();
         case PRINT: return iPrint();
         case PRINT_NEWLINE: return iPrintNewline();
+        case JUMP_ON_0: return iJumpIf();
         case STOP: return true;
     }
     return false;

+ 54 - 0
src/Compiler.c

@@ -207,6 +207,14 @@ static Token nextToken() {
     return tokenReadIndex < tokenWriteIndex ? tokens[tokenReadIndex++] : END;
 }
 
+static const char* peekLiteral() {
+    Token t = peekToken();
+    if(t != LITERAL) {
+        return nullptr;
+    }
+    return (char*)(tokens + tokenReadIndex + sizeof(Token));
+}
+
 static const char* readString() {
     if(tokenReadIndex >= tokenWriteIndex) {
         THROW_ERROR("readString on empty buffer, line %zu", lineCounter);
@@ -270,6 +278,21 @@ static double readDouble() {
     THROW_ERROR("Unexpected unknown token on line %zu", lineCounter);
 }
 
+static void consumeToken(Token t) {
+    Token actual = nextToken();
+    if(t != actual) {
+        unexpectedToken(actual);
+    }
+}
+
+static void consumeLiteral(const char* name) {
+    consumeToken(LITERAL);
+    const char* actual = readString();
+    if(strcmp(actual, name) != 0) {
+        THROW_ERROR("Unexpected literal(%s) on line %zu", actual, lineCounter);
+    }
+}
+
 static void compileConstant() {
     Token t = nextToken();
     if(t == STRING) {
@@ -296,7 +319,36 @@ static void compileExpression() {
     compileAdd();
 }
 
+static void compileLine(Token t);
+
+static void compileIf() {
+    compileExpression();
+    CODE(codePushInstruction(JUMP_ON_0));
+    size_t posIndex = codeGetWritePosition();
+    CODE(codePushSize(0));
+    consumeLiteral("then");
+    consumeToken(NEWLINE);
+    while(true) {
+        const char* s = peekLiteral();
+        if(s == nullptr || strcmp(s, "endif") != 0) {
+            compileLine(nextToken());
+            continue;
+        } else {
+            break;
+        }
+    }
+    consumeLiteral("endif");
+    consumeToken(NEWLINE);
+    size_t endIndex = codeGetWritePosition();
+    codeSetWritePosition(posIndex);
+    CODE(codePushSize(endIndex));
+    codeSetWritePosition(endIndex);
+}
+
 static void compileLine(Token t) {
+    if(t == NEWLINE) {
+        return;
+    }
     if(t != LITERAL) {
         unexpectedToken(t);
     }
@@ -308,6 +360,8 @@ static void compileLine(Token t) {
         }
         nextToken();
         CODE(codePushInstruction(PRINT_NEWLINE));
+    } else if(strcmp(s, "if") == 0) {
+        compileIf();
     } else {
         THROW_ERROR("Unexpected literal(%s) on line %zu", s, lineCounter);
     }

+ 2 - 0
test/Add.basic

@@ -1 +1,3 @@
 print 1 + 20
+print 1 + 20 + 4
+print 1 + 20 + 4 + 6

+ 2 - 0
test/Add.basic_result

@@ -1 +1,3 @@
 21
+25
+31

+ 22 - 0
test/If.basic

@@ -0,0 +1,22 @@
+if 1 then
+  print "wusi"
+  if 0 then
+    print "wusi4"
+  endif
+  if 1 then
+    print "wusi2"
+  endif
+endif
+
+if 1 + 1 then
+  print "wusi3"
+endif
+
+if 0 then
+  print "gusi"
+  if 1 then
+    print "gusi2"
+  endif
+endif
+
+print "end"

+ 4 - 0
test/If.basic_result

@@ -0,0 +1,4 @@
+wusi
+wusi2
+wusi3
+end