From 7e04b0fc6d4af5fc23fdc547865ff1f720b3136d Mon Sep 17 00:00:00 2001 From: cozis Date: Tue, 2 Nov 2021 08:02:58 +0000 Subject: [PATCH] working on the debugger mode --- build.sh | 2 +- src/debug.c | 255 ++++++++++++++++++++++++++++++++++++++++++ src/debug.h | 8 ++ src/main.c | 171 +++++----------------------- src/runtime/o_func.c | 2 +- src/runtime/runtime.c | 14 ++- src/runtime/runtime.h | 4 +- 7 files changed, 302 insertions(+), 154 deletions(-) create mode 100644 src/debug.c create mode 100644 src/debug.h diff --git a/build.sh b/build.sh index 87cdbe2..12075ed 100755 --- a/build.sh +++ b/build.sh @@ -64,7 +64,7 @@ ar rcs build/libnoja-runtime.a \ gcc tests/src/test-parse.c -o build/test-parse $FLAGS -Lbuild/ -lnoja-compile -lxjson gcc tests/src/test-objects.c -o build/test-objects $FLAGS -Lbuild/ -lnoja-objects -gcc src/main.c \ +gcc src/main.c src/debug.c \ temp/utils/hash.o \ temp/utils/stack.o \ temp/utils/source.o \ diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..cea47c5 --- /dev/null +++ b/src/debug.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include +#include +#include "debug.h" + +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_RESET "\x1b[0m" + +typedef struct { + char *name; + +} BreakPoint; + +struct xDebug { + +}; + +Debug *Debug_New() +{ + Debug *dbg = malloc(sizeof(Debug)); + + if(dbg == NULL) + return NULL; + + // Do stuff here. + + return dbg; +} + +void Debug_Free(Debug *dbg) +{ + if(dbg) + free(dbg); +} + +_Bool Debug_Callback(Runtime *runtime, void *userp) +{ + assert(runtime != NULL); + assert(userp != NULL); + + Debug *dbg = (Debug*) userp; + + char buffer[256]; + int length; + + int argc; + char *argv[32]; + + do { + + fprintf(stderr, ANSI_COLOR_GREEN "> " ANSI_COLOR_RESET); + + { + length = 0; + + char c; + while((c = getc(stdin)) != '\n') + { + if(length < (int) sizeof(buffer)-1) + buffer[length] = c; + + length += 1; + } + + if(length > (int) sizeof(buffer)-1) + { + fprintf(stdout, + "Command is too long. The internal buffer can only contain %ld bytes.\n" + "Try inserting another command.\n", + sizeof(buffer)-1); + continue; + } + + buffer[length] = '\0'; + } + + // Now split the buffer into words in the (argc, argv) style. + + { + argc = 0; + + _Bool again = 0; + int curs = 0; + while(1) + { + // Skip whitespace. + while(isspace(buffer[curs])) + curs += 1; + + if(buffer[curs] == '\0') + break; + + int offset = curs; + + while(!isspace(buffer[curs]) && buffer[curs] != '\0') + curs += 1; + + int length = curs - offset; + + assert(length > 0); + + { + int max_argc = sizeof(argv) / sizeof(argv[0]); + + if(argc == max_argc) + { + fprintf(stdout, + "Command has too many words. The internal buffer can only contain %d words.\n" + "Try inserting another command.\n", + max_argc); + again = 1; + break; + } + + argv[argc++] = buffer + offset; + } + + if(buffer[curs] == '\0') + break; + + assert(isspace(buffer[curs])); + + buffer[curs] = '\0'; + + curs += 1; // Consume the space that ended the word (not overwritten by a zero byte). + } + + if(again) + continue; + } + + if(argc == 0) + continue; + + { + if(!strcmp(argv[0], "help")) + { + if(argc == 1) + { + fprintf(stderr, + "help .............. Show this message\n" + "help .... Display additional information for a given command\n" + "step .............. Run an instruction\n" + "quit .............. Stop execution\n" + "continue .......... Run until a breakpoint or the end of the code is reached\n" + "breakpoint ........ Add a breakpoint\n"); + } + else if(!strcmp(argv[1], "help")) + { + fprintf(stderr, + "\n" + " Command | help\n" + " | \n" + " Usage | > help []\n" + " | \n" + " Description | List all available commands or show detailed \n" + " | information about a given command.\n" + "\n"); + } + else if(!strcmp(argv[1], "step")) + { + fprintf(stderr, + "\n" + " Command | step\n" + " | \n" + " Usage | > step\n" + " | \n" + " Description | Run a single instruction.\n" + "\n"); + } + else if(!strcmp(argv[1], "quit")) + { + fprintf(stderr, + "\n" + " Command | quit\n" + " | \n" + " Usage | > quit\n" + " | \n" + " Description | Stop the execution.\n" + "\n"); + } + else if(!strcmp(argv[1], "continue")) + { + fprintf(stderr, + "\n" + " Command | continue\n" + " | \n" + " Usage | > continue\n" + " | \n" + " Description | Run until a breakpoint or the end of the code is\n" + " | reached.\n" + "\n"); + } + else if(!strcmp(argv[1], "breakpoint")) + { + fprintf(stderr, + "\n" + " Command | breakpoint\n" + " | \n" + " Usage | > breakpoint { line | offset | index } \n" + " | \n" + " Description | Add a breakpoint. The first argument of the command \n" + " | specifies the source containing the breakpoint, while \n" + " | the second one specifies the way the breakpoint is \n" + " | expressed: \n" + " | \n" + " | line | by line number.\n" + " | | \n" + " | offset | by character offset.\n" + " | | \n" + " | index | by instruction index (relative to the \n" + " | | start of the source executable's body).\n" + " | \n" + " | the third argument is, based on the second one, either\n" + " | a line number, a character offset or an instruction index.\n" + "\n"); + } + else + { + fprintf(stdout, "Unknown command \"%s\".\n", argv[1]); + } + } + else if(!strcmp(argv[0], "breakpoint")) + { + fprintf(stderr, "Not implemented yet.\n"); + } + else if(!strcmp(argv[0], "continue")) + { + fprintf(stderr, "Not implemented yet.\n"); + } + else if(!strcmp(argv[0], "step")) + { + break; + } + else if(!strcmp(argv[0], "quit")) + { + return 0; + } + else + { + fprintf(stdout, "Unknown command \"%s\". Type \"help\" is you need help.\n", argv[0]); + } + } + + } while(1); + + return 1; +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..0aff082 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,8 @@ +#ifndef DEBUG_H +#define DEBUG_H +#include "runtime/runtime.h" +typedef struct xDebug Debug; +Debug *Debug_New(); +void Debug_Free(Debug *dbg); +_Bool Debug_Callback(Runtime *runtime, void *userp); +#endif \ No newline at end of file diff --git a/src/main.c b/src/main.c index a499e43..71b19bd 100644 --- a/src/main.c +++ b/src/main.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include "debug.h" #include "compiler/parse.h" #include "compiler/serialize.h" #include "compiler/compile.h" @@ -22,6 +22,8 @@ typedef struct { const char *input, *output; } Options; +_Bool debug_callback(Runtime *runtime, void *userp); + static int parse_args(Options *opts, int argc, char **argv, Error *error) { assert(argc >= 0); @@ -102,148 +104,6 @@ static int parse_args(Options *opts, int argc, char **argv, Error *error) return i; } -static _Bool debug_callback(Runtime *runtime, void *userp) -{ - assert(runtime != NULL); - assert(userp == NULL); - - #define ANSI_COLOR_RED "\x1b[31m" - #define ANSI_COLOR_GREEN "\x1b[32m" - #define ANSI_COLOR_YELLOW "\x1b[33m" - #define ANSI_COLOR_BLUE "\x1b[34m" - #define ANSI_COLOR_MAGENTA "\x1b[35m" - #define ANSI_COLOR_CYAN "\x1b[36m" - #define ANSI_COLOR_RESET "\x1b[0m" - - char buffer[256]; - int length; - - int argc; - char *argv[32]; - - do { - - fprintf(stderr, ANSI_COLOR_GREEN "> " ANSI_COLOR_RESET); - - { - length = 0; - - char c; - while((c = getc(stdin)) != '\n') - { - if(length < (int) sizeof(buffer)-1) - buffer[length] = c; - - length += 1; - } - - if(length > (int) sizeof(buffer)-1) - { - fprintf(stdout, - "Command is too long. The internal buffer can only contain %ld bytes.\n" - "Try inserting another command.\n", - sizeof(buffer)-1); - continue; - } - - buffer[length] = '\0'; - } - - // Now split the buffer into words in the (argc, argv) style. - - { - argc = 0; - - _Bool again = 0; - int curs = 0; - while(1) - { - // Skip whitespace. - while(isspace(buffer[curs])) - curs += 1; - - if(buffer[curs] == '\0') - break; - - int offset = curs; - - while(!isspace(buffer[curs]) && buffer[curs] != '\0') - curs += 1; - - int length = curs - offset; - - assert(length > 0); - - { - int max_argc = sizeof(argv) / sizeof(argv[0]); - - if(argc == max_argc) - { - fprintf(stdout, - "Command has too many words. The internal buffer can only contain %d words.\n" - "Try inserting another command.\n", - max_argc); - again = 1; - break; - } - - argv[argc++] = buffer + offset; - } - - if(buffer[curs] == '\0') - break; - - assert(isspace(buffer[curs])); - - buffer[curs] = '\0'; - - curs += 1; // Consume the space that ended the word (not overwritten by a zero byte). - } - - if(again) - continue; - } - - if(argc == 0) - continue; - - { - if(!strcmp(argv[0], "help")) - { - fprintf(stderr, - "help ...................... Show this message\n" - "step ...................... Run an instruction\n" - "quit ...................... Stop execution\n" - "continue .................. Run until a breakpoint or the end of the code is reached\n" - "breakpoint .. Add a breakpoint\n"); - } - else if(!strcmp(argv[0], "breakpoint")) - { - fprintf(stderr, "Not implemented yet.\n"); - } - else if(!strcmp(argv[0], "continue")) - { - fprintf(stderr, "Not implemented yet.\n"); - } - else if(!strcmp(argv[0], "step")) - { - break; - } - else if(!strcmp(argv[0], "quit")) - { - return 0; - } - else - { - fprintf(stdout, "Unknown command \"%s\". Type \"help\" is you need help.\n", argv[0]); - } - } - - } while(1); - - return 1; -} - int main(int argc, char **argv) { Error error; @@ -328,11 +188,30 @@ int main(int argc, char **argv) // Execute { - Runtime *runtime = Runtime_New(-1, -1); + Debug *dbg = NULL; + Runtime *runtime; + + if(opts.debug) + { + dbg = Debug_New(); + + if(dbg == NULL) + { + fprintf(stderr, "Couldn't initialize debug state.\n"); + Executable_Free(exe); + Source_Free(src); + return 1; + } + + runtime = Runtime_New(-1, -1, dbg, Debug_Callback); + } + else + runtime = Runtime_New(-1, -1, NULL, NULL); if(runtime == NULL) { fprintf(stderr, "Couldn't initialize runtime.\n"); + Debug_Free(dbg); Executable_Free(exe); Source_Free(src); return 1; @@ -341,7 +220,7 @@ int main(int argc, char **argv) RuntimeError error; RuntimeError_Init(&error, runtime); - Object *result = run(runtime, (Error*) &error, exe, 0, NULL, 0, NULL, opts.debug ? debug_callback : NULL); + Object *result = run(runtime, (Error*) &error, exe, 0, NULL, 0); if(result == NULL || !Object_Print(result, stderr, (Error*) &error)) { @@ -352,6 +231,7 @@ int main(int argc, char **argv) else fprintf(stderr, "No snapshot available.\n"); + Debug_Free(dbg); Source_Free(src); Executable_Free(exe); RuntimeError_Free(&error); @@ -361,6 +241,7 @@ int main(int argc, char **argv) fprintf(stderr, "\n"); Runtime_Free(runtime); + Debug_Free(dbg); } Executable_Free(exe); diff --git a/src/runtime/o_func.c b/src/runtime/o_func.c index 62dc6bf..3dc18b1 100644 --- a/src/runtime/o_func.c +++ b/src/runtime/o_func.c @@ -30,7 +30,7 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, assert(func->exe != NULL); assert(func->index >= 0); - return run(func->runtime, error, func->exe, func->index, argv, argc, NULL, NULL); + return run(func->runtime, error, func->exe, func->index, argv, argc); } Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, Heap *heap, Error *error) diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 99b75de..e8876ca 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -15,13 +15,15 @@ struct Frame { }; struct xRuntime { + void *callback_userp; + _Bool (*callback_addr)(Runtime*, void*); int depth; Frame *frame; Stack *stack; Heap *heap; }; -Runtime *Runtime_New(int stack_size, int heap_size) +Runtime *Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*)) { if(stack_size < 0) stack_size = 1024; @@ -53,6 +55,8 @@ Runtime *Runtime_New(int stack_size, int heap_size) free(runtime); } + runtime->callback_userp = callback_userp; + runtime->callback_addr = callback_addr; runtime->frame = NULL; runtime->depth = 0; } @@ -560,7 +564,7 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } -Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object **argv, int argc, void *userp, _Bool (*callback)(Runtime*, void*)) +Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object **argv, int argc) { assert(runtime != NULL); assert(error != NULL); @@ -599,13 +603,13 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object * // Run the code. - if(callback != NULL) + if(runtime->callback_addr != NULL) { - if(!callback(runtime, userp)) + if(!runtime->callback_addr(runtime, runtime->callback_userp)) Error_Report(error, 0, "Forced abortion"); else while(step(runtime, error)) - if(!callback(runtime, userp)) + if(!runtime->callback_addr(runtime, runtime->callback_userp)) { Error_Report(error, 0, "Forced abortion"); break; diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 096e778..2a0c5bc 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -6,7 +6,7 @@ #include "../common/executable.h" typedef struct xRuntime Runtime; -Runtime* Runtime_New(int stack_size, int heap_size); +Runtime* Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*)); void Runtime_Free(Runtime *runtime); _Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n); _Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj); @@ -16,7 +16,7 @@ Snapshot *Snapshot_New(Runtime *runtime); void Snapshot_Free(Snapshot *snapshot); void Snapshot_Print(Snapshot *snapshot, FILE *fp); -Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object **argv, int argc, void *userp, _Bool (*callback)(Runtime*, void*)); +Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object **argv, int argc); Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int offset, Heap *heap, Error *error); #endif \ No newline at end of file