|
@@ -5,157 +5,246 @@
|
|
|
#include "tokenizer/File.h"
|
|
|
#include "utils/Utils.h"
|
|
|
|
|
|
-#define MAX_DEFINES 50
|
|
|
+#define MAX_INDEX 50
|
|
|
|
|
|
-static FileError fileError = NULL;
|
|
|
-static FILE* file = NULL;
|
|
|
-static int readIndex = 0;
|
|
|
-static int writeIndex = 0;
|
|
|
-static int fileSize = 0;
|
|
|
-static char* fileContent = NULL;
|
|
|
+typedef struct {
|
|
|
+ char* content;
|
|
|
+ int size;
|
|
|
+ int index;
|
|
|
+ int arrayIndex;
|
|
|
+ FILE* file;
|
|
|
+} OpenFile;
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ int fileIndex;
|
|
|
+ int index;
|
|
|
+} FilePointer;
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ FilePointer name;
|
|
|
+ FilePointer code;
|
|
|
+} Define;
|
|
|
|
|
|
typedef struct {
|
|
|
- int nameLength;
|
|
|
- const char* name;
|
|
|
- const char* code;
|
|
|
-} Defines;
|
|
|
-
|
|
|
-static int defineIndex = 0;
|
|
|
-static Defines defines[MAX_DEFINES];
|
|
|
-static int defineReadIndex = 0;
|
|
|
-static const char* defineCode = NULL;
|
|
|
-
|
|
|
-static void fAdd(int c) {
|
|
|
- if(writeIndex >= fileSize) {
|
|
|
- fileSize *= 2;
|
|
|
- fileContent = realloc(fileContent, fileSize);
|
|
|
+ int fileIndex;
|
|
|
+ int defineIndex;
|
|
|
+ OpenFile files[MAX_INDEX];
|
|
|
+ Define defines[MAX_INDEX];
|
|
|
+ FilePointer readIndex;
|
|
|
+ FileError error;
|
|
|
+} OpenFiles;
|
|
|
+
|
|
|
+static OpenFiles files;
|
|
|
+static int lastChar = 0;
|
|
|
+static int stackIndex = 0;
|
|
|
+static FilePointer stack[MAX_INDEX];
|
|
|
+
|
|
|
+static void fAdd(OpenFile* of, const void* data, int size) {
|
|
|
+ while(of->index + size > of->size) {
|
|
|
+ of->size *= 2;
|
|
|
+ of->content = realloc(of->content, of->size);
|
|
|
}
|
|
|
- fileContent[writeIndex++] = c;
|
|
|
+ memcpy(of->content + of->index, data, size);
|
|
|
+ of->index += size;
|
|
|
}
|
|
|
|
|
|
-static void fReset() {
|
|
|
- readIndex = 0;
|
|
|
- writeIndex = 0;
|
|
|
- fileSize = 16;
|
|
|
- fileContent = malloc(fileSize);
|
|
|
- defineIndex = 0;
|
|
|
- defineReadIndex = 0;
|
|
|
- defineCode = NULL;
|
|
|
+static void fAddChar(OpenFile* of, int ic) {
|
|
|
+ char c = ic;
|
|
|
+ fAdd(of, &c, 1);
|
|
|
}
|
|
|
|
|
|
-void fOpen(const char* path, FileError fe) {
|
|
|
- fileError = fe;
|
|
|
- file = fopen(path, "r");
|
|
|
- if(file == NULL) {
|
|
|
- fileError("cannot read file '%s'", path);
|
|
|
- return;
|
|
|
+static int fReserverInt(OpenFile* of) {
|
|
|
+ int address = of->index;
|
|
|
+ int empty = 0x40404040;
|
|
|
+ fAdd(of, &empty, sizeof(int));
|
|
|
+ return address;
|
|
|
+}
|
|
|
+
|
|
|
+static void fSetInt(OpenFile* of, int address, int i) {
|
|
|
+ memcpy(of->content + address, &i, sizeof(int));
|
|
|
+}
|
|
|
+
|
|
|
+static int fReadInt(OpenFile* of, int address) {
|
|
|
+ int i = 0;
|
|
|
+ memcpy(&i, of->content + address, sizeof(int));
|
|
|
+ of->index += sizeof(int);
|
|
|
+ return i;
|
|
|
+}
|
|
|
+
|
|
|
+static int fGet(OpenFile* of) {
|
|
|
+ return fgetc(of->file);
|
|
|
+}
|
|
|
+
|
|
|
+static void fReadCommandString(OpenFile* of, char* buffer, int size) {
|
|
|
+ int index = 0;
|
|
|
+ int c = fGet(of);
|
|
|
+ while(c == ' ') {
|
|
|
+ c = fGet(of);
|
|
|
}
|
|
|
- fReset();
|
|
|
while(true) {
|
|
|
- int c = fgetc(file);
|
|
|
- if(c == '#') {
|
|
|
- while(c != EOF && c != '\n') {
|
|
|
- fAdd(c);
|
|
|
- c = fgetc(file);
|
|
|
- }
|
|
|
- fAdd('\0');
|
|
|
- }
|
|
|
- fAdd(c);
|
|
|
if(c == EOF) {
|
|
|
+ files.error("unexpected end of file");
|
|
|
+ } else if(index >= size - 1) {
|
|
|
+ files.error("unknown too long command");
|
|
|
+ } else if(isLetter(c)) {
|
|
|
+ buffer[index++] = c;
|
|
|
+ } else if(c == ' ') {
|
|
|
break;
|
|
|
+ } else {
|
|
|
+ files.error("unexpected character '%c'", (char)c);
|
|
|
}
|
|
|
+ c = fGet(of);
|
|
|
}
|
|
|
- fAdd('\0');
|
|
|
- fclose(file);
|
|
|
+ buffer[index] = '\0';
|
|
|
}
|
|
|
|
|
|
-void fClose() {
|
|
|
- free(fileContent);
|
|
|
+static void fDefine(OpenFile* of) {
|
|
|
+ if(files.defineIndex >= MAX_INDEX) {
|
|
|
+ files.error("too many defines");
|
|
|
+ }
|
|
|
+ Define* d = files.defines + files.defineIndex++;
|
|
|
+
|
|
|
+ fAddChar(of, '#');
|
|
|
+ int end = fReserverInt(of);
|
|
|
+
|
|
|
+ char command[64];
|
|
|
+ fReadCommandString(of, command, 64);
|
|
|
+ d->name.fileIndex = of->arrayIndex;
|
|
|
+ d->name.index = of->index;
|
|
|
+ fAdd(of, command, strlen(command) + 1);
|
|
|
+
|
|
|
+ d->code.fileIndex = of->arrayIndex;
|
|
|
+ d->code.index = of->index;
|
|
|
+ while(true) {
|
|
|
+ int c = fGet(of);
|
|
|
+ if(c == EOF || c == '\n') {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ fAddChar(of, c);
|
|
|
+ }
|
|
|
+ fAddChar(of, '\0');
|
|
|
+ fSetInt(of, end, of->index);
|
|
|
+ fAddChar(of, '\n');
|
|
|
}
|
|
|
|
|
|
-static void fSkipString(int skip) {
|
|
|
- readIndex += skip;
|
|
|
- while(fileContent[readIndex] == ' ') {
|
|
|
- readIndex++;
|
|
|
+static void fReadCommand(OpenFile* of) {
|
|
|
+ char command[64];
|
|
|
+ fReadCommandString(of, command, 64);
|
|
|
+ if(strcmp(command, "define") == 0) {
|
|
|
+ fDefine(of);
|
|
|
+ } else {
|
|
|
+ files.error("invalid command '%s'", command);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void fDefine() {
|
|
|
- fSkipString(7);
|
|
|
- const char* name = fileContent + readIndex;
|
|
|
+static void fReadFile(const char* path) {
|
|
|
+ if(files.fileIndex >= MAX_INDEX) {
|
|
|
+ files.error("cannot read file '%s': too many open files", path);
|
|
|
+ }
|
|
|
+ OpenFile* of = files.files + files.fileIndex;
|
|
|
+ of->arrayIndex = files.fileIndex++;
|
|
|
+ of->index = 0;
|
|
|
+ of->size = 16;
|
|
|
+ of->content = malloc(of->size);
|
|
|
+ of->file = fopen(path, "r");
|
|
|
+ if(of->file == NULL) {
|
|
|
+ files.error("cannot read file '%s'", path);
|
|
|
+ }
|
|
|
while(true) {
|
|
|
- if(fileContent[readIndex] == ' ') {
|
|
|
- fileContent[readIndex] = '\0';
|
|
|
+ int c = fGet(of);
|
|
|
+ if(c == '#') {
|
|
|
+ fReadCommand(of);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ fAddChar(of, c);
|
|
|
+ if(c == EOF) {
|
|
|
break;
|
|
|
- } else if(!isLetter(fileContent[readIndex])) {
|
|
|
- fileError("invalid define name '%s'", name);
|
|
|
}
|
|
|
- readIndex++;
|
|
|
}
|
|
|
- readIndex++;
|
|
|
- if(defineIndex >= MAX_DEFINES) {
|
|
|
- fileError("too many defines");
|
|
|
+ fAddChar(of, '\0');
|
|
|
+}
|
|
|
+
|
|
|
+void fOpen(const char* path, FileError fe) {
|
|
|
+ files.fileIndex = 0;
|
|
|
+ files.defineIndex = 0;
|
|
|
+ files.readIndex.fileIndex = 0;
|
|
|
+ files.readIndex.index = 0;
|
|
|
+ files.error = fe;
|
|
|
+ lastChar = 0;
|
|
|
+ stackIndex = 0;
|
|
|
+ fReadFile(path);
|
|
|
+}
|
|
|
+
|
|
|
+void fClose() {
|
|
|
+ for(int i = 0; i < files.fileIndex; i++) {
|
|
|
+ fclose(files.files[i].file);
|
|
|
+ free(files.files[i].content);
|
|
|
}
|
|
|
- defines[defineIndex].nameLength = strlen(name);
|
|
|
- defines[defineIndex].name = name;
|
|
|
- defines[defineIndex].code = fileContent + readIndex;
|
|
|
- defineIndex++;
|
|
|
- fSkipString(strlen(fileContent + readIndex));
|
|
|
}
|
|
|
|
|
|
-static bool fMatch(Defines* def, const char* code) {
|
|
|
- return strncmp(def->name, code, def->nameLength) == 0;
|
|
|
+static OpenFile* currentFile() {
|
|
|
+ return files.files + files.readIndex.fileIndex;
|
|
|
}
|
|
|
|
|
|
-static bool fPrepareChar() {
|
|
|
- if(defineCode != NULL) {
|
|
|
- if(defineCode[defineReadIndex] == '\0') {
|
|
|
- defineCode = NULL;
|
|
|
- defineReadIndex = 0;
|
|
|
- } else {
|
|
|
- return true;
|
|
|
+static int fReadChar() {
|
|
|
+ return currentFile()->content[files.readIndex.index];
|
|
|
+}
|
|
|
+
|
|
|
+static const char* fGetDefineName(Define* d) {
|
|
|
+ return files.files[d->name.fileIndex].content + d->name.index;
|
|
|
+}
|
|
|
+
|
|
|
+static bool fCompare(const char* a, const char* b, unsigned int bLength) {
|
|
|
+ return strncmp(a, b, bLength) == 0 && strlen(a) == bLength;
|
|
|
+}
|
|
|
+
|
|
|
+static void fEnter(Define* d) {
|
|
|
+ if(stackIndex >= MAX_INDEX) {
|
|
|
+ files.error("define stack overflow");
|
|
|
+ }
|
|
|
+ stack[stackIndex++] = files.readIndex;
|
|
|
+ files.readIndex = d->code;
|
|
|
+}
|
|
|
+
|
|
|
+static void fPrepareChar() {
|
|
|
+ int c = fReadChar();
|
|
|
+ if(c == '\0') {
|
|
|
+ if(stackIndex <= 0) {
|
|
|
+ files.error("define stack underflow");
|
|
|
}
|
|
|
+ files.readIndex = stack[--stackIndex];
|
|
|
}
|
|
|
- if(!isLetter(fileContent[readIndex])) {
|
|
|
- defineReadIndex = 0;
|
|
|
+ if(c == '#') {
|
|
|
+ int end = fReadInt(currentFile(), files.readIndex.index + 1);
|
|
|
+ files.readIndex.index = end;
|
|
|
}
|
|
|
- if(isLetter(fileContent[readIndex]) && defineReadIndex == 0) {
|
|
|
- const char* replace = fileContent + readIndex;
|
|
|
- for(int i = 0; i < defineIndex; i++) {
|
|
|
- if(fMatch(defines + i, replace)) {
|
|
|
- defineCode = defines[i].code;
|
|
|
- readIndex += defines[i].nameLength;
|
|
|
- return true;
|
|
|
- }
|
|
|
+ if(isLetter(c) && !isLetter(lastChar)) {
|
|
|
+ OpenFile* of = currentFile();
|
|
|
+ int start = files.readIndex.index;
|
|
|
+ int index = start;
|
|
|
+ while(index < of->index && isLetter(of->content[index])) {
|
|
|
+ index++;
|
|
|
}
|
|
|
- defineReadIndex = -1;
|
|
|
- }
|
|
|
- if(fileContent[readIndex] == '#') {
|
|
|
- const char* command = fileContent + readIndex + 1;
|
|
|
- if(strncmp(command, "define", 6) == 0) {
|
|
|
- fDefine();
|
|
|
- } else {
|
|
|
- fileError("unknown preprocessor command '%s'", command);
|
|
|
+ for(int i = 0; i < files.defineIndex; i++) {
|
|
|
+ Define* d = files.defines + i;
|
|
|
+ const char* name = fGetDefineName(d);
|
|
|
+ if(fCompare(name, of->content + start, index - start)) {
|
|
|
+ files.readIndex.index = index;
|
|
|
+ fEnter(d);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- if(fileContent[readIndex] == '\0') {
|
|
|
- readIndex++;
|
|
|
- }
|
|
|
- return false;
|
|
|
}
|
|
|
|
|
|
int fRead() {
|
|
|
- if(fPrepareChar()) {
|
|
|
- return defineCode[defineReadIndex++];
|
|
|
- }
|
|
|
- return fileContent[readIndex++];
|
|
|
+ fPrepareChar();
|
|
|
+ lastChar = fReadChar();
|
|
|
+ return currentFile()->content[files.readIndex.index++];
|
|
|
}
|
|
|
|
|
|
int fPeek() {
|
|
|
- if(fPrepareChar()) {
|
|
|
- return defineCode[defineReadIndex];
|
|
|
- }
|
|
|
- return fileContent[readIndex];
|
|
|
+ fPrepareChar();
|
|
|
+ return fReadChar();
|
|
|
}
|
|
|
|
|
|
bool fReadIf(int c) {
|