Browse Source

improved preprocessor errors

Kajetan Johannes Hammerle 1 year ago
parent
commit
cf386ff6a8

+ 20 - 3
Error.c

@@ -1,23 +1,40 @@
 #include <stdarg.h>
 #include <stdio.h>
+#include <string.h>
 
 #include "Error.h"
 
-void eInitError(Error* e, int line, const char* format, ...) {
+void eInitError(Error* e, const char* path, int line, const char* format, ...) {
     va_list args;
     va_start(args, format);
-    eInitErrorV(e, line, format, args);
+    eInitErrorV(e, path, line, format, args);
     va_end(args);
 }
 
-void eInitErrorV(Error* e, int line, const char* format, va_list ap) {
+void eInitErrorV(Error* e, const char* path, int line, const char* format,
+                 va_list ap) {
     e->line = line;
     vsnprintf(e->message, sizeof(e->message), format, ap);
+    snprintf(e->paths, sizeof(e->paths), "%s", path);
 }
 
 void eInitSuccess(Error* e) {
     e->line = -1;
     e->message[0] = '\0';
+    e->paths[0] = '\0';
+}
+
+void eAddPath(Error* e, const char* path) {
+    char buffer[sizeof(e->paths)];
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-truncation"
+    if(e->paths[0] == '\0') {
+        snprintf(buffer, sizeof(buffer), "%s", path);
+    } else {
+        snprintf(buffer, sizeof(buffer), "%s -> %s", path, e->paths);
+    }
+#pragma GCC diagnostic pop
+    memcpy(e->paths, buffer, sizeof(buffer));
 }
 
 bool eHasError(const Error* e) {

+ 5 - 2
Error.h

@@ -11,11 +11,14 @@ extern "C" {
 typedef struct Error {
     int line;
     char message[256];
+    char paths[256];
 } Error;
 
-void eInitError(Error* e, int line, const char* format, ...);
-void eInitErrorV(Error* e, int line, const char* format, va_list ap);
+void eInitError(Error* e, const char* path, int line, const char* format, ...);
+void eInitErrorV(Error* e, const char* path, int line, const char* format,
+                 va_list ap);
 void eInitSuccess(Error* e);
+void eAddPath(Error* e, const char* path);
 bool eHasError(const Error* e);
 
 #ifdef __cplusplus

+ 2 - 0
Main.c

@@ -25,12 +25,14 @@ static void start(int argAmount, const char** args) {
         if(eHasError(&e)) {
             puts(e.message);
             printf("line: %d\n", e.line);
+            printf("path: %s\n", e.paths);
             return;
         }
         ByteCode* code = cCompile();
         if(code == NULL) {
             puts(cGetError());
             printf("line: %d\n", cGetLine());
+            printf("path: %s\n", e.paths);
             return;
         }
         Script* sc = sInit(code);

+ 0 - 1
tests/another

@@ -1 +0,0 @@
-// another

+ 2 - 0
tests/includes/another

@@ -0,0 +1,2 @@
+// another
+//#define +

+ 0 - 0
tests/another.out → tests/includes/another.out


+ 1 - 1
tests/other → tests/includes/other

@@ -4,7 +4,7 @@
 #include "another"
 
 void wusi(int a) {
-    test(a);
+    //test(a);
 }
 
 #ifndef WUSI

+ 0 - 0
tests/other.out → tests/includes/other.out


+ 0 - 0
tests/includes/yet_another


+ 0 - 0
tests/includes/yet_another.out


+ 5 - 4
tests/test

@@ -1,7 +1,8 @@
-#include "other"
-#include "other"
-#include "other"
-#include "other"
+#include "includes/yet_another"
+#include "includes/other"
+#include "includes/other"
+#include "includes/other"
+#include "includes/other"
 
 void main() {
     int a = 5;

+ 85 - 40
tokenizer/FileTokens.c

@@ -7,7 +7,6 @@
 #include "utils/SnuviUtils.h"
 
 static Error* error;
-static int line = 0;
 
 typedef char String[64];
 #define STRING_LENGTH ((int)sizeof(String))
@@ -20,16 +19,67 @@ typedef struct {
 static Define defines[DEFINES];
 static int defineIndex = 0;
 
-static const char* ftGetPath(const FileTokens* ft) {
-    if(ft->length < 1 || ft->tokens[0].type != FT_PATH) {
-        eInitError(error, line, "path not set");
-        return "";
+static int ftGetLine(const FileTokens* ft, int index) {
+    int fileLayer = 0;
+    int lines = 1;
+    for(int i = index; i >= 0; i--) {
+        FileToken* t = ft->tokens + i;
+        if(t->type == FT_PATH) {
+            if(fileLayer == 0) {
+                return lines;
+            }
+            fileLayer--;
+        } else if(t->type == FT_END_PATH) {
+            fileLayer++;
+        } else if(t->type == FT_NEWLINE) {
+            lines += fileLayer == 0;
+        }
+    }
+    return 0;
+}
+
+static const char* ftGetPath(const FileTokens* ft, int index) {
+    int fileLayer = 0;
+    for(int i = index; i >= 0; i--) {
+        FileToken* t = ft->tokens + i;
+        if(t->type == FT_PATH) {
+            if(fileLayer == 0) {
+                return t->literal;
+            }
+            fileLayer--;
+        } else if(t->type == FT_END_PATH) {
+            fileLayer++;
+        }
     }
-    return ft->tokens[0].literal;
+    return "unknown path";
+}
+
+static void ftError(const FileTokens* ft, int index, const char* format, ...) {
+    va_list args;
+    va_start(args, format);
+    eInitErrorV(error, "", ftGetLine(ft, index), format, args);
+
+    int fileLayer = 0;
+    for(int i = index; i >= 0; i--) {
+        FileToken* t = ft->tokens + i;
+        if(t->type == FT_PATH) {
+            if(fileLayer == 0) {
+                eAddPath(error, t->literal);
+            } else {
+                fileLayer--;
+            }
+        } else if(t->type == FT_END_PATH) {
+            fileLayer++;
+        }
+    }
+
+    va_end(args);
 }
 
-static void ftSystemError(const char* msg, const FileTokens* ft) {
-    eInitError(error, line, "%s '%s': %s", msg, ftGetPath(ft), strerror(errno));
+static void ftSystemError(const char* msg, const FileTokens* parent,
+                          const FileTokens* ft, int index) {
+    ftError(parent, index, "%s '%s': %s", msg, ftGetPath(ft, 0),
+            strerror(errno));
 }
 
 static void ftToSpace(FileToken* t) {
@@ -77,7 +127,7 @@ static void ftAddSpace(FileTokens* ft) {
     ftAddToken(ft, FT_SPACE);
 }
 
-static void ftPrint(FileTokens* ft) {
+void ftPrint(FileTokens* ft) {
     for(int i = 0; i < ft->length; i++) {
         switch(ft->tokens[i].type) {
             case FT_PATH:
@@ -116,7 +166,6 @@ static void ftTokenize(FileTokens* ft, unsigned char* data) {
     int index = 0;
     int oldIndex = 0;
     bool inString = false;
-    int line = 1;
     while(true) {
         unsigned char c = data[index];
         if(isAllowedInName(c) || (inString && c != '"' && c != '\0')) {
@@ -132,7 +181,6 @@ static void ftTokenize(FileTokens* ft, unsigned char* data) {
         if(c == '\0') {
             break;
         } else if(c == '\n') {
-            line++;
             ftAddNewline(ft);
         } else if(c == ' ') {
             ftAddSpace(ft);
@@ -142,15 +190,14 @@ static void ftTokenize(FileTokens* ft, unsigned char* data) {
             }
             ftAddNewline(ft);
         } else if(c == '/' && data[index + 1] == '*') {
-            int startLine = line;
+            int startIndex = ft->length - 1;
             index += 2;
             while(true) {
                 if(data[index] == '\0') {
-                    eInitError(error, startLine, "unclosed multiline comment");
+                    ftError(ft, startIndex, "test");
                     return;
                 } else if(data[index] == '\n') {
                     ftAddNewline(ft);
-                    line++;
                 } else if(data[index] == '*' && data[index + 1] == '/') {
                     index++;
                     break;
@@ -165,14 +212,15 @@ static void ftTokenize(FileTokens* ft, unsigned char* data) {
     }
 }
 
-static void ftReadFull(FILE* file, FileTokens* ft) {
+static void ftReadFull(FILE* file, FileTokens* parent, FileTokens* ft,
+                       int index) {
     if(fseek(file, 0, SEEK_END)) {
-        ftSystemError("cannot seek end of file", ft);
+        ftSystemError("cannot seek end of file", parent, ft, index);
         return;
     }
     long length = ftell(file);
     if(length < 0) {
-        ftSystemError("cannot tell end of file", ft);
+        ftSystemError("cannot tell end of file", parent, ft, index);
         return;
     }
     rewind(file);
@@ -180,7 +228,7 @@ static void ftReadFull(FILE* file, FileTokens* ft) {
     unsigned char* data = malloc(length + 1);
     int readValues = fread(data, 1, length, file);
     if(readValues != length) {
-        ftSystemError("cannot read file", ft);
+        ftSystemError("cannot read file", parent, ft, index);
         free(data);
         return;
     }
@@ -190,15 +238,15 @@ static void ftReadFull(FILE* file, FileTokens* ft) {
     free(data);
 }
 
-static void ftReadFullFile(FileTokens* ft) {
-    FILE* file = fopen(ftGetPath(ft), "r");
+static void ftReadFullFile(FileTokens* parent, FileTokens* ft, int index) {
+    FILE* file = fopen(ftGetPath(ft, 0), "r");
     if(file == NULL) {
-        ftSystemError("cannot open file", ft);
+        ftSystemError("cannot open file", parent, ft, index);
         return;
     }
-    ftReadFull(file, ft);
+    ftReadFull(file, parent, ft, index);
     if(fclose(file) < 0) {
-        ftSystemError("cannot close file", ft);
+        ftSystemError("cannot close file", parent, ft, index);
     }
 }
 
@@ -245,7 +293,7 @@ const char* INCLUDE_ERROR = "include path must be a string";
 static bool ftIncludeDoubleQuote(int* index, FileTokens* ft) {
     if(*index >= ft->length || ft->tokens[*index].type != FT_SINGLE ||
        ft->tokens[*index].single != '"') {
-        eInitError(error, line, INCLUDE_ERROR);
+        ftError(ft, *index - 1, INCLUDE_ERROR);
         return true;
     }
     (*index)++;
@@ -258,14 +306,14 @@ static void ftHandleInclude(int* index, int start, FileTokens* ft) {
         return;
     }
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        eInitError(error, line, INCLUDE_ERROR);
+        ftError(ft, *index - 1, INCLUDE_ERROR);
         return;
     }
     const char* path = ft->tokens[(*index)++].literal;
     if(ftIncludeDoubleQuote(index, ft)) {
         return;
     }
-    const char* parentPath = ftGetPath(ft);
+    const char* parentPath = ftGetPath(ft, *index - 1);
 
     int afterLastSlash = 0;
     for(int i = 0; parentPath[i] != '\0'; i++) {
@@ -281,7 +329,7 @@ static void ftHandleInclude(int* index, int start, FileTokens* ft) {
     ftInitFileTokens(&include, fullPath);
     free(fullPath);
 
-    ftReadFullFile(&include);
+    ftReadFullFile(ft, &include, *index - 1);
     if(!ftHasError()) {
         ftReplace(start, *index, ft, &include);
         *index = start;
@@ -319,16 +367,15 @@ static int ftFindEndIf(int from, FileTokens* ft) {
 }
 
 static void ftHandleIfNotDefined(int* index, int start, FileTokens* ft) {
-    (void)start;
     ftSkipSpaces(index, ft);
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        eInitError(error, line, "ifndef expects a literal");
+        ftError(ft, start, "ifndef expects a literal");
         return;
     }
     const char* check = ft->tokens[(*index)++].literal;
     int endIf = ftFindEndIf(*index, ft);
     if(endIf == -1) {
-        eInitError(error, line, "cannot find #endif");
+        ftError(ft, start, "cannot find #endif");
         return;
     }
     if(ftIsDefined(check)) {
@@ -345,14 +392,14 @@ static void ftHandleIfNotDefined(int* index, int start, FileTokens* ft) {
     }
 }
 
-static void frHandleDefine(int* index, int start, FileTokens* ft) {
+static void ftHandleDefine(int* index, int start, FileTokens* ft) {
     if(defineIndex >= DEFINES) {
-        eInitError(error, line, "too much defines");
+        ftError(ft, *index - 1, "too much defines");
         return;
     }
     ftSkipSpaces(index, ft);
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        eInitError(error, line, "define expects a literal");
+        ftError(ft, *index - 1, "define expects a literal");
         return;
     }
     const char* define = ft->tokens[(*index)++].literal;
@@ -371,7 +418,7 @@ static void ftParseInstruction(int* index, FileTokens* ft) {
     int start = *index;
     (*index)++;
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        eInitError(error, line, "expected literal after #");
+        ftError(ft, *index - 1, "expected literal after #");
         return;
     }
     const char* name = ft->tokens[(*index)++].literal;
@@ -380,11 +427,11 @@ static void ftParseInstruction(int* index, FileTokens* ft) {
     } else if(ftStringCompare(name, "ifndef")) {
         ftHandleIfNotDefined(index, start, ft);
     } else if(ftStringCompare(name, "define")) {
-        frHandleDefine(index, start, ft);
+        ftHandleDefine(index, start, ft);
     } else if(ftStringCompare(name, "endif")) {
-        eInitError(error, line, "endif without if");
+        ftError(ft, *index - 1, "endif without if");
     } else {
-        eInitError(error, line, "unknown preprocessor literal '%s'", name);
+        ftError(ft, *index - 1, "unknown preprocessor literal '%s'", name);
     }
 }
 
@@ -401,12 +448,10 @@ void ftInit(const char* path, FileTokens* ft, Error* e) {
     error = e;
     eInitSuccess(error);
     ftInitFileTokens(ft, path);
-    ftReadFullFile(ft);
+    ftReadFullFile(ft, ft, 0);
     if(!ftHasError()) {
         ftSearchInstruction(ft);
     }
-    (void)ftPrint;
-    // ftPrint(ft);
 }
 
 void ftDelete(FileTokens* ft) {

+ 2 - 0
tokenizer/FileTokens.h

@@ -31,6 +31,8 @@ typedef struct {
 void ftInit(const char* path, FileTokens* ft, Error* e);
 void ftDelete(FileTokens* ft);
 
+void ftPrint(FileTokens* ft);
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
tokenizer/Tokenizer.c

@@ -26,7 +26,7 @@ static int16 line = 1;
 static void tError(const char* format, ...) {
     va_list args;
     va_start(args, format);
-    eInitErrorV(error, line, format, args);
+    eInitErrorV(error, "path not set", line, format, args);
     va_end(args);
     longjmp(errorJump, 0);
 }