X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=ftepp.c;h=838d0de38d37f9198fbe3fa2e795340e83c09394;hp=e1ee582c634c722eac2a285a575b595f9788bb15;hb=9edae7fa0a06516a94b411f5d6220bd25157cee7;hpb=0a57c408c0190f9cc267d14cbff648cf7cbebc3c diff --git a/ftepp.c b/ftepp.c index e1ee582..838d0de 100644 --- a/ftepp.c +++ b/ftepp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 + * Copyright (C) 2012, 2013 * Wolfgang Bumiller * Dale Weiler * @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include #include "gmqcc.h" #include "lexer.h" @@ -49,6 +50,7 @@ typedef struct { char **params; /* yes we need an extra flag since `#define FOO x` is not the same as `#define FOO() x` */ bool has_params; + bool variadic; pptoken **output; } ppmacro; @@ -68,22 +70,53 @@ typedef struct { char *includename; } ftepp_t; -typedef struct { - const char *name; - char *(*func)(lex_file *); -} predef_t; - /* * Implement the predef subsystem now. We can do this safely with the * help of lexer contexts. */ -static int ftepp_predef_countval = 0; -static int ftepp_predef_randval = 0; +static uint32_t ftepp_predef_countval = 0; +static uint32_t ftepp_predef_randval = 0; + +/* __DATE__ */ +char *ftepp_predef_date(lex_file *context) { + struct tm *itime; + time_t rtime; + char *value = mem_a(82); + /* 82 is enough for strftime but we also have " " in our string */ + + (void)context; + + /* get time */ + time (&rtime); + itime = localtime(&rtime); + + strftime(value, 82, "\"%b %d %Y\"", itime); + + return value; +} + +/* __TIME__ */ +char *ftepp_predef_time(lex_file *context) { + struct tm *itime; + time_t rtime; + char *value = mem_a(82); + /* 82 is enough for strftime but we also have " " in our string */ + + (void)context; + + /* get time */ + time (&rtime); + itime = localtime(&rtime); + + strftime(value, 82, "\"%X\"", itime); + + return value; +} /* __LINE__ */ char *ftepp_predef_line(lex_file *context) { - char *value = (char*)mem_a(128); - sprintf(value, "%d", (int)context->line); + char *value; + util_asprintf(&value, "%d", (int)context->line); return value; } /* __FILE__ */ @@ -97,46 +130,48 @@ char *ftepp_predef_file(lex_file *context) { } /* __COUNTER_LAST__ */ char *ftepp_predef_counterlast(lex_file *context) { - char *value = (char*)mem_a(128); - sprintf(value, "%d", ftepp_predef_countval); + char *value; + util_asprintf(&value, "%u", ftepp_predef_countval); (void)context; return value; } /* __COUNTER__ */ char *ftepp_predef_counter(lex_file *context) { - char *value = (char*)mem_a(128); + char *value; ftepp_predef_countval ++; - sprintf(value, "%d", ftepp_predef_countval); + util_asprintf(&value, "%u", ftepp_predef_countval); (void)context; return value; } /* __RANDOM__ */ char *ftepp_predef_random(lex_file *context) { - char *value = (char*)mem_a(128); - ftepp_predef_randval = rand() % 0xFFFF; /* short int */ - sprintf(value, "%d", ftepp_predef_randval); + char *value; + ftepp_predef_randval = (util_rand() % 0xFF) + 1; + util_asprintf(&value, "%u", ftepp_predef_randval); (void)context; return value; } /* __RANDOM_LAST__ */ char *ftepp_predef_randomlast(lex_file *context) { - char *value = (char*)mem_a(128); - sprintf(value, "%d", ftepp_predef_randval); + char *value; + util_asprintf(&value, "%u", ftepp_predef_randval); (void)context; return value; } -static const predef_t ftepp_predefs[] = { +const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT] = { { "__LINE__", &ftepp_predef_line }, { "__FILE__", &ftepp_predef_file }, { "__COUNTER__", &ftepp_predef_counter }, { "__COUNTER_LAST__", &ftepp_predef_counterlast }, { "__RANDOM__", &ftepp_predef_random }, { "__RANDOM_LAST__", &ftepp_predef_randomlast }, + { "__DATE__", &ftepp_predef_date }, + { "__TIME__", &ftepp_predef_time } }; #define ftepp_tokval(f) ((f)->lex->tok.value) @@ -231,9 +266,15 @@ static ftepp_t* ftepp_new() return ftepp; } +static void ftepp_flush_do(ftepp_t *self) +{ + vec_free(self->output_string); +} + static void ftepp_delete(ftepp_t *self) { size_t i; + ftepp_flush_do(self); if (self->itemname) mem_d(self->itemname); if (self->includename) @@ -336,15 +377,22 @@ static bool ftepp_define_params(ftepp_t *ftepp, ppmacro *macro) case TOKEN_IDENT: case TOKEN_TYPENAME: case TOKEN_KEYWORD: + vec_push(macro->params, util_strdup(ftepp_tokval(ftepp))); + break; + case TOKEN_DOTS: + macro->variadic = true; break; default: ftepp_error(ftepp, "unexpected token in parameter list"); return false; } - vec_push(macro->params, util_strdup(ftepp_tokval(ftepp))); ftepp_next(ftepp); if (!ftepp_skipspace(ftepp)) return false; + if (macro->variadic && ftepp->token != ')') { + ftepp_error(ftepp, "cannot have parameters after the variadic parameters"); + return false; + } } while (ftepp->token == ','); if (ftepp->token != ')') { ftepp_error(ftepp, "expected closing paren after macro parameter list"); @@ -359,6 +407,8 @@ 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); @@ -570,18 +620,38 @@ static void ftepp_recursion_footer(ftepp_t *ftepp) ftepp_out(ftepp, "\n#pragma pop(line)\n", false); } +static void ftepp_param_out(ftepp_t *ftepp, macroparam *param) +{ + size_t i; + pptoken *out; + for (i = 0; i < vec_size(param->tokens); ++i) { + out = param->tokens[i]; + if (out->token == TOKEN_EOL) + ftepp_out(ftepp, "\n", false); + else + ftepp_out(ftepp, out->value, false); + } +} + static bool ftepp_preprocess(ftepp_t *ftepp); static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *params) { - char *old_string = ftepp->output_string; - lex_file *old_lexer = ftepp->lex; - bool retval = true; + char *old_string = ftepp->output_string; + lex_file *old_lexer = ftepp->lex; + size_t vararg_start = vec_size(macro->params); + bool retval = true; + size_t varargs; - size_t o, pi, pv; + size_t o, pi; lex_file *inlex; int nextok; + if (vararg_start < vec_size(params)) + varargs = vec_size(params) - vararg_start; + else + varargs = 0; + /* really ... */ if (!vec_size(macro->output)) return true; @@ -590,21 +660,28 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param for (o = 0; o < vec_size(macro->output); ++o) { pptoken *out = macro->output[o]; switch (out->token) { + case TOKEN_VA_ARGS: + if (!macro->variadic) { + ftepp_error(ftepp, "internal preprocessor error: TOKEN_VA_ARGS in non-variadic macro"); + return false; + } + if (!varargs) + break; + pi = 0; + ftepp_param_out(ftepp, ¶ms[pi + vararg_start]); + for (++pi; pi < varargs; ++pi) { + ftepp_out(ftepp, ", ", false); + ftepp_param_out(ftepp, ¶ms[pi + vararg_start]); + } + break; case TOKEN_IDENT: case TOKEN_TYPENAME: case TOKEN_KEYWORD: if (!macro_params_find(macro, out->value, &pi)) { ftepp_out(ftepp, out->value, false); break; - } else { - for (pv = 0; pv < vec_size(params[pi].tokens); ++pv) { - out = params[pi].tokens[pv]; - if (out->token == TOKEN_EOL) - ftepp_out(ftepp, "\n", false); - else - ftepp_out(ftepp, out->value, false); - } - } + } else + ftepp_param_out(ftepp, ¶ms[pi]); break; case '#': if (o + 1 < vec_size(macro->output)) { @@ -646,13 +723,18 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param goto cleanup; } ftepp->output_string = old_string; + inlex->line = ftepp->lex->line; + inlex->sline = ftepp->lex->sline; ftepp->lex = inlex; ftepp_recursion_header(ftepp); if (!ftepp_preprocess(ftepp)) { + vec_free(ftepp->lex->open_string); + old_string = ftepp->output_string; lex_close(ftepp->lex); retval = false; goto cleanup; } + vec_free(ftepp->lex->open_string); ftepp_recursion_footer(ftepp); old_string = ftepp->output_string; @@ -688,8 +770,11 @@ static bool ftepp_macro_call(ftepp_t *ftepp, ppmacro *macro) if (!ftepp_macro_call_params(ftepp, ¶ms)) return false; - if (vec_size(params) != vec_size(macro->params)) { - ftepp_error(ftepp, "macro %s expects %u paramteters, %u provided", macro->name, + if ( vec_size(params) < vec_size(macro->params) || + (vec_size(params) > vec_size(macro->params) && !macro->variadic) ) + { + ftepp_error(ftepp, "macro %s expects%s %u paramteters, %u provided", macro->name, + (macro->variadic ? " at least" : ""), (unsigned int)vec_size(macro->params), (unsigned int)vec_size(params)); retval = false; @@ -737,6 +822,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; @@ -748,6 +834,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: @@ -804,6 +898,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: @@ -827,8 +922,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.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); @@ -1587,7 +1686,7 @@ const char *ftepp_get() void ftepp_flush() { - vec_free(ftepp->output_string); + ftepp_flush_do(ftepp); } void ftepp_finish()