123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567 |
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "tokenizer/FileTokens.h"
- #include "utils/SnuviUtils.h"
- static Error* error = NULL;
- typedef char String[64];
- #define STRING_LENGTH ((int)sizeof(String))
- typedef struct {
- String name;
- FileTokens tokens;
- } Define;
- #define DEFINES 256
- static Define defines[DEFINES];
- static int defineIndex = 0;
- 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 "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* parent,
- const FileTokens* ft, int index) {
- ftError(parent, index, "%s '%s': %s", msg, ftGetPath(ft, 0),
- strerror(errno));
- }
- static void ftToSpace(FileToken* t) {
- free(t->literal);
- if(t->type != FT_NEWLINE) {
- t->type = FT_SPACE;
- }
- t->literal = NULL;
- t->single = 0;
- }
- static FileToken* ftAddToken(FileTokens* ft, FileTokenType type) {
- if(ft->length >= ft->capacity) {
- ft->capacity = (ft->capacity * 5) / 4 + 8;
- ft->tokens = (FileToken*)realloc(ft->tokens, (size_t)ft->capacity *
- sizeof(FileToken));
- }
- FileToken* t = ft->tokens + ft->length++;
- t->type = type;
- t->literal = NULL;
- t->single = 0;
- return t;
- }
- static FileToken* ftAddCopyToken(FileTokens* ft, const FileToken* t) {
- FileToken* added = ftAddToken(ft, t->type);
- added->literal = t->literal == NULL ? NULL : strdup(t->literal);
- added->single = t->single;
- return added;
- }
- static void ftAddPath(FileTokens* ft, const char* path) {
- ftAddToken(ft, FT_PATH)->literal = strdup(path);
- }
- static void ftAddEndPath(FileTokens* ft) {
- ftAddToken(ft, FT_END_PATH);
- }
- static void ftAddNewline(FileTokens* ft) {
- ftAddToken(ft, FT_NEWLINE);
- }
- static void ftAddLiteral(FileTokens* ft, const char* path, int length) {
- ftAddToken(ft, FT_LITERAL)->literal = strndup(path, (size_t)length);
- }
- static void ftAddSingle(FileTokens* ft, int single) {
- ftAddToken(ft, FT_SINGLE)->single = single;
- }
- static void ftAddSpace(FileTokens* ft) {
- ftAddToken(ft, FT_SPACE);
- }
- void ftPrint(FileTokens* ft) {
- for(int i = 0; i < ft->length; i++) {
- switch(ft->tokens[i].type) {
- case FT_PATH:
- printf("\033[0;34mPath: %s\n", ft->tokens[i].literal);
- break;
- case FT_END_PATH: puts("\033[0;34mEnd Path"); break;
- case FT_NEWLINE: putchar('\n'); break;
- case FT_LITERAL:
- printf("\033[0;33m%s", ft->tokens[i].literal);
- break;
- case FT_SINGLE:
- printf("\033[0;31m%c", (char)ft->tokens[i].single);
- break;
- case FT_SPACE: putchar(' '); break;
- default: putchar('?'); break;
- }
- }
- printf("\033[0m");
- }
- static bool ftHasError(void) {
- return eHasError(error);
- }
- static bool ftStringCompare(const char* a, const char* b) {
- return strcmp(a, b) == 0;
- }
- static void ftInitFileTokens(FileTokens* ft) {
- ft->tokens = NULL;
- ft->capacity = 0;
- ft->length = 0;
- }
- static void ftInitFileTokensWithPath(FileTokens* ft, const char* path) {
- ftInitFileTokens(ft);
- ftAddPath(ft, path);
- }
- static void ftTokenize(FileTokens* ft, unsigned char* data) {
- int index = 0;
- int oldIndex = 0;
- bool inString = false;
- while(true) {
- unsigned char c = data[index];
- if(isAllowedInName(c) || (inString && c != '"' && c != '\0')) {
- index++;
- continue;
- }
- if(oldIndex < index) {
- ftAddLiteral(ft, (const char*)(data + oldIndex), index - oldIndex);
- }
- if(c == '"') {
- inString = !inString;
- }
- if(c == '\0') {
- break;
- } else if(c == '\n') {
- ftAddNewline(ft);
- } else if(c == ' ') {
- ftAddSpace(ft);
- } else if(c == '/' && data[index + 1] == '/') {
- while(data[index] != '\0' && data[index] != '\n') {
- index++;
- }
- ftAddNewline(ft);
- } else if(c == '/' && data[index + 1] == '*') {
- int startIndex = ft->length - 1;
- index += 2;
- while(true) {
- if(data[index] == '\0') {
- ftError(ft, startIndex, "test");
- return;
- } else if(data[index] == '\n') {
- ftAddNewline(ft);
- } else if(data[index] == '*' && data[index + 1] == '/') {
- index++;
- break;
- }
- index++;
- }
- } else {
- ftAddSingle(ft, c);
- }
- index++;
- oldIndex = index;
- }
- }
- static void ftReadFull(FILE* file, FileTokens* parent, FileTokens* ft,
- int index) {
- if(fseek(file, 0, SEEK_END)) {
- ftSystemError("cannot seek end of file", parent, ft, index);
- return;
- }
- long signedLength = ftell(file);
- if(signedLength < 0) {
- ftSystemError("cannot tell end of file", parent, ft, index);
- return;
- }
- size_t length = (size_t)signedLength;
- rewind(file);
- unsigned char* data = (unsigned char*)malloc(length + 1);
- size_t readValues = fread(data, 1, length, file);
- if(readValues != length) {
- ftSystemError("cannot read file", parent, ft, index);
- free(data);
- return;
- }
- data[length] = '\0';
- ftTokenize(ft, data);
- ftAddEndPath(ft);
- free(data);
- }
- static void ftReadFullFile(FileTokens* parent, FileTokens* ft, int index) {
- FILE* file = fopen(ftGetPath(ft, 0), "r");
- if(file == NULL) {
- ftSystemError("cannot open file", parent, ft, index);
- return;
- }
- ftReadFull(file, parent, ft, index);
- if(fclose(file) < 0) {
- ftSystemError("cannot close file", parent, ft, index);
- }
- }
- static void ftReplace(int from, int toEx, FileTokens* ft,
- const FileTokens* replacement) {
- int newCapacity = ft->capacity + replacement->capacity;
- FileToken* newTokens =
- (FileToken*)malloc((size_t)newCapacity * sizeof(FileToken));
- // these will be overwritten
- for(int i = from; i < toEx; i++) {
- free(ft->tokens[i].literal);
- ft->tokens[i].literal = NULL;
- }
- memcpy(newTokens, ft->tokens, (size_t)from * sizeof(FileToken));
- for(int i = 0; i < replacement->length; i++) {
- FileToken* src = replacement->tokens + i;
- FileToken* dst = newTokens + from + i;
- dst->literal = src->literal == NULL ? NULL : strdup(src->literal);
- dst->single = src->single;
- dst->type = src->type;
- }
- memcpy(newTokens + from + replacement->length, ft->tokens + toEx,
- (size_t)(ft->length - toEx) * sizeof(FileToken));
- free(ft->tokens);
- ft->tokens = newTokens;
- ft->capacity = newCapacity;
- ft->length = from + replacement->length + ft->length - toEx;
- }
- static void ftSkipSpaces(int* index, FileTokens* ft) {
- while(*index < ft->length) {
- FileToken* t = ft->tokens + *index;
- if(t->type != FT_SPACE) {
- return;
- }
- (*index)++;
- }
- }
- 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 != '"') {
- ftError(ft, *index - 1, INCLUDE_ERROR);
- return true;
- }
- (*index)++;
- return false;
- }
- static void ftHandleInclude(int* index, int start, FileTokens* ft) {
- ftSkipSpaces(index, ft);
- if(ftIncludeDoubleQuote(index, ft)) {
- return;
- }
- if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
- ftError(ft, *index - 1, INCLUDE_ERROR);
- return;
- }
- const char* path = ft->tokens[(*index)++].literal;
- if(ftIncludeDoubleQuote(index, ft)) {
- return;
- }
- const char* parentPath = ftGetPath(ft, *index - 1);
- size_t afterLastSlash = 0;
- for(size_t i = 0; parentPath[i] != '\0'; i++) {
- afterLastSlash = parentPath[i] == '/' ? i + 1 : afterLastSlash;
- }
- size_t pathLength = strlen(path) + 1;
- char* fullPath = (char*)malloc(afterLastSlash + pathLength);
- memcpy(fullPath, parentPath, afterLastSlash);
- memcpy(fullPath + afterLastSlash, path, pathLength);
- FileTokens include;
- ftInitFileTokensWithPath(&include, fullPath);
- free(fullPath);
- ftReadFullFile(ft, &include, *index - 1);
- if(!ftHasError()) {
- ftReplace(start, *index, ft, &include);
- *index = start;
- }
- ftDelete(&include);
- }
- static int ftGetDefineIndex(const char* s) {
- for(int i = 0; i < defineIndex; i++) {
- if(ftStringCompare(defines[i].name, s)) {
- return i;
- }
- }
- return -1;
- }
- static bool ftIsDefined(const char* s) {
- return ftGetDefineIndex(s) != -1;
- }
- static int ftFindEndIf(int from, FileTokens* ft) {
- int layer = 0;
- for(int i = from; i < ft->length - 1; i++) {
- if(ft->tokens[i].type != FT_SINGLE || ft->tokens[i].single != '#') {
- continue;
- } else if(ft->tokens[i + 1].type != FT_LITERAL) {
- continue;
- }
- if(ftStringCompare(ft->tokens[i + 1].literal, "ifndef")) {
- layer++;
- } else if(ftStringCompare(ft->tokens[i + 1].literal, "endif")) {
- if(layer == 0) {
- return i;
- }
- layer--;
- }
- }
- return -1;
- }
- static void ftHandleIfNotDefined(int* index, int start, FileTokens* ft) {
- ftSkipSpaces(index, ft);
- if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
- ftError(ft, start, "ifndef expects a literal");
- return;
- }
- const char* check = ft->tokens[(*index)++].literal;
- int endIf = ftFindEndIf(*index, ft);
- if(endIf == -1) {
- ftError(ft, start, "cannot find #endif");
- return;
- }
- if(ftIsDefined(check)) {
- for(int i = start; i < endIf + 2; i++) {
- ftToSpace(ft->tokens + i);
- }
- } else {
- ftToSpace(ft->tokens + start); // #
- ftToSpace(ft->tokens + start + 1); // ifndef
- ftToSpace(ft->tokens + (*index - 1)); // DEFINITION
- ftToSpace(ft->tokens + endIf); // #
- ftToSpace(ft->tokens + endIf + 1); // endif
- }
- }
- static void ftHandleDefine(int* index, int start, FileTokens* ft) {
- if(defineIndex >= DEFINES) {
- ftError(ft, *index - 1, "too much defines");
- return;
- }
- ftSkipSpaces(index, ft);
- if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
- ftError(ft, *index - 1, "define expects a literal");
- return;
- }
- const char* defineName = ft->tokens[(*index)++].literal;
- ftSkipSpaces(index, ft);
- int defineStart = *index;
- bool skip = false;
- while(*index < ft->length) {
- FileToken* t = ft->tokens + *index;
- if(!skip && t->type == FT_SINGLE && t->single == '\\') {
- skip = true;
- ftToSpace(t);
- } else if(t->type == FT_NEWLINE) {
- if(skip) {
- skip = false;
- } else {
- break;
- }
- } else if(skip) {
- ftError(ft, *index - 1, "expected newline after \\");
- return;
- }
- (*index)++;
- }
- int foundIndex = ftGetDefineIndex(defineName);
- if(foundIndex != -1) {
- ftError(ft, *index - 1, "'%s' redefined", defineName);
- return;
- }
- Define* define = NULL;
- if(foundIndex == -1) {
- define = defines + defineIndex++;
- strncpy(define->name, defineName, STRING_LENGTH - 1);
- define->name[STRING_LENGTH - 1] = '\0';
- } else {
- define = defines + foundIndex;
- ftDelete(&define->tokens);
- }
- ftInitFileTokens(&define->tokens);
- for(int i = defineStart; i < *index; i++) {
- ftAddCopyToken(&define->tokens, ft->tokens + i);
- if(ft->tokens[i].type == FT_NEWLINE) {
- FileToken* t = define->tokens.tokens + (define->tokens.length - 1);
- ftToSpace(t);
- t->type = FT_SPACE;
- }
- }
- for(int i = start; i < *index; i++) {
- ftToSpace(ft->tokens + i);
- }
- }
- static void ftHandleUndefine(int* index, int start, FileTokens* ft) {
- ftSkipSpaces(index, ft);
- if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
- ftError(ft, *index - 1, "undefine expects a literal");
- return;
- }
- const char* defineName = ft->tokens[(*index)++].literal;
- int foundIndex = ftGetDefineIndex(defineName);
- if(foundIndex != -1) {
- Define* define = defines + foundIndex;
- ftDelete(&define->tokens);
- defineIndex--;
- if(defineIndex != foundIndex) {
- memcpy(define, defines + defineIndex, sizeof(Define));
- }
- }
- for(int i = start; i < *index; i++) {
- ftToSpace(ft->tokens + i);
- }
- }
- static void ftParseInstruction(int* index, FileTokens* ft) {
- int start = *index;
- (*index)++;
- if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
- ftError(ft, *index - 1, "expected literal after #");
- return;
- }
- const char* name = ft->tokens[(*index)++].literal;
- if(ftStringCompare(name, "include")) {
- ftHandleInclude(index, start, ft);
- } else if(ftStringCompare(name, "ifndef")) {
- ftHandleIfNotDefined(index, start, ft);
- } else if(ftStringCompare(name, "define")) {
- ftHandleDefine(index, start, ft);
- } else if(ftStringCompare(name, "undef")) {
- ftHandleUndefine(index, start, ft);
- } else if(ftStringCompare(name, "endif")) {
- ftError(ft, *index - 1, "endif without if");
- } else {
- ftError(ft, *index - 1, "unknown preprocessor literal '%s'", name);
- }
- }
- static bool ftReplaceMakros(FileTokens* ft, int index) {
- FileToken* t = ft->tokens + index;
- int foundIndex = ftGetDefineIndex(t->literal);
- if(foundIndex != -1) {
- ftReplace(index, index + 1, ft, &(defines[foundIndex].tokens));
- return true;
- }
- return false;
- }
- static void ftSearchInstruction(FileTokens* ft) {
- for(int i = 0; i < ft->length && !ftHasError(); i++) {
- if(ft->tokens[i].type == FT_SINGLE && ft->tokens[i].single == '#') {
- ftParseInstruction(&i, ft);
- } else if(ft->tokens[i].type == FT_LITERAL) {
- if(ftReplaceMakros(ft, i)) {
- i--;
- }
- }
- }
- }
- void ftInit(const char* path, FileTokens* ft, Error* e) {
- defineIndex = 0;
- error = e;
- eInitSuccess(error);
- ftInitFileTokensWithPath(ft, path);
- ftReadFullFile(ft, ft, 0);
- if(!ftHasError()) {
- ftSearchInstruction(ft);
- }
- for(int i = 0; i < defineIndex; i++) {
- ftDelete(&(defines[i].tokens));
- }
- }
- void ftDelete(FileTokens* ft) {
- for(int i = 0; i < ft->length; i++) {
- free(ft->tokens[i].literal);
- }
- free(ft->tokens);
- ft->tokens = NULL;
- ft->capacity = 0;
- ft->length = 0;
- }
|