X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=lexer.c;h=b6d5ceb6d3bd94aed4e4cc0bb0d2926d932b9b6a;hb=7011a2ef2ceaf9652cea0b0e61319b338667888b;hp=db0a8f4d9bf541bdd25597c5047e040d7dc36fc5;hpb=685fa54daf0b3fdd92d9424e7fcab1ded9fb3c29;p=xonotic%2Fgmqcc.git diff --git a/lexer.c b/lexer.c index db0a8f4..b6d5ceb 100644 --- a/lexer.c +++ b/lexer.c @@ -20,10 +20,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include #include -#include +#include #include "gmqcc.h" #include "lexer.h" @@ -40,8 +38,6 @@ static const char *keywords_qc[] = { "return", "const" }; -static size_t num_keywords_qc = sizeof(keywords_qc) / sizeof(keywords_qc[0]); - /* For fte/gmgqcc */ static const char *keywords_fg[] = { "switch", "case", "default", @@ -52,34 +48,33 @@ static const char *keywords_fg[] = { "__builtin_debug_printtype" }; -static size_t num_keywords_fg = sizeof(keywords_fg) / sizeof(keywords_fg[0]); /* * Lexer code */ +static char* *lex_filenames; -char* *lex_filenames; - -void lexerror(lex_file *lex, const char *fmt, ...) +static void lexerror(lex_file *lex, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (lex) - con_vprintmsg(LVL_ERROR, lex->name, lex->sline, "parse error", fmt, ap); + con_vprintmsg(LVL_ERROR, lex->name, lex->sline, lex->column, "parse error", fmt, ap); else - con_vprintmsg(LVL_ERROR, "", 0, "parse error", fmt, ap); + con_vprintmsg(LVL_ERROR, "", 0, 0, "parse error", fmt, ap); va_end(ap); } -bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...) +static bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...) { - bool r; - lex_ctx ctx; - va_list ap; + bool r; + lex_ctx_t ctx; + va_list ap; - ctx.file = lex->name; - ctx.line = lex->sline; + ctx.file = lex->name; + ctx.line = lex->sline; + ctx.column = lex->column; va_start(ap, fmt); r = vcompile_warning(ctx, warntype, fmt, ap); @@ -174,17 +169,19 @@ static void lex_token_new(lex_file *lex) #else if (lex->tok.value) vec_shrinkto(lex->tok.value, 0); + lex->tok.constval.t = 0; - lex->tok.ctx.line = lex->sline; - lex->tok.ctx.file = lex->name; + lex->tok.ctx.line = lex->sline; + lex->tok.ctx.file = lex->name; + lex->tok.ctx.column = lex->column; #endif } #endif lex_file* lex_open(const char *file) { - lex_file *lex; - FILE *in = fs_file_open(file, "rb"); + lex_file *lex; + fs_file_t *in = fs_file_open(file, "rb"); if (!in) { lexerror(NULL, "open failed: '%s'\n", file); @@ -200,12 +197,12 @@ lex_file* lex_open(const char *file) memset(lex, 0, sizeof(*lex)); - lex->file = in; - lex->name = util_strdup(file); - lex->line = 1; /* we start counting at 1 */ - + lex->file = in; + lex->name = util_strdup(file); + lex->line = 1; /* we start counting at 1 */ + lex->column = 0; lex->peekpos = 0; - lex->eof = false; + lex->eof = false; vec_push(lex_filenames, lex->name); return lex; @@ -228,11 +225,11 @@ lex_file* lex_open_string(const char *str, size_t len, const char *name) lex->open_string_length = len; lex->open_string_pos = 0; - lex->name = util_strdup(name ? name : ""); - lex->line = 1; /* we start counting at 1 */ - + lex->name = util_strdup(name ? name : ""); + lex->line = 1; /* we start counting at 1 */ lex->peekpos = 0; - lex->eof = false; + lex->eof = false; + lex->column = 0; vec_push(lex_filenames, lex->name); @@ -271,14 +268,17 @@ void lex_close(lex_file *lex) static int lex_fgetc(lex_file *lex) { - if (lex->file) + if (lex->file) { + lex->column++; return fs_file_getc(lex->file); + } if (lex->open_string) { if (lex->open_string_pos >= lex->open_string_length) - return EOF; + return FS_FILE_EOF; + lex->column++; return lex->open_string[lex->open_string_pos++]; } - return EOF; + return FS_FILE_EOF; } /* Get or put-back data @@ -291,16 +291,22 @@ static int lex_try_trigraph(lex_file *lex, int old) { int c2, c3; c2 = lex_fgetc(lex); - if (!lex->push_line && c2 == '\n') + if (!lex->push_line && c2 == '\n') { lex->line++; + lex->column = 0; + } + if (c2 != '?') { lex_ungetch(lex, c2); return old; } c3 = lex_fgetc(lex); - if (!lex->push_line && c3 == '\n') + if (!lex->push_line && c3 == '\n') { lex->line++; + lex->column = 0; + } + switch (c3) { case '=': return '#'; case '/': return '\\'; @@ -347,14 +353,18 @@ static int lex_getch(lex_file *lex) if (lex->peekpos) { lex->peekpos--; - if (!lex->push_line && lex->peek[lex->peekpos] == '\n') + if (!lex->push_line && lex->peek[lex->peekpos] == '\n') { lex->line++; + lex->column = 0; + } return lex->peek[lex->peekpos]; } ch = lex_fgetc(lex); - if (!lex->push_line && ch == '\n') + if (!lex->push_line && ch == '\n') { lex->line++; + lex->column = 0; + } else if (ch == '?') return lex_try_trigraph(lex, ch); else if (!lex->flags.nodigraphs && (ch == '<' || ch == ':' || ch == '%')) @@ -365,8 +375,11 @@ static int lex_getch(lex_file *lex) static void lex_ungetch(lex_file *lex, int ch) { lex->peek[lex->peekpos++] = ch; - if (!lex->push_line && ch == '\n') + lex->column--; + if (!lex->push_line && ch == '\n') { lex->line--; + lex->column = 0; + } } /* classify characters @@ -376,12 +389,12 @@ static void lex_ungetch(lex_file *lex, int ch) /* Idents are alphanumberic, but they start with alpha or _ */ static bool isident_start(int ch) { - return isalpha(ch) || ch == '_'; + return util_isalpha(ch) || ch == '_'; } static bool isident(int ch) { - return isident_start(ch) || isdigit(ch); + return isident_start(ch) || util_isdigit(ch); } /* isxdigit_only is used when we already know it's not a digit @@ -481,7 +494,7 @@ static bool lex_try_pragma(lex_file *lex) goto unroll; lex->line = line; - while (ch != '\n' && ch != EOF) + while (ch != '\n' && ch != FS_FILE_EOF) ch = lex_getch(lex); vec_free(command); vec_free(param); @@ -561,7 +574,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite) do { ch = lex_getch(lex); - while (ch != EOF && isspace(ch)) { + while (ch != FS_FILE_EOF && util_isspace(ch)) { if (ch == '\n') { if (lex_try_pragma(lex)) continue; @@ -601,7 +614,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite) lex_tokench(lex, ' '); } - while (ch != EOF && ch != '\n') { + while (ch != FS_FILE_EOF && ch != '\n') { if (lex->flags.preprocessing) lex_tokench(lex, ' '); /* ch); */ ch = lex_getch(lex); @@ -626,7 +639,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite) lex_tokench(lex, ' '); } - while (ch != EOF) + while (ch != FS_FILE_EOF) { ch = lex_getch(lex); if (ch == '*') { @@ -659,7 +672,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite) ch = '/'; break; } - } while (ch != EOF && isspace(ch)); + } while (ch != FS_FILE_EOF && util_isspace(ch)); if (haswhite) { lex_endtoken(lex); @@ -675,7 +688,7 @@ static bool GMQCC_WARN lex_finish_ident(lex_file *lex) int ch; ch = lex_getch(lex); - while (ch != EOF && isident(ch)) + while (ch != FS_FILE_EOF && isident(ch)) { lex_tokench(lex, ch); ch = lex_getch(lex); @@ -695,7 +708,7 @@ static int lex_parse_frame(lex_file *lex) lex_token_new(lex); ch = lex_getch(lex); - while (ch != EOF && ch != '\n' && isspace(ch)) + while (ch != FS_FILE_EOF && ch != '\n' && util_isspace(ch)) ch = lex_getch(lex); if (ch == '\n') @@ -749,14 +762,15 @@ static bool lex_finish_frames(lex_file *lex) static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) { - uchar_t chr; + utf8ch_t chr = 0; int ch = 0; int nextch; bool hex; + bool oct; char u8buf[8]; /* way more than enough */ int u8len, uc; - while (ch != EOF) + while (ch != FS_FILE_EOF) { ch = lex_getch(lex); if (ch == quote) @@ -765,18 +779,18 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) if (lex->flags.preprocessing && ch == '\\') { lex_tokench(lex, ch); ch = lex_getch(lex); - if (ch == EOF) { + if (ch == FS_FILE_EOF) { lexerror(lex, "unexpected end of file"); - lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */ + lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */ return (lex->tok.ttype = TOKEN_ERROR); } lex_tokench(lex, ch); } else if (ch == '\\') { ch = lex_getch(lex); - if (ch == EOF) { + if (ch == FS_FILE_EOF) { lexerror(lex, "unexpected end of file"); - lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */ + lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */ return (lex->tok.ttype = TOKEN_ERROR); } @@ -838,17 +852,18 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) chr = 0; nextch = lex_getch(lex); hex = (nextch == 'x'); - if (!hex) + oct = (nextch == '0'); + if (!hex && !oct) lex_ungetch(lex, nextch); for (nextch = lex_getch(lex); nextch != '}'; nextch = lex_getch(lex)) { - if (!hex) { + if (!hex && !oct) { if (nextch >= '0' && nextch <= '9') chr = chr * 10 + nextch - '0'; else { lexerror(lex, "bad character code"); return (lex->tok.ttype = TOKEN_ERROR); } - } else { + } else if (!oct) { if (nextch >= '0' && nextch <= '9') chr = chr * 0x10 + nextch - '0'; else if (nextch >= 'a' && nextch <= 'f') @@ -859,6 +874,13 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) lexerror(lex, "bad character code"); return (lex->tok.ttype = TOKEN_ERROR); } + } else { + if (nextch >= '0' && nextch <= '9') + chr = chr * 8 + chr - '0'; + else { + lexerror(lex, "bad character code"); + return (lex->tok.ttype = TOKEN_ERROR); + } } if (chr > 0x10FFFF || (!OPTS_FLAG(UTF8) && chr > 255)) { @@ -867,14 +889,16 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) } } if (OPTS_FLAG(UTF8) && chr >= 128) { - u8len = u8_fromchar(chr, u8buf, sizeof(u8buf)); + u8len = utf8_from(u8buf, chr); if (!u8len) ch = 0; else { --u8len; + lex->column += u8len; for (uc = 0; uc < u8len; ++uc) lex_tokench(lex, u8buf[uc]); - /* the last character will be inserted with the tokench() call + /* + * the last character will be inserted with the tokench() call * below the switch */ ch = u8buf[uc]; @@ -897,7 +921,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) lex_tokench(lex, ch); } lexerror(lex, "unexpected end of file within string constant"); - lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */ + lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */ return (lex->tok.ttype = TOKEN_ERROR); } @@ -916,7 +940,7 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch) lex_tokench(lex, ch); ch = lex_getch(lex); - if (ch != '.' && !isdigit(ch)) + if (ch != '.' && !util_isdigit(ch)) { if (lastch != '0' || ch != 'x') { @@ -937,7 +961,7 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch) { lex_tokench(lex, ch); ch = lex_getch(lex); - while (isdigit(ch) || (ishex && isxdigit_only(ch))) + while (util_isdigit(ch) || (ishex && isxdigit_only(ch))) { lex_tokench(lex, ch); ch = lex_getch(lex); @@ -952,7 +976,7 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch) /* continue digits-only */ ch = lex_getch(lex); - while (isdigit(ch)) + while (util_isdigit(ch)) { lex_tokench(lex, ch); ch = lex_getch(lex); @@ -1018,7 +1042,7 @@ int lex_do(lex_file *lex) if (lex->eof) return (lex->tok.ttype = TOKEN_FATAL); - if (ch == EOF) { + if (ch == FS_FILE_EOF) { lex->eof = true; return (lex->tok.ttype = TOKEN_EOF); } @@ -1055,10 +1079,10 @@ int lex_do(lex_file *lex) if (!strcmp(v, "framevalue")) { ch = lex_getch(lex); - while (ch != EOF && isspace(ch) && ch != '\n') + while (ch != FS_FILE_EOF && util_isspace(ch) && ch != '\n') ch = lex_getch(lex); - if (!isdigit(ch)) { + if (!util_isdigit(ch)) { lexerror(lex, "$framevalue requires an integer parameter"); return lex_do(lex); } @@ -1135,7 +1159,7 @@ int lex_do(lex_file *lex) vec_free(lex->frames); /* skip line (fteqcc does it too) */ ch = lex_getch(lex); - while (ch != EOF && ch != '\n') + while (ch != FS_FILE_EOF && ch != '\n') ch = lex_getch(lex); return lex_do(lex); } @@ -1149,7 +1173,7 @@ int lex_do(lex_file *lex) { /* skip line */ ch = lex_getch(lex); - while (ch != EOF && ch != '\n') + while (ch != FS_FILE_EOF && ch != '\n') ch = lex_getch(lex); return lex_do(lex); } @@ -1216,7 +1240,7 @@ int lex_do(lex_file *lex) if (ch == '.') { nextch = lex_getch(lex); /* digits starting with a dot */ - if (isdigit(nextch)) { + if (util_isdigit(nextch)) { lex_ungetch(lex, nextch); lex->tok.ttype = lex_finish_digit(lex, ch); lex_endtoken(lex); @@ -1293,15 +1317,17 @@ int lex_do(lex_file *lex) } if (ch == '+' || ch == '-' || /* ++, --, +=, -= and -> as well! */ - ch == '>' || ch == '<' || /* <<, >>, <=, >= */ + ch == '>' || ch == '<' || /* <<, >>, <=, >= and >< as well! */ ch == '=' || ch == '!' || /* <=>, ==, != */ ch == '&' || ch == '|' || /* &&, ||, &=, |= */ - ch == '~' /* ~=, ~ */ + ch == '~' || ch == '^' /* ~=, ~, ^ */ ) { lex_tokench(lex, ch); nextch = lex_getch(lex); - if ((nextch == '=' && ch != '<') || (nextch == ch && ch != '!')) { + if ((nextch == '=' && ch != '<') || + (nextch == ch && ch != '!') || + (nextch == '<' && ch == '>')) { lex_tokench(lex, nextch); } else if (ch == '<' && nextch == '=') { lex_tokench(lex, nextch); @@ -1324,7 +1350,7 @@ int lex_do(lex_file *lex) } } else if (lex->flags.preprocessing && - ch == '-' && isdigit(nextch)) + ch == '-' && util_isdigit(nextch)) { lex->tok.ttype = lex_finish_digit(lex, nextch); if (lex->tok.ttype == TOKEN_INTCONST) @@ -1403,12 +1429,12 @@ int lex_do(lex_file *lex) lex->tok.constval.t = TYPE_VECTOR; } else { size_t kw; - for (kw = 0; kw < num_keywords_qc; ++kw) { + for (kw = 0; kw < GMQCC_ARRAY_COUNT(keywords_qc); ++kw) { if (!strcmp(v, keywords_qc[kw])) return (lex->tok.ttype = TOKEN_KEYWORD); } if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_QCC) { - for (kw = 0; kw < num_keywords_fg; ++kw) { + for (kw = 0; kw < GMQCC_ARRAY_COUNT(keywords_fg); ++kw) { if (!strcmp(v, keywords_fg[kw])) return (lex->tok.ttype = TOKEN_KEYWORD); } @@ -1457,14 +1483,10 @@ int lex_do(lex_file *lex) lex_endtoken(lex); lex->tok.ttype = TOKEN_CHARCONST; - /* It's a vector if we can successfully scan 3 floats */ -#ifdef _MSC_VER - if (sscanf_s(lex->tok.value, " %f %f %f ", - &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3) -#else - if (sscanf(lex->tok.value, " %f %f %f ", + + /* It's a vector if we can successfully scan 3 floats */ + if (util_sscanf(lex->tok.value, " %f %f %f ", &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3) -#endif { lex->tok.ttype = TOKEN_VECTORCONST; @@ -1472,9 +1494,9 @@ int lex_do(lex_file *lex) else { if (!lex->flags.preprocessing && strlen(lex->tok.value) > 1) { - uchar_t u8char; + utf8ch_t u8char; /* check for a valid utf8 character */ - if (!OPTS_FLAG(UTF8) || !u8_analyze(lex->tok.value, NULL, NULL, &u8char, 8)) { + if (!OPTS_FLAG(UTF8) || !utf8_to(&u8char, (const unsigned char *)lex->tok.value, 8)) { if (lexwarn(lex, WARN_MULTIBYTE_CHARACTER, ( OPTS_FLAG(UTF8) ? "invalid multibyte character sequence `%s`" : "multibyte character: `%s`" ), @@ -1491,7 +1513,7 @@ int lex_do(lex_file *lex) return lex->tok.ttype; } - if (isdigit(ch)) + if (util_isdigit(ch)) { lex->tok.ttype = lex_finish_digit(lex, ch); lex_endtoken(lex); @@ -1504,6 +1526,6 @@ int lex_do(lex_file *lex) return (lex->tok.ttype = ch); } - lexerror(lex, "unknown token: `%s`", lex->tok.value); + lexerror(lex, "unknown token: `%c`", ch); return (lex->tok.ttype = TOKEN_ERROR); }