X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=ftepp.c;h=34eec593bc8754019c635a4ddf1accc604cb54cb;hp=ea686612cfd08156d65fe7326a29a205516779e6;hb=36c5722273f1ea87603621c6ee20b7178a7a641b;hpb=7d14fdf530e49cb04b13572a790178c4c4bf75dc diff --git a/ftepp.c b/ftepp.c index ea68661..34eec59 100644 --- a/ftepp.c +++ b/ftepp.c @@ -68,6 +68,7 @@ typedef struct { char *itemname; char *includename; + bool in_macro; } ftepp_t; /* @@ -407,11 +408,55 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro) { pptoken *ptok; while (ftepp->token != TOKEN_EOL && ftepp->token < TOKEN_EOF) { - if (macro->variadic && !strcmp(ftepp_tokval(ftepp), "__VA_ARGS__")) - ftepp->token = TOKEN_VA_ARGS; - ptok = pptoken_make(ftepp); - vec_push(macro->output, ptok); - ftepp_next(ftepp); + bool subscript = false; + size_t index = 0; + if (macro->variadic && !strcmp(ftepp_tokval(ftepp), "__VA_ARGS__")) { + subscript = !!(ftepp_next(ftepp) == '#'); + + if (subscript && ftepp_next(ftepp) != '#') { + ftepp_error(ftepp, "expected `##` in __VA_ARGS__ for subscripting"); + return false; + } else if (subscript) { + if (ftepp_next(ftepp) == '[') { + if (ftepp_next(ftepp) != TOKEN_INTCONST) { + ftepp_error(ftepp, "expected index for __VA_ARGS__ subscript"); + return false; + } + + index = atoi(ftepp_tokval(ftepp)); + + if (ftepp_next(ftepp) != ']') { + ftepp_error(ftepp, "expected `]` in __VA_ARGS__ subscript"); + return false; + } + + /* + * mark it as an array to be handled later as such and not + * as traditional __VA_ARGS__ + */ + ftepp->token = TOKEN_VA_ARGS_ARRAY; + ptok = pptoken_make(ftepp); + ptok->constval.i = index; + vec_push(macro->output, ptok); + ftepp_next(ftepp); + } else { + ftepp_error(ftepp, "expected `[` for subscripting of __VA_ARGS__"); + return false; + } + } else { + int old = ftepp->token; + ftepp->token = TOKEN_VA_ARGS; + ptok = pptoken_make(ftepp); + vec_push(macro->output, ptok); + ftepp->token = old; + } + } + else + { + ptok = pptoken_make(ftepp); + vec_push(macro->output, ptok); + ftepp_next(ftepp); + } } /* recursive expansion can cause EOFs here */ if (ftepp->token != TOKEN_EOL && ftepp->token != TOKEN_EOF) { @@ -436,7 +481,7 @@ static bool ftepp_define(ftepp_t *ftepp) case TOKEN_KEYWORD: macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp)); if (macro && ftepp->output_on) { - if (ftepp_warn(ftepp, WARN_PREPROCESSOR, "redefining `%s`", ftepp_tokval(ftepp))) + if (ftepp_warn(ftepp, WARN_CPP, "redefining `%s`", ftepp_tokval(ftepp))) return false; ftepp_macro_delete(ftepp, ftepp_tokval(ftepp)); } @@ -634,17 +679,21 @@ static void ftepp_param_out(ftepp_t *ftepp, macroparam *param) } static bool ftepp_preprocess(ftepp_t *ftepp); -static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *params) +static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *params, bool resetline) { char *old_string = ftepp->output_string; + char *inner_string; lex_file *old_lexer = ftepp->lex; size_t vararg_start = vec_size(macro->params); bool retval = true; + bool has_newlines; size_t varargs; size_t o, pi; lex_file *inlex; + bool old_inmacro; + int nextok; if (vararg_start < vec_size(params)) @@ -663,10 +712,12 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param case TOKEN_VA_ARGS: if (!macro->variadic) { ftepp_error(ftepp, "internal preprocessor error: TOKEN_VA_ARGS in non-variadic macro"); + vec_free(old_string); return false; } if (!varargs) break; + pi = 0; ftepp_param_out(ftepp, ¶ms[pi + vararg_start]); for (++pi; pi < varargs; ++pi) { @@ -674,6 +725,17 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param ftepp_param_out(ftepp, ¶ms[pi + vararg_start]); } break; + + case TOKEN_VA_ARGS_ARRAY: + if ((size_t)out->constval.i >= varargs) { + ftepp_error(ftepp, "subscript of `[%u]` is out of bounds for `__VA_ARGS__`", out->constval.i); + vec_free(old_string); + return false; + } + + ftepp_param_out(ftepp, ¶ms[out->constval.i + vararg_start]); + break; + case TOKEN_IDENT: case TOKEN_TYPENAME: case TOKEN_KEYWORD: @@ -722,22 +784,47 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param retval = false; goto cleanup; } - ftepp->output_string = old_string; - inlex->line = ftepp->lex->line; + + inlex->line = ftepp->lex->line; inlex->sline = ftepp->lex->sline; - ftepp->lex = inlex; - ftepp_recursion_header(ftepp); + ftepp->lex = inlex; + + old_inmacro = ftepp->in_macro; + ftepp->in_macro = true; + ftepp->output_string = NULL; if (!ftepp_preprocess(ftepp)) { + ftepp->in_macro = old_inmacro; vec_free(ftepp->lex->open_string); - old_string = ftepp->output_string; + vec_free(ftepp->output_string); lex_close(ftepp->lex); retval = false; goto cleanup; } + ftepp->in_macro = old_inmacro; vec_free(ftepp->lex->open_string); - ftepp_recursion_footer(ftepp); - old_string = ftepp->output_string; + lex_close(ftepp->lex); + + inner_string = ftepp->output_string; + ftepp->output_string = old_string; + has_newlines = (strchr(inner_string, '\n') != NULL); + + if (has_newlines && !old_inmacro) + ftepp_recursion_header(ftepp); + + vec_append(ftepp->output_string, vec_size(inner_string), inner_string); + vec_free(inner_string); + + if (has_newlines && !old_inmacro) + ftepp_recursion_footer(ftepp); + + if (resetline && !ftepp->in_macro) { + char lineno[128]; + sprintf(lineno, "\n#pragma line(%lu)\n", (unsigned long)(old_lexer->sline)); + ftepp_out(ftepp, lineno, false); + } + + old_string = ftepp->output_string; cleanup: ftepp->lex = old_lexer; ftepp->output_string = old_string; @@ -749,9 +836,10 @@ static bool ftepp_macro_call(ftepp_t *ftepp, ppmacro *macro) size_t o; macroparam *params = NULL; bool retval = true; + size_t paramline; if (!macro->has_params) { - if (!ftepp_macro_expand(ftepp, macro, NULL)) + if (!ftepp_macro_expand(ftepp, macro, NULL, false)) return false; ftepp_next(ftepp); return true; @@ -767,6 +855,7 @@ static bool ftepp_macro_call(ftepp_t *ftepp, ppmacro *macro) } ftepp_next(ftepp); + paramline = ftepp->lex->sline; if (!ftepp_macro_call_params(ftepp, ¶ms)) return false; @@ -781,7 +870,7 @@ static bool ftepp_macro_call(ftepp_t *ftepp, ppmacro *macro) goto cleanup; } - if (!ftepp_macro_expand(ftepp, macro, params)) + if (!ftepp_macro_expand(ftepp, macro, params, (paramline != ftepp->lex->sline))) retval = false; ftepp_next(ftepp); @@ -822,6 +911,7 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out) { ppmacro *macro; bool wasnot = false; + bool wasneg = false; if (!ftepp_skipspace(ftepp)) return false; @@ -833,6 +923,14 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out) return false; } + if (ftepp->token == TOKEN_OPERATOR && !strcmp(ftepp_tokval(ftepp), "-")) + { + wasneg = true; + ftepp_next(ftepp); + if (!ftepp_skipspace(ftepp)) + return false; + } + switch (ftepp->token) { case TOKEN_IDENT: case TOKEN_TYPENAME: @@ -889,6 +987,7 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out) } break; case TOKEN_STRINGCONST: + *value_out = 0; *out = false; break; case TOKEN_INTCONST: @@ -912,8 +1011,12 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out) default: ftepp_error(ftepp, "junk in #if: `%s` ...", ftepp_tokval(ftepp)); + if (OPTS_OPTION_BOOL(OPTION_DEBUG)) + ftepp_error(ftepp, "internal: token %i\n", ftepp->token); return false; } + if (wasneg) + *value_out = -*value_out; if (wasnot) { *out = !*out; *value_out = (*out ? 1 : 0); @@ -1166,55 +1269,6 @@ static char *ftepp_include_find(ftepp_t *ftepp, const char *file) return filename; } -static bool ftepp_directive_warning(ftepp_t *ftepp) { - char *message = NULL; - - if (!ftepp_skipspace(ftepp)) - return false; - - /* handle the odd non string constant case so it works like C */ - if (ftepp->token != TOKEN_STRINGCONST) { - bool store = false; - vec_upload(message, "#warning", 8); - ftepp_next(ftepp); - while (ftepp->token != TOKEN_EOL) { - vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp))); - ftepp_next(ftepp); - } - vec_push(message, '\0'); - store = ftepp_warn(ftepp, WARN_CPP, message); - vec_free(message); - return store; - } - - unescape (ftepp_tokval(ftepp), ftepp_tokval(ftepp)); - return ftepp_warn(ftepp, WARN_CPP, "#warning %s", ftepp_tokval(ftepp)); -} - -static void ftepp_directive_error(ftepp_t *ftepp) { - char *message = NULL; - - if (!ftepp_skipspace(ftepp)) - return; - - /* handle the odd non string constant case so it works like C */ - if (ftepp->token != TOKEN_STRINGCONST) { - vec_upload(message, "#error", 6); - ftepp_next(ftepp); - while (ftepp->token != TOKEN_EOL) { - vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp))); - ftepp_next(ftepp); - } - vec_push(message, '\0'); - ftepp_error(ftepp, message); - vec_free(message); - return; - } - - unescape (ftepp_tokval(ftepp), ftepp_tokval(ftepp)); - ftepp_error(ftepp, "#error %s", ftepp_tokval(ftepp)); -} - /** * Include a file. * FIXME: do we need/want a -I option? @@ -1410,14 +1464,6 @@ static bool ftepp_hash(ftepp_t *ftepp) ftepp_out(ftepp, "#", false); break; } - else if (!strcmp(ftepp_tokval(ftepp), "warning")) { - ftepp_directive_warning(ftepp); - break; - } - else if (!strcmp(ftepp_tokval(ftepp), "error")) { - ftepp_directive_error(ftepp); - break; - } else { if (ftepp->output_on) { ftepp_error(ftepp, "unrecognized preprocessor directive: `%s`", ftepp_tokval(ftepp)); @@ -1525,7 +1571,7 @@ static bool ftepp_preprocess(ftepp_t *ftepp) break; case TOKEN_WHITE: /* same as default but don't set newline=false */ - ftepp_out(ftepp, ftepp_tokval(ftepp), false); + ftepp_out(ftepp, ftepp_tokval(ftepp), true); ftepp_next(ftepp); break; default: @@ -1624,7 +1670,7 @@ bool ftepp_init() /* set the right macro based on the selected standard */ ftepp_add_define(NULL, "GMQCC"); - if (opts.standard == COMPILER_FTEQCC) { + if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) { ftepp_add_define(NULL, "__STD_FTEQCC__"); /* 1.00 */ major[0] = '"'; @@ -1634,11 +1680,15 @@ bool ftepp_init() minor[0] = '"'; minor[1] = '0'; minor[2] = '"'; - } else if (opts.standard == COMPILER_GMQCC) { + } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) { ftepp_add_define(NULL, "__STD_GMQCC__"); sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR); sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR); - } else if (opts.standard == COMPILER_QCC) { + } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCCX) { + ftepp_add_define(NULL, "__STD_QCCX__"); + sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR); + sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR); + } else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) { ftepp_add_define(NULL, "__STD_QCC__"); /* 1.0 */ major[0] = '"';