|
@@ -1,3 +1,4 @@
|
|
|
+#include <stdarg.h>
|
|
|
#include <stdbool.h>
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
@@ -6,11 +7,12 @@
|
|
|
#include "Operation.h"
|
|
|
#include "Script.h"
|
|
|
|
|
|
-static const char* MISSING_INT_CONSTANT = "cannot read an int from the bytecode";
|
|
|
-static const char* NOT_AN_INT = "object is not an int";
|
|
|
-static const char* NOT_PRINTABLE = "cannot print given object";
|
|
|
-static const char* STACK_OVERFLOW = "stack overflow";
|
|
|
-static const char* STACK_UNDERFLOW = "stack underflow";
|
|
|
+static void sError(Script* sc, const char* format, ...) {
|
|
|
+ va_list args;
|
|
|
+ va_start(args, format);
|
|
|
+ vsnprintf(sc->error, SCRIPT_ERROR_SIZE, format, args);
|
|
|
+ va_end(args);
|
|
|
+}
|
|
|
|
|
|
static bool sPrinter(Object* o) {
|
|
|
if(o->type == OT_INT) {
|
|
@@ -35,13 +37,16 @@ static Operation sReadOperation(Script* sc) {
|
|
|
unsigned char c;
|
|
|
if(sRead(sc, &c, 1)) {
|
|
|
return OP_NOTHING;
|
|
|
+ } else if(sRead(sc, &sc->line, sizeof(int))) {
|
|
|
+ // operation without line
|
|
|
+ return OP_NOTHING;
|
|
|
}
|
|
|
return c;
|
|
|
}
|
|
|
|
|
|
static void sPush(Script* sc, Object* o) {
|
|
|
if(sc->stackIndex >= SCRIPT_STACK_SIZE) {
|
|
|
- sc->error = STACK_OVERFLOW;
|
|
|
+ sError(sc, "stack overflow on line %d", sc->line);
|
|
|
return;
|
|
|
}
|
|
|
sc->stack[sc->stackIndex++] = *o;
|
|
@@ -49,7 +54,7 @@ static void sPush(Script* sc, Object* o) {
|
|
|
|
|
|
static bool sPop(Script* sc, Object* o) {
|
|
|
if(sc->stackIndex <= 0) {
|
|
|
- sc->error = STACK_UNDERFLOW;
|
|
|
+ sError(sc, "stack underflow on line %d", sc->line);
|
|
|
return true;
|
|
|
}
|
|
|
*o = sc->stack[--sc->stackIndex];
|
|
@@ -59,7 +64,7 @@ static bool sPop(Script* sc, Object* o) {
|
|
|
static void sPushInt(Script* sc) {
|
|
|
int value = 0;
|
|
|
if(sRead(sc, &value, sizeof(int))) {
|
|
|
- sc->error = MISSING_INT_CONSTANT;
|
|
|
+ sError(sc, "cannot read an int from the bytecode on line %d", sc->line);
|
|
|
return;
|
|
|
}
|
|
|
Object o = {.type = OT_INT, .data.intValue = value};
|
|
@@ -81,7 +86,7 @@ static void sIntBinary(Script* sc, int (*f)(int, int)) {
|
|
|
return;
|
|
|
}
|
|
|
if(a.type != OT_INT || b.type != OT_INT) {
|
|
|
- sc->error = NOT_AN_INT;
|
|
|
+ sError(sc, "object is not an int on line %d", sc->line);
|
|
|
return;
|
|
|
}
|
|
|
Object o = {.type = OT_INT, .data.intValue = f(a.data.intValue, b.data.intValue)};
|
|
@@ -102,7 +107,7 @@ static void sPrint(Script* sc) {
|
|
|
return;
|
|
|
}
|
|
|
if(printer(&o)) {
|
|
|
- sc->error = NOT_PRINTABLE;
|
|
|
+ sError(sc, "cannot print given object on line %d", sc->line);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -123,11 +128,12 @@ static bool sHasData(Script* sc) {
|
|
|
|
|
|
Script* sInit(unsigned char* byteCode, int codeLength) {
|
|
|
Script* sc = malloc(sizeof(Script));
|
|
|
- sc->error = NULL;
|
|
|
+ sc->error[0] = '\0';
|
|
|
sc->byteCode = byteCode;
|
|
|
sc->byteCodeLength = codeLength;
|
|
|
sc->readIndex = 0;
|
|
|
sc->stackIndex = 0;
|
|
|
+ sc->line = 0;
|
|
|
return sc;
|
|
|
}
|
|
|
|
|
@@ -138,7 +144,7 @@ void sDelete(Script* sc) {
|
|
|
void sRun(Script* sc) {
|
|
|
while(sHasData(sc)) {
|
|
|
sConsumeInstruction(sc);
|
|
|
- if(sc->error != NULL) {
|
|
|
+ if(sc->error[0] != '\0') {
|
|
|
puts(sc->error);
|
|
|
return;
|
|
|
}
|