num_exp: bitwise ops and op precedence
[m6w6/ext-psi] / src / calc.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27 #include <assert.h>
28
29 #include "token.h"
30 #include "calc.h"
31
32 #define PSI_CALC_CAST_SET(in_type, in_val, out_val, out_var) \
33 switch (in_type) { \
34 case PSI_T_INT8: (out_val)->out_var = (in_val)->i8; break; \
35 case PSI_T_UINT8: (out_val)->out_var = (in_val)->u8; break; \
36 case PSI_T_INT16: (out_val)->out_var = (in_val)->i16; break; \
37 case PSI_T_UINT16: (out_val)->out_var = (in_val)->u16; break; \
38 case PSI_T_INT32: (out_val)->out_var = (in_val)->i32; break; \
39 case PSI_T_UINT32: (out_val)->out_var = (in_val)->u32; break; \
40 case PSI_T_INT64: (out_val)->out_var = (in_val)->i64; break; \
41 case PSI_T_UINT64: (out_val)->out_var = (in_val)->u64; break; \
42 case PSI_T_FLOAT: (out_val)->out_var = (in_val)->fval; break; \
43 case PSI_T_DOUBLE: (out_val)->out_var = (in_val)->dval; break; \
44 case PSI_T_LONG_DOUBLE: (out_val)->out_var = (in_val)->ldval; break; \
45 default: \
46 assert(0); \
47 }
48
49 #define PSI_CALC_CAST(in_type, in_val, out_type, out_val) \
50 switch (out_type) { \
51 case PSI_T_INT8: PSI_CALC_CAST_SET(in_type, in_val, out_val, i8) break; \
52 case PSI_T_UINT8: PSI_CALC_CAST_SET(in_type, in_val, out_val, u8) break; \
53 case PSI_T_INT16: PSI_CALC_CAST_SET(in_type, in_val, out_val, i16) break; \
54 case PSI_T_UINT16: PSI_CALC_CAST_SET(in_type, in_val, out_val, u16) break; \
55 case PSI_T_INT32: PSI_CALC_CAST_SET(in_type, in_val, out_val, i32) break; \
56 case PSI_T_UINT32: PSI_CALC_CAST_SET(in_type, in_val, out_val, u32) break; \
57 case PSI_T_INT64: PSI_CALC_CAST_SET(in_type, in_val, out_val, i64) break; \
58 case PSI_T_UINT64: PSI_CALC_CAST_SET(in_type, in_val, out_val, u64) break; \
59 case PSI_T_FLOAT: PSI_CALC_CAST_SET(in_type, in_val, out_val, fval) break; \
60 case PSI_T_DOUBLE: PSI_CALC_CAST_SET(in_type, in_val, out_val, dval) break; \
61 case PSI_T_LONG_DOUBLE: PSI_CALC_CAST_SET(in_type, in_val, out_val, ldval) break; \
62 default: \
63 assert(0); \
64 }
65
66 void psi_calc_cast(token_t in_type, impl_val *in_val, token_t out_type, impl_val *out_val)
67 {
68 PSI_CALC_CAST(in_type, in_val, out_type, out_val)
69 }
70
71 #if 0
72 #define PSI_CALC_OP(var) do { \
73 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
74 res->var = PSI_CALC(v1->var, v2->var); \
75 if (!res->var && (v1->var || v2->var)) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
76 } while (0)
77 #define PSI_CALC_OP2(vres, var1, var2) do { \
78 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
79 res->vres = PSI_CALC(v1->var1, v2->var2); \
80 if (!res->vres && (v1->var1 || v2->var2)) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
81 } while(0)
82 #else
83 #define PSI_CALC_OP(var) res->var = PSI_CALC(v1->var, v2->var)
84 #define PSI_CALC_OP2(vres, var1, var2) res->vres = PSI_CALC(v1->var1, v2->var2)
85 #endif
86
87 #ifdef HAVE_LONG_DOUBLE
88 # define PSI_CALC_NO_LD
89 # define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
90 # define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
91 # define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
92 #else
93 # define PSI_CALC_NO_LD abort()
94 # define PSI_CALC_OP_LD PSI_CALC_NO_LD
95 # define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
96 # define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
97 #endif
98
99 #define PSI_CALC_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
100 { \
101 if (t1 == t2) { \
102 switch (t1) { \
103 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
104 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
105 case PSI_T_LONG_DOUBLE: PSI_CALC_OP_LD; break; \
106 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
107 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
108 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
109 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
110 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
111 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
112 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
113 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
114 EMPTY_SWITCH_DEFAULT_CASE(); \
115 } \
116 return t1; \
117 } else if (t1 == PSI_T_DOUBLE) { \
118 switch (t2) { \
119 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(dval); return t2; \
120 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
121 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
122 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
123 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
124 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
125 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
126 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
127 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
128 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
129 EMPTY_SWITCH_DEFAULT_CASE(); \
130 } \
131 return t1; \
132 } else if (t2 == PSI_T_DOUBLE) { \
133 switch (t1) { \
134 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(dval); return t1; \
135 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
136 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
137 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
138 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
139 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
140 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
141 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
142 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
143 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
144 EMPTY_SWITCH_DEFAULT_CASE(); \
145 } \
146 return t2; \
147 } else if (t1 == PSI_T_LONG_DOUBLE) { \
148 PSI_CALC_NO_LD; \
149 switch (t2) { \
150 case PSI_T_DOUBLE: PSI_CALC_OP2_LD1(dval); break; \
151 case PSI_T_FLOAT: PSI_CALC_OP2_LD1(fval); break; \
152 case PSI_T_INT8: PSI_CALC_OP2_LD1(i8); break; \
153 case PSI_T_UINT8: PSI_CALC_OP2_LD1(u8); break; \
154 case PSI_T_INT16: PSI_CALC_OP2_LD1(i16); break; \
155 case PSI_T_UINT16: PSI_CALC_OP2_LD1(u16); break; \
156 case PSI_T_INT32: PSI_CALC_OP2_LD1(i32); break; \
157 case PSI_T_UINT32: PSI_CALC_OP2_LD1(u32); break; \
158 case PSI_T_INT64: PSI_CALC_OP2_LD1(i64); break; \
159 case PSI_T_UINT64: PSI_CALC_OP2_LD1(u64); break; \
160 EMPTY_SWITCH_DEFAULT_CASE(); \
161 } \
162 return t1; \
163 } else if (t2 == PSI_T_LONG_DOUBLE) { \
164 PSI_CALC_NO_LD; \
165 switch (t1) { \
166 case PSI_T_DOUBLE: PSI_CALC_OP2_LD2(dval); break; \
167 case PSI_T_FLOAT: PSI_CALC_OP2_LD2(fval); break; \
168 case PSI_T_INT8: PSI_CALC_OP2_LD2(i8); break; \
169 case PSI_T_UINT8: PSI_CALC_OP2_LD2(u8); break; \
170 case PSI_T_INT16: PSI_CALC_OP2_LD2(i16); break; \
171 case PSI_T_UINT16: PSI_CALC_OP2_LD2(u16); break; \
172 case PSI_T_INT32: PSI_CALC_OP2_LD2(i32); break; \
173 case PSI_T_UINT32: PSI_CALC_OP2_LD2(u32); break; \
174 case PSI_T_INT64: PSI_CALC_OP2_LD2(i64); break; \
175 case PSI_T_UINT64: PSI_CALC_OP2_LD2(u64); break; \
176 EMPTY_SWITCH_DEFAULT_CASE(); \
177 } \
178 return t2; \
179 } else if (t1 == PSI_T_FLOAT) { \
180 switch (t2) { \
181 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD2(fval); return t2; \
182 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
183 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
184 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
185 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
186 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
187 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
188 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
189 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
190 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
191 EMPTY_SWITCH_DEFAULT_CASE(); \
192 } \
193 return t1; \
194 } else if (t2 == PSI_T_FLOAT) { \
195 switch (t1) { \
196 case PSI_T_LONG_DOUBLE: PSI_CALC_OP2_LD1(fval); return t1; \
197 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
198 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
199 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
200 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
201 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
202 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
203 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
204 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
205 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
206 EMPTY_SWITCH_DEFAULT_CASE(); \
207 } \
208 return t2; \
209 } else { \
210 int64_t sval1 = v1->i64, sval2 = v2->i64; \
211 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
212 switch (t1) { \
213 case PSI_T_INT8: sval1 >>= 8; \
214 case PSI_T_INT16: sval1 >>= 8; \
215 case PSI_T_INT32: sval1 >>= 8; \
216 case PSI_T_INT64: \
217 switch (t2) { \
218 case PSI_T_INT8: sval2 >>= 8; \
219 case PSI_T_INT16: sval2 >>= 8; \
220 case PSI_T_INT32: sval2 >>= 8; \
221 case PSI_T_INT64: \
222 res->i64 = PSI_CALC(sval1 , sval2); \
223 return PSI_T_INT64; \
224 case PSI_T_UINT8: uval2 >>= 8; \
225 case PSI_T_UINT16: uval2 >>= 8; \
226 case PSI_T_UINT32: uval2 >>= 8; \
227 case PSI_T_UINT64: \
228 res->i64 = PSI_CALC(sval1, uval2); \
229 return PSI_T_INT64; \
230 } \
231 break; \
232 case PSI_T_UINT8: uval1 >>= 8; \
233 case PSI_T_UINT16: uval1 >>= 8; \
234 case PSI_T_UINT32: uval1 >>= 8; \
235 case PSI_T_UINT64: \
236 switch (t2) { \
237 case PSI_T_INT8: sval2 >>= 8; \
238 case PSI_T_INT16: sval2 >>= 8; \
239 case PSI_T_INT32: sval2 >>= 8; \
240 case PSI_T_INT64: \
241 res->i64 = PSI_CALC(uval1, sval2); \
242 return PSI_T_INT64; \
243 case PSI_T_UINT8: uval2 >>= 8; \
244 case PSI_T_UINT16: uval2 >>= 8; \
245 case PSI_T_UINT32: uval2 >>= 8; \
246 case PSI_T_UINT64: \
247 res->u64 = PSI_CALC(uval1, uval2); \
248 return PSI_T_UINT64; \
249 } \
250 break; \
251 } \
252 } \
253 assert(0); \
254 return 0; \
255 }
256
257 #undef PSI_CALC
258 #define PSI_CALC(var1, var2) (var1) + (var2)
259 PSI_CALC_FN(add)
260 #undef PSI_CALC
261 #define PSI_CALC(var1, var2) (var1) * (var2)
262 PSI_CALC_FN(mul)
263 #undef PSI_CALC
264 #define PSI_CALC(var1, var2) (var1) - (var2)
265 PSI_CALC_FN(sub)
266 #undef PSI_CALC
267 #define PSI_CALC(var1, var2) (var1) / (var2)
268 PSI_CALC_FN(div)
269 #undef PSI_CALC
270
271 #define PSI_CALC_BIN_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
272 { \
273 impl_val i1, i2; \
274 PSI_CALC_CAST(t1, v1, PSI_T_UINT64, &i1); \
275 PSI_CALC_CAST(t2, v2, PSI_T_UINT64, &i2); \
276 res->u64 = PSI_CALC(i1.u64, i2.u64); \
277 return PSI_T_UINT64; \
278 }
279
280 #define PSI_CALC(var1, var2) (var1) << (var2)
281 PSI_CALC_BIN_FN(bin_lshift)
282 #undef PSI_CALC
283 #define PSI_CALC(var1, var2) (var1) >> (var2)
284 PSI_CALC_BIN_FN(bin_rshift)
285 #undef PSI_CALC
286 #define PSI_CALC(var1, var2) (var1) & (var2)
287 PSI_CALC_BIN_FN(bin_and)
288 #undef PSI_CALC
289 #define PSI_CALC(var1, var2) (var1) ^ (var2)
290 PSI_CALC_BIN_FN(bin_xor)
291 #undef PSI_CALC
292 #define PSI_CALC(var1, var2) (var1) | (var2)
293 PSI_CALC_BIN_FN(bin_or)
294 #undef PSI_CALC
295