Ver código fonte

&& and || with short circuit evaluation

Kajetan Johannes Hammerle 4 anos atrás
pai
commit
6e3b078b55
9 arquivos alterados com 111 adições e 2 exclusões
  1. 25 1
      Compiler.c
  2. 4 1
      Operation.h
  3. 27 0
      Script.c
  4. 6 0
      Tokenizer.c
  5. 4 0
      Tokenizer.h
  6. 13 0
      tests/if/and
  7. 10 0
      tests/if/and.out
  8. 13 0
      tests/if/or
  9. 9 0
      tests/if/or.out

+ 25 - 1
Compiler.c

@@ -261,8 +261,32 @@ static void cComparison() {
     }
 }
 
-static void cExpression() {
+static void cLogical() {
     cComparison();
+    while(true) {
+        if(cConsumeTokenIf(T_AND)) {
+            cAddOperation(OP_DUPLICATE);
+            cAddOperation(OP_IF_GOTO);
+            int p = cReserveInt();
+            cComparison();
+            cAddOperation(OP_AND);
+            cSetInt(p, code->length);
+        } else if(cConsumeTokenIf(T_OR)) {
+            cAddOperation(OP_DUPLICATE);
+            cAddOperation(OP_NOT);
+            cAddOperation(OP_IF_GOTO);
+            int p = cReserveInt();
+            cComparison();
+            cAddOperation(OP_OR);
+            cSetInt(p, code->length);
+        } else {
+            break;
+        }
+    }
+}
+
+static void cExpression() {
+    cLogical();
 }
 
 static void cSetVar(const char* literal) {

+ 4 - 1
Operation.h

@@ -22,13 +22,16 @@ typedef enum Operation {
     OP_GREATER,
     OP_EQUAL,
     OP_NOT,
+    OP_AND,
+    OP_OR,
     OP_PRINT,
     OP_LINE,
     OP_GOTO,
     OP_GOSUB,
     OP_IF_GOTO,
     OP_SET_RETURN,
-    OP_RETURN
+    OP_RETURN,
+    OP_DUPLICATE
 } Operation;
 
 #endif

+ 27 - 0
Script.c

@@ -285,6 +285,20 @@ static void sNot(Script* sc) {
     }
 }
 
+static void sAnd(Script* sc) {
+    Object o[2];
+    if(!sPop(sc, o) && !sPop(sc, o + 1) && sCheckType(sc, o, OT_BOOL) && sCheckType(sc, o + 1, OT_BOOL)) {
+        sPushBool(sc, o[0].data.intValue && o[1].data.intValue);
+    }
+}
+
+static void sOr(Script* sc) {
+    Object o[2];
+    if(!sPop(sc, o) && !sPop(sc, o + 1) && sCheckType(sc, o, OT_BOOL) && sCheckType(sc, o + 1, OT_BOOL)) {
+        sPushBool(sc, o[0].data.intValue || o[1].data.intValue);
+    }
+}
+
 static void sPrint(Script* sc) {
     Object o;
     if(!sPop(sc, &o) && printer(&o)) {
@@ -342,6 +356,13 @@ static void sReturn(Script* sc) {
     }
 }
 
+static void sDuplicate(Script* sc) {
+    Object* o = sPeek(sc);
+    if(o != NULL) {
+        sPush(sc, o);
+    }
+}
+
 static void sConsumeInstruction(Script* sc) {
     switch(sReadOperation(sc)) {
         case OP_NOTHING: break;
@@ -364,6 +385,8 @@ static void sConsumeInstruction(Script* sc) {
         case OP_GREATER: sBoolBinary(sc, sIntGreater, sFloatGreater); break;
         case OP_EQUAL: sEqual(sc); break;
         case OP_NOT: sNot(sc); break;
+        case OP_AND: sAnd(sc); break;
+        case OP_OR: sOr(sc); break;
         case OP_PRINT: sPrint(sc); break;
         case OP_LINE: sLine(sc); break;
         case OP_GOTO: sGoTo(sc); break;
@@ -371,6 +394,7 @@ static void sConsumeInstruction(Script* sc) {
         case OP_IF_GOTO: sIfGoTo(sc); break;
         case OP_SET_RETURN: sSetReturn(sc); break;
         case OP_RETURN: sReturn(sc); break;
+        case OP_DUPLICATE: sDuplicate(sc); break;
     }
 }
 
@@ -461,6 +485,8 @@ void sPrintCode(Script* sc) {
             case OP_GREATER: puts("Greater"); break;
             case OP_EQUAL: puts("Equal"); break;
             case OP_NOT: puts("Not"); break;
+            case OP_AND: puts("And"); break;
+            case OP_OR: puts("And"); break;
             case OP_PRINT: puts("Print"); break;
             case OP_LINE: sPrintInt16(sc, "------------ Line"); break;
             case OP_GOTO: sPrintInt(sc, "GoTo"); break;
@@ -468,6 +494,7 @@ void sPrintCode(Script* sc) {
             case OP_IF_GOTO: sPrintInt(sc, "If GoTo"); break;
             case OP_SET_RETURN: puts("Set Return"); break;
             case OP_RETURN: puts("Return"); break;
+            case OP_DUPLICATE: puts("Duplicate"); break;
         }
     }
     sc->readIndex = oldRead;

+ 6 - 0
Tokenizer.c

@@ -154,6 +154,8 @@ static bool tParseToken() {
         case '>': return tReadIf('=') ? tAddToken(T_GREATER_EQUAL) : tAddToken(T_GREATER);
         case '=': return tReadIf('=') ? tAddToken(T_EQUAL) : tAddToken(T_SET);
         case '!': return tReadIf('=') ? tAddToken(T_NOT_EQUAL) : tAddToken(T_NOT);
+        case '&': return tReadIf('&') ? tAddToken(T_AND) : tAddToken(T_BIT_AND);
+        case '|': return tReadIf('|') ? tAddToken(T_OR) : tAddToken(T_BIT_OR);
         case ',': return tAddToken(T_COMMA);
         case ';': return tAddToken(T_SEMICOLON);
         case '(': return tAddToken(T_OPEN_BRACKET);
@@ -259,6 +261,10 @@ const char* tGetTokenName(Token token) {
         case T_EQUAL: return "==";
         case T_NOT_EQUAL: return "!=";
         case T_NOT: return "!";
+        case T_AND: return "&&";
+        case T_OR: return "||";
+        case T_BIT_AND: return "&";
+        case T_BIT_OR: return "|";
         case T_SET: return "=";
         case T_LITERAL: return "literal";
         case T_PRINT: return "print";

+ 4 - 0
Tokenizer.h

@@ -22,6 +22,10 @@ typedef enum Token {
     T_EQUAL,
     T_NOT_EQUAL,
     T_NOT,
+    T_AND,
+    T_OR,
+    T_BIT_AND,
+    T_BIT_OR,
     T_SET,
     T_LITERAL,
     T_PRINT,

+ 13 - 0
tests/if/and

@@ -0,0 +1,13 @@
+print false && false;
+print true && false;
+print false && true;
+print true && true;
+
+function test() {
+    print 1;
+    return true;
+}
+
+print false && test() && test();
+print true && test() && false && test();
+print true && test() && test();

+ 10 - 0
tests/if/and.out

@@ -0,0 +1,10 @@
+false
+false
+false
+true
+false
+1
+false
+1
+1
+true

+ 13 - 0
tests/if/or

@@ -0,0 +1,13 @@
+print false || false;
+print true || false;
+print false || true;
+print true || true;
+
+function test() {
+    print 1;
+    return true;
+}
+
+print false || test() || test();
+print false || test() || true || test();
+print true || test() || test();

+ 9 - 0
tests/if/or.out

@@ -0,0 +1,9 @@
+false
+true
+true
+true
+1
+true
+1
+true
+true