#include #include #include #include #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 bool sRead(Script* sc, void* buffer, int length) { if(sc->readIndex + length > sc->byteCodeLength) { return true; } memcpy(buffer, sc->byteCode + sc->readIndex, length); sc->readIndex += length; return false; } static Operation sReadOperation(Script* sc) { unsigned char c; if(sRead(sc, &c, 1)) { return OP_NOTHING; } return c; } static void sPush(Script* sc, Object* o) { if(sc->stackIndex >= SCRIPT_STACK_SIZE) { sc->error = STACK_OVERFLOW; return; } sc->stack[sc->stackIndex++] = *o; } static bool sPop(Script* sc, Object* o) { if(sc->stackIndex <= 0) { sc->error = STACK_UNDERFLOW; return true; } *o = sc->stack[--sc->stackIndex]; return false; } static void sPushInt(Script* sc) { int value = 0; if(sRead(sc, &value, sizeof(int))) { sc->error = MISSING_INT_CONSTANT; return; } Object o = {.type = OT_INT, .data.intValue = value}; sPush(sc, &o); } void sAdd(Script* sc) { Object a; if(sPop(sc, &a)) { return; } Object b; if(sPop(sc, &b)) { return; } if(a.type != OT_INT || b.type != OT_INT) { sc->error = NOT_AN_INT; return; } Object o = {.type = OT_INT, .data.intValue = a.data.intValue + b.data.intValue}; sPush(sc, &o); } void sPrint(Script* sc) { Object o; if(sPop(sc, &o)) { return; } if(o.type == OT_INT) { printf("%d\n", o.data.intValue); } else { sc->error = NOT_PRINTABLE; } } static void sConsumeInstruction(Script* sc) { switch(sReadOperation(sc)) { case OP_NOTHING: break; case OP_PUSH_INT: sPushInt(sc); break; case OP_ADD: sAdd(sc); break; case OP_PRINT: sPrint(sc); break; } } static bool sHasData(Script* sc) { return sc->readIndex < sc->byteCodeLength; } Script* sInit(unsigned char* byteCode, int codeLength) { Script* sc = malloc(sizeof(Script)); sc->error = NULL; sc->byteCode = byteCode; sc->byteCodeLength = codeLength; sc->readIndex = 0; sc->stackIndex = 0; return sc; } void sDelete(Script* sc) { free(sc->byteCode); } void sRun(Script* sc) { while(sHasData(sc)) { sConsumeInstruction(sc); if(sc->error != NULL) { puts(sc->error); return; } } }