]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
Implemented bitwise xor operator.
authorDale Weiler <killfieldengine@gmail.com>
Sat, 15 Jun 2013 09:48:40 +0000 (09:48 +0000)
committerDale Weiler <killfieldengine@gmail.com>
Sat, 15 Jun 2013 09:48:40 +0000 (09:48 +0000)
lexer.c
parser.c
tests/xor.qc [new file with mode: 0644]
tests/xor.tmpl [new file with mode: 0644]

diff --git a/lexer.c b/lexer.c
index cc717848b6279e8ca651eacd514582522981e8e4..7cd7794bfaed056ffa72519a0bf0a39bfe0f843e 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -1309,7 +1309,7 @@ int lex_do(lex_file *lex)
         ch == '>' || ch == '<' || /* <<, >>, <=, >=                  */
         ch == '=' || ch == '!' || /* <=>, ==, !=                     */
         ch == '&' || ch == '|' || /* &&, ||, &=, |=                  */
-        ch == '~'                 /* ~=, ~                           */
+        ch == '~' || ch == '^'    /* ~=, ~, ^                        */
     )  {
         lex_tokench(lex, ch);
 
index 62c21dfb2b4e3e2d49a048c02738fa0fca271553..2f8867414984c8b7524cd13b99cc395f9c780d6b 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[0]->vtype != TYPE_FLOAT) {                \
+                    ast_type_to_string(exprs[0], 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('>','>'):
diff --git a/tests/xor.qc b/tests/xor.qc
new file mode 100644 (file)
index 0000000..81fb114
--- /dev/null
@@ -0,0 +1,12 @@
+void main() {
+    float x = 5;
+    float y = 3;
+    float z = x ^ y; // 6
+    
+    float a = 2;
+    float b = 10;
+    float c = a ^ b; // 8
+    
+    print(ftos(z), "\n");
+    print(ftos(c), "\n");
+}
diff --git a/tests/xor.tmpl b/tests/xor.tmpl
new file mode 100644 (file)
index 0000000..681a982
--- /dev/null
@@ -0,0 +1,7 @@
+I: xor.qc
+D: test bitwise xor
+T: -execute
+C: -std=gmqcc
+E: $null
+M: 6
+M: 8