]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ftepp.c
Set correct macro for PP based on the selected standard
[xonotic/gmqcc.git] / ftepp.c
diff --git a/ftepp.c b/ftepp.c
index de5022a4133583565a2a35c6419516083accd06c..7969231299a00b2dd8f06bafa0d33e2c8f838bde 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)
@@ -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);
@@ -652,7 +655,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 +717,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 +739,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 +758,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->token != TOKEN_OPERATOR)
+    if (!ftepp_if_op(ftepp))
+        return false;
+
+    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 +852,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 +864,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 +972,50 @@ 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);
+    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, '/');
+    }
+    else {
+        len = strlen(pathfile);
+        memcpy(vec_add(filename, len), pathfile, len);
+        if (vec_last(filename) != '/')
             vec_push(filename, '/');
-        }
-        else {
-            len = strlen(ftepp->itemname);
-            memcpy(vec_add(filename, len), ftepp->itemname, len);
-            if (vec_last(filename) != '/')
-                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 +1031,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 +1051,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);
         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;
 
@@ -1202,6 +1303,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 +1319,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;
@@ -1258,7 +1363,15 @@ bool ftepp_init()
     ftepp = ftepp_new();
     if (!ftepp)
         return false;
-    ftepp_add_define(NULL, "GMQCC");
+    
+    /* set the right macro based on the selected standard */
+    if (opts_standard == COMPILER_FTEQCC)
+        ftepp_add_define(NULL, "FTEQCC");
+    else if (opts_standard == COMPILER_GMQCC)
+        ftepp_add_define(NULL, "GMQCC");
+    else if (opts_standard == COMPILER_QCC)
+        ftepp_add_define(NULL, "QCC");
+    
     return true;
 }