Debugger
This commit is contained in:
@@ -149,9 +149,63 @@ GroundValueType stringToValueType(char* in) {
|
|||||||
if (strcmp(in, "list") == 0) {
|
if (strcmp(in, "list") == 0) {
|
||||||
return LIST;
|
return LIST;
|
||||||
}
|
}
|
||||||
|
if (strcmp(in, "function") == 0) {
|
||||||
|
return FUNCTION;
|
||||||
|
}
|
||||||
return CUSTOM;
|
return CUSTOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundDebugInstruction parseDebugInstruction(char* in) {
|
||||||
|
GroundDebugInstruction gdi;
|
||||||
|
size_t insize = strlen(in);
|
||||||
|
size_t spacepos = -1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < insize; i++) {
|
||||||
|
if (in[i] == ' ') {
|
||||||
|
spacepos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spacepos == -1) {
|
||||||
|
spacepos = insize;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* instruction = malloc(spacepos + 1);
|
||||||
|
if (!instruction) {
|
||||||
|
gdi.type = UNKNOWN;
|
||||||
|
gdi.arg = NULL;
|
||||||
|
return gdi;
|
||||||
|
}
|
||||||
|
strncpy(instruction, in, spacepos);
|
||||||
|
instruction[spacepos] = '\0';
|
||||||
|
|
||||||
|
if (strcmp(instruction, "dump") == 0) {
|
||||||
|
gdi.type = DUMP;
|
||||||
|
} else if (strcmp(instruction, "inspect") == 0) {
|
||||||
|
gdi.type = INSPECT;
|
||||||
|
} else if (strcmp(instruction, "eval") == 0) {
|
||||||
|
gdi.type = EVAL;
|
||||||
|
} else if (strcmp(instruction, "continue") == 0) {
|
||||||
|
gdi.type = CONTINUE;
|
||||||
|
} else if (strcmp(instruction, "exit") == 0) {
|
||||||
|
gdi.type = EXIT;
|
||||||
|
} else if (strcmp(instruction, "help") == 0) {
|
||||||
|
gdi.type = HELP;
|
||||||
|
} else {
|
||||||
|
gdi.type = UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t arglen = insize - spacepos;
|
||||||
|
gdi.arg = malloc(arglen + 1);
|
||||||
|
if (gdi.arg) {
|
||||||
|
strcpy(gdi.arg, in + spacepos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(instruction);
|
||||||
|
return gdi;
|
||||||
|
}
|
||||||
|
|
||||||
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||||
GroundLabel* labels = NULL;
|
GroundLabel* labels = NULL;
|
||||||
GroundVariable* variables = NULL;
|
GroundVariable* variables = NULL;
|
||||||
@@ -223,6 +277,92 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (in->instructions[i].type == PAUSE) {
|
||||||
|
printf("Paused execution\n");
|
||||||
|
printf("Previous instruction: ");
|
||||||
|
if (i > 0) {
|
||||||
|
printGroundInstruction(&in->instructions[i - 1]);
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
printf("\nprompt> ");
|
||||||
|
char buffer[256];
|
||||||
|
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
|
||||||
|
buffer[strcspn(buffer, "\n")] = '\0';
|
||||||
|
} else {
|
||||||
|
runtimeError(FIXME, "Failed to read input from console with fgets", NULL, -1);
|
||||||
|
}
|
||||||
|
GroundDebugInstruction gdi = parseDebugInstruction(buffer);
|
||||||
|
|
||||||
|
bool shouldBreak = false;
|
||||||
|
switch (gdi.type) {
|
||||||
|
case CONTINUE: {
|
||||||
|
shouldBreak = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EXIT: {
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DUMP: {
|
||||||
|
if (scope.variables == NULL) {
|
||||||
|
printf("Can't access variables");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*scope.variables == NULL) {
|
||||||
|
printf("Can't access variables");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GroundVariable* entry;
|
||||||
|
GroundVariable* tmp;
|
||||||
|
GroundVariable* head = *scope.variables;
|
||||||
|
HASH_ITER(hh, head, entry, tmp) {
|
||||||
|
if (entry != NULL) {
|
||||||
|
printf("%s: ", entry->id);
|
||||||
|
printGroundValue(&entry->value);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INSPECT: {
|
||||||
|
printf("%s: ", gdi.arg);
|
||||||
|
GroundVariable* var = findVariable(*scope.variables, gdi.arg);
|
||||||
|
if (var == NULL) {
|
||||||
|
printf("(nothing)");
|
||||||
|
} else {
|
||||||
|
printGroundValue(&var->value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVAL: {
|
||||||
|
GroundProgram program = parseFile(gdi.arg);
|
||||||
|
interpretGroundProgram(&program, &scope);
|
||||||
|
freeGroundProgram(&program);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HELP: {
|
||||||
|
printf("Ground Debugger Help\n");
|
||||||
|
printf("Didn't mean to end up here? Type \"continue\" to escape this prompt.\n");
|
||||||
|
printf("Commands:\n");
|
||||||
|
printf(" continue: Continue execution of the program\n");
|
||||||
|
printf(" exit: Stop execution early\n");
|
||||||
|
printf(" dump: Shows all variables and their contents\n");
|
||||||
|
printf(" inspect (variable): Shows the contents of a variable\n");
|
||||||
|
printf(" eval (code): Runs Ground code in the current scope\n");
|
||||||
|
printf(" help: Shows this help message");
|
||||||
|
}
|
||||||
|
case UNKNOWN: {
|
||||||
|
printf("Unknown instruction (type \"help\" for help)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shouldBreak) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int ci = currentInstruction;
|
int ci = currentInstruction;
|
||||||
GroundValue gv = interpretGroundInstruction(in->instructions[i], &scope);
|
GroundValue gv = interpretGroundInstruction(in->instructions[i], &scope);
|
||||||
if (gv.type != NONE) {
|
if (gv.type != NONE) {
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ typedef enum GroundRuntimeError {
|
|||||||
ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, FIXME
|
ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, FIXME
|
||||||
} GroundRuntimeError;
|
} GroundRuntimeError;
|
||||||
|
|
||||||
|
typedef enum GroundDebugInstructionType {
|
||||||
|
DUMP, INSPECT, EVAL, CONTINUE, EXIT, HELP, UNKNOWN
|
||||||
|
} GroundDebugInstructionType;
|
||||||
|
|
||||||
typedef struct GroundLabel {
|
typedef struct GroundLabel {
|
||||||
char id[MAX_ID_LEN];
|
char id[MAX_ID_LEN];
|
||||||
int lineNum;
|
int lineNum;
|
||||||
@@ -27,6 +31,11 @@ typedef struct GroundScope {
|
|||||||
GroundVariable** variables;
|
GroundVariable** variables;
|
||||||
} GroundScope;
|
} GroundScope;
|
||||||
|
|
||||||
|
typedef struct GroundDebugInstruction {
|
||||||
|
GroundDebugInstructionType type;
|
||||||
|
char* arg;
|
||||||
|
} GroundDebugInstruction;
|
||||||
|
|
||||||
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
|
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
|
||||||
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
|
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
|
||||||
|
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ static GroundInstType getInstructionType(const char* inst) {
|
|||||||
if (strcmp(inst, "init") == 0) return INIT;
|
if (strcmp(inst, "init") == 0) return INIT;
|
||||||
if (strcmp(inst, "use") == 0) return USE;
|
if (strcmp(inst, "use") == 0) return USE;
|
||||||
if (strcmp(inst, "extern") == 0) return EXTERN;
|
if (strcmp(inst, "extern") == 0) return EXTERN;
|
||||||
|
if (strcmp(inst, "PAUSE") == 0) return PAUSE;
|
||||||
|
|
||||||
fprintf(stderr, "Error: Unknown instruction: %s\n", inst);
|
fprintf(stderr, "Error: Unknown instruction: %s\n", inst);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|||||||
@@ -126,6 +126,10 @@ void printGroundValue(GroundValue* gv) {
|
|||||||
printf("]");
|
printf("]");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FUNCTION: {
|
||||||
|
printf("<function>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
printf("FIXME");
|
printf("FIXME");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef enum GroundInstType {
|
typedef enum GroundInstType {
|
||||||
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, USE, EXTERN, CREATELABEL
|
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, USE, EXTERN, CREATELABEL, PAUSE
|
||||||
} GroundInstType;
|
} GroundInstType;
|
||||||
|
|
||||||
typedef enum GroundValueType {
|
typedef enum GroundValueType {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fun !dingus -string -int &x
|
fun !dingus -string
|
||||||
return "dinglefart"
|
return "dingus"
|
||||||
endfun
|
endfun
|
||||||
|
|
||||||
call !dingus &e
|
call !dingus &e
|
||||||
|
|||||||
8
tests/pause.grnd
Normal file
8
tests/pause.grnd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fun !dingle -int
|
||||||
|
|
||||||
|
endfun
|
||||||
|
|
||||||
|
set &x 5
|
||||||
|
set &y "dingle"
|
||||||
|
PAUSE
|
||||||
|
println "continuing"
|
||||||
Reference in New Issue
Block a user