|
@@ -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) {
|