]> de.git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ftepp.c
Make it a function
[xonotic/gmqcc.git] / ftepp.c
diff --git a/ftepp.c b/ftepp.c
index 36bb1a7b59faeca6390ef3ce31fac56e8de5127f..7b24c647eebaf940ac017bddc1ef2ced095c1ebf 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013
+ * Copyright (C) 2012, 2013, 2014
  *     Wolfgang Bumiller
  *     Dale Weiler
  *
@@ -23,7 +23,6 @@
  */
 #include <string.h>
 #include <stdlib.h>
-#include <time.h>
 #include <sys/stat.h>
 
 #include "gmqcc.h"
@@ -75,17 +74,13 @@ 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) {
+static char *ftepp_predef_date(ftepp_t *context) {
     const struct tm *itime = NULL;
     char            *value = (char*)mem_a(82);
     time_t           rtime;
@@ -100,7 +95,7 @@ static char *ftepp_predef_date(lex_file *context) {
 }
 
 /* __TIME__ */
-static char *ftepp_predef_time(lex_file *context) {
+static char *ftepp_predef_time(ftepp_t *context) {
     const struct tm *itime = NULL;
     char            *value = (char*)mem_a(82);
     time_t           rtime;
@@ -115,61 +110,58 @@ static char *ftepp_predef_time(lex_file *context) {
 }
 
 /* __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;
     const char *find;
     char       *value;
     size_t      size;
 
-    if (stat(context->name, &finfo))
+    if (stat(context->lex->name, &finfo))
         return util_strdup("\"<failed to determine timestamp>\"");
 
     find = util_ctime(&finfo.st_mtime);
@@ -184,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[] = {
@@ -214,7 +206,7 @@ bool ftepp_predef_exists(const char *name) {
 }
 
 /* singleton because we're allowed */
-static GMQCC_INLINE char *(*ftepp_predef(const char *name))(lex_file *context) {
+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;
 }
@@ -306,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;
 }
@@ -504,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))
@@ -517,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;
@@ -703,6 +734,7 @@ static void ftepp_recursion_footer(ftepp_t *ftepp)
     ftepp_out(ftepp, "\n#pragma pop(line)\n", false);
 }
 
+static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *params, bool resetline);
 static void ftepp_param_out(ftepp_t *ftepp, macroparam *param)
 {
     size_t   i;
@@ -711,8 +743,13 @@ static void ftepp_param_out(ftepp_t *ftepp, macroparam *param)
         out = param->tokens[i];
         if (out->token == TOKEN_EOL)
             ftepp_out(ftepp, "\n", false);
-        else
-            ftepp_out(ftepp, out->value, false);
+        else {
+            ppmacro *find = ftepp_macro_find(ftepp, out->value);
+            if (OPTS_FLAG(FTEPP_INDIRECT_EXPANSION) && find && !find->has_params)
+                ftepp_macro_expand(ftepp, find, NULL, false);
+            else
+                ftepp_out(ftepp, out->value, false);
+        }
     }
 }
 
@@ -732,6 +769,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
     lex_file *inlex;
 
     bool      old_inmacro;
+    bool      strip = false;
 
     int nextok;
 
@@ -796,6 +834,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    ||
@@ -804,6 +843,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, &params[pi]);
                         break;
                     }
@@ -814,7 +854,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;
         }
     }
@@ -1687,9 +1735,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);
 
@@ -1822,6 +1870,7 @@ ftepp_t *ftepp_create()
     ftepp_t *ftepp;
     char minor[32];
     char major[32];
+    size_t i;
 
     ftepp = ftepp_new();
     if (!ftepp)
@@ -1871,6 +1920,13 @@ 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;
 }