|
@@ -26,6 +26,7 @@ static ObjectPrinter printer = sPrinter;
|
|
|
|
|
|
static bool sRead(Script* sc, void* buffer, int length) {
|
|
|
if(sc->readIndex + length > sc->byteCodeLength) {
|
|
|
+ sError(sc, "cannot read expected %d bytes of data from bytecode on line %d", sc->line);
|
|
|
return true;
|
|
|
}
|
|
|
memcpy(buffer, sc->byteCode + sc->readIndex, length);
|
|
@@ -37,19 +38,21 @@ static Operation sReadOperation(Script* sc) {
|
|
|
unsigned char c;
|
|
|
if(sRead(sc, &c, 1)) {
|
|
|
return OP_NOTHING;
|
|
|
- } /*else if(sRead(sc, &sc->line, 2)) {
|
|
|
- sError(sc, "operation without line near line %d", sc->line);
|
|
|
- return OP_NOTHING;
|
|
|
- }*/
|
|
|
+ }
|
|
|
return c;
|
|
|
}
|
|
|
|
|
|
-static void sPush(Script* sc, Object* o) {
|
|
|
+static bool sReadInt(Script* sc, int* i) {
|
|
|
+ return !sRead(sc, i, sizeof(int));
|
|
|
+}
|
|
|
+
|
|
|
+static bool sPush(Script* sc, Object* o) {
|
|
|
if(sc->stackIndex >= SCRIPT_STACK_SIZE) {
|
|
|
sError(sc, "stack overflow on line %d", sc->line);
|
|
|
- return;
|
|
|
+ return false;
|
|
|
}
|
|
|
sc->stack[sc->stackIndex++] = *o;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
static bool sPop(Script* sc, Object* o) {
|
|
@@ -61,9 +64,9 @@ static bool sPop(Script* sc, Object* o) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static void sPushInt(Script* sc, int value) {
|
|
|
+static bool sPushInt(Script* sc, int value) {
|
|
|
Object o = {.type = OT_INT, .data.intValue = value};
|
|
|
- sPush(sc, &o);
|
|
|
+ return sPush(sc, &o);
|
|
|
}
|
|
|
|
|
|
static void sPushFloat(Script* sc, float value) {
|
|
@@ -83,51 +86,43 @@ static void sPushBool(Script* sc, bool value) {
|
|
|
|
|
|
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);
|
|
|
+ if(sReadInt(sc, &value)) {
|
|
|
+ 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;
|
|
|
+ if(sReadInt(sc, &value)) {
|
|
|
+ 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;
|
|
|
+ if(sReadInt(sc, &value)) {
|
|
|
+ sPop(sc, sc->stack + value);
|
|
|
}
|
|
|
- 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;
|
|
|
+ if(sReadInt(sc, &value)) {
|
|
|
+ sPush(sc, sc->stack + value);
|
|
|
}
|
|
|
- sPush(sc, sc->stack + value);
|
|
|
}
|
|
|
|
|
|
static void sPushCodeInt(Script* sc) {
|
|
|
int value = 0;
|
|
|
- if(sRead(sc, &value, sizeof(int))) {
|
|
|
- sError(sc, "cannot read an int from the bytecode on line %d", sc->line);
|
|
|
- return;
|
|
|
+ if(sReadInt(sc, &value)) {
|
|
|
+ sPushInt(sc, value);
|
|
|
}
|
|
|
- sPushInt(sc, value);
|
|
|
}
|
|
|
|
|
|
static void sPushCodeFloat(Script* sc) {
|
|
@@ -184,10 +179,7 @@ static float sFloatMul(float a, float b) {
|
|
|
|
|
|
static void sPrint(Script* sc) {
|
|
|
Object o;
|
|
|
- if(sPop(sc, &o)) {
|
|
|
- return;
|
|
|
- }
|
|
|
- if(printer(&o)) {
|
|
|
+ if(!sPop(sc, &o) && printer(&o)) {
|
|
|
sError(sc, "cannot print given object on line %d", sc->line);
|
|
|
}
|
|
|
}
|
|
@@ -198,6 +190,31 @@ static void sLine(Script* sc) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void sGoTo(Script* sc) {
|
|
|
+ int gotoIndex;
|
|
|
+ if(sReadInt(sc, &gotoIndex)) {
|
|
|
+ sc->readIndex = gotoIndex;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void sGoSub(Script* sc) {
|
|
|
+ int gotoIndex;
|
|
|
+ if(sReadInt(sc, &gotoIndex) && sPushInt(sc, sc->readIndex)) {
|
|
|
+ sc->readIndex = gotoIndex;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void sReturn(Script* sc) {
|
|
|
+ Object o;
|
|
|
+ if(sPop(sc, &o)) {
|
|
|
+ return;
|
|
|
+ } else if(o.type != OT_INT) {
|
|
|
+ sError(sc, "return address on stack is not an int");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ sc->readIndex = o.data.intValue;
|
|
|
+}
|
|
|
+
|
|
|
static void sConsumeInstruction(Script* sc) {
|
|
|
switch(sReadOperation(sc)) {
|
|
|
case OP_NOTHING: break;
|
|
@@ -214,6 +231,9 @@ static void sConsumeInstruction(Script* sc) {
|
|
|
case OP_MUL: sIntBinary(sc, sIntMul, sFloatMul); break;
|
|
|
case OP_PRINT: sPrint(sc); break;
|
|
|
case OP_LINE: sLine(sc); break;
|
|
|
+ case OP_GOTO: sGoTo(sc); break;
|
|
|
+ case OP_GOSUB: sGoSub(sc); break;
|
|
|
+ case OP_RETURN: sReturn(sc); break;
|
|
|
}
|
|
|
}
|
|
|
|