From 472a4a623c8af480b0ace97b32af7210de2812e9 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 30 May 2024 21:06:03 +0200 Subject: [PATCH] feature: added error diagnostics and the ability to parse multiple files --- src/ast/ast.c | 17 ++- src/ast/ast.h | 5 +- src/io/files.c | 224 ++++++++++++++++++++++++++++++++++++ src/io/files.h | 77 +++++++++++++ src/lex/util.c | 14 ++- src/lex/util.h | 2 + src/main.c | 116 +++++++++++++------ src/sys/log.h | 2 +- src/yacc/parser.y | 286 ++++++++++++++++++---------------------------- 9 files changed, 530 insertions(+), 213 deletions(-) create mode 100644 src/io/files.c create mode 100644 src/io/files.h diff --git a/src/ast/ast.c b/src/ast/ast.c index 892af1f..8c65510 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -5,7 +5,7 @@ #include #include -struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value) { +struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value) { DEBUG("creating new AST node: %d \"%s\"", kind, value); assert(kind < AST_ELEMENT_COUNT); @@ -23,6 +23,7 @@ struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value node->child_count = 0; node->kind = kind; node->value = value; + node->location = location; return node; } @@ -114,6 +115,14 @@ const char* AST_node_to_string(const struct AST_Node_t* node) { return string; } +static inline unsigned long int min(unsigned long int a, unsigned long int b) { + return a > b ? b : a; +} + +static inline unsigned long int max(unsigned long int a, unsigned long int b) { + return a > b ? a : b; +} + void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) { DEBUG("Adding new node %p to %p", child, owner); assert(owner != NULL); @@ -134,6 +143,12 @@ void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) { PANIC("failed to allocate children array of AST node"); } + owner->location.col_end = max(owner->location.col_end, child->location.col_end); + owner->location.line_end = max(owner->location.line_end, child->location.line_end); + + owner->location.col_start = min(owner->location.col_start, child->location.col_start); + owner->location.line_start = min(owner->location.line_start, child->location.line_start); + assert(owner->children != NULL); owner->children[owner->child_count++] = child; diff --git a/src/ast/ast.h b/src/ast/ast.h index ff8297b..7edbe81 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -3,6 +3,7 @@ #define _AST_H_ #include +#include /** * @brief The type of a AST node @@ -94,6 +95,8 @@ struct AST_Node_t { // optional value: integer literal, string literal, ... const char* value; + TokenLocation location; + // number of child nodes ownd by this node // length of children array size_t child_count; @@ -133,7 +136,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node); [[maybe_unused]] [[nodiscard("pointer must be freed")]] [[gnu::returns_nonnull]] -struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value); +struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value); /** * @brief Deallocate this node and all of its children. diff --git a/src/io/files.c b/src/io/files.c new file mode 100644 index 0000000..97daed1 --- /dev/null +++ b/src/io/files.c @@ -0,0 +1,224 @@ +// +// Created by servostar on 5/30/24. +// + +#include +#include +#include +#include + +ModuleFile *push_file(ModuleFileStack *stack, const char *path) { + assert(stack != NULL); + + // lazy init of heap stack + if (stack->files == NULL) { + stack->files = g_array_new(FALSE, FALSE, sizeof(ModuleFile)); + } + + ModuleFile new_file = { + .path = path, + .handle = NULL + }; + + g_array_append_val(stack->files, new_file); + + return ((ModuleFile *) stack->files->data) + stack->files->len - 1; +} + +void delete_files(ModuleFileStack *stack) { + for (size_t i = 0; i < stack->files->len; i++) { + ModuleFile *file = ((ModuleFile *) stack->files->data) + i; + + if (file->handle != NULL) { + DEBUG("closing file: %s", file->path); + fclose(file->handle); + } + + } + + g_array_free(stack->files, TRUE); + DEBUG("deleted module file stack"); +} + +#define SEEK_BUF_BYTES 256 + +static inline unsigned long int min(unsigned long int a, unsigned long int b) { + return a > b ? b : a; +} + +// behaves like fgets except that it has defined behavior when n == 1 +static void custom_fgets(char *buffer, size_t n, FILE *stream) { + if (n == 1) { + buffer[0] = (char) fgetc(stream); + buffer[1] = 0; + } else { + fgets(buffer, (int) n, stream); + } +} + +void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, const char *message) { + assert(file->handle != NULL); + assert(location != NULL); + assert(message != NULL); + + // reset to start + rewind(file->handle); + + char *buffer = alloca(SEEK_BUF_BYTES); + unsigned long int line_count = 1; + + // seek to first line + while (line_count < location->line_start && fgets(buffer, SEEK_BUF_BYTES, file->handle) != NULL) { + line_count += strchr(buffer, '\n') != NULL; + } + + const char *accent_color = RESET; + const char *kind_text = "unknown"; + switch (kind) { + case Info: + kind_text = "info"; + accent_color = CYAN; + file->statistics.info_count++; + break; + case Warning: + kind_text = "warning"; + accent_color = YELLOW; + file->statistics.warning_count++; + break; + case Error: + kind_text = "error"; + accent_color = RED; + file->statistics.error_count++; + break; + } + + char absolute_path[PATH_MAX]; + realpath(file->path, absolute_path); + + printf("%s%s:%ld:%s %s%s:%s %s\n", BOLD, absolute_path, location->line_start, RESET, accent_color, kind_text, RESET, + message); + + size_t lines = location->line_end - location->line_start + 1; + + for (size_t l = 0; l < lines; l++) { + printf(" %4ld | ", location->line_start + l); + + size_t limit; + size_t chars = 0; + + // print line before token group start + limit = min(location->col_start, SEEK_BUF_BYTES); + while (limit > 1) { + custom_fgets(buffer, (int) limit, file->handle); + chars += printf("%s", buffer); + limit = min(location->col_start - chars, SEEK_BUF_BYTES); + + if (strchr(buffer, '\n') != NULL) { + goto cont; + } + } + + printf("%s", accent_color); + + chars = 0; + limit = min(location->col_end - location->col_start + 1, SEEK_BUF_BYTES); + while (limit > 0) { + custom_fgets(buffer, (int) limit, file->handle); + chars += printf("%s", buffer); + limit = min(location->col_end - location->col_start + 1 - chars, SEEK_BUF_BYTES); + + if (strchr(buffer, '\n') != NULL) { + goto cont; + } + } + + printf("%s", RESET); + + // print rest of the line + do { + custom_fgets(buffer, SEEK_BUF_BYTES, file->handle); + printf("%s", buffer); + } while (strchr(buffer, '\n') == NULL); + + cont: + printf("%s", RESET); + } + + printf(" | "); + for (size_t i = 1; i < location->col_start; i++) { + printf(" "); + } + + printf("%s", accent_color); + printf("^"); + for (size_t i = 0; i < location->col_end - location->col_start; i++) { + printf("~"); + } + + printf("%s\n\n", RESET); +} + +TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end, + unsigned long int col_end) { + TokenLocation location; + + location.line_start = line_start; + location.line_end = line_end; + location.col_start = col_start; + location.col_end = col_end; + + return location; +} + +void print_file_statistics(ModuleFile *file) { + if (file->statistics.info_count + file->statistics.warning_count + file->statistics.error_count < 1) { + return; + } + + printf("File %s generated ", file->path); + + if (file->statistics.info_count > 0) { + printf("%ld notice(s) ", file->statistics.info_count); + } + + if (file->statistics.warning_count > 0) { + printf("%ld warning(s) ", file->statistics.warning_count); + } + + if (file->statistics.error_count > 0) { + printf("%ld error(s) ", file->statistics.error_count); + } + + printf("\n\n"); +} + +void print_unit_statistics(ModuleFileStack *file_stack) { + FileDiagnosticStatistics stats; + stats.info_count = 0; + stats.warning_count = 0; + stats.error_count = 0; + + for (size_t i = 0; i < file_stack->files->len; i++) { + ModuleFile *file = (ModuleFile *) file_stack->files->data; + + stats.info_count += file->statistics.warning_count; + stats.warning_count += file->statistics.warning_count; + stats.error_count += file->statistics.error_count; + } + + printf("%d files generated ", file_stack->files->len); + + if (stats.info_count > 0) { + printf("%ld notice(s) ", stats.info_count); + } + + if (stats.warning_count > 0) { + printf("%ld warning(s) ", stats.warning_count); + } + + if (stats.error_count > 0) { + printf("%ld error(s) ", stats.error_count); + } + + printf("\n\n"); +} diff --git a/src/io/files.h b/src/io/files.h new file mode 100644 index 0000000..5441805 --- /dev/null +++ b/src/io/files.h @@ -0,0 +1,77 @@ +// +// Created by servostar on 5/30/24. +// + +#ifndef GEMSTONE_FILES_H +#define GEMSTONE_FILES_H + +#include +#include + +typedef struct FileDiagnosticStatistics_t { + size_t error_count; + size_t warning_count; + size_t info_count; +} FileDiagnosticStatistics; + +typedef struct ModuleFile_t { + const char *path; + FILE *handle; + FileDiagnosticStatistics statistics; +} ModuleFile; + +typedef struct ModuleFileStack_t { + GArray *files; +} ModuleFileStack; + +typedef enum Message_t { + Info, + Warning, + Error +} Message; + +typedef struct TokenLocation_t { + unsigned long int line_start; + unsigned long int col_start; + unsigned long int line_end; + unsigned long int col_end; +} TokenLocation; + +/** + * @brief Add a new file to the file stack. + * @attention The file handle returned will be invalid + * @param stack + * @param path + * @return A new file module + */ +[[gnu::nonnull(1), gnu::nonnull(2)]] +ModuleFile *push_file(ModuleFileStack *stack, const char *path); + +/** + * @brief Delete all files in the stack and the stack itself + * @param stack + */ +[[gnu::nonnull(1)]] +void delete_files(ModuleFileStack *stack); + +/** + * Create a new token location + * @param line_start + * @param col_start + * @param line_end + * @param col_end + * @return + */ +TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end, + unsigned long int col_end); + +[[gnu::nonnull(1), gnu::nonnull(2)]] +void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, const char *message); + +[[gnu::nonnull(1)]] +void print_file_statistics(ModuleFile *file); + +[[gnu::nonnull(1)]] +void print_unit_statistics(ModuleFileStack *file_stack); + +#endif //GEMSTONE_FILES_H diff --git a/src/lex/util.c b/src/lex/util.c index b5b92ac..81f2855 100644 --- a/src/lex/util.c +++ b/src/lex/util.c @@ -25,6 +25,16 @@ void lex_init(void) { atexit(lex_deinit); } +void lex_reset(void) { + eof = 0; + nRow = 0; + nBuffer = 0; + lBuffer = 0; + nTokenStart = 0; + nTokenLength = 0; + nTokenNextStart = 0; +} + void beginToken(char *t) { nTokenStart = nTokenNextStart; nTokenLength = (int) strlen(t); @@ -41,7 +51,7 @@ int nextChar(char *dst) { if (eof) return 0; - + while (nBuffer >= lBuffer) { frc = getNextLine(); if (frc != 0) { @@ -57,7 +67,7 @@ int nextChar(char *dst) { int getNextLine(void) { char *p; - + nBuffer = 0; nTokenStart = -1; nTokenNextStart = 1; diff --git a/src/lex/util.h b/src/lex/util.h index 12e0837..6939526 100644 --- a/src/lex/util.h +++ b/src/lex/util.h @@ -16,6 +16,8 @@ extern char* buffer; */ void lex_init(void); +void lex_reset(void); + /** * @brief Begin counting a new token. This will fill the global struct yylloc. * @param t the text of the token. Must be null terminated diff --git a/src/main.c b/src/main.c index 27bca44..0b75508 100644 --- a/src/main.c +++ b/src/main.c @@ -4,11 +4,52 @@ #include #include #include +#include +#include -#define LOG_LEVEL LOG_LEVEL_DEBUG +extern void yyrestart(FILE *); -extern FILE *yyin; +[[maybe_unused]] AST_NODE_PTR root; +[[maybe_unused]] +ModuleFile *current_file; + +/** + * @brief Compile the specified file into AST + * @param ast + * @param file + * @return EXIT_SUCCESS in case the parsing was success full anything lese if not + */ +[[nodiscard("AST may be in invalid state")]] +[[gnu::nonnull(1), gnu::nonnull(1)]] +static size_t compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) { + assert(file->path != NULL); + assert(ast != NULL); + + file->handle = fopen(file->path, "r"); + + if (file->handle == NULL) { + INFO("unable to open file: %s", file->path); + return 1; + } + + DEBUG("parsing file: %s", file->path); + // setup global state + root = ast; + current_file = file; + yyin = file->handle; + yyrestart(yyin); + lex_reset(); + + yyparse(); + + // clean up global state + // current_file = NULL; + root = NULL; + yyin = NULL; + + return 0; +} /** * @brief Log a debug message to inform about beginning exit procedures @@ -22,9 +63,9 @@ void notify_exit(void) { DEBUG("Exiting gemstone..."); } */ void close_file(void) { - if (NULL != yyin) { - fclose(yyin); - } + if (NULL != yyin) { + fclose(yyin); + } } /** @@ -32,52 +73,57 @@ void close_file(void) { * */ void setup(void) { - // setup preample + // setup preample - log_init(); - DEBUG("starting gemstone..."); + log_init(); + DEBUG("starting gemstone..."); #if LOG_LEVEL <= LOG_LEVEL_DEBUG - atexit(¬ify_exit); + atexit(¬ify_exit); #endif - // actual setup - AST_init(); + // actual setup + AST_init(); - col_init(); + col_init(); - lex_init(); + lex_init(); - DEBUG("finished starting up gemstone..."); + DEBUG("finished starting up gemstone..."); } int main(int argc, char *argv[]) { - setup(); - atexit(close_file); + setup(); + atexit(close_file); - // Check for file input as argument - if (2 != argc) { - INFO("Usage: %s \n", argv[0]); - PANIC("No File could be found"); - } + ModuleFileStack files; + files.files = NULL; - // filename as first argument - char *filename = argv[1]; + for (int i = 1; i < argc; i++) { + printf("Compiling file: %s\n\n", argv[i]); - FILE *file = fopen(filename, "r"); + TokenLocation location = { + .line_start = 0, + .line_end = 0, + .col_start = 0, + .col_end = 0 + }; + AST_NODE_PTR ast = AST_new_node(location, AST_Module, NULL); + ModuleFile *file = push_file(&files, argv[i]); - if (NULL == file) { - PANIC("File couldn't be opened!"); - } - yyin = file; + if (compile_file_to_ast(ast, file) == EXIT_SUCCESS) { + // TODO: parse AST to semantic values + // TODO: backend codegen + } - root = AST_new_node(AST_Module, NULL); - yyparse(); + AST_delete_node(ast); - FILE *output = fopen("test.txt", "w"); - AST_fprint_graphviz(output, root); - fclose(output); - AST_delete_node(root); - return 0; + print_file_statistics(file); + } + + print_unit_statistics(&files); + + delete_files(&files); + return 0; } diff --git a/src/sys/log.h b/src/sys/log.h index 6b8991d..50fded1 100644 --- a/src/sys/log.h +++ b/src/sys/log.h @@ -10,7 +10,7 @@ #define LOG_LEVEL_INFORMATION 1 #define LOG_LEVEL_DEBUG 0 -#define LOG_LEVEL LOG_LEVEL_DEBUG +#define LOG_LEVEL LOG_LEVEL_ERROR #define LOG_STRING_PANIC "Critical" #define LOG_STRING_FATAL "Fatal" diff --git a/src/yacc/parser.y b/src/yacc/parser.y index 753c7bc..d599c8d 100644 --- a/src/yacc/parser.y +++ b/src/yacc/parser.y @@ -5,8 +5,9 @@ #include #include #include + #include extern int yylineno; - + extern ModuleFile* current_file; int yyerror(const char*); @@ -15,7 +16,8 @@ extern int yylex(); extern AST_NODE_PTR root; - + + #define new_loc() new_location(yylloc.first_line, yylloc.first_column, yylloc.last_line, yylloc.last_column) } %union { @@ -144,11 +146,11 @@ programbody: moduleimport {$$ = $1;} -expr: ValFloat {$$ = AST_new_node(AST_Float, $1);} - | ValInt {$$ = AST_new_node(AST_Int, $1);} - | ValMultistr {$$ = AST_new_node(AST_String, $1);} - | ValStr {$$ = AST_new_node(AST_String, $1);} - | Ident {$$ = AST_new_node(AST_Ident, $1);} +expr: ValFloat {$$ = AST_new_node(new_loc(), AST_Float, $1);} + | ValInt {$$ = AST_new_node(new_loc(), AST_Int, $1);} + | ValMultistr {$$ = AST_new_node(new_loc(), AST_String, $1);} + | ValStr {$$ = AST_new_node(new_loc(), AST_String, $1);} + | Ident {$$ = AST_new_node(new_loc(), AST_Ident, $1);} | operation {$$ = $1;} | boxaccess {$$ = $1;} | boxselfaccess{$$ = $1;} @@ -157,22 +159,22 @@ expr: ValFloat {$$ = AST_new_node(AST_Float, $1);} exprlist: expr ',' exprlist {AST_push_node($3, $1); $$ = $3;} - | expr {AST_NODE_PTR list = AST_new_node(AST_ExprList, NULL); + | expr {AST_NODE_PTR list = AST_new_node(new_loc(), AST_ExprList, NULL); AST_push_node(list, $1); $$ = list;}; argumentlist: argumentlist '(' exprlist ')' {AST_push_node($1, $3); $$ = $1;} - | '(' exprlist ')'{AST_NODE_PTR list = AST_new_node(AST_ArgList, NULL); + | '(' exprlist ')'{AST_NODE_PTR list = AST_new_node(new_loc(), AST_ArgList, NULL); AST_push_node(list, $2); $$ = list;} | argumentlist '(' ')' - | '(' ')'{AST_NODE_PTR list = AST_new_node(AST_ArgList, NULL); + | '(' ')'{AST_NODE_PTR list = AST_new_node(new_loc(), AST_ArgList, NULL); $$ = list;}; -fundef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(AST_Fun, NULL); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $2); +fundef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_Fun, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $2); AST_push_node(fun, ident); AST_push_node(fun, $3); AST_push_node(fun, $5); @@ -182,66 +184,66 @@ fundef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_ paramlist: paramlist '(' params ')' {AST_push_node($1, $3); $$ = $1;} | paramlist '(' ')'{$$ = $1;} - | '(' params ')' {AST_NODE_PTR list = AST_new_node(AST_List, NULL); + | '(' params ')' {AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL); AST_push_node(list, $2); $$ = list;} - | '(' ')' {$$ = AST_new_node(AST_List, NULL);}; + | '(' ')' {$$ = AST_new_node(new_loc(), AST_List, NULL);}; -params: IOqualifyier paramdecl ',' params {AST_NODE_PTR parameter = AST_new_node(AST_Parameter, NULL); +params: IOqualifyier paramdecl ',' params {AST_NODE_PTR parameter = AST_new_node(new_loc(), AST_Parameter, NULL); AST_push_node(parameter, $1); AST_push_node(parameter, $2); AST_push_node($4, parameter); $$ = $4;} - | IOqualifyier paramdecl {AST_NODE_PTR list = AST_new_node(AST_ParamList, NULL); - AST_NODE_PTR parameter = AST_new_node(AST_Parameter, NULL); + | IOqualifyier paramdecl {AST_NODE_PTR list = AST_new_node(new_loc(), AST_ParamList, NULL); + AST_NODE_PTR parameter = AST_new_node(new_loc(), AST_Parameter, NULL); AST_push_node(parameter, $1); AST_push_node(parameter, $2); AST_push_node(list, parameter); $$ = list;}; -IOqualifyier: KeyIn { AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in"); - AST_NODE_PTR list = AST_new_node(AST_List, NULL); +IOqualifyier: KeyIn { AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in"); + AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL); AST_push_node(list, in); $$ = list;} - | KeyOut{ AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out"); - AST_NODE_PTR list = AST_new_node(AST_List, NULL); + | KeyOut{ AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out"); + AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL); AST_push_node(list, out); $$ = list;} - | KeyIn KeyOut{ AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in"); - AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out"); - AST_NODE_PTR list = AST_new_node(AST_List, NULL); + | KeyIn KeyOut{ AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in"); + AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out"); + AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL); AST_push_node(list, in); AST_push_node(list, out); $$ = list;} - | KeyOut KeyIn{ AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in"); - AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out"); - AST_NODE_PTR list = AST_new_node(AST_List, NULL); + | KeyOut KeyIn{ AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in"); + AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out"); + AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL); AST_push_node(list, in); AST_push_node(list, out); $$ = list;} - | {$$ = AST_new_node(AST_List, NULL);}; + | {$$ = AST_new_node(new_loc(), AST_List, NULL);}; -paramdecl: type ':' Ident { AST_NODE_PTR paramdecl = AST_new_node(AST_ParamDecl, NULL); +paramdecl: type ':' Ident { AST_NODE_PTR paramdecl = AST_new_node(new_loc(), AST_ParamDecl, NULL); AST_push_node(paramdecl, $1); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $3); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $3); AST_push_node(paramdecl, ident); $$ = paramdecl; DEBUG("Param-Declaration"); }; -box: KeyType KeyBox ':' Ident '{' boxbody '}' {AST_NODE_PTR box = AST_new_node(AST_Box, NULL); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $4); +box: KeyType KeyBox ':' Ident '{' boxbody '}' {AST_NODE_PTR box = AST_new_node(new_loc(), AST_Box, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4); AST_push_node(box, ident); AST_push_node(box, $6); $$ = box; DEBUG("Box"); } - | KeyType KeyBox ':' Ident '{' '}' {AST_NODE_PTR box = AST_new_node(AST_Box, NULL); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $4); + | KeyType KeyBox ':' Ident '{' '}' {AST_NODE_PTR box = AST_new_node(new_loc(), AST_Box, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4); AST_push_node(box, ident); $$ = box;}; boxbody: boxbody boxcontent {AST_push_node($1, $2); $$ = $1;} - | boxcontent {AST_NODE_PTR list = AST_new_node(AST_List, NULL); + | boxcontent {AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL); AST_push_node(list, $1); $$ = list;}; @@ -249,66 +251,66 @@ boxcontent: decl { $$ = $1;DEBUG("Box decl Content"); } | definition { $$ = $1;DEBUG("Box def Content"); } | fundef { $$ = $1;DEBUG("Box fun Content"); }; -boxselfaccess: KeySelf '.' Ident {AST_NODE_PTR boxselfaccess = AST_new_node(AST_List, NULL); - AST_NODE_PTR self = AST_new_node(AST_Ident, "self"); +boxselfaccess: KeySelf '.' Ident {AST_NODE_PTR boxselfaccess = AST_new_node(new_loc(), AST_List, NULL); + AST_NODE_PTR self = AST_new_node(new_loc(), AST_Ident, "self"); AST_push_node(boxselfaccess, self); - AST_NODE_PTR identlist = AST_new_node(AST_IdentList, NULL); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $3); + AST_NODE_PTR identlist = AST_new_node(new_loc(), AST_IdentList, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $3); AST_push_node(identlist,ident); AST_push_node(boxselfaccess, identlist); $$ = boxselfaccess;} - | KeySelf '.' boxaccess {AST_NODE_PTR boxselfaccess = AST_new_node(AST_List, NULL); - AST_NODE_PTR self = AST_new_node(AST_Ident, "self"); + | KeySelf '.' boxaccess {AST_NODE_PTR boxselfaccess = AST_new_node(new_loc(), AST_List, NULL); + AST_NODE_PTR self = AST_new_node(new_loc(), AST_Ident, "self"); AST_push_node(boxselfaccess, self); AST_push_node(boxselfaccess, $3); $$ = boxselfaccess;}; -boxaccess: Ident '.' Ident {AST_NODE_PTR identlist = AST_new_node(AST_IdentList, NULL); - AST_NODE_PTR ident1 = AST_new_node(AST_Ident, $1); - AST_NODE_PTR ident2 = AST_new_node(AST_Ident, $3); +boxaccess: Ident '.' Ident {AST_NODE_PTR identlist = AST_new_node(new_loc(), AST_IdentList, NULL); + AST_NODE_PTR ident1 = AST_new_node(new_loc(), AST_Ident, $1); + AST_NODE_PTR ident2 = AST_new_node(new_loc(), AST_Ident, $3); AST_push_node(identlist,ident1); AST_push_node(identlist,ident2); $$ = identlist;} - | Ident '.' boxaccess {AST_NODE_PTR ident = AST_new_node(AST_Ident, $1); + | Ident '.' boxaccess {AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1); AST_push_node($3,ident); $$ = $3;}; -boxcall: boxaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(AST_Call, NULL); +boxcall: boxaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(new_loc(), AST_Call, NULL); AST_push_node(boxcall, $1); AST_push_node(boxcall, $2); $$ = boxcall;} - | boxselfaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(AST_Call, NULL); + | boxselfaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(new_loc(), AST_Call, NULL); AST_push_node(boxcall, $1); AST_push_node(boxcall, $2); $$ = boxcall;}; -typecast: expr KeyAs type %prec KeyAs {AST_NODE_PTR cast = AST_new_node(AST_Typecast, NULL); +typecast: expr KeyAs type %prec KeyAs {AST_NODE_PTR cast = AST_new_node(new_loc(), AST_Typecast, NULL); AST_push_node(cast, $1); AST_push_node(cast, $3); $$ = cast; DEBUG("Type-Cast"); }; -reinterpretcast: '(' type ')' expr { AST_NODE_PTR cast = AST_new_node(AST_Transmute, NULL); +reinterpretcast: '(' type ')' expr { AST_NODE_PTR cast = AST_new_node(new_loc(), AST_Transmute, NULL); AST_push_node(cast, $4); AST_push_node(cast, $2); $$ = cast; DEBUG("Reinterpret-Cast"); }; -funcall: Ident argumentlist {AST_NODE_PTR funcall = AST_new_node(AST_Call, NULL); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $1); +funcall: Ident argumentlist {AST_NODE_PTR funcall = AST_new_node(new_loc(), AST_Call, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1); AST_push_node(funcall, ident); AST_push_node(funcall, $2); $$ = funcall; DEBUG("Function call"); }; -moduleimport: KeyImport ValStr {$$ = AST_new_node(AST_Import, $2); +moduleimport: KeyImport ValStr {$$ = AST_new_node(new_loc(), AST_Import, $2); DEBUG("Module-Import"); }; statementlist: statementlist statement {AST_push_node($1, $2); $$ = $1;} - | statement {AST_NODE_PTR list = AST_new_node(AST_StmtList, NULL); + | statement {AST_NODE_PTR list = AST_new_node(new_loc(), AST_StmtList, NULL); AST_push_node(list, $1); $$ = list;}; @@ -320,16 +322,16 @@ statement: assign {$$ = $1;} | funcall {$$ = $1;} | boxcall{$$ = $1;}; -branchif: KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(AST_If, NULL); +branchif: KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_If, NULL); AST_push_node(branch, $2); AST_push_node(branch, $4); $$ = branch; }; -branchelse: KeyElse '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(AST_Else, NULL); +branchelse: KeyElse '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_Else, NULL); AST_push_node(branch, $3); $$ = branch; }; -branchelseif: KeyElse KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(AST_IfElse, NULL); +branchelseif: KeyElse KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_IfElse, NULL); AST_push_node(branch, $3); AST_push_node(branch, $5); $$ = branch; }; @@ -337,49 +339,49 @@ branchelseif: KeyElse KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = A branchfull: branchhalf { $$ = $1;}; |branchhalf branchelse { AST_push_node($1 , $2); $$ = $1; } -branchhalf: branchif { AST_NODE_PTR branch = AST_new_node(AST_Stmt, NULL); +branchhalf: branchif { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_Stmt, NULL); AST_push_node(branch, $1); $$ = branch; } | branchhalf branchelseif { AST_push_node($1 , $2); $$ = $1; }; -while: KeyWhile expr '{' statementlist '}' {AST_NODE_PTR whilenode = AST_new_node(AST_While, NULL); +while: KeyWhile expr '{' statementlist '}' {AST_NODE_PTR whilenode = AST_new_node(new_loc(), AST_While, NULL); AST_push_node(whilenode, $2); AST_push_node(whilenode, $4); $$ = whilenode;}; -identlist: Ident ',' identlist {AST_NODE_PTR ident = AST_new_node(AST_Ident, $1); +identlist: Ident ',' identlist {AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1); AST_push_node($3, ident); $$ = $3;} - | Ident {AST_NODE_PTR list = AST_new_node(AST_IdentList, NULL); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $1); + | Ident {AST_NODE_PTR list = AST_new_node(new_loc(), AST_IdentList, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1); AST_push_node(list, ident); $$ = list;}; -decl: type ':' identlist {AST_NODE_PTR decl = AST_new_node(AST_Decl, NULL); +decl: type ':' identlist {AST_NODE_PTR decl = AST_new_node(new_loc(), AST_Decl, NULL); AST_push_node(decl, $1); AST_push_node(decl, $3); $$ = decl;} - | storagequalifier type ':' identlist {AST_NODE_PTR decl = AST_new_node(AST_Decl, NULL); + | storagequalifier type ':' identlist {AST_NODE_PTR decl = AST_new_node(new_loc(), AST_Decl, NULL); AST_push_node(decl, $1); AST_push_node(decl, $2); AST_push_node(decl, $4); $$ = decl;} -definition: decl '=' expr { AST_NODE_PTR def = AST_new_node(AST_Def, NULL); +definition: decl '=' expr { AST_NODE_PTR def = AST_new_node(new_loc(), AST_Def, NULL); AST_push_node(def, $1); AST_push_node(def, $3); $$ = def; DEBUG("Definition"); }; -storagequalifier: KeyGlobal {$$ = AST_new_node(AST_Storage, "global");} - | KeyStatic {$$ = AST_new_node(AST_Storage, "static");} - | KeyLocal {$$ = AST_new_node(AST_Storage, "local");}; +storagequalifier: KeyGlobal {$$ = AST_new_node(new_loc(), AST_Storage, "global");} + | KeyStatic {$$ = AST_new_node(new_loc(), AST_Storage, "static");} + | KeyLocal {$$ = AST_new_node(new_loc(), AST_Storage, "local");}; -assign: Ident '=' expr { AST_NODE_PTR assign = AST_new_node(AST_Assign, NULL); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $1); +assign: Ident '=' expr { AST_NODE_PTR assign = AST_new_node(new_loc(), AST_Assign, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1); AST_push_node(assign, ident); AST_push_node(assign, $3); $$ = assign; @@ -388,60 +390,60 @@ assign: Ident '=' expr { AST_NODE_PTR assign = AST_new_node(AST_Assign, NULL); | boxaccess '=' expr | boxselfaccess '=' expr ; -sign: KeySigned {$$ = AST_new_node(AST_Sign, "signed");} - | KeyUnsigned{$$ = AST_new_node(AST_Sign, "unsigned");}; +sign: KeySigned {$$ = AST_new_node(new_loc(), AST_Sign, "signed");} + | KeyUnsigned{$$ = AST_new_node(new_loc(), AST_Sign, "unsigned");}; -typedef: KeyType type':' Ident {AST_NODE_PTR typeDef = AST_new_node(AST_Typedef, NULL); +typedef: KeyType type':' Ident {AST_NODE_PTR typeDef = AST_new_node(new_loc(), AST_Typedef, NULL); AST_push_node(typeDef, $2); - AST_NODE_PTR ident = AST_new_node(AST_Ident, $4); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4); AST_push_node(typeDef, ident); $$ = typeDef;}; -scale: scale KeyShort {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "short"); +scale: scale KeyShort {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "short"); AST_push_node($1, shortnode); $$ = $1;} - | scale KeyHalf {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "half"); + | scale KeyHalf {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "half"); AST_push_node($1, shortnode); $$ = $1;} - | scale KeyLong {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "long"); + | scale KeyLong {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "long"); AST_push_node($1, shortnode); $$ = $1;} - | scale KeyDouble {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "double"); + | scale KeyDouble {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "double"); AST_push_node($1, shortnode); $$ = $1;} - | KeyShort {AST_NODE_PTR scale = AST_new_node(AST_List, NULL); - AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "short"); + | KeyShort {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL); + AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "short"); AST_push_node(scale, shortnode); $$ = scale;} - | KeyHalf {AST_NODE_PTR scale = AST_new_node(AST_List, NULL); - AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "half"); + | KeyHalf {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL); + AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "half"); AST_push_node(scale, shortnode); $$ = scale;} - | KeyLong {AST_NODE_PTR scale = AST_new_node(AST_List, NULL); - AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "long"); + | KeyLong {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL); + AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "long"); AST_push_node(scale, shortnode); $$ = scale;} - | KeyDouble {AST_NODE_PTR scale = AST_new_node(AST_List, NULL); - AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "double"); + | KeyDouble {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL); + AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "double"); AST_push_node(scale, shortnode); $$ = scale;}; -typekind: Ident {$$ = AST_new_node(AST_Typekind, $1);} - | KeyInt {$$ = AST_new_node(AST_Typekind, "int");} - | KeyFloat {$$ = AST_new_node(AST_Typekind, "float");}; +typekind: Ident {$$ = AST_new_node(new_loc(), AST_Typekind, $1);} + | KeyInt {$$ = AST_new_node(new_loc(), AST_Typekind, "int");} + | KeyFloat {$$ = AST_new_node(new_loc(), AST_Typekind, "float");}; -type: typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL); +type: typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL); AST_push_node(type, $1); $$ = type;} - | scale typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL); + | scale typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL); AST_push_node(type, $1); AST_push_node(type, $2); $$ = type;} - | sign typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL); + | sign typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL); AST_push_node(type, $1); AST_push_node(type, $2); $$ = type;} - | sign scale typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL); + | sign scale typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL); AST_push_node(type, $1); AST_push_node(type, $2); AST_push_node(type, $3); @@ -452,136 +454,74 @@ operation: oparith {$$ = $1;} | opbool {$$ = $1;} | opbit {$$ = $1;}; -oparith: expr '+' expr {AST_NODE_PTR add = AST_new_node(AST_Add, NULL); +oparith: expr '+' expr {AST_NODE_PTR add = AST_new_node(new_loc(), AST_Add, NULL); AST_push_node(add, $1); AST_push_node(add, $3); $$ = add;} - | expr '-' expr {AST_NODE_PTR subtract = AST_new_node(AST_Sub, NULL); + | expr '-' expr {AST_NODE_PTR subtract = AST_new_node(new_loc(), AST_Sub, NULL); AST_push_node(subtract, $1); AST_push_node(subtract, $3); $$ = subtract;} - | expr '*' expr {AST_NODE_PTR mul = AST_new_node(AST_Mul, NULL); + | expr '*' expr {AST_NODE_PTR mul = AST_new_node(new_loc(), AST_Mul, NULL); AST_push_node(mul, $1); AST_push_node(mul, $3); $$ = mul;} - | expr '/' expr {AST_NODE_PTR div = AST_new_node(AST_Div, NULL); + | expr '/' expr {AST_NODE_PTR div = AST_new_node(new_loc(), AST_Div, NULL); AST_push_node(div, $1); AST_push_node(div, $3); $$ = div;} - | '-' expr %prec '*'{AST_NODE_PTR negator = AST_new_node(AST_Negate, NULL); + | '-' expr %prec '*'{AST_NODE_PTR negator = AST_new_node(new_loc(), AST_Negate, NULL); AST_push_node(negator, $2); $$ = negator;}; -oplogic: expr OpEquals expr {AST_NODE_PTR equals = AST_new_node(AST_Eq, NULL); +oplogic: expr OpEquals expr {AST_NODE_PTR equals = AST_new_node(new_loc(), AST_Eq, NULL); AST_push_node(equals, $1); AST_push_node(equals, $3); $$ = equals;} - | expr '<' expr {AST_NODE_PTR less = AST_new_node(AST_Less, NULL); + | expr '<' expr {AST_NODE_PTR less = AST_new_node(new_loc(), AST_Less, NULL); AST_push_node(less, $1); AST_push_node(less, $3); $$ = less;} - | expr '>' expr{AST_NODE_PTR greater = AST_new_node(AST_Greater, NULL); + | expr '>' expr{AST_NODE_PTR greater = AST_new_node(new_loc(), AST_Greater, NULL); AST_push_node(greater, $1); AST_push_node(greater, $3); $$ = greater;}; -opbool: expr OpAnd expr {AST_NODE_PTR and = AST_new_node(AST_BoolAnd, NULL); +opbool: expr OpAnd expr {AST_NODE_PTR and = AST_new_node(new_loc(), AST_BoolAnd, NULL); AST_push_node(and, $1); AST_push_node(and, $3); $$ = and;} - | expr OpOr expr{AST_NODE_PTR or = AST_new_node(AST_BoolOr, NULL); + | expr OpOr expr{AST_NODE_PTR or = AST_new_node(new_loc(), AST_BoolOr, NULL); AST_push_node(or, $1); AST_push_node(or, $3); $$ = or;} - | expr OpXor expr{AST_NODE_PTR xor = AST_new_node(AST_BoolXor, NULL); + | expr OpXor expr{AST_NODE_PTR xor = AST_new_node(new_loc(), AST_BoolXor, NULL); AST_push_node(xor, $1); AST_push_node(xor, $3); $$ = xor;} - | OpNot expr %prec OpAnd{AST_NODE_PTR not = AST_new_node(AST_BoolNot, NULL); + | OpNot expr %prec OpAnd{AST_NODE_PTR not = AST_new_node(new_loc(), AST_BoolNot, NULL); AST_push_node(not, $2); $$ = not;}; -opbit: expr OpBitand expr {AST_NODE_PTR and = AST_new_node(AST_BitAnd, NULL); +opbit: expr OpBitand expr {AST_NODE_PTR and = AST_new_node(new_loc(), AST_BitAnd, NULL); AST_push_node(and, $1); AST_push_node(and, $3); $$ = and;} - | expr OpBitor expr{AST_NODE_PTR or = AST_new_node(AST_BitOr, NULL); + | expr OpBitor expr{AST_NODE_PTR or = AST_new_node(new_loc(), AST_BitOr, NULL); AST_push_node(or, $1); AST_push_node(or, $3); $$ = or;} - | expr OpBitxor expr{AST_NODE_PTR xor = AST_new_node(AST_BitXor, NULL); + | expr OpBitxor expr{AST_NODE_PTR xor = AST_new_node(new_loc(), AST_BitXor, NULL); AST_push_node(xor, $1); AST_push_node(xor, $3); $$ = xor;} - | OpBitnot expr %prec OpBitand{AST_NODE_PTR not = AST_new_node(AST_BitNot, NULL); + | OpBitnot expr %prec OpBitand{AST_NODE_PTR not = AST_new_node(new_loc(), AST_BitNot, NULL); AST_push_node(not, $2); $$ = not;}; %% - -const char* ERROR = "error"; -const char* WARNING = "warning"; -const char* NOTE = "note"; - -int print_message(const char* kind, const char* message) { - // number of characters written - int char_count = 0; - // highlight to use - char* HIGHLIGHT = CYAN; - - // convert message kind into color - if (kind == ERROR) { - HIGHLIGHT = RED; - } else if (kind == WARNING) { - HIGHLIGHT = YELLOW; - } - - // print message - char_count += printf("%sfilename:%d:%d%s:%s%s %s: %s%s\n", BOLD, yylloc.first_line, yylloc.first_column, RESET, HIGHLIGHT, BOLD, kind, RESET, message); - - // print line in which error occurred - - char_count += printf(" %4d | ", yylloc.first_line); - - for (int i = 0; i < yylloc.first_column - 1; i++) { - if (buffer[i] == '\n') { - break; - } - printf("%c", buffer[i]); - } - - char_count += printf("%s%s", BOLD, HIGHLIGHT); - - for (int i = yylloc.first_column - 1; i < yylloc.last_column; i++) { - if (buffer[i] == '\n') { - break; - } - char_count += printf("%c", buffer[i]); - } - - char_count += printf("%s", RESET); - - for (int i = yylloc.last_column; buffer[i] != '\0' && buffer[i] != '\n'; i++) { - printf("%c", buffer[i]); - } - - char_count += printf("\n | "); - - for (int i = 0; i < yylloc.first_column - 1; i++) { - char_count += printf(" "); - } - - char_count += printf("%s^", HIGHLIGHT); - - for (int i = 0; i < yylloc.last_column - yylloc.first_column; i++) { - printf("~"); - } - - char_count += printf("%s\n\n", RESET); - - return char_count; -} - int yyerror(const char *s) { - return print_message(ERROR, s); + TokenLocation location = new_loc(); + print_diagnostic(current_file, &location, Error, s); + return 0; } \ No newline at end of file