#include #include #include #include "tokenizer/File.h" #include "utils/Utils.h" #define MAX_INDEX 50 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 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 = 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); } while(true) { 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); } buffer[index] = '\0'; } 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 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 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) { 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); } void fClose() { for(int i = 0; i < files.fileIndex; i++) { fclose(files.files[i].file); free(files.files[i].content); } } static OpenFile* currentFile() { return files.files + files.readIndex.fileIndex; } 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(c == '#') { int end = fReadInt(currentFile(), files.readIndex.index + 1); files.readIndex.index = end; } 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++; } 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); } } } } int fRead() { fPrepareChar(); lastChar = fReadChar(); return currentFile()->content[files.readIndex.index++]; } int fPeek() { fPrepareChar(); return fReadChar(); } bool fReadIf(int c) { if(fPeek() == c) { fRead(); return true; } return false; }