Kajetan Johannes Hammerle 3 年之前
父節點
當前提交
ee12c6c9c6
共有 5 個文件被更改,包括 71 次插入8 次删除
  1. 40 5
      Compiler.c
  2. 4 3
      Tokenizer.c
  3. 1 0
      Tokenizer.h
  4. 19 0
      tests/loops/break
  5. 7 0
      tests/loops/break.out

+ 40 - 5
Compiler.c

@@ -10,6 +10,7 @@
 
 #define ERROR_LENGTH 256
 #define RETURN_BUFFER 16
+#define BREAK_BUFFER 32
 
 static jmp_buf errorJump;
 static char error[ERROR_LENGTH] = {'\0'};
@@ -26,6 +27,10 @@ static int returns[RETURN_BUFFER];
 static int returnIndex = 0;
 static int returnState = 0;
 
+static int breaks[BREAK_BUFFER];
+static int breakIndex = 0;
+static int forWhileStack = 0;
+
 static void cError(const char* format, ...) {
     va_list args;
     va_start(args, format);
@@ -475,7 +480,7 @@ static void cFunctionBody(const char* name, int arguments) {
     returnState = 0;
 
     int p = cAddPush(arguments);
-    cConsumeBody();
+    cConsumeBody(false);
     cAddPop(p, vars[1].entries);
 
     cLinkReturns();
@@ -543,7 +548,7 @@ static void cIf() {
     cConsumeToken(T_CLOSE_BRACKET);
     cAddOperation(OP_IF_GOTO);
     int ifP = cReserveInt();
-    cConsumeBody();
+    cConsumeBody(false);
     cSetInt(ifP, code->length);
 
     if(cConsumeTokenIf(T_ELSE)) {
@@ -553,12 +558,19 @@ static void cIf() {
         if(cConsumeTokenIf(T_IF)) {
             cIf();
         } else {
-            cConsumeBody();
+            cConsumeBody(false);
         }
         cSetInt(elseP, code->length);
     }
 }
 
+static void cConsumeBreaks(int start, int address) {
+    for(int i = start; i < breakIndex; i++) {
+        cSetInt(breaks[i], address);
+    }
+    breakIndex = start;
+}
+
 static void cWhile() {
     int start = code->length;
     cConsumeToken(T_OPEN_BRACKET);
@@ -566,10 +578,14 @@ static void cWhile() {
     cConsumeToken(T_CLOSE_BRACKET);
     cAddOperation(OP_IF_GOTO);
     int ifP = cReserveInt();
-    cConsumeBody();
+    int breakStart = breakIndex;
+    forWhileStack++;
+    cConsumeBody(true);
+    forWhileStack--;
     cAddOperation(OP_GOTO);
     cAddInt(start);
     cSetInt(ifP, code->length);
+    cConsumeBreaks(breakStart, code->length);
 }
 
 static void cLineExpression(Token t) {
@@ -604,10 +620,25 @@ static void cFor() {
     cAddInt(startCheck);
     cConsumeToken(T_CLOSE_BRACKET);
     cSetInt(beginBody, code->length);
-    cConsumeBody();
+    int breakStart = breakIndex;
+    forWhileStack++;
+    cConsumeBody(true);
+    forWhileStack--;
     cAddOperation(OP_GOTO);
     cAddInt(startPerLoop);
     cSetInt(end, code->length);
+    cConsumeBreaks(breakStart, code->length);
+}
+
+static void cBreak() {
+    if(forWhileStack == 0) {
+        cError("break without for or while on line %d", line);
+    } else if(breakIndex >= BREAK_BUFFER) {
+        cError("too much breaks around line %d", line);
+    }
+    cAddOperation(OP_GOTO);
+    breaks[breakIndex++] = cReserveInt();
+    cConsumeToken(T_SEMICOLON);
 }
 
 static void cLine(Token t) {
@@ -620,6 +651,7 @@ static void cLine(Token t) {
         case T_IF: cIf(); break;
         case T_WHILE: cWhile(); break;
         case T_FOR: cFor(); break;
+        case T_BREAK: cBreak(); break;
         default: cLineExpression(t); cConsumeToken(T_SEMICOLON);
     }
 }
@@ -650,6 +682,9 @@ static void cLinkQueuedFunctions() {
 static void cAllocAndCompile() {
     varIndex = 0;
     returnIndex = 0;
+    returnState = 0;
+    forWhileStack = 0;
+    breakIndex = 0;
     simInit(vars);
     simInit(vars + 1);
     fmInit(&functions);

+ 4 - 3
Tokenizer.c

@@ -22,9 +22,9 @@ typedef struct Literal {
     Token token;
 } Literal;
 
-Literal LITERALS[] = {{"print", T_PRINT},       {"null", T_NULL},     {"true", T_TRUE}, {"false", T_FALSE},
-                      {"function", T_FUNCTION}, {"return", T_RETURN}, {"if", T_IF},     {"else", T_ELSE},
-                      {"while", T_WHILE},       {"for", T_FOR}};
+Literal LITERALS[] = {{"print", T_PRINT},       {"null", T_NULL},     {"true", T_TRUE},  {"false", T_FALSE},
+                      {"function", T_FUNCTION}, {"return", T_RETURN}, {"if", T_IF},      {"else", T_ELSE},
+                      {"while", T_WHILE},       {"for", T_FOR},       {"break", T_BREAK}};
 const int LITERAL_AMOUNT = sizeof(LITERALS) / sizeof(Literal);
 
 static void tError(const char* format, ...) {
@@ -313,6 +313,7 @@ const char* tGetTokenName(Token token) {
         case T_ELSE: return "else";
         case T_WHILE: return "while";
         case T_FOR: return "for";
+        case T_BREAK: return "break";
         case T_FUNCTION: return "function";
         case T_RETURN: return "return";
         case T_COMMA: return ",";

+ 1 - 0
Tokenizer.h

@@ -49,6 +49,7 @@ typedef enum Token {
     T_ELSE,
     T_WHILE,
     T_FOR,
+    T_BREAK,
     T_FUNCTION,
     T_RETURN,
     T_COMMA,

+ 19 - 0
tests/loops/break

@@ -0,0 +1,19 @@
+for(i = 0; i < 10; i++) {
+    print i;
+    if(i == 4) {
+        break;
+    }
+}
+for(x = 0; x < 3; ++x) {
+    if(false) {
+        break;
+    }
+    while(true) {
+        print x;
+        break;
+        print y;
+    }
+    if(x == 1) {
+        break;
+    }
+}

+ 7 - 0
tests/loops/break.out

@@ -0,0 +1,7 @@
+0
+1
+2
+3
+4
+0
+1