Forráskód Böngészése

bit operations, stricter enforcement of operator precedence from C

Kajetan Johannes Hammerle 3 éve
szülő
commit
f2bf937ebd
15 módosított fájl, 219 hozzáadás és 34 törlés
  1. 84 27
      Compiler.c
  2. 6 0
      Operation.h
  3. 45 1
      Script.c
  4. 39 6
      Tokenizer.c
  5. 9 0
      Tokenizer.h
  6. 5 0
      tests/bits/and
  7. 2 0
      tests/bits/and.out
  8. 2 0
      tests/bits/invert
  9. 2 0
      tests/bits/invert.out
  10. 5 0
      tests/bits/or
  11. 2 0
      tests/bits/or.out
  12. 9 0
      tests/bits/shift
  13. 2 0
      tests/bits/shift.out
  14. 5 0
      tests/bits/xor
  15. 2 0
      tests/bits/xor.out

+ 84 - 27
Compiler.c

@@ -242,6 +242,9 @@ static void cPreUnary() {
         if((counter & 1) == 0) {
             cAddOperation(OP_NOT);
         }
+    } else if(cConsumeTokenIf(T_BIT_NOT)) {
+        cPrimary();
+        cAddOperation(OP_BIT_NOT);
     } else {
         cPrimary();
     }
@@ -280,62 +283,111 @@ static void cAdd() {
     }
 }
 
-static void cComparison() {
+static void cShift() {
     cAdd();
     while(true) {
-        if(cConsumeTokenIf(T_LESS)) {
+        if(cConsumeTokenIf(T_LEFT_SHIFT)) {
             cAdd();
+            cAddOperation(OP_LEFT_SHIFT);
+        } else if(cConsumeTokenIf(T_RIGHT_SHIFT)) {
+            cAdd();
+            cAddOperation(OP_RIGHT_SHIFT);
+        } else {
+            break;
+        }
+    }
+}
+
+static void cComparison() {
+    cShift();
+    while(true) {
+        if(cConsumeTokenIf(T_LESS)) {
+            cShift();
             cAddOperation(OP_LESS);
         } else if(cConsumeTokenIf(T_LESS_EQUAL)) {
-            cAdd();
+            cShift();
             cAddOperation(OP_GREATER);
             cAddOperation(OP_NOT);
         } else if(cConsumeTokenIf(T_GREATER)) {
-            cAdd();
+            cShift();
             cAddOperation(OP_GREATER);
         } else if(cConsumeTokenIf(T_GREATER_EQUAL)) {
-            cAdd();
+            cShift();
             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;
         }
     }
 }
 
-static void cLogical() {
+static void cEqual() {
     cComparison();
     while(true) {
-        if(cConsumeTokenIf(T_AND)) {
-            cAddOperation(OP_DUPLICATE);
-            cAddOperation(OP_IF_GOTO);
-            int p = cReserveInt();
+        if(cConsumeTokenIf(T_EQUAL)) {
             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();
+            cAddOperation(OP_EQUAL);
+        } else if(cConsumeTokenIf(T_NOT_EQUAL)) {
             cComparison();
-            cAddOperation(OP_OR);
-            cSetInt(p, code->length);
+            cAddOperation(OP_EQUAL);
+            cAddOperation(OP_NOT);
         } else {
             break;
         }
     }
 }
 
+static void cBitAnd() {
+    cEqual();
+    while(cConsumeTokenIf(T_BIT_AND)) {
+        cEqual();
+        cAddOperation(OP_BIT_AND);
+    }
+}
+
+static void cBitXor() {
+    cBitAnd();
+    while(cConsumeTokenIf(T_BIT_XOR)) {
+        cBitAnd();
+        cAddOperation(OP_BIT_XOR);
+    }
+}
+
+static void cBitOr() {
+    cBitXor();
+    while(cConsumeTokenIf(T_BIT_OR)) {
+        cBitXor();
+        cAddOperation(OP_BIT_OR);
+    }
+}
+
+static void cAnd() {
+    cBitOr();
+    while(cConsumeTokenIf(T_AND)) {
+        cAddOperation(OP_DUPLICATE);
+        cAddOperation(OP_IF_GOTO);
+        int p = cReserveInt();
+        cBitOr();
+        cAddOperation(OP_AND);
+        cSetInt(p, code->length);
+    }
+}
+
+static void cOr() {
+    cAnd();
+    while(cConsumeTokenIf(T_OR)) {
+        cAddOperation(OP_DUPLICATE);
+        cAddOperation(OP_NOT);
+        cAddOperation(OP_IF_GOTO);
+        int p = cReserveInt();
+        cAnd();
+        cAddOperation(OP_OR);
+        cSetInt(p, code->length);
+    }
+}
+
 static void cExpression() {
-    cLogical();
+    cOr();
 }
 
 static void cSetVar(const char* literal) {
@@ -362,6 +414,11 @@ static void cLineLiteral() {
         case T_MUL_SET: cOperationSetVar(literal, OP_MUL); break;
         case T_DIV_SET: cOperationSetVar(literal, OP_DIV); break;
         case T_MOD_SET: cOperationSetVar(literal, OP_MOD); break;
+        case T_BIT_AND_SET: cOperationSetVar(literal, OP_BIT_AND); break;
+        case T_BIT_OR_SET: cOperationSetVar(literal, OP_BIT_OR); break;
+        case T_BIT_XOR_SET: cOperationSetVar(literal, OP_BIT_XOR); break;
+        case T_LEFT_SHIFT_SET: cOperationSetVar(literal, OP_LEFT_SHIFT); break;
+        case T_RIGHT_SHIFT_SET: cOperationSetVar(literal, OP_RIGHT_SHIFT); break;
         case T_OPEN_BRACKET: cCallFunction(literal, true); break;
         case T_INCREMENT:
             cPostIncrement(literal);

+ 6 - 0
Operation.h

@@ -29,6 +29,12 @@ typedef enum Operation {
     OP_NOT,
     OP_AND,
     OP_OR,
+    OP_BIT_NOT,
+    OP_BIT_AND,
+    OP_BIT_OR,
+    OP_BIT_XOR,
+    OP_LEFT_SHIFT,
+    OP_RIGHT_SHIFT,
     OP_PRINT,
     OP_LINE,
     OP_GOTO,

+ 45 - 1
Script.c

@@ -283,6 +283,31 @@ static int sMod(Script* sc, int a, int b) {
     return b % a;
 }
 
+static int sBitAnd(Script* sc, int a, int b) {
+    (void)sc;
+    return b & a;
+}
+
+static int sBitOr(Script* sc, int a, int b) {
+    (void)sc;
+    return b | a;
+}
+
+static int sBitXor(Script* sc, int a, int b) {
+    (void)sc;
+    return b ^ a;
+}
+
+static int sLeftShift(Script* sc, int a, int b) {
+    (void)sc;
+    return b << a;
+}
+
+static int sRightShift(Script* sc, int a, int b) {
+    (void)sc;
+    return b >> a;
+}
+
 static float sFloatAdd(float a, float b) {
     return a + b;
 }
@@ -373,6 +398,13 @@ static void sNot(Script* sc) {
     }
 }
 
+static void sBitNot(Script* sc) {
+    Object* o = sPeek(sc);
+    if(o != NULL && sCheckType(sc, o, OT_INT)) {
+        o->data.intValue = ~o->data.intValue;
+    }
+}
+
 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)) {
@@ -480,6 +512,12 @@ static void sConsumeInstruction(Script* sc) {
         case OP_NOT: sNot(sc); break;
         case OP_AND: sAnd(sc); break;
         case OP_OR: sOr(sc); break;
+        case OP_BIT_NOT: sBitNot(sc); break;
+        case OP_BIT_AND: sIntBinary(sc, sBitAnd); break;
+        case OP_BIT_OR: sIntBinary(sc, sBitOr); break;
+        case OP_BIT_XOR: sIntBinary(sc, sBitXor); break;
+        case OP_LEFT_SHIFT: sIntBinary(sc, sLeftShift); break;
+        case OP_RIGHT_SHIFT: sIntBinary(sc, sRightShift); break;
         case OP_PRINT: sPrint(sc); break;
         case OP_LINE: sLine(sc); break;
         case OP_GOTO: sGoTo(sc); break;
@@ -584,7 +622,13 @@ void sPrintCode(Script* sc) {
             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_OR: puts("Or"); break;
+            case OP_BIT_NOT: puts("Bit Not"); break;
+            case OP_BIT_AND: puts("Bit And"); break;
+            case OP_BIT_OR: puts("Bit Or"); break;
+            case OP_BIT_XOR: puts("Bit Xor"); break;
+            case OP_LEFT_SHIFT: puts("Left Shift"); break;
+            case OP_RIGHT_SHIFT: puts("Right Shift"); break;
             case OP_PRINT: puts("Print"); break;
             case OP_LINE: sPrintInt16(sc, "------------ Line"); break;
             case OP_GOTO: sPrintInt(sc, "GoTo"); break;

+ 39 - 6
Tokenizer.c

@@ -134,6 +134,28 @@ static bool tParseNumber(int c) {
     }
 }
 
+static bool tAddTokenChecked(int c, Token tc, Token te, Token t) {
+    if(tReadIf(c)) {
+        return tAddToken(tc);
+    } else if(tReadIf('=')) {
+        return tAddToken(te);
+    }
+    return tAddToken(t);
+}
+
+static bool tAddLongTokenChecked(int c, Token tce, Token tc, Token te, Token t) {
+    if(tReadIf(c)) {
+        if(tReadIf('=')) {
+            return tAddToken(tce);
+        } else {
+            return tAddToken(tc);
+        }
+    } else if(tReadIf('=')) {
+        return tAddToken(te);
+    }
+    return tAddToken(t);
+}
+
 static bool tParseToken() {
     int c = tRead();
     if(c == EOF) {
@@ -146,17 +168,19 @@ static bool tParseToken() {
     switch(c) {
         case ' ': return true;
         case '\n': line++; return true;
-        case '+': return tReadIf('+') ? tAddToken(T_INCREMENT) : tReadIf('=') ? tAddToken(T_ADD_SET) : tAddToken(T_ADD);
-        case '-': return tReadIf('-') ? tAddToken(T_DECREMENT) : tReadIf('=') ? tAddToken(T_SUB_SET) : tAddToken(T_SUB);
+        case '+': return tAddTokenChecked('+', T_INCREMENT, T_ADD_SET, T_ADD);
+        case '-': return tAddTokenChecked('-', T_DECREMENT, T_SUB_SET, T_SUB);
         case '*': return tReadIf('=') ? tAddToken(T_MUL_SET) : tAddToken(T_MUL);
         case '/': return tReadIf('=') ? tAddToken(T_DIV_SET) : tAddToken(T_DIV);
         case '%': return tReadIf('=') ? tAddToken(T_MOD_SET) : tAddToken(T_MOD);
-        case '<': return tReadIf('=') ? tAddToken(T_LESS_EQUAL) : tAddToken(T_LESS);
-        case '>': return tReadIf('=') ? tAddToken(T_GREATER_EQUAL) : tAddToken(T_GREATER);
+        case '<': return tAddLongTokenChecked('<', T_LEFT_SHIFT_SET, T_LEFT_SHIFT, T_LESS_EQUAL, T_LESS);
+        case '>': return tAddLongTokenChecked('>', T_RIGHT_SHIFT_SET, T_RIGHT_SHIFT, T_GREATER_EQUAL, 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 tAddTokenChecked('&', T_AND, T_BIT_AND_SET, T_BIT_AND);
+        case '|': return tAddTokenChecked('|', T_OR, T_BIT_OR_SET, T_BIT_OR);
+        case '~': return tAddToken(T_BIT_NOT);
+        case '^': return tReadIf('=') ? tAddToken(T_BIT_XOR_SET) : tAddToken(T_BIT_XOR);
         case ',': return tAddToken(T_COMMA);
         case ';': return tAddToken(T_SEMICOLON);
         case '(': return tAddToken(T_OPEN_BRACKET);
@@ -264,14 +288,23 @@ const char* tGetTokenName(Token token) {
         case T_NOT: return "!";
         case T_AND: return "&&";
         case T_OR: return "||";
+        case T_BIT_NOT: return "~";
         case T_BIT_AND: return "&";
         case T_BIT_OR: return "|";
+        case T_BIT_XOR: return "^";
+        case T_LEFT_SHIFT: return "<<";
+        case T_RIGHT_SHIFT: return ">>";
         case T_SET: return "=";
         case T_ADD_SET: return "+=";
         case T_SUB_SET: return "-=";
         case T_MUL_SET: return "*=";
         case T_DIV_SET: return "/=";
         case T_MOD_SET: return "%=";
+        case T_BIT_AND_SET: return "&=";
+        case T_BIT_OR_SET: return "|=";
+        case T_BIT_XOR_SET: return "^=";
+        case T_LEFT_SHIFT_SET: return "<<=";
+        case T_RIGHT_SHIFT_SET: return ">>=";
         case T_INCREMENT: return "++";
         case T_DECREMENT: return "--";
         case T_LITERAL: return "literal";

+ 9 - 0
Tokenizer.h

@@ -24,14 +24,23 @@ typedef enum Token {
     T_NOT,
     T_AND,
     T_OR,
+    T_BIT_NOT,
     T_BIT_AND,
     T_BIT_OR,
+    T_BIT_XOR,
+    T_LEFT_SHIFT,
+    T_RIGHT_SHIFT,
     T_SET,
     T_ADD_SET,
     T_SUB_SET,
     T_MUL_SET,
     T_DIV_SET,
     T_MOD_SET,
+    T_BIT_AND_SET,
+    T_BIT_OR_SET,
+    T_BIT_XOR_SET,
+    T_LEFT_SHIFT_SET,
+    T_RIGHT_SHIFT_SET,
     T_INCREMENT,
     T_DECREMENT,
     T_LITERAL,

+ 5 - 0
tests/bits/and

@@ -0,0 +1,5 @@
+a = 7;
+a = a & 15;
+print a;
+a &= 9;
+print a;

+ 2 - 0
tests/bits/and.out

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

+ 2 - 0
tests/bits/invert

@@ -0,0 +1,2 @@
+print ~0;
+print ~(~7);

+ 2 - 0
tests/bits/invert.out

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

+ 5 - 0
tests/bits/or

@@ -0,0 +1,5 @@
+a = 0;
+a = a | 2;
+print a;
+a |= 5;
+print a;

+ 2 - 0
tests/bits/or.out

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

+ 9 - 0
tests/bits/shift

@@ -0,0 +1,9 @@
+a = 1;
+a = a << 2;
+a <<= 3;
+print a;
+
+a = 100;
+a = a >> 2;
+a >>= 3;
+print a;

+ 2 - 0
tests/bits/shift.out

@@ -0,0 +1,2 @@
+32
+3

+ 5 - 0
tests/bits/xor

@@ -0,0 +1,5 @@
+a = 0;
+a = a ^ 2;
+print a;
+a ^= 7;
+print a;

+ 2 - 0
tests/bits/xor.out

@@ -0,0 +1,2 @@
+2
+5