diff --git a/CMakeLists.txt b/CMakeLists.txt index a7c57bb..45473f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,8 @@ include_directories(src) add_executable(groundc src/main.c + src/interpreter.c + src/interpreter.h src/parser.c src/parser.h src/lexer.c diff --git a/src/interpreter.c b/src/interpreter.c index 289544c..599fa16 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -50,13 +50,6 @@ void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where 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); @@ -68,10 +61,14 @@ void deleteLabel(GroundLabel** head, GroundLabel *item) { free(item); } -void addVariable(GroundVariable **head, const char *id, GroundValue data) { - GroundVariable* item = malloc(sizeof(GroundVariable)); +void addLabel(GroundLabel **head, const char *id, int data) { + GroundLabel* label = findLabel(*head, id); + if (label) { + deleteLabel(head, label); + } + GroundLabel* item = malloc(sizeof(GroundLabel)); snprintf(item->id, MAX_ID_LEN, "%s", id); - item->value = data; + item->lineNum = data; HASH_ADD_STR(*head, id, item); } @@ -86,6 +83,17 @@ void deleteVariable(GroundVariable** head, GroundVariable *item) { free(item); } +void addVariable(GroundVariable **head, const char *id, GroundValue data) { + GroundVariable* variable = findVariable(*head, id); + if (variable) { + deleteVariable(head, variable); + } + GroundVariable* item = malloc(sizeof(GroundVariable)); + snprintf(item->id, MAX_ID_LEN, "%s", id); + item->value = data; + HASH_ADD_STR(*head, id, item); +} + void interpretGroundProgram(GroundProgram* in) { GroundLabel* labels = NULL; GroundVariable* variables = NULL; @@ -100,18 +108,22 @@ void interpretGroundProgram(GroundProgram* in) { } } while (currentInstruction < in->size) { - interpretGroundInstruction(&in->instructions[currentInstruction], &scope); + interpretGroundInstruction(in->instructions[currentInstruction], &scope); currentInstruction++; } } -void interpretGroundInstruction(GroundInstruction* in, GroundScope* scope) { +void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { + GroundInstruction copied_inst = copyGroundInstruction(&inst); + GroundInstruction* in = &copied_inst; + // Insert variables prefixed with $ for (int i = 0; i < in->args.length; i++) { if (in->args.args[i].type == VALREF) { - GroundVariable* variable = findVariable(*scope->variables, in->args.args[0].value.refName); + GroundVariable* variable = findVariable(*scope->variables, in->args.args[i].value.refName); if (variable) { + free(in->args.args[i].value.refName); // Free the strdup'd refName in->args.args[i].value.value = variable->value; in->args.args[i].type = VALUE; } else { @@ -239,7 +251,7 @@ void interpretGroundInstruction(GroundInstruction* in, GroundScope* scope) { if (right->type != STRING) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a String for arg 2", in, currentInstruction); } - char* newString = malloc(sizeof(char)); + char* newString = malloc(strlen(left->data.stringVal) + strlen(right->data.stringVal)); strcpy(newString, left->data.stringVal); strcat(newString, right->data.stringVal); @@ -261,7 +273,7 @@ void interpretGroundInstruction(GroundInstruction* in, GroundScope* scope) { if (right->type == INT) { result += right->data.intVal; - } else if (left->type == DOUBLE) { + } else if (right->type == DOUBLE) { result += right->data.doubleVal; } @@ -275,9 +287,67 @@ void interpretGroundInstruction(GroundInstruction* in, GroundScope* scope) { } break; } + case EQUAL: { + if (in->args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); + } + if (in->args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); + } + if (in->args.args[0].type != VALUE) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 1", in, currentInstruction); + } + if (in->args.args[1].type != VALUE) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction); + } + if (in->args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); + } + + GroundValue* left = &in->args.args[0].value.value; + GroundValue* right = &in->args.args[1].value.value; + + if (left->type != right->type) { + addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(false)); + } else { + switch (left->type) { + case INT: { + bool cond = (left->data.intVal == right->data.intVal); + addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); + break; + } + case DOUBLE: { + bool cond = (left->data.doubleVal == right->data.doubleVal); + addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); + break; + } + case STRING: { + bool cond = (strcmp(left->data.stringVal, right->data.stringVal) == 0); + addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); + break; + } + case CHAR: { + bool cond = (left->data.charVal == right->data.charVal); + addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); + break; + } + case BOOL: { + bool cond = (left->data.boolVal == right->data.boolVal); + addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(cond)); + break; + } + default: { + addVariable(scope->variables, in->args.args[2].value.refName, createBoolGroundValue(false)); + break; + } + } + } + break; + } default: { runtimeError(FIXME, "Currently unimplemented instruction", in, currentInstruction); } } + freeGroundInstruction(in); } diff --git a/src/interpreter.h b/src/interpreter.h index 06c677f..24e242a 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -28,5 +28,7 @@ typedef struct GroundScope { } GroundScope; void interpretGroundProgram(GroundProgram* in); -void interpretGroundInstruction(GroundInstruction* in, GroundScope* scope); +void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope); + + #endif diff --git a/src/types.c b/src/types.c index 169e869..07d0987 100644 --- a/src/types.c +++ b/src/types.c @@ -142,8 +142,33 @@ void freeGroundInstruction(GroundInstruction* gi) { for (size_t i = 0; i < gi-> args.length; i++) { freeGroundArg(&gi->args.args[i]); } + free(gi->args.args); } +GroundInstruction copyGroundInstruction(const GroundInstruction* inst) { + GroundInstruction newInst; + newInst.type = inst->type; + newInst.args.length = inst->args.length; + if (inst->args.length > 0) { + newInst.args.args = malloc(inst->args.length * sizeof(GroundArg)); + for (size_t i = 0; i < inst->args.length; i++) { + newInst.args.args[i].type = inst->args.args[i].type; + if (inst->args.args[i].type == VALUE) { + newInst.args.args[i].value.value = inst->args.args[i].value.value; + if (inst->args.args[i].value.value.type == STRING) { + newInst.args.args[i].value.value.data.stringVal = strdup(inst->args.args[i].value.value.data.stringVal); + } + } else { + newInst.args.args[i].value.refName = strdup(inst->args.args[i].value.refName); + } + } + } else { + newInst.args.args = NULL; + } + return newInst; +} + + void addArgToInstruction(GroundInstruction* gi, GroundArg arg) { gi->args.length ++; GroundArg* newArgs = realloc(gi->args.args, gi->args.length * sizeof(GroundArg)); diff --git a/src/types.h b/src/types.h index c980fc2..6bfbad3 100644 --- a/src/types.h +++ b/src/types.h @@ -116,6 +116,9 @@ GroundInstruction createGroundInstruction(GroundInstType type); // Frees all data stored on the heap in a GroundInstruction. void freeGroundInstruction(GroundInstruction* gi); +// Creates a deep copy of a GroundInstruction. +GroundInstruction copyGroundInstruction(const GroundInstruction* gi); + // Adds arg (arg) to the GroundInstruction (gi). void addArgToInstruction(GroundInstruction* gi, GroundArg arg); diff --git a/tests/to1000.grnd b/tests/to1000.grnd new file mode 100644 index 0000000..96e4e95 --- /dev/null +++ b/tests/to1000.grnd @@ -0,0 +1,9 @@ +set &var 0 +println "dingle" +@jump +add 1 $var &var +println $var +equal $var 1000000 &cond +if $cond %end +jump %jump +@end