|
@@ -1,36 +1,78 @@
|
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
|
|
|
+#include <string.h>
|
|
|
|
|
|
|
|
#include "Code.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
|
|
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(a);
|
|
|
POP_VALUE(b);
|
|
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) {
|
|
static bool iPushConstantString(Code* c) {
|
|
|
- return pushValue(CSTRING_VALUE(codeReadConstantString(c)));
|
|
|
|
|
|
|
+ return iPushValue(c, CSTRING_VALUE(codeReadConstantString(c)));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static bool iPushInt(Code* c) {
|
|
static bool iPushInt(Code* c) {
|
|
|
i64 i = 0;
|
|
i64 i = 0;
|
|
|
if(codeReadI64(c, &i)) {
|
|
if(codeReadI64(c, &i)) {
|
|
|
|
|
+ SET_ERROR("PushInt without value");
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
- return pushValue(INT_VALUE(i));
|
|
|
|
|
|
|
+ return iPushValue(c, INT_VALUE(i));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static bool iPrint() {
|
|
|
|
|
|
|
+static bool iPrint(Code* c) {
|
|
|
POP_VALUE(a);
|
|
POP_VALUE(a);
|
|
|
switch(a.type) {
|
|
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;
|
|
return false;
|
|
|
}
|
|
}
|
|
@@ -44,6 +86,7 @@ static bool iJumpIf(Code* c) {
|
|
|
POP_VALUE(a);
|
|
POP_VALUE(a);
|
|
|
size_t jumpPos = 0;
|
|
size_t jumpPos = 0;
|
|
|
if(codeReadSize(c, &jumpPos)) {
|
|
if(codeReadSize(c, &jumpPos)) {
|
|
|
|
|
+ SET_ERROR("JumpIf without position");
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
if(a.intValue == 0) {
|
|
if(a.intValue == 0) {
|
|
@@ -52,14 +95,59 @@ static bool iJumpIf(Code* c) {
|
|
|
return false;
|
|
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) {
|
|
static bool execute(Code* c, Instruction command) {
|
|
|
switch(command) {
|
|
switch(command) {
|
|
|
- case ADD: return iAdd();
|
|
|
|
|
|
|
+ case ADD: return iAdd(c);
|
|
|
case PUSH_CONSTANT_STRING: return iPushConstantString(c);
|
|
case PUSH_CONSTANT_STRING: return iPushConstantString(c);
|
|
|
case PUSH_INT64: return iPushInt(c);
|
|
case PUSH_INT64: return iPushInt(c);
|
|
|
- case PRINT: return iPrint();
|
|
|
|
|
|
|
+ case PRINT: return iPrint(c);
|
|
|
case PRINT_NEWLINE: return iPrintNewline();
|
|
case PRINT_NEWLINE: return iPrintNewline();
|
|
|
case JUMP_ON_0: return iJumpIf(c);
|
|
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;
|
|
case STOP: return true;
|
|
|
}
|
|
}
|
|
|
return false;
|
|
return false;
|
|
@@ -68,3 +156,11 @@ static bool execute(Code* c, Instruction command) {
|
|
|
void codeRun(Code* c) {
|
|
void codeRun(Code* c) {
|
|
|
while(!execute(c, codeReadInstruction(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;
|
|
|
|
|
+}
|