#include "interpreter.h" #include "parser.h" #include "types.h" #include "include/uthash.h" #include int currentInstruction = 0; GroundLabel* labels = NULL; void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine) { printf("Ground runtime error:\n ErrorType: "); switch (error) { case ARG_TYPE_MISMATCH: { printf("ArgTypeMismatch"); break; } case TOO_FEW_ARGS: { printf("TooFewArgs"); break; } case TOO_MANY_ARGS: { printf("TooManyArgs"); break; } default: case FIXME: { printf("FIXME (please report issue to https://chsp.au/ground/cground)"); } } printf("\n"); if (what != NULL) { printf(" ErrorContext: %s\n", what); } if (where != NULL) { printf(" ErrorInstruction: "); printGroundInstruction(where); printf("\n"); } if (whereLine > -1) { printf(" ErrorLine: %d\n", whereLine + 1); } exit(1); } void addLabel(GroundLabel **head, const char *id, int data) { GroundLabel* item = malloc(sizeof(GroundLabel)); snprintf(item->id, MAX_ID_LEN, "%s", id); item->lineNum = data; HASH_ADD_STR(*head, id, item); } GroundLabel* findLabel(GroundLabel* head, const char *id) { GroundLabel *item; HASH_FIND_STR(head, id, item); return item; } void deleteLabel(GroundLabel** head, GroundLabel *item) { HASH_DEL(*head, item); free(item); } void delete_all(GroundLabel **head) { GroundLabel *current, *tmp; HASH_ITER(hh, *head, current, tmp) { HASH_DEL(*head, current); free(current); } } void interpretGroundProgram(GroundProgram* in) { // Preprocess all labels for (int i = 0; i < in->size; i++) { if (in->instructions[i].type == CREATELABEL) { addLabel(&labels, in->instructions[i].args.args[0].value.refName, i); } } while (currentInstruction < in->size) { interpretGroundInstruction(&in->instructions[currentInstruction]); currentInstruction++; } } void interpretGroundInstruction(GroundInstruction* in) { switch (in->type) { // We can safely ignore any CREATELABEL instructions, these have been preprocessed case CREATELABEL: { break; } case IF: { if (in->args.length < 2) { runtimeError(TOO_FEW_ARGS, "Expecting 2 arguments", in, currentInstruction); } if (in->args.length > 2) { runtimeError(TOO_MANY_ARGS, "Expecting 2 arguments", in, currentInstruction); } if (in->args.args[0].type != VALUE && in->args.args[0].value.value.type != BOOL) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a bool for arg 0", in, currentInstruction); } if (in->args.args[0].type != LINEREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a LineRef for arg 1", in, currentInstruction); } if (in->args.args[0].value.value.data.boolVal) { GroundLabel* label = findLabel(labels, in->args.args[1].value.refName); if (label) { currentInstruction = label->lineNum; } else { runtimeError(UNKNOWN_LABEL, NULL, in, currentInstruction); } } } case JUMP: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 argument", in, currentInstruction); } if (in->args.length > 1) { runtimeError(TOO_MANY_ARGS, "Expecting 1 argument", in, currentInstruction); } if (in->args.args[0].type != LINEREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a LineRef for arg 1", in, currentInstruction); } GroundLabel* label = findLabel(labels, in->args.args[0].value.refName); if (label) { currentInstruction = label->lineNum; } else { runtimeError(UNKNOWN_LABEL, NULL, in, currentInstruction); } } case END: { if (in->args.length < 1) { exit(0); } else { } break; } case PRINT: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, NULL, in, currentInstruction); } for (int i = 0; i < in->args.length; i++) { printGroundArg(&in->args.args[i]); printf(" "); } break; } case PRINTLN: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, NULL, in, currentInstruction); } for (int i = 0; i < in->args.length; i++) { printGroundArg(&in->args.args[i]); printf(" "); } printf("\n"); break; } default: { runtimeError(FIXME, "Currently unimplemented instruction", in, currentInstruction); } } }