]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
Fix bug
[xonotic/gmqcc.git] / parser.c
index 06aca6bf3acd3d2eb7ac6f1e81066f5d0a14f00e..2efeafd1fc604e9e1d3bf85050d130873e486c89 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1034,8 +1034,57 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                     exprs[0], exprs[1]);
             break;
         case opid1('^'):
-            compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor via ^");
-            return false;
+            /*
+             * ^ can be implemented as:
+             * (LHS | RHS) & ~(LHS & RHS)
+             * to implement ~ we need to use -1-X, as you can see the
+             * whole process ends up becoming:
+             * (LHS | RHS) & (-1 - (LHS & RHS))
+             */
+            #define TRY_TYPE(I)                                       \
+                if (exprs[(I)]->vtype != TYPE_FLOAT) {                \
+                    ast_type_to_string(exprs[(I)], ty1, sizeof(ty1)); \
+                    compile_error (                                   \
+                        ast_ctx(exprs[(I)]),                          \
+                        "invalid type for bit-xor in %s: %s",         \
+                        ty1,                                          \
+                        ((I) == 0)                                    \
+                            ? "left-hand-side of expression"          \
+                            : "right-hand-side of expression"         \
+                    );                                                \
+                    return false;                                     \
+                }
+            TRY_TYPE(0)
+            TRY_TYPE(1)
+            #undef TRY_TYPE
+
+            if(CanConstFold(exprs[0], exprs[1])) {
+                out = (ast_expression*)parser_const_float(parser, (float)((qcint)(ConstF(0)) ^ ((qcint)(ConstF(1)))));
+            } else {
+                out = (ast_expression*)
+                    ast_binary_new(
+                        ctx,
+                        INSTR_BITAND,
+                        (ast_expression*)ast_binary_new(
+                            ctx,
+                            INSTR_BITOR,
+                            exprs[0],
+                            exprs[1]
+                        ),
+                        (ast_expression*)ast_binary_new(
+                            ctx,
+                            INSTR_SUB_F,
+                            (ast_expression*)parser_const_float_neg1(parser),
+                            (ast_expression*)ast_binary_new(
+                                ctx,
+                                INSTR_BITAND,
+                                exprs[0],
+                                exprs[1]
+                            )
+                        )
+                    );
+            }
+            break;
 
         case opid2('<','<'):
         case opid2('>','>'):
@@ -1568,7 +1617,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
     for (i = 0; i < paramcount; ++i)
         vec_push(call->params, sy->out[fid+1 + i].out);
     vec_shrinkby(sy->out, paramcount);
-    (void)!ast_call_check_types(call);
+    (void)!ast_call_check_types(call, parser->function->vtype->expression.varparam);
     if (parser->max_param_count < paramcount)
         parser->max_param_count = paramcount;
 
@@ -1703,8 +1752,12 @@ static ast_expression* parse_vararg_do(parser_t *parser)
     ast_expression *idx, *out;
     ast_value      *typevar;
     ast_value      *funtype = parser->function->vtype;
+    lex_ctx         ctx     = parser_ctx(parser);
 
-    lex_ctx ctx = parser_ctx(parser);
+    if (!parser->function->varargs) {
+        parseerror(parser, "function has no variable argument list");
+        return NULL;
+    }
 
     if (!parser_next(parser) || parser->tok != '(') {
         parseerror(parser, "expected parameter index and type in parenthesis");
@@ -1720,9 +1773,14 @@ static ast_expression* parse_vararg_do(parser_t *parser)
         return NULL;
 
     if (parser->tok != ',') {
-        ast_unref(idx);
-        parseerror(parser, "expected comma after parameter index");
-        return NULL;
+        if (parser->tok != ')') {
+            ast_unref(idx);
+            parseerror(parser, "expected comma after parameter index");
+            return NULL;
+        }
+        /* vararg piping: ...(start) */
+        out = (ast_expression*)ast_argpipe_new(ctx, idx);
+        return out;
     }
 
     if (!parser_next(parser) || (parser->tok != TOKEN_IDENT && parser->tok != TOKEN_TYPENAME)) {
@@ -1744,22 +1802,6 @@ static ast_expression* parse_vararg_do(parser_t *parser)
         return NULL;
     }
 
-#if 0
-    if (!parser_next(parser)) {
-        ast_unref(idx);
-        ast_delete(typevar);
-        parseerror(parser, "parse error after vararg");
-        return NULL;
-    }
-#endif
-
-    if (!parser->function->varargs) {
-        ast_unref(idx);
-        ast_delete(typevar);
-        parseerror(parser, "function has no variable argument list");
-        return NULL;
-    }
-
     if (funtype->expression.varparam &&
         !ast_compare_type((ast_expression*)typevar, (ast_expression*)funtype->expression.varparam))
     {
@@ -1925,7 +1967,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
                  * it in the predef table.  And diagnose it better :)
                  */
                 if (!OPTS_FLAG(FTEPP_PREDEFS) && ftepp_predef_exists(parser_tokval(parser))) {
-                    parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
+                    parseerror(parser, "unexpected identifier: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
                     return false;
                 }
 
@@ -1936,7 +1978,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
                  * We should also consider adding correction tables for
                  * other things as well.
                  */
-                if (OPTS_OPTION_BOOL(OPTION_CORRECTION)) {
+                if (OPTS_OPTION_BOOL(OPTION_CORRECTION) && strlen(parser_tokval(parser)) <= 16) {
                     correction_t corr;
                     correct_init(&corr);
 
@@ -1952,12 +1994,12 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
                     correct_free(&corr);
 
                     if (correct) {
-                        parseerror(parser, "unexpected ident: %s (did you mean %s?)", parser_tokval(parser), correct);
+                        parseerror(parser, "unexpected identifier: %s (did you mean %s?)", parser_tokval(parser), correct);
                         mem_d(correct);
                         return false;
                     }
                 }
-                parseerror(parser, "unexpected ident: %s", parser_tokval(parser));
+                parseerror(parser, "unexpected identifier: %s", parser_tokval(parser));
                 return false;
             }
         }
@@ -2004,7 +2046,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
     while (true)
     {
         if (parser->tok == TOKEN_TYPENAME) {
-            parseerror(parser, "unexpected typename");
+            parseerror(parser, "unexpected typename `%s`", parser_tokval(parser));
             goto onerr;
         }
 
@@ -4339,7 +4381,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
     }
 
     vec_push(func->blocks, block);
-    
+
 
     parser->function = old;
     if (!parser_leaveblock(parser))
@@ -5770,29 +5812,22 @@ skipvar:
             }
         }
 
-        if ((OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_HCODE)
-                ? parser->tok != ':'
-                : true
-        ){
-            if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) {
-                if (parser->tok != '=') {
-                    parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser));
-                    break;
-                }
-
-                if (!parser_next(parser)) {
-                    parseerror(parser, "error parsing initializer");
-                    break;
-                }
+        if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) {
+            if (parser->tok != '=') {
+                parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser));
+                break;
             }
-            else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
-                parseerror(parser, "expected '=' before function body in this standard");
+
+            if (!parser_next(parser)) {
+                parseerror(parser, "error parsing initializer");
+                break;
             }
         }
+        else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) {
+            parseerror(parser, "expected '=' before function body in this standard");
+        }
 
-        if (parser->tok == '#' ||
-            (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_HCODE && parser->tok == ':'))
-        {
+        if (parser->tok == '#') {
             ast_function *func   = NULL;
             ast_value    *number = NULL;
             float         fractional;
@@ -6233,7 +6268,7 @@ static bool parser_compile(parser_t *parser)
         {
             if (!parser_global_statement(parser)) {
                 if (parser->tok == TOKEN_EOF)
-                    parseerror(parser, "unexpected eof");
+                    parseerror(parser, "unexpected end of file");
                 else if (compile_errors)
                     parseerror(parser, "there have been errors, bailing out");
                 lex_close(parser->lex);