|
@@ -5,16 +5,50 @@
|
|
|
|
|
|
#include "tokenizer/FileReader.h"
|
|
|
|
|
|
-static void frFullRead(FILE* file, const char* path, FileReader* fr, Error* e) {
|
|
|
+typedef char String[64];
|
|
|
+#define STRING_LENGTH ((int)sizeof(String))
|
|
|
+
|
|
|
+#define END_IF "#endif"
|
|
|
+#define END_IF_LENGTH ((int)sizeof(END_IF) - 1)
|
|
|
+
|
|
|
+static Error* error;
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ String name;
|
|
|
+} Define;
|
|
|
+
|
|
|
+#define DEFINES 256
|
|
|
+static Define defines[DEFINES];
|
|
|
+static int defineIndex = 0;
|
|
|
+
|
|
|
+static bool frHasError() {
|
|
|
+ return error->message[0] != '\0';
|
|
|
+}
|
|
|
+
|
|
|
+static bool frStringCompare(const String a, const char* b) {
|
|
|
+ return strcmp(a, b) == 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void frInitFileReader(FileReader* fr, const char* path) {
|
|
|
+ fr->data = NULL;
|
|
|
+ fr->path = path;
|
|
|
+ fr->length = 0;
|
|
|
+ fr->readIndex = 0;
|
|
|
+ fr->line = 1;
|
|
|
+}
|
|
|
+
|
|
|
+static void frSystemError(const char* msg, FileReader* fr) {
|
|
|
+ eInitError(error, fr->line, "%s '%s': %s", msg, fr->path, strerror(errno));
|
|
|
+}
|
|
|
+
|
|
|
+static void frFullRead(FILE* file, FileReader* fr) {
|
|
|
if(fseek(file, 0, SEEK_END)) {
|
|
|
- eInitError(e, 1, "cannot seek end of file '%s': %s", path,
|
|
|
- strerror(errno));
|
|
|
+ frSystemError("cannot seek end of file", fr);
|
|
|
return;
|
|
|
}
|
|
|
long length = ftell(file);
|
|
|
if(length < 0) {
|
|
|
- eInitError(e, 1, "cannot tell end of file '%s': %s", path,
|
|
|
- strerror(errno));
|
|
|
+ frSystemError("cannot tell end of file", fr);
|
|
|
return;
|
|
|
}
|
|
|
rewind(file);
|
|
@@ -22,31 +56,234 @@ static void frFullRead(FILE* file, const char* path, FileReader* fr, Error* e) {
|
|
|
fr->length = length;
|
|
|
int readValues = fread(fr->data, 1, length, file);
|
|
|
if(readValues != length) {
|
|
|
- eInitError(e, 1, "cannot read file '%s': %s", path, strerror(errno));
|
|
|
+ frSystemError("cannot read file", fr);
|
|
|
fr->data[0] = '\0';
|
|
|
+ fr->length = 0;
|
|
|
return;
|
|
|
}
|
|
|
fr->data[length] = '\0';
|
|
|
- eInitSuccess(e);
|
|
|
}
|
|
|
|
|
|
-void frInit(const char* path, FileReader* fr, Error* e) {
|
|
|
- fr->data = NULL;
|
|
|
- fr->length = 0;
|
|
|
- fr->readIndex = 0;
|
|
|
-
|
|
|
- FILE* file = fopen(path, "r");
|
|
|
+static void frFullReadFile(FileReader* fr) {
|
|
|
+ FILE* file = fopen(fr->path, "r");
|
|
|
if(file == NULL) {
|
|
|
- eInitError(e, 1, "cannot open file '%s': %s", path, strerror(errno));
|
|
|
+ frSystemError("cannot open file", fr);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ frFullRead(file, fr);
|
|
|
+}
|
|
|
+
|
|
|
+static int frReadUntil(int from, char end, String s, FileReader* fr) {
|
|
|
+ int index = 0;
|
|
|
+ while(from < fr->length && index < STRING_LENGTH - 1 &&
|
|
|
+ fr->data[from] != end) {
|
|
|
+ s[index++] = fr->data[from];
|
|
|
+ from++;
|
|
|
+ }
|
|
|
+ s[index] = '\0';
|
|
|
+ return index;
|
|
|
+}
|
|
|
+
|
|
|
+static int frReadUntilOrLine(int from, char end, String s, FileReader* fr) {
|
|
|
+ int index = 0;
|
|
|
+ while(from < fr->length && index < STRING_LENGTH - 1 &&
|
|
|
+ fr->data[from] != end && fr->data[from] != '\n') {
|
|
|
+ s[index++] = fr->data[from];
|
|
|
+ from++;
|
|
|
+ }
|
|
|
+ s[index] = '\0';
|
|
|
+ return index;
|
|
|
+}
|
|
|
+
|
|
|
+static void frMakePath(String fullPath, const char* parent, String name) {
|
|
|
+ int i = 0;
|
|
|
+ int lastSlash = 0;
|
|
|
+ while(i < STRING_LENGTH - 1 && parent[i] != '\0') {
|
|
|
+ fullPath[i] = parent[i];
|
|
|
+ lastSlash = parent[i] == '/' ? i : lastSlash;
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ i = lastSlash + 1;
|
|
|
+ int nameI = 0;
|
|
|
+ while(i < STRING_LENGTH - 1 && name[nameI] != '\0') {
|
|
|
+ fullPath[i] = name[nameI];
|
|
|
+ i++;
|
|
|
+ nameI++;
|
|
|
+ }
|
|
|
+ fullPath[i] = '\0';
|
|
|
+}
|
|
|
+
|
|
|
+static void frReplace(int from, int to, FileReader* fr,
|
|
|
+ FileReader* replacement) {
|
|
|
+ int replaceLength = replacement->length - 1;
|
|
|
+ replaceLength = replaceLength < 0 ? 0 : replaceLength;
|
|
|
+ int newLength = fr->length + replaceLength - (to - from);
|
|
|
+ unsigned char* newData = malloc(newLength + 1);
|
|
|
+ memcpy(newData, fr->data, from);
|
|
|
+ memcpy(newData + from, replacement->data, replaceLength);
|
|
|
+ memcpy(newData + from + replaceLength, fr->data + to, fr->length - to);
|
|
|
+ newData[newLength] = '\0';
|
|
|
+
|
|
|
+ free(fr->data);
|
|
|
+ fr->data = newData;
|
|
|
+ fr->length = newLength;
|
|
|
+}
|
|
|
+
|
|
|
+static int skipSpaces(int index, FileReader* fr) {
|
|
|
+ while(index < fr->length && fr->data[index] == ' ') {
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+ return index;
|
|
|
+}
|
|
|
+
|
|
|
+static void frHandleInclude(int from, int length, FileReader* fr) {
|
|
|
+ int index = from + length;
|
|
|
+ index = skipSpaces(index, fr);
|
|
|
+ if(index >= fr->length || fr->data[index] != '"') {
|
|
|
+ eInitError(error, fr->line, "expected '\"' and not '%c' in '%s'",
|
|
|
+ fr->data[index], fr->path);
|
|
|
return;
|
|
|
}
|
|
|
- frFullRead(file, path, fr, e);
|
|
|
- fclose(file);
|
|
|
+ index++;
|
|
|
+ String s;
|
|
|
+ int pathLength = frReadUntil(index, '"', s, fr) + 1;
|
|
|
+
|
|
|
+ String fullPath;
|
|
|
+ frMakePath(fullPath, fr->path, s);
|
|
|
+
|
|
|
+ FileReader include;
|
|
|
+ frInitFileReader(&include, fullPath);
|
|
|
+ frFullReadFile(&include);
|
|
|
+ if(frHasError()) {
|
|
|
+ frDelete(&include);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ frReplace(from, index + pathLength, fr, &include);
|
|
|
+ frDelete(&include);
|
|
|
+}
|
|
|
+
|
|
|
+static int frReadWord(String s, int from, FileReader* fr) {
|
|
|
+ int index = skipSpaces(from, fr);
|
|
|
+ int wordLength = frReadUntilOrLine(index, ' ', s, fr);
|
|
|
+ return index + wordLength;
|
|
|
+}
|
|
|
+
|
|
|
+static bool frIsDefined(String s) {
|
|
|
+ for(int i = 0; i < defineIndex; i++) {
|
|
|
+ if(frStringCompare(defines[i].name, s)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static bool frIsMatching(int from, FileReader* fr, const char* s) {
|
|
|
+ int i = 0;
|
|
|
+ while(true) {
|
|
|
+ if(s[i] == '\0') {
|
|
|
+ return true;
|
|
|
+ } else if(from >= fr->length || fr->data[from] != s[i]) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ from++;
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int frFindEndIf(int from, FileReader* fr) {
|
|
|
+ int layer = 0;
|
|
|
+ for(int i = from; i < fr->length; i++) {
|
|
|
+ if(frIsMatching(i, fr, END_IF)) {
|
|
|
+ if(layer == 0) {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ layer--;
|
|
|
+ } else if(frIsMatching(i, fr, "#ifndef")) {
|
|
|
+ layer++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static void frHandleIfNotDefined(int from, int length, FileReader* fr) {
|
|
|
+ String s;
|
|
|
+ int end = frReadWord(s, from + length, fr);
|
|
|
+ int endIf = frFindEndIf(end, fr);
|
|
|
+ if(endIf == -1) {
|
|
|
+ eInitError(error, fr->line, "cannot find #endif in '%s'", fr->path);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(frIsDefined(s)) {
|
|
|
+ memset(fr->data + from, ' ', endIf - from + END_IF_LENGTH);
|
|
|
+ } else {
|
|
|
+ memset(fr->data + from, ' ', end - from);
|
|
|
+ memset(fr->data + endIf, ' ', END_IF_LENGTH);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void frHandleDefine(int from, int length, FileReader* fr) {
|
|
|
+ if(defineIndex >= DEFINES) {
|
|
|
+ eInitError(error, fr->line, "too much defines in '%s'", fr->path);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String s;
|
|
|
+ int end = frReadWord(s, from + length, fr);
|
|
|
+ if(frIsDefined(s)) {
|
|
|
+ puts("already defined");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ strncpy(defines[defineIndex].name, s, STRING_LENGTH);
|
|
|
+ defineIndex++;
|
|
|
+ printf("defined '%s'\n", s);
|
|
|
+ memset(fr->data + from, ' ', end - from);
|
|
|
+}
|
|
|
+
|
|
|
+static void frParseInstruction(int from, FileReader* fr) {
|
|
|
+ String s;
|
|
|
+ int length = frReadUntil(from, ' ', s, fr);
|
|
|
+ if(frStringCompare(s, "#include")) {
|
|
|
+ frHandleInclude(from, length, fr);
|
|
|
+ } else if(frStringCompare(s, "#ifndef")) {
|
|
|
+ frHandleIfNotDefined(from, length, fr);
|
|
|
+ } else if(frStringCompare(s, "#define")) {
|
|
|
+ frHandleDefine(from, length, fr);
|
|
|
+ } else {
|
|
|
+ eInitError(error, fr->line, "unknown preprocessor token '%s' in '%s'",
|
|
|
+ s, fr->path);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void frSearchInstruction(FileReader* fr) {
|
|
|
+ if(fr->data == NULL) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for(int i = 0; i < fr->length && !frHasError(); i++) {
|
|
|
+ unsigned char c = fr->data[i];
|
|
|
+ if(c == '#') {
|
|
|
+ frParseInstruction(i, fr);
|
|
|
+ i--;
|
|
|
+ } else if(c == '\n') {
|
|
|
+ fr->line++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void frInit(const char* path, FileReader* fr, Error* e) {
|
|
|
+ defineIndex = 0;
|
|
|
+ error = e;
|
|
|
+ eInitSuccess(error);
|
|
|
+ frInitFileReader(fr, path);
|
|
|
+ frFullReadFile(fr);
|
|
|
+ frSearchInstruction(fr);
|
|
|
+ if(fr->data != NULL) {
|
|
|
+ printf((char*)fr->data);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void frDelete(FileReader* fr) {
|
|
|
free(fr->data);
|
|
|
fr->data = NULL;
|
|
|
+ fr->path = NULL;
|
|
|
fr->length = 0;
|
|
|
fr->readIndex = 0;
|
|
|
}
|