#include #include #include #include "tokenizer/File.h" #include "utils/SnuviUtils.h" #define MAX_INDEX 50 typedef struct { char* content; int size; int index; int arrayIndex; bool newLines; char* path; FILE* file; } OpenFile; typedef struct { int fileIndex; int index; } FilePointer; typedef struct { FilePointer name; FilePointer code; } Define; typedef struct { 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); } memcpy(of->content + of->index, data, size); of->index += size; } static void fAddChar(OpenFile* of, int ic) { char c = ic; fAdd(of, &c, 1); } static int fReserverInt(OpenFile* of) { int address = of->index; int empty = 0; 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) { int c = fgetc(of->file); if(!of->newLines && c == '\n') { return ' '; } return c; } static bool fReadCommandString(OpenFile* of, char* buffer, int size) { int index = 0; int c = fGet(of); while(c == ' ') { c = fGet(of); } int text = 0; while(true) { if(c == EOF) { files.error("unexpected end of file"); } else if(index >= size - 1) { files.error("unknown too long command"); } else if(c == '"' && text < 2) { text++; buffer[index++] = c; } else if((isLetter(c) || text == 1) && text < 2) { buffer[index++] = c; } else if(c == ' ' || c == '\n') { buffer[index] = '\0'; return c == '\n'; } else { files.error("unexpected character '%c'", (char)c); } c = fGet(of); } } static const char* fGetDefineName(Define* d) { return files.files[d->name.fileIndex].content + d->name.index; } static int fStartDefine(OpenFile* of, bool* newLine) { fAddChar(of, '#'); int end = fReserverInt(of); int nameFileIndex = fReserverInt(of); int nameIndex = fReserverInt(of); int codeFileIndex = fReserverInt(of); int codeIndex = fReserverInt(of); char command[64]; *newLine = fReadCommandString(of, command, 64); fSetInt(of, nameFileIndex, of->arrayIndex); fSetInt(of, nameIndex, of->index); fAdd(of, command, strlen(command) + 1); fSetInt(of, codeFileIndex, of->arrayIndex); fSetInt(of, codeIndex, of->index); return end; } static void fFinishDefine(OpenFile* of, int end, int newLines) { fAddChar(of, '\0'); fSetInt(of, end, of->index); for(int i = 0; i < newLines; i++) { fAddChar(of, '\n'); } } static void fDefine(OpenFile* of) { bool newLine = false; int end = fStartDefine(of, &newLine); int newLines = newLine; while(true) { int c = fGet(of); if(c == '#') { char end[64]; newLines += fReadCommandString(of, end, 64); if(strcmp(end, "end") == 0) { break; } files.error("invalid command '%s' inside define region", end); } else if(c == EOF) { files.error("unclosed #define"); } if(c == '\n') { newLines++; c = ' '; } fAddChar(of, c); } fFinishDefine(of, end, newLines); } static void fReadFile(const char* path, bool newLines); static void fEnter(FilePointer* fp); static int fConcat(char* buffer, int size, const char* s) { int l = strlen(s) + 1; if(l > size) { files.error("too long include path"); } memcpy(buffer, s, l); return l; } static void fInclude(OpenFile* of) { char path[64]; if(fReadCommandString(of, path, 64)) { fAddChar(of, '\n'); } int l = strlen(path); if(l < 2 || path[0] != '"' || path[l - 1] != '"') { files.error("invalid include path '%s'", path); } path[l - 1] = '\0'; const char* cutPath = path + 1; char fullName[256]; int index = fConcat(fullName, 256, of->path); while(index > 0 && fullName[index - 1] != '/') { index--; } fConcat(fullName + index, 256 - index, cutPath); FilePointer fp = {files.fileIndex, 0}; fEnter(&fp); fReadFile(fullName, false); } static void fReadCommand(OpenFile* of) { char command[64]; fReadCommandString(of, command, 64); if(strcmp(command, "define") == 0) { fDefine(of); } else if(strcmp(command, "include") == 0) { fInclude(of); } else { files.error("invalid command '%s'", command); } } static void fReadFile(const char* path, bool newLines) { 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->newLines = newLines; of->content = malloc(of->size); of->file = fopen(path, "r"); of->path = strdup(path); if(of->file == NULL) { files.error("cannot read file '%s'", path); } while(true) { int c = fGet(of); if(c == '#') { fReadCommand(of); continue; } fAddChar(of, c); if(c == EOF) { break; } } 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, true); } void fClose() { for(int i = 0; i < files.fileIndex; i++) { if(files.files[i].file != NULL) { fclose(files.files[i].file); } free(files.files[i].path); free(files.files[i].content); } } static OpenFile* currentFile() { return files.files + files.readIndex.fileIndex; } static int fReadChar() { return currentFile()->content[files.readIndex.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(FilePointer* fp) { if(stackIndex >= MAX_INDEX) { files.error("define stack overflow"); } stack[stackIndex++] = files.readIndex; files.readIndex = *fp; } static bool fCheckForReplacement() { OpenFile* of = currentFile(); int start = files.readIndex.index; int index = start; while(index < of->index && isLetter(of->content[index])) { index++; } 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->code); return true; } } return false; } static void fReadDefine() { int base = files.readIndex.index + 1; int end = fReadInt(currentFile(), base); int nameFileIndex = fReadInt(currentFile(), base + sizeof(int)); int nameIndex = fReadInt(currentFile(), base + sizeof(int) * 2); int codeFileIndex = fReadInt(currentFile(), base + sizeof(int) * 3); int codeIndex = fReadInt(currentFile(), base + sizeof(int) * 4); const char* name = files.files[nameFileIndex].content + nameIndex; if(files.defineIndex >= MAX_INDEX) { files.error("too many defines"); } Define* d = files.defines + files.defineIndex++; for(int i = 0; i < files.defineIndex - 1; i++) { if(strcmp(name, fGetDefineName(files.defines + i)) == 0) { d = files.defines + i; files.defineIndex--; break; } } d->name.fileIndex = nameFileIndex; d->name.index = nameIndex; d->code.fileIndex = codeFileIndex; d->code.index = codeIndex; files.readIndex.index = end; } static void fPrepareChar() { while(true) { int c = fReadChar(); if(c == '\0') { if(stackIndex <= 0) { files.error("define stack underflow"); } files.readIndex = stack[--stackIndex]; } else if(c == EOF && stackIndex > 0) { files.readIndex = stack[--stackIndex]; } else if(c == '#') { fReadDefine(); } else if(isLetter(c) && !isLetter(lastChar)) { if(fCheckForReplacement()) { continue; } break; } else { break; } } } static int fReadI() { fPrepareChar(); lastChar = fReadChar(); return currentFile()->content[files.readIndex.index++]; } int fRead() { int i = fReadI(); // putchar(i); return i; } int fPeek() { fPrepareChar(); return fReadChar(); } bool fReadIf(int c) { if(fPeek() == c) { fRead(); return true; } return false; }