X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=lexer.c;h=a2e69d5f17f1c5bce8fb555cfebfeaa77539f928;hp=8fb7ef0547109fff9eb32e4d8537047a11a5559d;hb=82f37c87fcec69cfd9067581c13bc07128eec76b;hpb=8e077f378e7860d6a8e0fc2190a85c42dfda3731 diff --git a/lexer.c b/lexer.c index 8fb7ef0..a2e69d5 100644 --- a/lexer.c +++ b/lexer.c @@ -74,20 +74,17 @@ void lexerror(lex_file *lex, const char *fmt, ...) bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...) { + bool r; + lex_ctx ctx; va_list ap; - int lvl = LVL_WARNING; - if (!OPTS_WARN(warntype)) - return false; - - if (opts_werror) - lvl = LVL_ERROR; + ctx.file = lex->name; + ctx.line = lex->sline; va_start(ap, fmt); - con_vprintmsg(lvl, lex->name, lex->sline, (opts_werror ? "error" : "warning"), fmt, ap); + r = vcompile_warning(ctx, warntype, fmt, ap); va_end(ap); - - return opts_werror; + return r; } @@ -187,7 +184,7 @@ static void lex_token_new(lex_file *lex) lex_file* lex_open(const char *file) { lex_file *lex; - FILE *in = util_fopen(file, "rb"); + FILE *in = file_open(file, "rb"); if (!in) { lexerror(NULL, "open failed: '%s'\n", file); @@ -196,7 +193,7 @@ lex_file* lex_open(const char *file) lex = (lex_file*)mem_a(sizeof(*lex)); if (!lex) { - fclose(in); + file_close(in); lexerror(NULL, "out of memory\n"); return NULL; } @@ -261,7 +258,7 @@ void lex_close(lex_file *lex) vec_free(lex->modelname); if (lex->file) - fclose(lex->file); + file_close(lex->file); #if 0 if (lex->tok) token_delete(lex->tok); @@ -745,6 +742,9 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) { int ch = 0; int nextch; + bool hex; + char u8buf[8]; /* way more than enough */ + int u8len, uc; while (ch != EOF) { @@ -826,13 +826,51 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) case ']': ch = 17; break; case '{': ch = 0; + nextch = lex_getch(lex); + hex = (nextch == 'x'); + if (!hex) + lex_ungetch(lex, nextch); for (nextch = lex_getch(lex); nextch != '}'; nextch = lex_getch(lex)) { - ch = ch * 10 + nextch - '0'; - if (nextch < '0' || nextch > '9' || ch > 255) { - lexerror(lex, "bad character code"); + if (!hex) { + if (nextch >= '0' && nextch <= '9') + ch = ch * 10 + nextch - '0'; + else { + lexerror(lex, "bad character code"); + return (lex->tok.ttype = TOKEN_ERROR); + } + } else { + if (nextch >= '0' || nextch <= '9') + ch = ch * 16 + nextch - '0'; + else if (nextch >= 'a' && nextch <= 'f') + ch = ch * 16 + nextch - 'a' + 10; + else if (nextch >= 'A' && nextch <= 'F') + ch = ch * 16 + nextch - 'A' + 10; + else { + lexerror(lex, "bad character code"); + return (lex->tok.ttype = TOKEN_ERROR); + } + } + if ( (!OPTS_FLAG(UTF8) && ch > 255) || + ( OPTS_FLAG(UTF8) && ch > 0x10FFFF) ) + { + lexerror(lex, "character code out of range"); return (lex->tok.ttype = TOKEN_ERROR); } } + if (OPTS_FLAG(UTF8) && ch >= 128) { + u8len = u8_fromchar((uchar_t)ch, u8buf, sizeof(u8buf)); + if (!u8len) + ch = 0; + else { + --u8len; + for (uc = 0; uc < u8len; ++uc) + lex_tokench(lex, u8buf[uc]); + /* the last character will be inserted with the tokench() call + * below the switch + */ + ch = u8buf[uc]; + } + } break; case '\n': ch = '\n'; break; @@ -1064,7 +1102,6 @@ int lex_do(lex_file *lex) if (rc < 0) return (lex->tok.ttype = TOKEN_FATAL); - v = lex->tok.value; if (lex->modelname) { frame_macro m; m.value = lex->framevalue; @@ -1119,6 +1156,15 @@ int lex_do(lex_file *lex) switch (ch) { case '[': + nextch = lex_getch(lex); + if (nextch == '[') { + lex_tokench(lex, ch); + lex_tokench(lex, nextch); + lex_endtoken(lex); + return (lex->tok.ttype = TOKEN_ATTRIBUTE_OPEN); + } + lex_ungetch(lex, nextch); + /* FALL THROUGH */ case '(': case ':': case '?': @@ -1128,11 +1174,23 @@ int lex_do(lex_file *lex) return (lex->tok.ttype = ch); else return (lex->tok.ttype = TOKEN_OPERATOR); + + case ']': + if (lex->flags.noops) { + nextch = lex_getch(lex); + if (nextch == ']') { + lex_tokench(lex, ch); + lex_tokench(lex, nextch); + lex_endtoken(lex); + return (lex->tok.ttype = TOKEN_ATTRIBUTE_CLOSE); + } + lex_ungetch(lex, nextch); + } + /* FALL THROUGH */ case ')': case ';': case '{': case '}': - case ']': case '#': lex_tokench(lex, ch); @@ -1304,7 +1362,7 @@ int lex_do(lex_file *lex) if (!strcmp(v, keywords_qc[kw])) return (lex->tok.ttype = TOKEN_KEYWORD); } - if (opts_standard != COMPILER_QCC) { + if (opts.standard != COMPILER_QCC) { for (kw = 0; kw < num_keywords_fg; ++kw) { if (!strcmp(v, keywords_fg[kw])) return (lex->tok.ttype = TOKEN_KEYWORD); @@ -1355,7 +1413,7 @@ int lex_do(lex_file *lex) lex->tok.ttype = TOKEN_CHARCONST; /* It's a vector if we can successfully scan 3 floats */ -#ifdef WIN32 +#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 @@ -1369,10 +1427,20 @@ int lex_do(lex_file *lex) else { if (!lex->flags.preprocessing && strlen(lex->tok.value) > 1) { - if (lexwarn(lex, WARN_MULTIBYTE_CHARACTER, "multibyte character: `%s`", lex->tok.value)) - return (lex->tok.ttype = TOKEN_ERROR); + uchar_t u8char; + /* check for a valid utf8 character */ + if (!OPTS_FLAG(UTF8) || !u8_analyze(lex->tok.value, NULL, NULL, &u8char, 8)) { + if (lexwarn(lex, WARN_MULTIBYTE_CHARACTER, + ( OPTS_FLAG(UTF8) ? "invalid multibyte character sequence `%s`" + : "multibyte character: `%s`" ), + lex->tok.value)) + return (lex->tok.ttype = TOKEN_ERROR); + } + else + lex->tok.constval.i = u8char; } - lex->tok.constval.i = lex->tok.value[0]; + else + lex->tok.constval.i = lex->tok.value[0]; } return lex->tok.ttype;