Ver Fonte

Add comparison and logical features

Kajetan Johannes Hammerle há 1 semana atrás
pai
commit
22a7f342ef
11 ficheiros alterados com 336 adições e 54 exclusões
  1. 71 0
      src/Code.c
  2. 9 0
      src/Code.h
  3. 74 16
      src/Compiler.c
  4. 54 16
      src/Tokenizer.c
  5. 13 6
      src/Tokenizer.h
  6. 23 0
      test/Condition.basic
  7. 18 0
      test/Condition.basic_result
  8. 4 4
      test/Function3.basic
  9. 12 12
      test/If.basic
  10. 31 0
      test/Logic.basic
  11. 27 0
      test/Logic.basic_result

+ 71 - 0
src/Code.c

@@ -106,6 +106,59 @@ static bool iDiv(Code* c) {
     return iPushValue(c, INT_VALUE(b.data / a.data));
 }
 
+static bool iAnd(Code* c) {
+    POP_VALUE(a);
+    POP_VALUE(b);
+    return iPushValue(c, INT_VALUE(b.data && a.data));
+}
+
+static bool iOr(Code* c) {
+    POP_VALUE(a);
+    POP_VALUE(b);
+    return iPushValue(c, INT_VALUE(b.data || a.data));
+}
+
+static bool iNot(Code* c) {
+    POP_VALUE(a);
+    return iPushValue(c, INT_VALUE(!a.data));
+}
+
+static bool iEqual(Code* c) {
+    POP_VALUE(a);
+    POP_VALUE(b);
+    return iPushValue(c, INT_VALUE(b.data == a.data));
+}
+
+static bool iNotEqual(Code* c) {
+    POP_VALUE(a);
+    POP_VALUE(b);
+    return iPushValue(c, INT_VALUE(b.data != a.data));
+}
+
+static bool iGreater(Code* c) {
+    POP_VALUE(a);
+    POP_VALUE(b);
+    return iPushValue(c, INT_VALUE(b.data > a.data));
+}
+
+static bool iSmaller(Code* c) {
+    POP_VALUE(a);
+    POP_VALUE(b);
+    return iPushValue(c, INT_VALUE(b.data < a.data));
+}
+
+static bool iGreaterOrEqual(Code* c) {
+    POP_VALUE(a);
+    POP_VALUE(b);
+    return iPushValue(c, INT_VALUE(b.data >= a.data));
+}
+
+static bool iSmallerOrEqual(Code* c) {
+    POP_VALUE(a);
+    POP_VALUE(b);
+    return iPushValue(c, INT_VALUE(b.data <= a.data));
+}
+
 static bool iPushConstantString(Code* c) {
     const char* s = codeReadConstantString(c);
     i32 address = (i32)((const u8*)s - c->code.data);
@@ -273,6 +326,15 @@ static bool execute(Code* c, Instruction command) {
         case READ_VARIABLE: return iReadVariable(c);
         case SET_VARIABLE: return iSetVariable(c);
         case PUSH_STACK_VARIABLES: return iPushStackVariables(c);
+        case AND: return iAnd(c);
+        case OR: return iOr(c);
+        case NOT: return iNot(c);
+        case EQUAL: return iEqual(c);
+        case NOT_EQUAL: return iNotEqual(c);
+        case GREATER: return iGreater(c);
+        case SMALLER: return iSmaller(c);
+        case GREATER_OR_EQUAL: return iGreaterOrEqual(c);
+        case SMALLER_OR_EQUAL: return iSmallerOrEqual(c);
         case STOP: return true;
     }
     return false;
@@ -337,6 +399,15 @@ void codeDump(const Code* code) {
             DUMP_INT(READ_VARIABLE);
             DUMP_INT(SET_VARIABLE);
             DUMP_INT(PUSH_STACK_VARIABLES);
+            DUMP(AND);
+            DUMP(OR);
+            DUMP(NOT);
+            DUMP(EQUAL);
+            DUMP(NOT_EQUAL);
+            DUMP(GREATER);
+            DUMP(SMALLER);
+            DUMP(GREATER_OR_EQUAL);
+            DUMP(SMALLER_OR_EQUAL);
             DUMP(STOP);
             case PUSH_CONSTANT_STRING:
                 fprintf(

+ 9 - 0
src/Code.h

@@ -33,6 +33,15 @@ typedef enum : u8 {
     READ_VARIABLE,
     SET_VARIABLE,
     PUSH_STACK_VARIABLES,
+    AND,
+    OR,
+    NOT,
+    EQUAL,
+    NOT_EQUAL,
+    GREATER,
+    SMALLER,
+    GREATER_OR_EQUAL,
+    SMALLER_OR_EQUAL,
     STOP
 } Instruction;
 

+ 74 - 16
src/Compiler.c

@@ -264,17 +264,27 @@ static void compileConstant(Context* c) {
     }
 }
 
+static void compileUnary(Context* c) {
+    if(tokenizerPeek(c->tokenizer).type == TT_NOT) {
+        consumeToken(c, TT_NOT);
+        compileUnary(c);
+        codePushInstruction(c, NOT);
+    } else {
+        compileConstant(c);
+    }
+}
+
 static void compileMul(Context* c) {
-    compileConstant(c);
+    compileUnary(c);
     while(true) {
         Token t = tokenizerPeek(c->tokenizer);
-        if(t.type == TT_ASTERISK) {
+        if(t.type == TT_MULTIPLY) {
             tokenizerNext(c->tokenizer);
-            compileMul(c);
+            compileUnary(c);
             codePushInstruction(c, MUL);
-        } else if(t.type == TT_SLASH) {
+        } else if(t.type == TT_DIVIDE) {
             tokenizerNext(c->tokenizer);
-            compileMul(c);
+            compileUnary(c);
             codePushInstruction(c, DIV);
         } else {
             break;
@@ -286,11 +296,11 @@ static void compileAdd(Context* c) {
     compileMul(c);
     while(true) {
         Token t = tokenizerPeek(c->tokenizer);
-        if(t.type == TT_PLUS) {
+        if(t.type == TT_ADD) {
             tokenizerNext(c->tokenizer);
             compileMul(c);
             codePushInstruction(c, ADD);
-        } else if(t.type == TT_MINUS) {
+        } else if(t.type == TT_SUBTRACT) {
             tokenizerNext(c->tokenizer);
             compileMul(c);
             codePushInstruction(c, SUB);
@@ -300,8 +310,60 @@ static void compileAdd(Context* c) {
     }
 }
 
-static void compileExpression(Context* c) {
+static void compileCompare(Context* c) {
     compileAdd(c);
+    while(true) {
+        Token t = tokenizerPeek(c->tokenizer);
+        if(t.type == TT_EQUAL) {
+            tokenizerNext(c->tokenizer);
+            compileAdd(c);
+            codePushInstruction(c, EQUAL);
+        } else if(t.type == TT_NOT_EQUAL) {
+            tokenizerNext(c->tokenizer);
+            compileAdd(c);
+            codePushInstruction(c, NOT_EQUAL);
+        } else if(t.type == TT_GREATER) {
+            tokenizerNext(c->tokenizer);
+            compileAdd(c);
+            codePushInstruction(c, GREATER);
+        } else if(t.type == TT_SMALLER) {
+            tokenizerNext(c->tokenizer);
+            compileAdd(c);
+            codePushInstruction(c, SMALLER);
+        } else if(t.type == TT_GREATER_OR_EQUAL) {
+            tokenizerNext(c->tokenizer);
+            compileAdd(c);
+            codePushInstruction(c, GREATER_OR_EQUAL);
+        } else if(t.type == TT_SMALLER_OR_EQUAL) {
+            tokenizerNext(c->tokenizer);
+            compileAdd(c);
+            codePushInstruction(c, SMALLER_OR_EQUAL);
+        } else {
+            break;
+        }
+    }
+}
+
+static void compileLogical(Context* c) {
+    compileCompare(c);
+    while(true) {
+        Token t = tokenizerPeek(c->tokenizer);
+        if(t.type == TT_AND) {
+            tokenizerNext(c->tokenizer);
+            compileCompare(c);
+            codePushInstruction(c, AND);
+        } else if(t.type == TT_OR) {
+            tokenizerNext(c->tokenizer);
+            compileCompare(c);
+            codePushInstruction(c, OR);
+        } else {
+            break;
+        }
+    }
+}
+
+static void compileExpression(Context* c) {
+    compileLogical(c);
 }
 
 static void compileLine(Context* c, Token token);
@@ -311,21 +373,17 @@ static void compileIf(Context* c) {
     codePushInstruction(c, JUMP_ON_0);
     size_t posIndex = codeGetWritePosition(c);
     codePushI32(c, 0);
-    consumeToken(c, TT_THEN);
     consumeNewline(c);
-    while(true) {
-        if(tokenizerPeek(c->tokenizer).type == TT_ENDIF) {
-            break;
-        }
+    while(tokenizerPeek(c->tokenizer).type != TT_END) {
         compileLine(c, tokenizerNext(c->tokenizer));
     }
-    consumeToken(c, TT_ENDIF);
+    consumeToken(c, TT_END);
     consumeNewline(c);
     codeRewriteI32(c, posIndex, (i32)codeGetWritePosition(c));
 }
 
 static void compileSetVariable(Context* c, const char* name, bool forceGlobal) {
-    consumeToken(c, TT_EQUAL);
+    consumeToken(c, TT_ASSIGN);
     compileExpression(c);
     i32 index = addVariable(c, name, forceGlobal);
     codePushInstruction(c, SET_VARIABLE);
@@ -462,7 +520,7 @@ static void compileLine(Context* c, Token token) {
         }
         consumeNewline(c);
         codePushInstruction(c, PRINT_NEWLINE);
-    } else if(tokenizerPeek(c->tokenizer).type == TT_EQUAL) {
+    } else if(tokenizerPeek(c->tokenizer).type == TT_ASSIGN) {
         compileSetVariable(c, s, false);
     } else if(tokenizerPeek(c->tokenizer).type == TT_OPEN_ROUND_BRACKET) {
         compileCallFunction(c, token);

+ 54 - 16
src/Tokenizer.c

@@ -69,10 +69,6 @@ static const char* tokenizerAddLiteral(TState* t, const char* s) {
     }
     if(strcmp(buffer, "if") == 0) {
         tAddToken(t, TT_IF);
-    } else if(strcmp(buffer, "then") == 0) {
-        tAddToken(t, TT_THEN);
-    } else if(strcmp(buffer, "endif") == 0) {
-        tAddToken(t, TT_ENDIF);
     } else if(strcmp(buffer, "function") == 0) {
         tAddToken(t, TT_FUNCTION);
     } else if(strcmp(buffer, "end") == 0) {
@@ -157,26 +153,61 @@ static void tParseLineString(TState* t, const char* s) {
             tAddToken(t, TT_DOLLAR);
             s++;
         } else if(c == '+') {
-            tAddToken(t, TT_PLUS);
+            tAddToken(t, TT_ADD);
             s++;
         } else if(c == '-') {
-            tAddToken(t, TT_MINUS);
+            tAddToken(t, TT_SUBTRACT);
             s++;
         } else if(c == '*') {
-            tAddToken(t, TT_ASTERISK);
+            tAddToken(t, TT_MULTIPLY);
             s++;
         } else if(c == '/') {
-            tAddToken(t, TT_SLASH);
+            tAddToken(t, TT_DIVIDE);
             s++;
         } else if(c == '=') {
-            tAddToken(t, TT_EQUAL);
             s++;
+            if(*s == '=') {
+                s++;
+                tAddToken(t, TT_EQUAL);
+            } else {
+                tAddToken(t, TT_ASSIGN);
+            }
+        } else if(c == '!') {
+            s++;
+            if(*s == '=') {
+                s++;
+                tAddToken(t, TT_NOT_EQUAL);
+            } else {
+                tAddToken(t, TT_NOT);
+            }
+        } else if(c == '>') {
+            s++;
+            if(*s == '=') {
+                s++;
+                tAddToken(t, TT_GREATER_OR_EQUAL);
+            } else {
+                tAddToken(t, TT_GREATER);
+            }
+        } else if(c == '<') {
+            s++;
+            if(*s == '=') {
+                s++;
+                tAddToken(t, TT_SMALLER_OR_EQUAL);
+            } else {
+                tAddToken(t, TT_SMALLER);
+            }
         } else if(c == '(') {
             tAddToken(t, TT_OPEN_ROUND_BRACKET);
             s++;
         } else if(c == ')') {
             tAddToken(t, TT_CLOSE_ROUND_BRACKET);
             s++;
+        } else if(c == '&' && s[1] == '&') {
+            s += 2;
+            tAddToken(t, TT_AND);
+        } else if(c == '|' && s[1] == '|') {
+            s += 2;
+            tAddToken(t, TT_OR);
         } else if(c == '\0') {
             break;
         } else {
@@ -270,14 +301,21 @@ void tokenizerPrintToken(const Token* token, char* buffer, size_t n) {
         TOKEN_PRINTER(TT_STRING, "String(%s)", token->stringValue);
         TOKEN_PRINTER(TT_DOLLAR, "$");
         TOKEN_PRINTER(TT_COMMA, ",");
-        TOKEN_PRINTER(TT_PLUS, "+");
-        TOKEN_PRINTER(TT_MINUS, "-");
-        TOKEN_PRINTER(TT_ASTERISK, "*");
-        TOKEN_PRINTER(TT_SLASH, "/");
-        TOKEN_PRINTER(TT_EQUAL, "=");
+        TOKEN_PRINTER(TT_ADD, "+");
+        TOKEN_PRINTER(TT_SUBTRACT, "-");
+        TOKEN_PRINTER(TT_MULTIPLY, "*");
+        TOKEN_PRINTER(TT_DIVIDE, "/");
+        TOKEN_PRINTER(TT_ASSIGN, "=");
+        TOKEN_PRINTER(TT_AND, "&&");
+        TOKEN_PRINTER(TT_OR, "||");
+        TOKEN_PRINTER(TT_NOT, "!");
+        TOKEN_PRINTER(TT_EQUAL, "==");
+        TOKEN_PRINTER(TT_NOT_EQUAL, "!=");
+        TOKEN_PRINTER(TT_GREATER, ">");
+        TOKEN_PRINTER(TT_SMALLER, "<");
+        TOKEN_PRINTER(TT_GREATER_OR_EQUAL, ">=");
+        TOKEN_PRINTER(TT_SMALLER_OR_EQUAL, "<=");
         TOKEN_PRINTER(TT_IF, "If");
-        TOKEN_PRINTER(TT_THEN, "Then");
-        TOKEN_PRINTER(TT_ENDIF, "EndIf");
         TOKEN_PRINTER(TT_FUNCTION, "Function");
         TOKEN_PRINTER(TT_END, "End");
         TOKEN_PRINTER(TT_RETURN, "Return");

+ 13 - 6
src/Tokenizer.h

@@ -10,14 +10,21 @@ typedef enum : u8 {
     TT_STRING,
     TT_COMMA,
     TT_DOLLAR,
-    TT_PLUS,
-    TT_MINUS,
-    TT_ASTERISK,
-    TT_SLASH,
+    TT_ADD,
+    TT_SUBTRACT,
+    TT_MULTIPLY,
+    TT_DIVIDE,
+    TT_ASSIGN,
+    TT_AND,
+    TT_OR,
+    TT_NOT,
     TT_EQUAL,
+    TT_NOT_EQUAL,
+    TT_GREATER,
+    TT_SMALLER,
+    TT_GREATER_OR_EQUAL,
+    TT_SMALLER_OR_EQUAL,
     TT_IF,
-    TT_THEN,
-    TT_ENDIF,
     TT_FUNCTION,
     TT_END,
     TT_RETURN,

+ 23 - 0
test/Condition.basic

@@ -0,0 +1,23 @@
+print 3 < 5
+print 5 < 3
+print 3 < 3
+
+print 3 > 5
+print 5 > 3
+print 3 > 3
+
+print 3 == 5
+print 5 == 3
+print 3 == 3
+
+print 3 != 5
+print 5 != 3
+print 3 != 3
+
+print 3 <= 5
+print 5 <= 3
+print 3 <= 3
+
+print 3 >= 5
+print 5 >= 3
+print 3 >= 3

+ 18 - 0
test/Condition.basic_result

@@ -0,0 +1,18 @@
+1
+0
+0
+0
+1
+0
+0
+0
+1
+1
+1
+0
+1
+0
+1
+0
+1
+1

+ 4 - 4
test/Function3.basic

@@ -11,10 +11,10 @@ print wusi(3, 4)
 print wusi(5, 4)
 
 function fac(n)
-    if n then
-        return n * fac(n - 1)
-    endif
-    return 1
+    if n == 0
+        return 1
+    end
+    return n * fac(n - 1)
 end
 
 function baum()

+ 12 - 12
test/If.basic

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

+ 31 - 0
test/Logic.basic

@@ -0,0 +1,31 @@
+print 0 && 0
+print 1 && 0
+print 0 && 1
+print 1 && 1
+
+print 0 || 0
+print 1 || 0
+print 0 || 1
+print 1 || 1
+
+print 0 && 0 && 0
+print 1 && 0 && 0
+print 0 && 1 && 0
+print 1 && 1 && 0
+print 0 && 0 && 1
+print 1 && 0 && 1
+print 0 && 1 && 1
+print 1 && 1 && 1
+
+print 0 || 0 || 0
+print 1 || 0 || 0
+print 0 || 1 || 0
+print 1 || 1 || 0
+print 0 || 0 || 1
+print 1 || 0 || 1
+print 0 || 1 || 1
+print 1 || 1 || 1
+
+print !3
+print !!3
+print !!!3

+ 27 - 0
test/Logic.basic_result

@@ -0,0 +1,27 @@
+0
+0
+0
+1
+0
+1
+1
+1
+0
+0
+0
+0
+0
+0
+0
+1
+0
+1
+1
+1
+1
+1
+1
+1
+0
+1
+0