]> de.git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ftepp.c
Don't expand macros inside #if 0 at _all_
[xonotic/gmqcc.git] / ftepp.c
diff --git a/ftepp.c b/ftepp.c
index 158daa1a16ec19f64a0805ed654894eff3e58a95..b9d0dedf6e6e41b77efb1cc5a122b63f19e252d0 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
@@ -65,6 +65,7 @@ typedef struct {
     char        *output_string;
 
     char        *itemname;
+    char        *includename;
 } ftepp_t;
 
 #define ftepp_tokval(f) ((f)->lex->tok.value)
@@ -77,7 +78,7 @@ static void ftepp_errorat(ftepp_t *ftepp, lex_ctx ctx, const char *fmt, ...)
     ftepp->errors++;
 
     va_start(ap, fmt);
-    con_vprintmsg(LVL_ERROR, ctx.file, ctx.line, "error", fmt, ap);
+    con_cvprintmsg((void*)&ctx, LVL_ERROR, "error", fmt, ap);
     va_end(ap);
 }
 
@@ -88,7 +89,7 @@ static void ftepp_error(ftepp_t *ftepp, const char *fmt, ...)
     ftepp->errors++;
 
     va_start(ap, fmt);
-    con_vprintmsg(LVL_ERROR, ftepp->lex->tok.ctx.file, ftepp->lex->tok.ctx.line, "error", fmt, ap);
+    con_cvprintmsg((void*)&ftepp->lex->tok.ctx, LVL_ERROR, "error", fmt, ap);
     va_end(ap);
 }
 
@@ -106,7 +107,7 @@ static bool GMQCC_WARN ftepp_warn(ftepp_t *ftepp, int warntype, const char *fmt,
     }
 
     va_start(ap, fmt);
-    con_vprintmsg(lvl, ftepp->lex->tok.ctx.file, ftepp->lex->tok.ctx.line, "error", fmt, ap);
+    con_cvprintmsg((void*)&ftepp->lex->tok.ctx, lvl, "error", fmt, ap);
     va_end(ap);
     return opts_werror;
 }
@@ -135,7 +136,7 @@ static void pptoken_delete(pptoken *self)
 static ppmacro *ppmacro_new(lex_ctx ctx, const char *name)
 {
     ppmacro *macro = (ppmacro*)mem_a(sizeof(ppmacro));
-    
+
     (void)ctx;
     memset(macro, 0, sizeof(*macro));
     macro->name = util_strdup(name);
@@ -172,6 +173,8 @@ static void ftepp_delete(ftepp_t *self)
     size_t i;
     if (self->itemname)
         mem_d(self->itemname);
+    if (self->includename)
+        vec_free(self->includename);
     for (i = 0; i < vec_size(self->macros); ++i)
         ppmacro_delete(self->macros[i]);
     vec_free(self->macros);
@@ -308,6 +311,8 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
 static bool ftepp_define(ftepp_t *ftepp)
 {
     ppmacro *macro;
+    size_t l = ftepp_ctx(ftepp).line;
+
     (void)ftepp_next(ftepp);
     if (!ftepp_skipspace(ftepp))
         return false;
@@ -348,6 +353,9 @@ static bool ftepp_define(ftepp_t *ftepp)
     else {
         ppmacro_delete(macro);
     }
+
+    for (; l < ftepp_ctx(ftepp).line; ++l)
+        ftepp_out(ftepp, "\n", true);
     return true;
 }
 
@@ -652,7 +660,17 @@ cleanup:
  * parameter lists on macros are errors
  * No mathematical calculations are executed
  */
-static bool ftepp_if_expr(ftepp_t *ftepp, bool *out)
+static bool ftepp_if_expr(ftepp_t *ftepp, bool *out, double *value_out);
+static bool ftepp_if_op(ftepp_t *ftepp)
+{
+    ftepp->lex->flags.noops = false;
+    ftepp_next(ftepp);
+    if (!ftepp_skipspace(ftepp))
+        return false;
+    ftepp->lex->flags.noops = true;
+    return true;
+}
+static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
 {
     ppmacro *macro;
     bool     wasnot = false;
@@ -704,13 +722,16 @@ static bool ftepp_if_expr(ftepp_t *ftepp, bool *out)
             macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp));
             if (!macro || !vec_size(macro->output)) {
                 *out = false;
+                *value_out = 0;
             } else {
                 /* This does not expand recursively! */
                 switch (macro->output[0]->token) {
                     case TOKEN_INTCONST:
-                        *out = !!(macro->output[0]->constval.f);
+                        *value_out = macro->output[0]->constval.i;
+                        *out = !!(macro->output[0]->constval.i);
                         break;
                     case TOKEN_FLOATCONST:
+                        *value_out = macro->output[0]->constval.f;
                         *out = !!(macro->output[0]->constval.f);
                         break;
                     default:
@@ -723,15 +744,17 @@ static bool ftepp_if_expr(ftepp_t *ftepp, bool *out)
             *out = false;
             break;
         case TOKEN_INTCONST:
+            *value_out = ftepp->lex->tok.constval.i;
             *out = !!(ftepp->lex->tok.constval.i);
             break;
         case TOKEN_FLOATCONST:
+            *value_out = ftepp->lex->tok.constval.f;
             *out = !!(ftepp->lex->tok.constval.f);
             break;
 
         case '(':
             ftepp_next(ftepp);
-            if (!ftepp_if_expr(ftepp, out))
+            if (!ftepp_if_expr(ftepp, out, value_out))
                 return false;
             if (ftepp->token != ')') {
                 ftepp_error(ftepp, "expected closing paren in #if expression");
@@ -740,38 +763,89 @@ static bool ftepp_if_expr(ftepp_t *ftepp, bool *out)
             break;
 
         default:
-            ftepp_error(ftepp, "junk in #if");
+            ftepp_error(ftepp, "junk in #if: `%s` ...", ftepp_tokval(ftepp));
             return false;
     }
-    if (wasnot)
+    if (wasnot) {
         *out = !*out;
+        *value_out = (*out ? 1 : 0);
+    }
+    return true;
+}
 
-    ftepp->lex->flags.noops = false;
-    ftepp_next(ftepp);
-    if (!ftepp_skipspace(ftepp))
+/*
+static bool ftepp_if_nextvalue(ftepp_t *ftepp, bool *out, double *value_out)
+{
+    if (!ftepp_next(ftepp))
         return false;
-    ftepp->lex->flags.noops = true;
+    return ftepp_if_value(ftepp, out, value_out);
+}
+*/
 
-    if (ftepp->token == ')')
-        return true;
+static bool ftepp_if_expr(ftepp_t *ftepp, bool *out, double *value_out)
+{
+    if (!ftepp_if_value(ftepp, out, value_out))
+        return false;
+
+    if (!ftepp_if_op(ftepp))
+        return false;
 
-    if (ftepp->token != TOKEN_OPERATOR)
+    if (ftepp->token == ')' || ftepp->token != TOKEN_OPERATOR)
         return true;
 
+    /* FTEQCC is all right-associative and no precedence here */
     if (!strcmp(ftepp_tokval(ftepp), "&&") ||
         !strcmp(ftepp_tokval(ftepp), "||"))
     {
         bool next = false;
         char opc  = ftepp_tokval(ftepp)[0];
+        double nextvalue;
 
-        ftepp_next(ftepp);
-        if (!ftepp_if_expr(ftepp, &next))
+        (void)nextvalue;
+        if (!ftepp_next(ftepp))
+            return false;
+        if (!ftepp_if_expr(ftepp, &next, &nextvalue))
             return false;
 
         if (opc == '&')
             *out = *out && next;
         else
             *out = *out || next;
+
+        *value_out = (*out ? 1 : 0);
+        return true;
+    }
+    else if (!strcmp(ftepp_tokval(ftepp), "==") ||
+             !strcmp(ftepp_tokval(ftepp), "!=") ||
+             !strcmp(ftepp_tokval(ftepp), ">=") ||
+             !strcmp(ftepp_tokval(ftepp), "<=") ||
+             !strcmp(ftepp_tokval(ftepp), ">") ||
+             !strcmp(ftepp_tokval(ftepp), "<"))
+    {
+        bool next = false;
+        const char opc0 = ftepp_tokval(ftepp)[0];
+        const char opc1 = ftepp_tokval(ftepp)[1];
+        double other;
+
+        if (!ftepp_next(ftepp))
+            return false;
+        if (!ftepp_if_expr(ftepp, &next, &other))
+            return false;
+
+        if (opc0 == '=')
+            *out = (*value_out == other);
+        else if (opc0 == '!')
+            *out = (*value_out != other);
+        else if (opc0 == '>') {
+            if (opc1 == '=') *out = (*value_out >= other);
+            else             *out = (*value_out > other);
+        }
+        else if (opc0 == '<') {
+            if (opc1 == '=') *out = (*value_out <= other);
+            else             *out = (*value_out < other);
+        }
+        *value_out = (*out ? 1 : 0);
+
         return true;
     }
     else {
@@ -783,6 +857,7 @@ static bool ftepp_if_expr(ftepp_t *ftepp, bool *out)
 static bool ftepp_if(ftepp_t *ftepp, ppcondition *cond)
 {
     bool result = false;
+    double dummy = 0;
 
     memset(cond, 0, sizeof(*cond));
     (void)ftepp_next(ftepp);
@@ -794,7 +869,7 @@ static bool ftepp_if(ftepp_t *ftepp, ppcondition *cond)
         return false;
     }
 
-    if (!ftepp_if_expr(ftepp, &result))
+    if (!ftepp_if_expr(ftepp, &result, &dummy))
         return false;
 
     cond->on = result;
@@ -902,29 +977,44 @@ static void unescape(const char *str, char *out) {
     *out = 0;
 }
 
-static char *ftepp_include_find(ftepp_t *ftepp, const char *file)
+static char *ftepp_include_find_path(const char *file, const char *pathfile)
 {
-    char *filename = NULL;
-    size_t len;
+    FILE       *fp;
+    char       *filename = NULL;
+    const char *last_slash;
+    size_t      len;
 
-    if (ftepp->itemname) {
-        const char *last_slash;
-        last_slash = strrchr(ftepp->itemname, '/');
-        if (last_slash) {
-            len = last_slash - ftepp->itemname;
-            memcpy(vec_add(filename, len), ftepp->itemname, len);
-            vec_push(filename, '/');
-        }
-        else {
-            len = strlen(ftepp->itemname);
-            memcpy(vec_add(filename, len), ftepp->itemname, len);
-            if (vec_last(filename) != '/')
-                vec_push(filename, '/');
-        }
+    if (!pathfile)
+        return NULL;
+
+    last_slash = strrchr(pathfile, '/');
+
+    if (last_slash) {
+        len = last_slash - pathfile;
+        memcpy(vec_add(filename, len), pathfile, len);
+        vec_push(filename, '/');
     }
+
     len = strlen(file);
-    memcpy(vec_add(filename, len), file, len);
-    vec_push(filename, 0);
+    memcpy(vec_add(filename, len+1), file, len);
+    vec_last(filename) = 0;
+
+    fp = util_fopen(filename, "rb");
+    if (fp) {
+        fclose(fp);
+        return filename;
+    }
+    vec_free(filename);
+    return NULL;
+}
+
+static char *ftepp_include_find(ftepp_t *ftepp, const char *file)
+{
+    char *filename = NULL;
+
+    filename = ftepp_include_find_path(file, ftepp->includename);
+    if (!filename)
+        filename = ftepp_include_find_path(file, ftepp->itemname);
     return filename;
 }
 
@@ -940,6 +1030,7 @@ static bool ftepp_include(ftepp_t *ftepp)
     lex_ctx  ctx;
     char     lineno[128];
     char     *filename;
+    char     *old_includename;
 
     (void)ftepp_next(ftepp);
     if (!ftepp_skipspace(ftepp))
@@ -959,19 +1050,28 @@ static bool ftepp_include(ftepp_t *ftepp)
     ftepp_out(ftepp, ")\n#pragma line(1)\n", false);
 
     filename = ftepp_include_find(ftepp, ftepp_tokval(ftepp));
+    if (!filename) {
+        ftepp_error(ftepp, "failed to open include file `%s`", ftepp_tokval(ftepp));
+        return false;
+    }
     inlex = lex_open(filename);
     if (!inlex) {
-        ftepp_error(ftepp, "failed to open include file `%s`", filename);
+        ftepp_error(ftepp, "open failed on include file `%s`", filename);
         vec_free(filename);
         return false;
     }
-    vec_free(filename);
     ftepp->lex = inlex;
+    old_includename = ftepp->includename;
+    ftepp->includename = filename;
     if (!ftepp_preprocess(ftepp)) {
+        vec_free(ftepp->includename);
+        ftepp->includename = old_includename;
         lex_close(ftepp->lex);
         ftepp->lex = old_lexer;
         return false;
     }
+    vec_free(ftepp->includename);
+    ftepp->includename = old_includename;
     lex_close(ftepp->lex);
     ftepp->lex = old_lexer;
 
@@ -1165,6 +1265,8 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
             case TOKEN_KEYWORD:
             case TOKEN_IDENT:
             case TOKEN_TYPENAME:
+                if (!ftepp->output_on)
+                    break;
                 macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp));
                 if (!macro) {
                     ftepp_out(ftepp, ftepp_tokval(ftepp), false);
@@ -1202,6 +1304,10 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
         }
     } while (!ftepp->errors && ftepp->token < TOKEN_EOF);
 
+    /* force a 0 at the end but don't count it as added to the output */
+    vec_push(ftepp->output_string, 0);
+    vec_shrinkby(ftepp->output_string, 1);
+
     newline = ftepp->token == TOKEN_EOF;
     return newline;
 }
@@ -1214,12 +1320,12 @@ static ftepp_t *ftepp;
 static bool ftepp_preprocess_done()
 {
     bool retval = true;
-    lex_close(ftepp->lex);
-    ftepp->lex = NULL;
     if (vec_size(ftepp->conditions)) {
         if (ftepp_warn(ftepp, WARN_MULTIFILE_IF, "#if spanning multiple files, is this intended?"))
             retval = false;
     }
+    lex_close(ftepp->lex);
+    ftepp->lex = NULL;
     if (ftepp->itemname) {
         mem_d(ftepp->itemname);
         ftepp->itemname = NULL;
@@ -1235,10 +1341,8 @@ bool ftepp_preprocess_file(const char *filename)
         con_out("failed to open file \"%s\"\n", filename);
         return false;
     }
-    if (!ftepp_preprocess(ftepp)) {
-        ftepp_delete(ftepp);
+    if (!ftepp_preprocess(ftepp))
         return false;
-    }
     return ftepp_preprocess_done();
 }
 
@@ -1250,17 +1354,36 @@ bool ftepp_preprocess_string(const char *name, const char *str)
         con_out("failed to create lexer for string \"%s\"\n", name);
         return false;
     }
-    if (!ftepp_preprocess(ftepp)) {
-        ftepp_delete(ftepp);
+    if (!ftepp_preprocess(ftepp))
         return false;
-    }
     return ftepp_preprocess_done();
 }
 
 bool ftepp_init()
 {
     ftepp = ftepp_new();
-    return !!ftepp;
+    if (!ftepp)
+        return false;
+
+    /* set the right macro based on the selected standard */
+    ftepp_add_define(NULL, "GMQCC");
+    if (opts_standard == COMPILER_FTEQCC)
+        ftepp_add_define(NULL, "__STD_FTEQCC__");
+    else if (opts_standard == COMPILER_GMQCC)
+        ftepp_add_define(NULL, "__STD_GMQCC__");
+    else if (opts_standard == COMPILER_QCC)
+        ftepp_add_define(NULL, "__STD_QCC__");
+
+    return true;
+}
+
+void ftepp_add_define(const char *source, const char *name)
+{
+    ppmacro *macro;
+    lex_ctx ctx = { "__builtin__", 0 };
+    ctx.file = source;
+    macro = ppmacro_new(ctx, name);
+    vec_push(ftepp->macros, macro);
 }
 
 const char *ftepp_get()