1 /*
2  * The contents of this file are subject to the Mozilla Public License
3  * Version 1.0 (the "License"); you may not use this file except in
4  * compliance with the License. You may obtain a copy of the License at
5  * http://www.mozilla.org/MPL/
6  *
7  * Software distributed under the License is distributed on an "AS IS"
8  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
9  * License for the specific language governing rights and limitations
10  * under the License.
11  *
12  * The Initial Developer of this code is David Baum.
13  * Portions created by David Baum are Copyright (C) 1999 David Baum.
14  * All Rights Reserved.
15  *
16  * Portions created by John Hansen are Copyright (C) 2005 John Hansen.
17  * All Rights Reserved.
18  *
19  */
20 
21 #include "RelExpr.h"
22 #include "Bytecode.h"
23 /*
24 #include "parser.h"
25 #include "RCX_Constants.h"
26 */
27 
28 // these are VERY dependent on RCX_Constants
29 static int sReversed[] = {
30 	RelExpr::kGreaterOrEqual, RelExpr::kLessOrEqual, RelExpr::kNotEqualTo,
31 	RelExpr::kEqualTo, RelExpr::kLessThan, RelExpr::kGreaterThan
32 };
33 
34 static int sInverted[] = {
35 	RelExpr::kGreaterThan, RelExpr::kLessThan, RelExpr::kEqualTo,
36 	RelExpr::kNotEqualTo, RelExpr::kLessOrEqual, RelExpr::kGreaterOrEqual
37 };
38 
39 static RCX_Relation sRCX_Codes[] = {
40 	kRCX_LessOrEqual, kRCX_GreaterOrEqual, kRCX_NotEqualTo, kRCX_EqualTo
41 };
42 
43 
RelExpr(Expr * lhs,int relation,Expr * rhs)44 RelExpr::RelExpr (Expr *lhs, int relation, Expr *rhs)
45 	: NodeExpr(lhs, rhs), fRelation(relation)
46 {
47 }
48 
49 
50 
Clone(Mapping * b) const51 Expr* RelExpr::Clone(Mapping *b) const
52 {
53 	return new RelExpr(Get(0)->Clone(b), fRelation, Get(1)->Clone(b));
54 }
55 
56 
Evaluate(int & v) const57 bool RelExpr::Evaluate(int &v) const
58 {
59 	int v1, v2;
60 	bool b;
61 
62 	if (!Get(0)->Evaluate(v1)) return false;
63 	if (!Get(1)->Evaluate(v2)) return false;
64 
65 	switch(fRelation)
66 	{
67 		case kLessOrEqual:
68 			b = (v1 <= v2);
69 			break;
70 		case kGreaterOrEqual:
71 			b = (v1 >= v2);
72 			break;
73 		case kNotEqualTo:
74 			b = (v1 != v2);
75 			break;
76 		case kEqualTo:
77 			b = (v1 == v2);
78 			break;
79 		case kGreaterThan:
80 			b = (v1 > v2);
81 			break;
82 		case kLessThan:
83 			b = (v1 < v2);
84 			break;
85 		default:
86 			return false;
87 
88 	}
89 
90 	v = b ? 1 : 0;
91 
92 	return true;
93 }
94 
95 
EmitBranch_(Bytecode & b,int label,bool condition) const96 bool RelExpr::EmitBranch_(Bytecode &b, int label, bool condition) const
97 {
98 	bool ok = true;
99 	int r = fRelation;
100 	RCX_Value ea1 = Get(0)->EmitConstrained(b, TEST_MASK);
101 	RCX_Value ea2 = Get(1)->EmitConstrained(b, TEST_MASK);
102 
103 	// if value 2 is constant, swap with value 1
104 	if (RCX_VALUE_TYPE(ea2) == kRCX_ConstantType)
105 	{
106 		RCX_Value t = ea1;
107 		ea1 = ea2;
108 		ea2 = t;
109 		r = sReversed[r];
110 	}
111 
112 	// invert if emitting false branch
113 	if (!condition)
114 		r = sInverted[r];
115 
116 	switch(r)
117 	{
118 		case kLessOrEqual:
119 		case kGreaterOrEqual:
120 		case kNotEqualTo:
121 		case kEqualTo:
122 			b.AddTest(ea1, sRCX_Codes[r], ea2, label);
123 			break;
124 		case kGreaterThan:
125 		case kLessThan:
126 			if (RCX_VALUE_TYPE(ea1) == kRCX_ConstantType)
127 			{
128 				RCX_Relation rel;
129 				short adjust;
130 				short limit;
131 				short c;
132 
133 				if (r == kGreaterThan)
134 				{
135 					rel = kRCX_GreaterOrEqual;
136 					adjust = -1;
137 					limit = -32768;
138 				}
139 				else
140 				{
141 					rel = kRCX_LessOrEqual;
142 					adjust = 1;
143 					limit = 32767;
144 				}
145 
146 				c = RCX_VALUE_DATA(ea1);
147 
148 				// check for impossible range
149 				if (c == limit)
150 				{
151 					ok = false;
152 					break;
153 				}
154 
155 				// test for adjusted range
156 				b.AddTest(RCX_VALUE(kRCX_ConstantType, c+adjust), rel, ea2, label);
157 			}
158 			else
159 			{
160 				int around = b.NewLabel();
161 				b.AddTest(ea1, sRCX_Codes[sInverted[r]], ea2, around);
162 				b.AddJump(label);
163 				b.SetLabel(around);
164 			}
165 			break;
166 	}
167 
168 	b.ReleaseTempEA(ea1);
169 	b.ReleaseTempEA(ea2);
170 	return ok;
171 }
172