diff --git a/README.md b/README.md index a9b099b..8abd17d 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ Progress marker: - [x] Values - [x] References - [ ] Interpreter - - [ ] Labels + - [x] Labels - [ ] Console I/O - - [ ] Control flow + - [x] Control flow - [ ] Data - [ ] Variable creation - [ ] Variable access diff --git a/src/interpreter.c b/src/interpreter.c index 852a46f..46fcd1f 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -6,6 +6,8 @@ int currentInstruction = 0; +GroundLabel* labels = NULL; + void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine) { printf("Ground runtime error:\n ErrorType: "); switch (error) { @@ -41,11 +43,37 @@ 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); + 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) { - // labelHashmap.addLabel() + addLabel(&labels, in->instructions[i].args.args[0].value.refName, i); } } while (currentInstruction < in->size) { @@ -61,6 +89,54 @@ void interpretGroundInstruction(GroundInstruction* in) { 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); @@ -82,13 +158,6 @@ void interpretGroundInstruction(GroundInstruction* in) { printf("\n"); break; } - case END: { - if (in->args.length < 1) { - exit(0); - } else { - } - break; - } default: { runtimeError(FIXME, "Currently unimplemented instruction", in, currentInstruction); } diff --git a/src/interpreter.h b/src/interpreter.h index 81cecfe..9d4522b 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -1,16 +1,19 @@ #ifndef INTERPRETER_H #define INTERPRETER_H +#define MAX_ID_LEN 64 #include "types.h" #include "parser.h" #include "include/uthash.h" typedef enum GroundRuntimeError { - ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, FIXME + ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, FIXME } GroundRuntimeError; typedef struct GroundLabel { - + char id[MAX_ID_LEN]; + int lineNum; + UT_hash_handle hh; } GroundLabel; void interpretGroundProgram(GroundProgram* in); diff --git a/tests/simple.grnd b/tests/simple.grnd index ea96f55..002ef14 100644 --- a/tests/simple.grnd +++ b/tests/simple.grnd @@ -1 +1,3 @@ -print +@myLabel +println "dingus" +jump %myLabel