#include "../../include/ground.h" #include "../linenoise/linenoise.h" #include #include typedef struct DebugCommand { char* command; struct { char* at[32]; GroundSize count; } args; } DebugCommand; static inline DebugCommand parseCommand(char* input) { DebugCommand debugCommand; // split by spaces const char* delim = " "; debugCommand.command = strtok(input, delim); for (GroundSize i = 0; i < 32; i++) { char* buf = strtok(NULL, delim); if (buf == NULL) { debugCommand.args.count = i; break; } debugCommand.args.at[i] = buf; } return debugCommand; } typedef struct Debugger { GroundSize currentInst; } Debugger; enum DebuggerStatus { DBG_DONE, DBG_CONTINUE, DBG_WAIT, DBG_STEP }; static inline enum DebuggerStatus runCommand(char* input, GroundBytecode* bytecode, Debugger* debugger) { DebugCommand cmd = parseCommand(input); if (strcmp(cmd.command, "help") == 0) { printf( "Commands: \n" \ " help - Show this help message\n" \ " continue - Run the program until next breakpoint, error, or otherwise termination\n" \ " step - Run one instruction\n" \ " break [idx] - Sets a breakpoint on the specified index\n" \ " exit - Stop debugging and exit\n\n" \ " dump - Dump current state of VM\n" \ " view [slot] - Prints the variable in the current slot\n" \ " set [slot] [value] - Sets the current slot to the specified value\n" \ " copy [slot] [slot] - Copies a value from the second slot to the first\n" \ ); return DBG_CONTINUE; } if (strcmp(cmd.command, "continue") == 0) { return DBG_CONTINUE; } if (strcmp(cmd.command, "step") == 0) { return DBG_STEP; } if (strcmp(cmd.command, "break") == 0) { return DBG_WAIT; } if (strcmp(cmd.command, "exit") == 0) { return DBG_DONE; } if (strcmp(cmd.command, "dump") == 0) { printf("%s", Ground.Stringify.Bytecode(bytecode)); return DBG_WAIT; } if (strcmp(cmd.command, "view") == 0) { return DBG_WAIT; } if (strcmp(cmd.command, "set") == 0) { return DBG_WAIT; } if (strcmp(cmd.command, "copy") == 0) { return DBG_WAIT; } fprintf(stderr, "Unknown command %s\n", cmd.command); return DBG_WAIT; } static inline void runInstruction(GroundBytecodeProgram* program, GroundBytecodeHeap* heap) { GroundSize i = 0; while (i < program->len) { struct GroundExecutionResult status = Ground.Bytecode.Instruction.execute(&program->at[i], heap); if (Ground.Flags.error) { fprintf(stderr, "Errors while debugging: \n"); Ground.Log.printErrors(); } switch (status.type) { case _GER_CONTINUE: i++; break; case _GER_RETURN: return; case _GER_JUMP: i = status.as.line; break; case _GER_END: exit(status.as.end); } } } void runDebugger(GroundBytecode* bytecode) { printf("Ground Debugger\n"); printf("Type 'help' for a list of commands\n"); printf("Type 'start' to begin debugging\n"); printf("Type 'exit' to exit\n"); Debugger debugger; for (;;) { char* input = linenoise("> "); if (input == NULL) { continue; } switch (runCommand(input, bytecode, &debugger)) { case DBG_DONE: { return; } case DBG_CONTINUE: { break; } case DBG_WAIT: { break; } case DBG_STEP: { break; } } free(input); } }