Ver código fonte

rest of comparison operators: >, <=, >=, ==, !=

Kajetan Johannes Hammerle 4 anos atrás
pai
commit
6abfe0a3de

+ 25 - 3
Compiler.c

@@ -223,9 +223,31 @@ static void cAdd() {
 
 static void cComparison() {
     cAdd();
-    while(cConsumeTokenIf(T_LESS)) {
-        cAdd();
-        cAddOperation(OP_LESS);
+    while(true) {
+        if(cConsumeTokenIf(T_LESS)) {
+            cAdd();
+            cAddOperation(OP_LESS);
+        } else if(cConsumeTokenIf(T_LESS_EQUAL)) {
+            cAdd();
+            cAddOperation(OP_GREATER);
+            cAddOperation(OP_NOT);
+        } else if(cConsumeTokenIf(T_GREATER)) {
+            cAdd();
+            cAddOperation(OP_GREATER);
+        } else if(cConsumeTokenIf(T_GREATER_EQUAL)) {
+            cAdd();
+            cAddOperation(OP_LESS);
+            cAddOperation(OP_NOT);
+        } else if(cConsumeTokenIf(T_EQUAL)) {
+            cAdd();
+            cAddOperation(OP_EQUAL);
+        } else if(cConsumeTokenIf(T_NOT_EQUAL)) {
+            cAdd();
+            cAddOperation(OP_EQUAL);
+            cAddOperation(OP_NOT);
+        } else {
+            break;
+        }
     }
 }
 

+ 3 - 0
Operation.h

@@ -17,6 +17,9 @@ typedef enum Operation {
     OP_SUB,
     OP_MUL,
     OP_LESS,
+    OP_GREATER,
+    OP_EQUAL,
+    OP_NOT,
     OP_PRINT,
     OP_LINE,
     OP_GOTO,

+ 55 - 0
Script.c

@@ -72,6 +72,14 @@ static void sPopEmpty(Script* sc) {
     sPop(sc, &o);
 }
 
+static Object* sPeek(Script* sc) {
+    if(sc->stackIndex <= 0) {
+        sError(sc, "stack underflow on line %d", sc->line);
+        return NULL;
+    }
+    return sc->stack + (sc->stackIndex - 1);
+}
+
 static bool sPushInt(Script* sc, int value) {
     Object o = {.type = OT_INT, .data.intValue = value};
     return sPush(sc, &o);
@@ -222,10 +230,51 @@ static bool sIntLess(int a, int b) {
     return b < a;
 }
 
+static bool sIntGreater(int a, int b) {
+    return b > a;
+}
+
 static bool sFloatLess(float a, float b) {
     return b < a;
 }
 
+static bool sFloatGreater(float a, float b) {
+    return b > a;
+}
+
+static void sEqual(Script* sc) {
+    Object o[2];
+    if(sPop(sc, o) || sPop(sc, o + 1)) {
+        return;
+    }
+    if(o[0].type == OT_INT && o[1].type == OT_INT) {
+        sPushBool(sc, o[0].data.intValue == o[1].data.intValue);
+    } else if(o[0].type == OT_INT && o[1].type == OT_FLOAT) {
+        sPushBool(sc, o[0].data.intValue == o[1].data.floatValue);
+    } else if(o[0].type == OT_FLOAT && o[1].type == OT_INT) {
+        sPushBool(sc, o[0].data.floatValue == o[1].data.intValue);
+    } else if(o[0].type == OT_FLOAT && o[1].type == OT_FLOAT) {
+        sPushBool(sc, o[0].data.floatValue == o[1].data.floatValue);
+    } else if(o[0].type == OT_BOOL && o[1].type == OT_BOOL) {
+        sPushBool(sc, o[0].data.intValue == o[1].data.intValue);
+    } else if(o[0].type == OT_NULL && o[1].type == OT_NULL) {
+        sPushBool(sc, true);
+    } else {
+        sError(sc, "object types do not match on line %d", sc->line);
+    }
+}
+
+static void sNot(Script* sc) {
+    Object* o = sPeek(sc);
+    if(o == NULL) {
+        return;
+    } else if(o->type != OT_BOOL) {
+        sError(sc, "object is not a bool on line %d", sc->line);
+        return;
+    }
+    o->data.intValue = !o->data.intValue;
+}
+
 static void sPrint(Script* sc) {
     Object o;
     if(!sPop(sc, &o) && printer(&o)) {
@@ -308,6 +357,9 @@ static void sConsumeInstruction(Script* sc) {
         case OP_SUB: sIntBinary(sc, sIntSub, sFloatSub); break;
         case OP_MUL: sIntBinary(sc, sIntMul, sFloatMul); break;
         case OP_LESS: sBoolBinary(sc, sIntLess, sFloatLess); break;
+        case OP_GREATER: sBoolBinary(sc, sIntGreater, sFloatGreater); break;
+        case OP_EQUAL: sEqual(sc); break;
+        case OP_NOT: sNot(sc); break;
         case OP_PRINT: sPrint(sc); break;
         case OP_LINE: sLine(sc); break;
         case OP_GOTO: sGoTo(sc); break;
@@ -400,6 +452,9 @@ void sPrintCode(Script* sc) {
             case OP_SUB: puts("Sub"); break;
             case OP_MUL: puts("Mul"); break;
             case OP_LESS: puts("Less"); break;
+            case OP_GREATER: puts("Greater"); break;
+            case OP_EQUAL: puts("Equal"); break;
+            case OP_NOT: puts("Not"); break;
             case OP_PRINT: puts("Print"); break;
             case OP_LINE: sPrintInt16(sc, "------------ Line"); break;
             case OP_GOTO: sPrintInt(sc, "GoTo"); break;

+ 18 - 2
Tokenizer.c

@@ -67,6 +67,14 @@ static int tPeek() {
     return c;
 }
 
+static int tReadIf(int c) {
+    if(tPeek() == c) {
+        tRead();
+        return true;
+    }
+    return false;
+}
+
 static bool tParseLiteral(int c) {
     int index = 1;
     char buffer[64];
@@ -140,8 +148,10 @@ static bool tParseToken() {
         case '+': return tAddToken(T_ADD);
         case '-': return tAddToken(T_SUB);
         case '*': return tAddToken(T_MUL);
-        case '<': return tAddToken(T_LESS);
-        case '=': return tAddToken(T_SET);
+        case '<': return tReadIf('=') ? tAddToken(T_LESS_EQUAL) : tAddToken(T_LESS);
+        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 tAddToken(T_COMMA);
         case ';': return tAddToken(T_SEMICOLON);
         case '(': return tAddToken(T_OPEN_BRACKET);
@@ -239,6 +249,12 @@ const char* tGetTokenName(Token token) {
         case T_SUB: return "-";
         case T_MUL: return "*";
         case T_LESS: return "<";
+        case T_LESS_EQUAL: return "<=";
+        case T_GREATER: return ">";
+        case T_GREATER_EQUAL: return ">=";
+        case T_EQUAL: return "==";
+        case T_NOT_EQUAL: return "!=";
+        case T_NOT: return "!";
         case T_SET: return "=";
         case T_LITERAL: return "literal";
         case T_PRINT: return "print";

+ 6 - 0
Tokenizer.h

@@ -14,6 +14,12 @@ typedef enum Token {
     T_SUB,
     T_MUL,
     T_LESS,
+    T_LESS_EQUAL,
+    T_GREATER,
+    T_GREATER_EQUAL,
+    T_EQUAL,
+    T_NOT_EQUAL,
+    T_NOT,
     T_SET,
     T_LITERAL,
     T_PRINT,

+ 3 - 0
tests/calc/sub

@@ -0,0 +1,3 @@
+print 0 - 5;
+print 2 - 5 + 3 - 6;
+print 2 - (5 + 3) - 6;

+ 3 - 0
tests/calc/sub.out

@@ -0,0 +1,3 @@
+-5
+-6
+-12

+ 25 - 0
tests/comparison/equal

@@ -0,0 +1,25 @@
+print 0 == 5;
+print 4 == 5;
+print 5 == 5;
+print 6 == 5;
+print 10 == 5;
+print 0.0 == 5.0;
+print 4.0 == 5.0;
+print 5.0 == 5.0;
+print 6.0 == 5.0;
+print 10.0 == 5.0;
+print 0.0 == 5;
+print 4.0 == 5;
+print 5.0 == 5;
+print 6.0 == 5;
+print 10.0 == 5;
+print 0 == 5.0;
+print 4 == 5.0;
+print 5 == 5.0;
+print 6 == 5.0;
+print 10 == 5.0;
+print false == false;
+print true == false;
+print false == true;
+print true == true;
+print null == null;

+ 25 - 0
tests/comparison/equal.out

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

+ 20 - 0
tests/comparison/greater

@@ -0,0 +1,20 @@
+print 0 > 5;
+print 4 > 5;
+print 5 > 5;
+print 6 > 5;
+print 10 > 5;
+print 0.0 > 5.0;
+print 4.0 > 5.0;
+print 5.0 > 5.0;
+print 6.0 > 5.0;
+print 10.0 > 5.0;
+print 0.0 > 5;
+print 4.0 > 5;
+print 5.0 > 5;
+print 6.0 > 5;
+print 10.0 > 5;
+print 0 > 5.0;
+print 4 > 5.0;
+print 5 > 5.0;
+print 6 > 5.0;
+print 10 > 5.0;

+ 20 - 0
tests/comparison/greater.out

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

+ 20 - 0
tests/comparison/greater_equal

@@ -0,0 +1,20 @@
+print 0 >= 5;
+print 4 >= 5;
+print 5 >= 5;
+print 6 >= 5;
+print 10 >= 5;
+print 0.0 >= 5.0;
+print 4.0 >= 5.0;
+print 5.0 >= 5.0;
+print 6.0 >= 5.0;
+print 10.0 >= 5.0;
+print 0.0 >= 5;
+print 4.0 >= 5;
+print 5.0 >= 5;
+print 6.0 >= 5;
+print 10.0 >= 5;
+print 0 >= 5.0;
+print 4 >= 5.0;
+print 5 >= 5.0;
+print 6 >= 5.0;
+print 10 >= 5.0;

+ 20 - 0
tests/comparison/greater_equal.out

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

+ 20 - 0
tests/comparison/less

@@ -0,0 +1,20 @@
+print 0 < 5;
+print 4 < 5;
+print 5 < 5;
+print 6 < 5;
+print 10 < 5;
+print 0.0 < 5.0;
+print 4.0 < 5.0;
+print 5.0 < 5.0;
+print 6.0 < 5.0;
+print 10.0 < 5.0;
+print 0.0 < 5;
+print 4.0 < 5;
+print 5.0 < 5;
+print 6.0 < 5;
+print 10.0 < 5;
+print 0 < 5.0;
+print 4 < 5.0;
+print 5 < 5.0;
+print 6 < 5.0;
+print 10 < 5.0;

+ 20 - 0
tests/comparison/less.out

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

+ 20 - 0
tests/comparison/less_equal

@@ -0,0 +1,20 @@
+print 0 <= 5;
+print 4 <= 5;
+print 5 <= 5;
+print 6 <= 5;
+print 10 <= 5;
+print 0.0 <= 5.0;
+print 4.0 <= 5.0;
+print 5.0 <= 5.0;
+print 6.0 <= 5.0;
+print 10.0 <= 5.0;
+print 0.0 <= 5;
+print 4.0 <= 5;
+print 5.0 <= 5;
+print 6.0 <= 5;
+print 10.0 <= 5;
+print 0 <= 5.0;
+print 4 <= 5.0;
+print 5 <= 5.0;
+print 6 <= 5.0;
+print 10 <= 5.0;

+ 20 - 0
tests/comparison/less_equal.out

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

+ 25 - 0
tests/comparison/not_equal

@@ -0,0 +1,25 @@
+print 0 != 5;
+print 4 != 5;
+print 5 != 5;
+print 6 != 5;
+print 10 != 5;
+print 0.0 != 5.0;
+print 4.0 != 5.0;
+print 5.0 != 5.0;
+print 6.0 != 5.0;
+print 10.0 != 5.0;
+print 0.0 != 5;
+print 4.0 != 5;
+print 5.0 != 5;
+print 6.0 != 5;
+print 10.0 != 5;
+print 0 != 5.0;
+print 4 != 5.0;
+print 5 != 5.0;
+print 6 != 5.0;
+print 10 != 5.0;
+print false != false;
+print true != false;
+print false != true;
+print true != true;
+print null != null;

+ 25 - 0
tests/comparison/not_equal.out

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