Kajetan Johannes Hammerle před 1 týdnem
rodič
revize
45f6ca8082
12 změnil soubory, kde provedl 228 přidání a 80 odebrání
  1. 0 1
      CMakeLists.txt
  2. 20 0
      src/Code.h
  3. 109 13
      src/CodeRunner.c
  4. 64 0
      src/Compiler.c
  5. 1 0
      src/Constants.h
  6. 3 15
      src/Main.c
  7. 4 0
      src/Tokenizer.c
  8. 1 0
      src/Tokenizer.h
  9. 0 22
      src/Values.c
  10. 0 29
      src/Values.h
  11. 17 0
      test/Var.basic
  12. 9 0
      test/Var.basic_result

+ 0 - 1
CMakeLists.txt

@@ -7,7 +7,6 @@ set(SRC
     "src/Main.c"
     "src/Code.c"
     "src/CodeRunner.c"
-    "src/Values.c"
     "src/Error.c"
     "src/Compiler.c"
     "src/Tokenizer.c"

+ 20 - 0
src/Code.h

@@ -5,6 +5,20 @@
 #include "Error.h"
 #include "Types.h"
 
+typedef enum : u8 { VT_INT64, VT_CONSTANT_STRING } ValueType;
+
+typedef struct {
+    ValueType type;
+    u8 reserved1;
+    u8 reserved2;
+    u8 reserved3;
+
+    union {
+        i64 intValue;
+        const char* constantStringValue;
+    };
+} Value;
+
 typedef enum : u8 {
     ADD,
     PUSH_CONSTANT_STRING,
@@ -12,12 +26,18 @@ typedef enum : u8 {
     PRINT,
     PRINT_NEWLINE,
     JUMP_ON_0,
+    READ_VARIABLE,
+    SET_VARIABLE,
+    PUSH_STACK_VARIABLES,
     STOP
 } Instruction;
 
 typedef struct {
     Buffer code;
     Error error;
+    Value* stack;
+    size_t maxStackSize;
+    size_t stackIndex;
 } Code;
 
 void codeInit(Code* code);

+ 109 - 13
src/CodeRunner.c

@@ -1,36 +1,78 @@
 #include <stdio.h>
+#include <string.h>
 
 #include "Code.h"
-#include "Values.h"
+#include "Constants.h"
+#include "Memory.h"
 
-#define POP_VALUE(name) \
-    Value name;         \
-    if(popValue(&name)) \
+#define POP_VALUE(name)     \
+    Value name;             \
+    if(iPopValue(c, &name)) \
     return true
 
-static bool iAdd() {
+#define INT_VALUE(value) ((Value){.type = VT_INT64, .intValue = (value)})
+#define CSTRING_VALUE(value)                                              \
+    ((Value){.type = VT_CONSTANT_STRING, .constantStringValue = (value)})
+
+#define SET_ERROR(format, ...)                \
+    snprintf(                                 \
+        c->error.text, sizeof(c->error.text), \
+        format __VA_OPT__(, ) __VA_ARGS__)
+
+static bool iPushValue(Code* c, Value v) {
+    while(c->stackIndex >= c->maxStackSize) {
+        size_t newSize = c->maxStackSize <= 0 ? 16 : (c->maxStackSize * 5) / 4;
+        if(newSize >= MAX_STACK_VALUES) {
+            SET_ERROR("Stack overflow");
+            return true;
+        }
+        Value* newValues = memoryAllocate(sizeof(Value) * newSize);
+        if(newValues == nullptr) {
+            SET_ERROR("Out of memory for stack");
+            return true;
+        }
+        memcpy(newValues, c->stack, sizeof(Value) * c->stackIndex);
+        memoryFree(c->stack);
+        c->stack = newValues;
+        c->maxStackSize = newSize;
+    }
+    c->stack[c->stackIndex++] = v;
+    return false;
+}
+
+static bool iPopValue(Code* c, Value* v) {
+    if(c->stackIndex <= 0) {
+        SET_ERROR("Pop on empty stack");
+        return true;
+    }
+    *v = c->stack[--c->stackIndex];
+    return false;
+}
+
+static bool iAdd(Code* c) {
     POP_VALUE(a);
     POP_VALUE(b);
-    return pushValue(INT_VALUE(a.intValue + b.intValue));
+    return iPushValue(c, INT_VALUE(a.intValue + b.intValue));
 }
 
 static bool iPushConstantString(Code* c) {
-    return pushValue(CSTRING_VALUE(codeReadConstantString(c)));
+    return iPushValue(c, CSTRING_VALUE(codeReadConstantString(c)));
 }
 
 static bool iPushInt(Code* c) {
     i64 i = 0;
     if(codeReadI64(c, &i)) {
+        SET_ERROR("PushInt without value");
         return true;
     }
-    return pushValue(INT_VALUE(i));
+    return iPushValue(c, INT_VALUE(i));
 }
 
-static bool iPrint() {
+static bool iPrint(Code* c) {
     POP_VALUE(a);
     switch(a.type) {
-        case INT64: printf("%ld", a.intValue); break;
-        case CONSTANT_STRING: printf("%s", a.constantStringValue); break;
+        case VT_INT64: printf("%ld", a.intValue); break;
+        case VT_CONSTANT_STRING: printf("%s", a.constantStringValue); break;
     }
     return false;
 }
@@ -44,6 +86,7 @@ static bool iJumpIf(Code* c) {
     POP_VALUE(a);
     size_t jumpPos = 0;
     if(codeReadSize(c, &jumpPos)) {
+        SET_ERROR("JumpIf without position");
         return true;
     }
     if(a.intValue == 0) {
@@ -52,14 +95,59 @@ static bool iJumpIf(Code* c) {
     return false;
 }
 
+static bool iReadVariable(Code* c) {
+    i64 address = 0;
+    if(codeReadI64(c, &address)) {
+        SET_ERROR("ReadVariable without address");
+        return true;
+    } else if((size_t)address >= c->stackIndex) {
+        SET_ERROR("ReadVariable with invalid address");
+        return true;
+    }
+    return iPushValue(c, c->stack[address]);
+}
+
+static bool iSetVariable(Code* c) {
+    i64 address = 0;
+    if(codeReadI64(c, &address)) {
+        SET_ERROR("SetVariable without address");
+        return true;
+    } else if((size_t)address >= c->stackIndex) {
+        SET_ERROR("SetVariable with invalid address");
+        return true;
+    }
+    POP_VALUE(a);
+    c->stack[address] = a;
+    return false;
+}
+
+static bool iPushStackVariables(Code* c) {
+    i64 amount = 0;
+    if(codeReadI64(c, &amount)) {
+        SET_ERROR("PushStackVariables without amount");
+        return true;
+    }
+    Value v = INT_VALUE(0);
+    while(amount > 0) {
+        if(iPushValue(c, v)) {
+            return true;
+        }
+        amount--;
+    }
+    return false;
+}
+
 static bool execute(Code* c, Instruction command) {
     switch(command) {
-        case ADD: return iAdd();
+        case ADD: return iAdd(c);
         case PUSH_CONSTANT_STRING: return iPushConstantString(c);
         case PUSH_INT64: return iPushInt(c);
-        case PRINT: return iPrint();
+        case PRINT: return iPrint(c);
         case PRINT_NEWLINE: return iPrintNewline();
         case JUMP_ON_0: return iJumpIf(c);
+        case READ_VARIABLE: return iReadVariable(c);
+        case SET_VARIABLE: return iSetVariable(c);
+        case PUSH_STACK_VARIABLES: return iPushStackVariables(c);
         case STOP: return true;
     }
     return false;
@@ -68,3 +156,11 @@ static bool execute(Code* c, Instruction command) {
 void codeRun(Code* c) {
     while(!execute(c, codeReadInstruction(c))) {}
 }
+
+bool codeHasRunError(const Code* code) {
+    return hasError(&code->error);
+}
+
+const char* codeGetRunError(const Code* code) {
+    return code->error.text;
+}

+ 64 - 0
src/Compiler.c

@@ -6,6 +6,15 @@
 #include <string.h>
 
 #include "Code.h"
+#include "Memory.h"
+
+typedef struct Variable Variable;
+
+struct Variable {
+    Variable* next;
+    i32 index;
+    char name[];
+};
 
 typedef struct {
     Tokenizer* tokenizer;
@@ -13,6 +22,7 @@ typedef struct {
     Error error;
     int line;
     jmp_buf jump;
+    Variable* variables;
 } Context;
 
 #define THROW_ERROR(format, ...)                                   \
@@ -28,6 +38,34 @@ typedef struct {
         }                                            \
     } while(false)
 
+static i32 addVariable(Context* c, const char* name) {
+    for(Variable* v = c->variables; v != nullptr; v = v->next) {
+        if(strcmp(v->name, name) == 0) {
+            return v->index;
+        }
+    }
+    size_t l = strlen(name) + 1;
+    Variable* v = memoryAllocate(sizeof(Variable) + l);
+    if(v == nullptr) {
+        THROW_ERROR("Too less memory for variables");
+    }
+    v->next = c->variables;
+    v->index = c->variables != nullptr ? c->variables->index + 1 : 0;
+    memcpy(v->name, name, l);
+    c->variables = v;
+    return v->index;
+}
+
+static void cleanContext(Context* c) {
+    Variable* v = c->variables;
+    while(v != nullptr) {
+        Variable* next = v->next;
+        memoryFree(v);
+        v = next;
+    }
+    c->variables = nullptr;
+}
+
 [[noreturn]] static void unexpectedToken(Context* c, Token token) {
     char buffer[128];
     tokenizerPrintToken(&token, buffer, sizeof(buffer));
@@ -56,6 +94,10 @@ static void compileConstant(Context* c) {
     } else if(token.type == INT64) {
         CODE(codePushInstruction(c->code, PUSH_INT64));
         CODE(codePushI64(c->code, token.intValue));
+    } else if(token.type == LITERAL) {
+        i32 index = addVariable(c, token.stringValue);
+        CODE(codePushInstruction(c->code, READ_VARIABLE));
+        CODE(codePushI64(c->code, index));
     } else {
         unexpectedToken(c, token);
     }
@@ -97,6 +139,14 @@ static void compileIf(Context* c) {
     codeSetWritePosition(c->code, endIndex);
 }
 
+static void compileSetVariable(Context* c, const char* name) {
+    consumeToken(c, EQUAL);
+    compileExpression(c);
+    i32 index = addVariable(c, name);
+    CODE(codePushInstruction(c->code, SET_VARIABLE));
+    CODE(codePushI64(c->code, index));
+}
+
 static void compileLine(Context* c, Token token) {
     if(token.type == NEWLINE) {
         c->line++;
@@ -115,6 +165,8 @@ static void compileLine(Context* c, Token token) {
         }
         consumeNewline(c);
         CODE(codePushInstruction(c->code, PRINT_NEWLINE));
+    } else if(tokenizerPeek(c->tokenizer).type == EQUAL) {
+        compileSetVariable(c, s);
     } else {
         THROW_ERROR("Unexpected literal(%s)", s);
     }
@@ -122,6 +174,10 @@ static void compileLine(Context* c, Token token) {
 
 static void parseTokens(Context* c) {
     codeReset(c->code);
+    CODE(codePushInstruction(c->code, PUSH_STACK_VARIABLES));
+    size_t stackVarsLoc = codeGetWritePosition(c->code);
+    CODE(codePushI64(c->code, 0));
+
     while(true) {
         Token token = tokenizerNext(c->tokenizer);
         if(token.type == END) {
@@ -129,6 +185,13 @@ static void parseTokens(Context* c) {
         }
         compileLine(c, token);
     }
+
+    size_t oldPos = codeGetWritePosition(c->code);
+    codeSetWritePosition(c->code, stackVarsLoc);
+    if(c->variables != nullptr) {
+        CODE(codePushI64(c->code, c->variables->index + 1));
+    }
+    codeSetWritePosition(c->code, oldPos);
 }
 
 Error compileFile(Tokenizer* t, Code* code) {
@@ -136,5 +199,6 @@ Error compileFile(Tokenizer* t, Code* code) {
     if(!setjmp(c.jump)) {
         parseTokens(&c);
     }
+    cleanContext(&c);
     return c.error;
 }

+ 1 - 0
src/Constants.h

@@ -7,5 +7,6 @@
 [[maybe_unused]] constexpr size_t MAX_LINE_LENGTH = 128;
 [[maybe_unused]] constexpr size_t MAX_LITERAL_LENGTH = 64;
 [[maybe_unused]] constexpr size_t MAX_STRING_LENGTH = 64;
+[[maybe_unused]] constexpr size_t MAX_STACK_VALUES = 4096;
 
 #endif

+ 3 - 15
src/Main.c

@@ -6,20 +6,6 @@
 #include "Memory.h"
 #include "Tokenizer.h"
 
-static void compileAndRun(Tokenizer* t) {
-    Code code;
-    codeInit(&code);
-
-    Error e = compileFile(t, &code);
-    if(hasError(&e)) {
-        puts(e.text);
-    } else {
-        codeRun(&code);
-    }
-
-    codeDestroy(&code);
-}
-
 int main(int argCount, const char** args) {
     if(argCount < 2) {
         return 0;
@@ -63,10 +49,12 @@ int main(int argCount, const char** args) {
         puts(e.text);
     } else {
         codeRun(&code);
+        if(codeHasRunError(&code)) {
+            puts(codeGetRunError(&code));
+        }
     }
 
     codeDestroy(&code);
-    compileAndRun(&t);
 
     // while(true) {
     //     Token token = tokenizerNext(&t);

+ 4 - 0
src/Tokenizer.c

@@ -155,6 +155,9 @@ static void tParseLineString(TState* t, const char* s) {
         } else if(c == '+') {
             tAddToken(t, PLUS);
             s++;
+        } else if(c == '=') {
+            tAddToken(t, EQUAL);
+            s++;
         } else if(c == '\0') {
             break;
         } else {
@@ -247,6 +250,7 @@ void tokenizerPrintToken(const Token* token, char* buffer, size_t n) {
         TOKEN_PRINTER(INT64, "Int64(%ld)", token->intValue);
         TOKEN_PRINTER(STRING, "String(%s)", token->stringValue);
         TOKEN_PRINTER(PLUS, "Plus");
+        TOKEN_PRINTER(EQUAL, "Equal");
         TOKEN_PRINTER(IF, "If");
         TOKEN_PRINTER(THEN, "Then");
         TOKEN_PRINTER(ENDIF, "EndIf");

+ 1 - 0
src/Tokenizer.h

@@ -9,6 +9,7 @@ typedef enum : u8 {
     INT64,
     STRING,
     PLUS,
+    EQUAL,
     IF,
     THEN,
     ENDIF,

+ 0 - 22
src/Values.c

@@ -1,22 +0,0 @@
-#include "Values.h"
-
-#include "Constants.h"
-
-static Value valueStack[MAX_VALUES];
-static size_t valueStackIndex = 0;
-
-bool pushValue(Value v) {
-    if(valueStackIndex >= MAX_VALUES) {
-        return true;
-    }
-    valueStack[valueStackIndex++] = v;
-    return false;
-}
-
-bool popValue(Value* v) {
-    if(valueStackIndex <= 0) {
-        return true;
-    }
-    *v = valueStack[--valueStackIndex];
-    return false;
-}

+ 0 - 29
src/Values.h

@@ -1,29 +0,0 @@
-#ifndef BASIC_VALUES_H
-#define BASIC_VALUES_H
-
-#include "Types.h"
-
-typedef enum : u8 { INT64, CONSTANT_STRING } ValueType;
-
-typedef struct {
-    ValueType type;
-    u8 reserved1;
-    u8 reserved2;
-    u8 reserved3;
-
-    union {
-        i64 intValue;
-        const char* constantStringValue;
-    };
-} Value;
-
-static_assert(sizeof(Value) == 16, "invalid Value size");
-
-#define INT_VALUE(value) ((Value){.type = INT64, .intValue = (value)})
-#define CSTRING_VALUE(value)                                           \
-    ((Value){.type = CONSTANT_STRING, .constantStringValue = (value)})
-
-[[nodiscard]] bool pushValue(Value v);
-[[nodiscard]] bool popValue(Value* v);
-
-#endif

+ 17 - 0
test/Var.basic

@@ -0,0 +1,17 @@
+abc = 5
+wusi = 10
+baum = 12 + wusi
+
+print abc
+print wusi
+print baum
+print nothing
+
+wusi = 6
+
+print abc
+print wusi
+print baum
+print nothing
+
+print abc + wusi + baum

+ 9 - 0
test/Var.basic_result

@@ -0,0 +1,9 @@
+5
+10
+22
+0
+5
+6
+22
+0
+33