X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=ftepp.c;h=8f452754d74b85b3f2787cfba12ee6ddbba112b6;hp=55d4fffb1e3330cb4e6f4b605a3c6ce1a61cf414;hb=bbeb2517c0bdf7477124f9a3acda0213ebe36529;hpb=0eab97283f30db40344105a699440d7b5fbd2f96 diff --git a/ftepp.c b/ftepp.c index 55d4fff..8f45275 100644 --- a/ftepp.c +++ b/ftepp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 + * Copyright (C) 2012, 2013, 2014 * Wolfgang Bumiller * Dale Weiler * @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include #include #include #include @@ -30,6 +29,7 @@ #include "lexer.h" #define HT_MACROS 1024 + typedef struct { bool on; bool was_on; @@ -41,7 +41,7 @@ typedef struct { char *value; /* a copy from the lexer */ union { - vector v; + vec3_t v; int i; double f; int t; /* type */ @@ -49,7 +49,7 @@ typedef struct { } pptoken; typedef struct { - lex_ctx ctx; + lex_ctx_t ctx; char *name; char **params; @@ -74,123 +74,97 @@ typedef struct ftepp_s { char *itemname; char *includename; bool in_macro; -} ftepp_t; -/* - * Implement the predef subsystem now. We can do this safely with the - * help of lexer contexts. - */ -static uint32_t ftepp_predef_countval = 0; -static uint32_t ftepp_predef_randval = 0; + uint32_t predef_countval; + uint32_t predef_randval; +} ftepp_t; /* __DATE__ */ -static char *ftepp_predef_date(lex_file *context) { - struct tm *itime = NULL; - time_t rtime; - char *value = (char*)mem_a(82); - /* 82 is enough for strftime but we also have " " in our string */ +static char *ftepp_predef_date(ftepp_t *context) { + const struct tm *itime = NULL; + char *value = (char*)mem_a(82); + time_t rtime; (void)context; - /* get time */ time (&rtime); - -#ifdef _MSC_VER - localtime_s(itime, &rtime); -#else - itime = localtime(&rtime); -#endif - + itime = util_localtime(&rtime); strftime(value, 82, "\"%b %d %Y\"", itime); return value; } /* __TIME__ */ -static char *ftepp_predef_time(lex_file *context) { - struct tm *itime = NULL; - time_t rtime; - char *value = (char*)mem_a(82); - /* 82 is enough for strftime but we also have " " in our string */ +static char *ftepp_predef_time(ftepp_t *context) { + const struct tm *itime = NULL; + char *value = (char*)mem_a(82); + time_t rtime; (void)context; - /* get time */ time (&rtime); - -#ifdef _MSC_VER - localtime_s(itime, &rtime); -#else - itime = localtime(&rtime); -#endif - + itime = util_localtime(&rtime); strftime(value, 82, "\"%X\"", itime); return value; } /* __LINE__ */ -static char *ftepp_predef_line(lex_file *context) { - char *value; - util_asprintf(&value, "%d", (int)context->line); +static char *ftepp_predef_line(ftepp_t *context) { + char *value; + + util_asprintf(&value, "%d", (int)context->lex->line); return value; } /* __FILE__ */ -static char *ftepp_predef_file(lex_file *context) { - size_t length = strlen(context->name) + 3; /* two quotes and a terminator */ - char *value = (char*)mem_a(length); - util_snprintf(value, length, "\"%s\"", context->name); +static char *ftepp_predef_file(ftepp_t *context) { + size_t length = strlen(context->lex->name) + 3; /* two quotes and a terminator */ + char *value = (char*)mem_a(length); + util_snprintf(value, length, "\"%s\"", context->lex->name); return value; } /* __COUNTER_LAST__ */ -static char *ftepp_predef_counterlast(lex_file *context) { - char *value; - util_asprintf(&value, "%u", ftepp_predef_countval); - - (void)context; +static char *ftepp_predef_counterlast(ftepp_t *context) { + char *value; + util_asprintf(&value, "%u", context->predef_countval); return value; } /* __COUNTER__ */ -static char *ftepp_predef_counter(lex_file *context) { - char *value; - ftepp_predef_countval ++; - util_asprintf(&value, "%u", ftepp_predef_countval); - (void)context; +static char *ftepp_predef_counter(ftepp_t *context) { + char *value; + + context->predef_countval ++; + util_asprintf(&value, "%u", context->predef_countval); return value; } /* __RANDOM__ */ -static char *ftepp_predef_random(lex_file *context) { - char *value; - ftepp_predef_randval = (util_rand() % 0xFF) + 1; - util_asprintf(&value, "%u", ftepp_predef_randval); +static char *ftepp_predef_random(ftepp_t *context) { + char *value; - (void)context; + context->predef_randval = (util_rand() % 0xFF) + 1; + util_asprintf(&value, "%u", context->predef_randval); return value; } /* __RANDOM_LAST__ */ -static char *ftepp_predef_randomlast(lex_file *context) { - char *value; - util_asprintf(&value, "%u", ftepp_predef_randval); +static char *ftepp_predef_randomlast(ftepp_t *context) { + char *value; - (void)context; + util_asprintf(&value, "%u", context->predef_randval); return value; } /* __TIMESTAMP__ */ -static char *ftepp_predef_timestamp(lex_file *context) { +static char *ftepp_predef_timestamp(ftepp_t *context) { struct stat finfo; - char *find; + const char *find; char *value; size_t size; - if (stat(context->name, &finfo)) + + if (stat(context->lex->name, &finfo)) return util_strdup("\"\""); - /* - * ctime and its fucking annoying newline char, no worries, we're - * professionals here. - */ - find = ctime(&finfo.st_mtime); + find = util_ctime(&finfo.st_mtime); value = (char*)mem_a(strlen(find) + 1); memcpy(&value[1], find, (size = strlen(find)) - 1); @@ -202,7 +176,7 @@ static char *ftepp_predef_timestamp(lex_file *context) { typedef struct { const char *name; - char *(*func)(lex_file *); + char *(*func)(ftepp_t *); } ftepp_predef_t; static const ftepp_predef_t ftepp_predefs[] = { @@ -217,36 +191,37 @@ static const ftepp_predef_t ftepp_predefs[] = { { "__TIME_STAMP__", &ftepp_predef_timestamp } }; -static GMQCC_INLINE int ftepp_predef_index(const char *name) { +static GMQCC_INLINE size_t ftepp_predef_index(const char *name) { /* no hashtable here, we simply check for one to exist the naive way */ - int i; - for(i = 0; i < (int)(sizeof(ftepp_predefs)/sizeof(*ftepp_predefs)); i++) - if (!strcmp(ftepp_predefs[i].name, name)) + size_t i; + for(i = 1; i < GMQCC_ARRAY_COUNT(ftepp_predefs) + 1; i++) + if (!strcmp(ftepp_predefs[i-1].name, name)) return i; - return -1; + return 0; } +bool ftepp_predef_exists(const char *name); bool ftepp_predef_exists(const char *name) { - return ftepp_predef_index(name) != -1; + return ftepp_predef_index(name) != 0; } /* singleton because we're allowed */ -static GMQCC_INLINE char *(*ftepp_predef(const char *name))(lex_file *context) { - int i = ftepp_predef_index(name); - return (i != -1) ? ftepp_predefs[i].func : NULL; +static GMQCC_INLINE char *(*ftepp_predef(const char *name))(ftepp_t *context) { + size_t i = ftepp_predef_index(name); + return (i != 0) ? ftepp_predefs[i-1].func : NULL; } #define ftepp_tokval(f) ((f)->lex->tok.value) #define ftepp_ctx(f) ((f)->lex->tok.ctx) -static void ftepp_errorat(ftepp_t *ftepp, lex_ctx ctx, const char *fmt, ...) +static void ftepp_errorat(ftepp_t *ftepp, lex_ctx_t ctx, const char *fmt, ...) { va_list ap; ftepp->errors++; va_start(ap, fmt); - con_cvprintmsg((void*)&ctx, LVL_ERROR, "error", fmt, ap); + con_cvprintmsg(ctx, LVL_ERROR, "error", fmt, ap); va_end(ap); } @@ -257,7 +232,7 @@ static void ftepp_error(ftepp_t *ftepp, const char *fmt, ...) ftepp->errors++; va_start(ap, fmt); - con_cvprintmsg((void*)&ftepp->lex->tok.ctx, LVL_ERROR, "error", fmt, ap); + con_cvprintmsg(ftepp->lex->tok.ctx, LVL_ERROR, "error", fmt, ap); va_end(ap); } @@ -293,7 +268,7 @@ static GMQCC_INLINE void pptoken_delete(pptoken *self) mem_d(self); } -static ppmacro *ppmacro_new(lex_ctx ctx, const char *name) +static ppmacro *ppmacro_new(lex_ctx_t ctx, const char *name) { ppmacro *macro = (ppmacro*)mem_a(sizeof(ppmacro)); @@ -323,8 +298,10 @@ static ftepp_t* ftepp_new(void) ftepp = (ftepp_t*)mem_a(sizeof(*ftepp)); memset(ftepp, 0, sizeof(*ftepp)); - ftepp->macros = util_htnew(HT_MACROS); - ftepp->output_on = true; + ftepp->macros = util_htnew(HT_MACROS); + ftepp->output_on = true; + ftepp->predef_countval = 0; + ftepp->predef_randval = 0; return ftepp; } @@ -521,10 +498,29 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro) return true; } +static const char *ftepp_math_constants[][2] = { + { "M_E", "2.7182818284590452354" }, /* e */ + { "M_LOG2E", "1.4426950408889634074" }, /* log_2 e */ + { "M_LOG10E", "0.43429448190325182765" }, /* log_10 e */ + { "M_LN2", "0.69314718055994530942" }, /* log_e 2 */ + { "M_LN10", "2.30258509299404568402" }, /* log_e 10 */ + { "M_PI", "3.14159265358979323846" }, /* pi */ + { "M_PI_2", "1.57079632679489661923" }, /* pi/2 */ + { "M_PI_4", "0.78539816339744830962" }, /* pi/4 */ + { "M_1_PI", "0.31830988618379067154" }, /* 1/pi */ + { "M_2_PI", "0.63661977236758134308" }, /* 2/pi */ + { "M_2_SQRTPI", "1.12837916709551257390" }, /* 2/sqrt(pi) */ + { "M_SQRT2", "1.41421356237309504880" }, /* sqrt(2) */ + { "M_SQRT1_2", "0.70710678118654752440" }, /* 1/sqrt(2) */ + { "M_TAU", "6.28318530717958647692" } /* pi*2 */ +}; + static bool ftepp_define(ftepp_t *ftepp) { ppmacro *macro = NULL; size_t l = ftepp_ctx(ftepp).line; + size_t i; + bool mathconstant = false; (void)ftepp_next(ftepp); if (!ftepp_skipspace(ftepp)) @@ -534,7 +530,25 @@ static bool ftepp_define(ftepp_t *ftepp) case TOKEN_IDENT: case TOKEN_TYPENAME: case TOKEN_KEYWORD: + if (OPTS_FLAG(FTEPP_MATHDEFS)) { + for (i = 0; i < GMQCC_ARRAY_COUNT(ftepp_math_constants); i++) { + if (!strcmp(ftepp_math_constants[i][0], ftepp_tokval(ftepp))) { + mathconstant = true; + break; + } + } + } + macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp)); + + if (OPTS_FLAG(FTEPP_MATHDEFS)) { + /* user defined ones take precedence */ + if (macro && mathconstant) { + ftepp_macro_delete(ftepp, ftepp_tokval(ftepp)); + macro = NULL; + } + } + if (macro && ftepp->output_on) { if (ftepp_warn(ftepp, WARN_CPP, "redefining `%s`", ftepp_tokval(ftepp))) return false; @@ -624,7 +638,7 @@ static bool ftepp_macro_call_params(ftepp_t *ftepp, macroparam **out_params) ptok = pptoken_make(ftepp); vec_push(mp.tokens, ptok); if (ftepp_next(ftepp) >= TOKEN_EOF) { - ftepp_error(ftepp, "unexpected EOF in macro call"); + ftepp_error(ftepp, "unexpected end of file in macro call"); goto on_error; } } @@ -637,16 +651,10 @@ static bool ftepp_macro_call_params(ftepp_t *ftepp, macroparam **out_params) goto on_error; } if (ftepp_next(ftepp) >= TOKEN_EOF) { - ftepp_error(ftepp, "unexpected EOF in macro call"); + ftepp_error(ftepp, "unexpected end of file in macro call"); goto on_error; } } - /* need to leave that up - if (ftepp_next(ftepp) >= TOKEN_EOF) { - ftepp_error(ftepp, "unexpected EOF in macro call"); - goto on_error; - } - */ *out_params = params; return true; @@ -755,6 +763,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param lex_file *inlex; bool old_inmacro; + bool strip = false; int nextok; @@ -819,6 +828,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param if (nextok == '#') { /* raw concatenation */ ++o; + strip = true; break; } if ( (nextok == TOKEN_IDENT || @@ -827,6 +837,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param macro_params_find(macro, macro->output[o+1]->value, &pi)) { ++o; + ftepp_stringify(ftepp, ¶ms[pi]); break; } @@ -837,7 +848,15 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param ftepp_out(ftepp, "\n", false); break; default: - ftepp_out(ftepp, out->value, false); + buffer = out->value; + #define buffer_stripable(X) ((X) == ' ' || (X) == '\t') + if (vec_size(macro->output) > o + 1 && macro->output[o+1]->token == '#' && buffer_stripable(*buffer)) + buffer++; + if (strip) { + while (buffer_stripable(*buffer)) buffer++; + strip = false; + } + ftepp_out(ftepp, buffer, false); break; } } @@ -1298,7 +1317,7 @@ static void unescape(const char *str, char *out) { static char *ftepp_include_find_path(const char *file, const char *pathfile) { - FILE *fp; + fs_file_t *fp; char *filename = NULL; const char *last_slash; size_t len; @@ -1346,10 +1365,10 @@ static bool ftepp_directive_warning(ftepp_t *ftepp) { /* 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); + vec_append(message, 8, "#warning"); ftepp_next(ftepp); while (ftepp->token != TOKEN_EOL) { - vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp))); + vec_append(message, strlen(ftepp_tokval(ftepp)), ftepp_tokval(ftepp)); ftepp_next(ftepp); } vec_push(message, '\0'); @@ -1376,10 +1395,10 @@ static void ftepp_directive_error(ftepp_t *ftepp) { /* handle the odd non string constant case so it works like C */ if (ftepp->token != TOKEN_STRINGCONST) { - vec_upload(message, "#error", 6); + vec_append(message, 6, "#error"); ftepp_next(ftepp); while (ftepp->token != TOKEN_EOL) { - vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp))); + vec_append(message, strlen(ftepp_tokval(ftepp)), ftepp_tokval(ftepp)); ftepp_next(ftepp); } vec_push(message, '\0'); @@ -1404,15 +1423,15 @@ static void ftepp_directive_message(ftepp_t *ftepp) { /* handle the odd non string constant case so it works like C */ if (ftepp->token != TOKEN_STRINGCONST) { - vec_upload(message, "#message", 8); + vec_append(message, 8, "#message"); ftepp_next(ftepp); while (ftepp->token != TOKEN_EOL) { - vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp))); + vec_append(message, strlen(ftepp_tokval(ftepp)), ftepp_tokval(ftepp)); ftepp_next(ftepp); } vec_push(message, '\0'); if (ftepp->output_on) - con_cprintmsg(&ftepp->lex->tok.ctx, LVL_MSG, "message", message); + con_cprintmsg(ftepp->lex->tok.ctx, LVL_MSG, "message", message); vec_free(message); return; } @@ -1421,7 +1440,7 @@ static void ftepp_directive_message(ftepp_t *ftepp) { return; unescape (ftepp_tokval(ftepp), ftepp_tokval(ftepp)); - con_cprintmsg(&ftepp->lex->tok.ctx, LVL_MSG, "message", ftepp_tokval(ftepp)); + con_cprintmsg(ftepp->lex->tok.ctx, LVL_MSG, "message", ftepp_tokval(ftepp)); } /** @@ -1433,7 +1452,7 @@ static bool ftepp_include(ftepp_t *ftepp) { lex_file *old_lexer = ftepp->lex; lex_file *inlex; - lex_ctx ctx; + lex_ctx_t ctx; char lineno[128]; char *filename; char *old_includename; @@ -1518,12 +1537,17 @@ static bool ftepp_else_allowed(ftepp_t *ftepp) return true; } +static GMQCC_INLINE void ftepp_inmacro(ftepp_t *ftepp, const char *hash) { + if (ftepp->in_macro) + (void)!ftepp_warn(ftepp, WARN_DIRECTIVE_INMACRO, "`#%s` directive in macro", hash); +} + static bool ftepp_hash(ftepp_t *ftepp) { ppcondition cond; ppcondition *pc; - lex_ctx ctx = ftepp_ctx(ftepp); + lex_ctx_t ctx = ftepp_ctx(ftepp); if (!ftepp_skipspace(ftepp)) return false; @@ -1533,12 +1557,15 @@ static bool ftepp_hash(ftepp_t *ftepp) case TOKEN_IDENT: case TOKEN_TYPENAME: if (!strcmp(ftepp_tokval(ftepp), "define")) { + ftepp_inmacro(ftepp, "define"); return ftepp_define(ftepp); } else if (!strcmp(ftepp_tokval(ftepp), "undef")) { + ftepp_inmacro(ftepp, "undef"); return ftepp_undef(ftepp); } else if (!strcmp(ftepp_tokval(ftepp), "ifdef")) { + ftepp_inmacro(ftepp, "ifdef"); if (!ftepp_ifdef(ftepp, &cond)) return false; cond.was_on = cond.on; @@ -1547,6 +1574,7 @@ static bool ftepp_hash(ftepp_t *ftepp) break; } else if (!strcmp(ftepp_tokval(ftepp), "ifndef")) { + ftepp_inmacro(ftepp, "ifndef"); if (!ftepp_ifdef(ftepp, &cond)) return false; cond.on = !cond.on; @@ -1556,6 +1584,7 @@ static bool ftepp_hash(ftepp_t *ftepp) break; } else if (!strcmp(ftepp_tokval(ftepp), "elifdef")) { + ftepp_inmacro(ftepp, "elifdef"); if (!ftepp_else_allowed(ftepp)) return false; if (!ftepp_ifdef(ftepp, &cond)) @@ -1567,6 +1596,7 @@ static bool ftepp_hash(ftepp_t *ftepp) break; } else if (!strcmp(ftepp_tokval(ftepp), "elifndef")) { + ftepp_inmacro(ftepp, "elifndef"); if (!ftepp_else_allowed(ftepp)) return false; if (!ftepp_ifdef(ftepp, &cond)) @@ -1579,6 +1609,7 @@ static bool ftepp_hash(ftepp_t *ftepp) break; } else if (!strcmp(ftepp_tokval(ftepp), "elif")) { + ftepp_inmacro(ftepp, "elif"); if (!ftepp_else_allowed(ftepp)) return false; if (!ftepp_if(ftepp, &cond)) @@ -1590,6 +1621,7 @@ static bool ftepp_hash(ftepp_t *ftepp) break; } else if (!strcmp(ftepp_tokval(ftepp), "if")) { + ftepp_inmacro(ftepp, "if"); if (!ftepp_if(ftepp, &cond)) return false; cond.was_on = cond.on; @@ -1598,6 +1630,7 @@ static bool ftepp_hash(ftepp_t *ftepp) break; } else if (!strcmp(ftepp_tokval(ftepp), "else")) { + ftepp_inmacro(ftepp, "else"); if (!ftepp_else_allowed(ftepp)) return false; pc = &vec_last(ftepp->conditions); @@ -1608,6 +1641,7 @@ static bool ftepp_hash(ftepp_t *ftepp) break; } else if (!strcmp(ftepp_tokval(ftepp), "endif")) { + ftepp_inmacro(ftepp, "endif"); if (!vec_size(ftepp->conditions)) { ftepp_error(ftepp, "#endif without #if"); return false; @@ -1618,6 +1652,7 @@ static bool ftepp_hash(ftepp_t *ftepp) break; } else if (!strcmp(ftepp_tokval(ftepp), "include")) { + ftepp_inmacro(ftepp, "include"); return ftepp_include(ftepp); } else if (!strcmp(ftepp_tokval(ftepp), "pragma")) { @@ -1694,9 +1729,9 @@ static bool ftepp_preprocess(ftepp_t *ftepp) case TOKEN_TYPENAME: /* is it a predef? */ if (OPTS_FLAG(FTEPP_PREDEFS)) { - char *(*predef)(lex_file*) = ftepp_predef(ftepp_tokval(ftepp)); + char *(*predef)(ftepp_t*) = ftepp_predef(ftepp_tokval(ftepp)); if (predef) { - expand = predef(ftepp->lex); + expand = predef(ftepp); ftepp_out (ftepp, expand, false); ftepp_next(ftepp); @@ -1814,10 +1849,10 @@ void ftepp_add_macro(ftepp_t *ftepp, const char *name, const char *value) { return; } - vec_upload(create, "#define ", 8); - vec_upload(create, name, strlen(name)); + vec_append(create, 8, "#define "); + vec_append(create, strlen(name), name); vec_push (create, ' '); - vec_upload(create, value, strlen(value)); + vec_append(create, strlen(value), value); vec_push (create, 0); ftepp_preprocess_string(ftepp, "__builtin__", create); @@ -1829,6 +1864,7 @@ ftepp_t *ftepp_create() ftepp_t *ftepp; char minor[32]; char major[32]; + size_t i; ftepp = ftepp_new(); if (!ftepp) @@ -1878,13 +1914,20 @@ ftepp_t *ftepp_create() */ ftepp_add_macro(ftepp, "__NULL__", "nil"); + /* add all the math constants if they can be */ + if (OPTS_FLAG(FTEPP_MATHDEFS)) { + for (i = 0; i < GMQCC_ARRAY_COUNT(ftepp_math_constants); i++) + if (!ftepp_macro_find(ftepp, ftepp_math_constants[i][0])) + ftepp_add_macro(ftepp, ftepp_math_constants[i][0], ftepp_math_constants[i][1]); + } + return ftepp; } void ftepp_add_define(ftepp_t *ftepp, const char *source, const char *name) { ppmacro *macro; - lex_ctx ctx = { "__builtin__", 0, 0 }; + lex_ctx_t ctx = { "__builtin__", 0, 0 }; ctx.file = source; macro = ppmacro_new(ctx, name); /*vec_push(ftepp->macros, macro);*/