| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 | #include <limits.h>#include <setjmp.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "tokenizer/File.h"#include "tokenizer/Tokenizer.h"#include "utils/SnuviUtils.h"#define TOKEN_BUFFER_LENGTH (1024 * 1024)#define ERROR_LENGTH 256static jmp_buf errorJump;static char tokenBuffer[TOKEN_BUFFER_LENGTH];static int writeIndex = 0;static int readIndex = 0;static int16 line = 1;static char error[ERROR_LENGTH] = {'\0'};static void tError(const char* format, ...) {    va_list args;    va_start(args, format);    vsnprintf(error, ERROR_LENGTH, format, args);    va_end(args);    longjmp(errorJump, 0);}static void tAdd(const void* data, int length) {    if(writeIndex + length > TOKEN_BUFFER_LENGTH) {        tError("the token buffer is too small");    }    memcpy(tokenBuffer + writeIndex, data, length);    writeIndex += length;}static void tAddToken(Token token) {    unsigned char c = token;    tAdd(&c, 1);    tAdd(&line, sizeof(line));}static bool tReadTokens(void* dest, int length) {    if(readIndex + length > writeIndex) {        return false;    }    memcpy(dest, tokenBuffer + readIndex, length);    readIndex += length;    return true;}static void tParseLiteral(int c) {    int index = 1;    char buffer[64];    buffer[0] = c;    while(isAllowedInName(fPeek())) {        if(index >= 63) {            tError("literal is too long");        }        buffer[index++] = fRead();    }    buffer[index] = '\0';    Token t = tFromName(buffer);    if(t != T_END) {        tAddToken(t);    } else {        tAddToken(T_LITERAL);        tAdd(buffer, index + 1);    }}static bool tParseInt(char* s, int length, long long* l) {    *l = 0;    for(int i = 0; i < length; i++) {        if(*l > (LLONG_MAX / 10)) {            return true;        }        *l *= 10;        int digit = s[i] - '0';        if(*l > LLONG_MAX - digit) {            return true;        }        *l += digit;    }    return false;}static void tParseNumber(int c) {    int index = 1;    char buffer[64];    buffer[0] = c;    bool point = false;    while(true) {        int c = fPeek();        if(c == '.') {            point = true;        } else if(!isNumber(c)) {            break;        } else if(index >= 63) {            tError("number is too long");        }        buffer[index++] = fRead();    }    buffer[index] = '\0';    if(fPeek() == 'L' || fPeek() == 'l') {        fRead();        if(point) {            tError("invalid mix of long and float", line);        }        long long l;        if(tParseInt(buffer, index, &l) || l > INT64_MAX) {            tError("invalid long on line %d", line);        }        int64 i = l;        tAddToken(T_CONST_INT64);        tAdd(&i, sizeof(int64));    } else if(point) {        char* end = NULL;        float f = strtof(buffer, &end);        if(end[0] != '\0') {            tError("invalid float on line %d", line);        }        tAddToken(T_CONST_FLOAT);        tAdd(&f, sizeof(float));    } else {        long long l;        if(tParseInt(buffer, index, &l) || l > INT32_MAX) {            tError("invalid int on line %d", line);        }        int32 i = l;        tAddToken(T_CONST_INT32);        tAdd(&i, sizeof(int32));    }}static int32 tUnicode(int32 c) {    if(c == '\\') {        switch(fRead()) {            case '"': c = '"'; break;            case '\\': c = '\\'; break;            case 'n': c = '\n'; break;            case 'r': c = '\r'; break;            case 't': c = '\t'; break;            default: tError("unknown escaped character at line %d", line);        }    }    if((c & 0xE0) == 0xC0) {        c = ((c & 0x1F) << 6) | (fRead() & 0x3F);    } else if((c & 0xF0) == 0xE0) {        c = ((c & 0xF) << 12) | ((fRead() & 0x3F) << 6);        c |= fRead() & 0x3F;    } else if((c & 0xF8) == 0xF0) {        c = ((c & 0x7) << 18) | ((fRead() & 0x3F) << 12);        c |= (fRead() & 0x3F) << 6;        c |= fRead() & 0x3F;    }    return c;}static void tAddString() {    tAddToken(T_TEXT);    while(true) {        int32 c = fRead();        if(c == '"') {            break;        } else if(c == EOF) {            tError("unclosed string starting at line %d", line);        }        c = tUnicode(c);        tAdd(&c, sizeof(int32));    }    int32 c = 0;    tAdd(&c, sizeof(int32));}static void tAddUnicode() {    int32 c = fRead();    c = tUnicode(c);    tAddToken(T_CONST_INT32);    tAdd(&c, sizeof(int32));    if(fRead() != '\'') {        tError("expecting unicode end");    }}static void tAddToken2(Token te, Token t) {    if(fReadIf('=')) {        tAddToken(te);    } else {        tAddToken(t);    }}static void tAddToken3(int c, Token tc, Token te, Token t) {    if(fReadIf(c)) {        tAddToken(tc);    } else {        tAddToken2(te, t);    }}static void tAddToken4(int c, Token tce, Token tc, Token te, Token t) {    if(fReadIf(c)) {        tAddToken2(tce, tc);    } else {        tAddToken2(te, t);    }}static void tAddTokenMinus() {    tAddToken3('-', T_DECREMENT, T_SUB_SET, fReadIf('>') ? T_ARROW : T_SUB);}static void tLineComment() {    while(true) {        int c = fRead();        if(c == EOF || c == '\n') {            line++;            return;        }    }}static void tMultipleLineComment() {    while(true) {        int c = fRead();        if(c == EOF) {            tError("unclosed comment at line %d", line);        } else if(c == '\n') {            line++;        } else if(c == '*' && fReadIf('/')) {            return;        }    }}static void tSlash() {    if(fReadIf('/')) {        tLineComment();    } else if(fReadIf('*')) {        tMultipleLineComment();    } else {        tAddToken2(T_DIV_SET, T_DIV);    }}static void tParseToken(int c) {    if(isLetter(c)) {        tParseLiteral(c);        return;    } else if(isNumber(c)) {        tParseNumber(c);        return;    }    switch(c) {        case ' ': return;        case '\n': line++; return;        case '+': tAddToken3('+', T_INCREMENT, T_ADD_SET, T_ADD); return;        case '-': tAddTokenMinus(); return;        case '*': tAddToken2(T_MUL_SET, T_MUL); return;        case '/': tSlash(); return;        case '%': tAddToken2(T_MOD_SET, T_MOD); return;        case '<':            tAddToken4('<', T_LEFT_SHIFT_SET, T_LEFT_SHIFT, T_LESS_EQUAL,                       T_LESS);            return;        case '>':            tAddToken4('>', T_RIGHT_SHIFT_SET, T_RIGHT_SHIFT, T_GREATER_EQUAL,                       T_GREATER);            return;        case '=': tAddToken2(T_EQUAL, T_SET); return;        case '!': tAddToken2(T_NOT_EQUAL, T_NOT); return;        case '&': tAddToken3('&', T_AND, T_BIT_AND_SET, T_BIT_AND); return;        case '|': tAddToken3('|', T_OR, T_BIT_OR_SET, T_BIT_OR); return;        case '~': tAddToken(T_BIT_NOT); return;        case '^': tAddToken2(T_BIT_XOR_SET, T_BIT_XOR); return;        case ',': tAddToken(T_COMMA); return;        case ';': tAddToken(T_SEMICOLON); return;        case '(': tAddToken(T_OPEN_BRACKET); return;        case ')': tAddToken(T_CLOSE_BRACKET); return;        case '{': tAddToken(T_OPEN_CURVED_BRACKET); return;        case '}': tAddToken(T_CLOSE_CURVED_BRACKET); return;        case '"': tAddString(); return;        case '\'': tAddUnicode(); return;        case '.': tAddToken(T_POINT); return;        case '[': tAddToken(T_OPEN_SQUARE_BRACKET); return;        case ']': tAddToken(T_CLOSE_SQUARE_BRACKET); return;    }    tError("unknown character on line %d: %c", line, c);}static void tParseFile() {    readIndex = 0;    writeIndex = 0;    line = 1;    error[0] = '\0';    while(true) {        int c = fRead();        if(c == EOF) {            return;        }        tParseToken(c);    }}bool tTokenize(const char* path) {    if(!setjmp(errorJump)) {        fOpen(path, tError);        tParseFile();    }    fClose();    return error[0] != '\0';}const char* tGetError() {    return error;}int tGetLine() {    return line;}void tResetReader() {    readIndex = 0;}Token tPeekToken() {    if(readIndex >= writeIndex) {        return T_END;    }    return tokenBuffer[readIndex];}Token tReadToken() {    if(readIndex >= writeIndex) {        return T_END;    }    return tokenBuffer[readIndex++];}bool tReadInt16(int16* i) {    return tReadTokens(i, sizeof(int16));}bool tReadInt32(int32* i) {    return tReadTokens(i, sizeof(int32));}bool tReadInt64(int64* i) {    return tReadTokens(i, sizeof(int64));}bool tReadFloat(float* f) {    return tReadTokens(f, sizeof(float));}const char* tReadString() {    const char* s = tokenBuffer + readIndex;    while(readIndex <= writeIndex) {        if(tokenBuffer[readIndex++] == '\0') {            return s;        }    }    return NULL;}int tGetMarker() {    return readIndex;}void tReset(int marker) {    readIndex = marker;}
 |