Browse Source

variables

Kajetan Johannes Hammerle 4 years ago
parent
commit
163d563286
7 changed files with 180 additions and 7 deletions
  1. 85 5
      Compiler.c
  2. 4 0
      Operation.h
  3. 44 0
      Script.c
  4. 25 1
      Tokenizer.c
  5. 7 1
      Tokenizer.h
  6. 10 0
      tests/vars/set
  7. 5 0
      tests/vars/set.out

+ 85 - 5
Compiler.c

@@ -9,6 +9,7 @@
 
 #define MAX_BYTES (1024 * 1024)
 #define ERROR_LENGTH 256
+#define VARS 256
 
 static char error[ERROR_LENGTH] = {'\0'};
 
@@ -16,6 +17,9 @@ static unsigned char byteCode[MAX_BYTES];
 static int writeIndex = 0;
 static int16 line = 1;
 
+static const char* vars[VARS];
+static int varIndex = 0;
+
 static void cError(const char* format, ...) {
     va_list args;
     va_start(args, format);
@@ -23,17 +27,45 @@ static void cError(const char* format, ...) {
     va_end(args);
 }
 
+static int cAddVar(const char* var) {
+    for(int i = 0; i < varIndex; i++) {
+        if(strcmp(var, vars[i]) == 0) {
+            return i;
+        }
+    }
+    if(varIndex >= VARS) {
+        cError("variable buffer is too small");
+        return -1;
+    }
+    int index = varIndex;
+    vars[varIndex++] = var;
+    return index;
+}
+
 static void cUnexpectedToken(Token t) {
     cError("unexpected token on line %d: %s", line, tGetTokenName(t));
 }
 
-static bool cAddBytes(const void* data, int length) {
+static void* cReserveBytes(int length) {
     if(writeIndex + length > MAX_BYTES) {
         cError("the compiler buffer is too small");
-        return false;
+        return NULL;
     }
-    memcpy(byteCode + writeIndex, data, length);
+    unsigned char* p = byteCode + writeIndex;
     writeIndex += length;
+    return p;
+}
+
+static void cSetBytes(const void* data, void* dest, int length) {
+    memcpy(dest, data, length);
+}
+
+static bool cAddBytes(const void* data, int length) {
+    void* p = cReserveBytes(length);
+    if(p == NULL) {
+        return false;
+    }
+    cSetBytes(data, p, length);
     return true;
 }
 
@@ -84,6 +116,17 @@ static bool cPrimary() {
         return cAddOperation(OP_PUSH_FALSE);
     } else if(cConsumeTokenIf(T_OPEN_BRACKET)) {
         return cExpression() && cConsumeToken(T_CLOSE_BRACKET);
+    } else if(cConsumeTokenIf(T_LITERAL)) {
+        const char* literal = tReadString();
+        if(literal == NULL) {
+            cError("literal without string on line %d", line);
+            return false;
+        }
+        int varPointer = cAddVar(literal);
+        if(varPointer == -1) {
+            return false;
+        }
+        return cAddOperation(OP_GET) && cAddBytes(&varPointer, sizeof(int));
     }
     cUnexpectedToken(tPeekToken());
     return false;
@@ -117,6 +160,24 @@ static bool cExpression() {
     return cAdd();
 }
 
+static bool cLiteral() {
+    const char* literal = tReadString();
+    if(literal == NULL) {
+        cError("literal without string on line %d", line);
+        return false;
+    }
+    Token t = tReadTokenAndLine();
+    if(t != T_SET) {
+        cUnexpectedToken(t);
+        return false;
+    }
+    int varPointer = cAddVar(literal);
+    if(varPointer == -1) {
+        return false;
+    }
+    return cExpression() && cAddOperation(OP_SET) && cAddBytes(&varPointer, sizeof(int)) && cConsumeToken(T_SEMICOLON);
+}
+
 static bool cPrint() {
     return cExpression() && cConsumeToken(T_SEMICOLON) && cAddOperation(OP_PRINT);
 }
@@ -130,16 +191,35 @@ static bool cLine() {
     }
     if(t == T_PRINT) {
         return cPrint();
+    } else if(t == T_LITERAL) {
+        return cLiteral();
     }
     cUnexpectedToken(t);
     return false;
 }
 
-unsigned char* cCompile(int* codeLength) {
+static void cForEachLine() {
     writeIndex = 0;
-    error[0] = '\0';
+    varIndex = 0;
+    if(!cAddOperation(OP_PUSH)) {
+        return;
+    }
+    void* globalVars = cReserveBytes(sizeof(int));
+    if(globalVars == NULL) {
+        return;
+    }
     while(cLine()) {
     }
+    if(!cAddOperation(OP_POP)) {
+        return;
+    }
+    cSetBytes(&varIndex, globalVars, sizeof(int));
+    cAddBytes(&varIndex, sizeof(int));
+}
+
+unsigned char* cCompile(int* codeLength) {
+    error[0] = '\0';
+    cForEachLine();
     if(error[0] != '\0') {
         return NULL;
     }

+ 4 - 0
Operation.h

@@ -8,6 +8,10 @@ typedef enum Operation {
     OP_PUSH_NULL,
     OP_PUSH_TRUE,
     OP_PUSH_FALSE,
+    OP_PUSH,
+    OP_POP,
+    OP_SET,
+    OP_GET,
     OP_ADD,
     OP_MUL,
     OP_PRINT,

+ 44 - 0
Script.c

@@ -81,6 +81,46 @@ static void sPushBool(Script* sc, bool value) {
     sPush(sc, &o);
 }
 
+static void sPushVars(Script* sc) {
+    int value = 0;
+    if(sRead(sc, &value, sizeof(int))) {
+        sError(sc, "cannot read stack frame size from the bytecode on line %d", sc->line);
+        return;
+    }
+    for(int i = 0; i < value; i++) {
+        sPushNull(sc);
+    }
+}
+
+static void sPopVars(Script* sc) {
+    int value = 0;
+    if(sRead(sc, &value, sizeof(int))) {
+        sError(sc, "cannot read stack frame size from the bytecode on line %d", sc->line);
+    } else if(sc->stackIndex < value) {
+        sError(sc, "stack underflow on line %d", sc->line);
+    } else {
+        sc->stackIndex -= value;
+    }
+}
+
+static void sSet(Script* sc) {
+    int value = 0;
+    if(sRead(sc, &value, sizeof(int))) {
+        sError(sc, "cannot read address of variable on line %d", sc->line);
+        return;
+    }
+    sPop(sc, sc->stack + value);
+}
+
+static void sGet(Script* sc) {
+    int value = 0;
+    if(sRead(sc, &value, sizeof(int))) {
+        sError(sc, "cannot read address of variable on line %d", sc->line);
+        return;
+    }
+    sPush(sc, sc->stack + value);
+}
+
 static void sPushCodeInt(Script* sc) {
     int value = 0;
     if(sRead(sc, &value, sizeof(int))) {
@@ -166,6 +206,10 @@ static void sConsumeInstruction(Script* sc) {
         case OP_PUSH_NULL: sPushNull(sc); break;
         case OP_PUSH_TRUE: sPushBool(sc, true); break;
         case OP_PUSH_FALSE: sPushBool(sc, false); break;
+        case OP_PUSH: sPushVars(sc); break;
+        case OP_POP: sPopVars(sc); break;
+        case OP_SET: sSet(sc); break;
+        case OP_GET: sGet(sc); break;
         case OP_ADD: sIntBinary(sc, sIntAdd, sFloatAdd); break;
         case OP_MUL: sIntBinary(sc, sIntMul, sFloatMul); break;
         case OP_PRINT: sPrint(sc); break;

+ 25 - 1
Tokenizer.c

@@ -26,6 +26,7 @@ static void tError(const char* format, ...) {
 
 static bool tAdd(const void* data, int length) {
     if(writeIndex + length > TOKEN_BUFFER_LENGTH) {
+        tError("the token buffer is too small");
         return false;
     }
     memcpy(tokenBuffer + writeIndex, data, length);
@@ -78,7 +79,7 @@ static bool tParseLiteral(int c) {
     } else if(strcmp(buffer, "false") == 0) {
         return tAddToken(T_FALSE);
     }
-    return true;
+    return tAddToken(T_LITERAL) && tAdd(buffer, index + 1);
 }
 
 static bool tParseNumber(int c) {
@@ -133,6 +134,7 @@ static bool tParseToken() {
         case '\n': line++; return true;
         case '+': return tAddToken(T_ADD);
         case '*': return tAddToken(T_MUL);
+        case '=': return tAddToken(T_SET);
         case ';': return tAddToken(T_SEMICOLON);
         case '(': return tAddToken(T_OPEN_BRACKET);
         case ')': return tAddToken(T_CLOSE_BRACKET);
@@ -204,6 +206,18 @@ bool tReadFloat(float* f) {
     return false;
 }
 
+const char* tReadString() {
+    const char* s = tokenBuffer + readIndex;
+    while(readIndex <= writeIndex) {
+        if(tokenBuffer[readIndex] == '\0') {
+            readIndex++;
+            return s;
+        }
+        readIndex++;
+    }
+    return NULL;
+}
+
 const char* tGetTokenName(Token token) {
     switch(token) {
         case T_INT: return "int";
@@ -213,6 +227,8 @@ const char* tGetTokenName(Token token) {
         case T_FALSE: return "false";
         case T_ADD: return "+";
         case T_MUL: return "*";
+        case T_SET: return "=";
+        case T_LITERAL: return "literal";
         case T_PRINT: return "print";
         case T_SEMICOLON: return ";";
         case T_OPEN_BRACKET: return "(";
@@ -222,6 +238,14 @@ const char* tGetTokenName(Token token) {
     return "Unknown";
 }
 
+int tGetMarker() {
+    return readIndex;
+}
+
+void tResetToMarker(int marker) {
+    readIndex = marker;
+}
+
 void tPrint() {
     puts("----------------");
     while(true) {

+ 7 - 1
Tokenizer.h

@@ -11,6 +11,8 @@ typedef enum Token {
     T_FALSE,
     T_ADD,
     T_MUL,
+    T_SET,
+    T_LITERAL,
     T_PRINT,
     T_SEMICOLON,
     T_OPEN_BRACKET,
@@ -28,7 +30,11 @@ Token tPeekToken();
 Token tReadToken();
 bool tReadInt(int* i);
 bool tReadInt16(int16* i);
-bool tReadFloat(float* i);
+bool tReadFloat(float* f);
+const char* tReadString();
+
+int tGetMarker();
+void tResetToMarker(int marker);
 
 const char* tGetTokenName(Token token);
 

+ 10 - 0
tests/vars/set

@@ -0,0 +1,10 @@
+a = 3;
+b = 4;
+c = 2 + 4;
+d = c + 0;
+c = 1 + 4;
+print a;
+print b + 10;
+print c;
+print d;
+print e;

+ 5 - 0
tests/vars/set.out

@@ -0,0 +1,5 @@
+3
+14
+5
+6
+null