calc: generate calculators
[m6w6/ext-psi] / src / types / num_exp.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
28 #include <assert.h>
29
30 #include "data.h"
31 #include "context.h"
32 #include "call.h"
33 #include "calc.h"
34
35
36 struct psi_num_exp *psi_num_exp_init_binary(token_t op,
37 struct psi_num_exp *lhs, struct psi_num_exp *rhs)
38 {
39 struct psi_num_exp *exp = calloc(1, sizeof(*exp));
40
41 exp->op = op;
42 exp->data.b.lhs = lhs;
43 exp->data.b.rhs = rhs;
44
45 return exp;
46 }
47
48 struct psi_num_exp *psi_num_exp_init_unary(token_t op,
49 struct psi_num_exp *u)
50 {
51 struct psi_num_exp *exp = calloc(1, sizeof(*exp));
52
53 exp->op = op;
54 exp->data.u = u;
55
56 return exp;
57 }
58
59 struct psi_num_exp *psi_num_exp_init_num(struct psi_number *n)
60 {
61 struct psi_num_exp *exp = calloc(1, sizeof(*exp));
62
63 exp->data.n = n;
64
65 return exp;
66 }
67
68 struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp)
69 {
70 struct psi_num_exp *cpy;
71
72 if (!exp) {
73 return NULL;
74 }
75
76 cpy = malloc(sizeof(*cpy));
77 *cpy = *exp;
78
79 switch (exp->op) {
80 case 0:
81 cpy->data.n = psi_number_copy(exp->data.n);
82 break;
83
84 case PSI_T_NOT:
85 case PSI_T_TILDE:
86 case PSI_T_LPAREN:
87 cpy->data.u = psi_num_exp_copy(exp->data.u);
88 break;
89
90 case PSI_T_OR:
91 case PSI_T_AND:
92
93 case PSI_T_CMP_EQ:
94 case PSI_T_CMP_NE:
95 case PSI_T_CMP_LE:
96 case PSI_T_CMP_GE:
97 case PSI_T_RCHEVR:
98 case PSI_T_LCHEVR:
99
100 case PSI_T_PIPE:
101 case PSI_T_CARET:
102 case PSI_T_AMPERSAND:
103 case PSI_T_LSHIFT:
104 case PSI_T_RSHIFT:
105 case PSI_T_PLUS:
106 case PSI_T_MINUS:
107 case PSI_T_ASTERISK:
108 case PSI_T_SLASH:
109 case PSI_T_MODULO:
110 cpy->data.b.lhs = psi_num_exp_copy(exp->data.b.lhs);
111 cpy->data.b.rhs = psi_num_exp_copy(exp->data.b.rhs);
112 break;
113
114 default:
115 assert(0);
116 }
117
118 if (exp->token) {
119 cpy->token = psi_token_copy(exp->token);
120 }
121
122 return cpy;
123 }
124
125 void psi_num_exp_free(struct psi_num_exp **c_ptr)
126 {
127 if (*c_ptr) {
128 struct psi_num_exp *c = *c_ptr;
129
130 *c_ptr = NULL;
131
132 switch (c->op) {
133 case 0:
134 psi_number_free(&c->data.n);
135 break;
136 case PSI_T_NOT:
137 case PSI_T_TILDE:
138 case PSI_T_LPAREN:
139 psi_num_exp_free(&c->data.u);
140 break;
141
142 case PSI_T_OR:
143 case PSI_T_AND:
144
145 case PSI_T_CMP_EQ:
146 case PSI_T_CMP_NE:
147 case PSI_T_CMP_LE:
148 case PSI_T_CMP_GE:
149 case PSI_T_RCHEVR:
150 case PSI_T_LCHEVR:
151
152 case PSI_T_PIPE:
153 case PSI_T_CARET:
154 case PSI_T_AMPERSAND:
155 case PSI_T_LSHIFT:
156 case PSI_T_RSHIFT:
157 case PSI_T_PLUS:
158 case PSI_T_MINUS:
159 case PSI_T_ASTERISK:
160 case PSI_T_SLASH:
161 case PSI_T_MODULO:
162 psi_num_exp_free(&c->data.b.lhs);
163 psi_num_exp_free(&c->data.b.rhs);
164 break;
165
166 default:
167 assert(0);
168 }
169
170 if (c->token) {
171 free(c->token);
172 }
173
174 free(c);
175 }
176 }
177
178 static inline const char *psi_num_exp_op_tok(token_t op)
179 {
180 switch (op) {
181 case PSI_T_NOT:
182 return "!";
183 case PSI_T_TILDE:
184 return "~";
185 case PSI_T_LPAREN:
186 return "(";
187
188 case PSI_T_PIPE:
189 return "|";
190 case PSI_T_CARET:
191 return "^";
192 case PSI_T_AMPERSAND:
193 return "&";
194
195 case PSI_T_LSHIFT:
196 return "<<";
197 case PSI_T_RSHIFT:
198 return ">>";
199
200 case PSI_T_PLUS:
201 return "+";
202 case PSI_T_MINUS:
203 return "-";
204
205 case PSI_T_ASTERISK:
206 return "*";
207 case PSI_T_SLASH:
208 return "/";
209 case PSI_T_MODULO:
210 return "%";
211
212 case PSI_T_OR:
213 return "||";
214 case PSI_T_AND:
215 return "&&";
216
217 case PSI_T_CMP_EQ:
218 return "==";
219 case PSI_T_CMP_NE:
220 return "!=";
221 case PSI_T_CMP_LE:
222 return "<=";
223 case PSI_T_CMP_GE:
224 return ">=";
225 case PSI_T_RCHEVR:
226 return ">";
227 case PSI_T_LCHEVR:
228 return "<";
229
230 default:
231 assert(0);
232 }
233 return 0;
234 }
235
236 void psi_num_exp_dump(int fd, struct psi_num_exp *exp)
237 {
238 switch (exp->op) {
239 case 0:
240 psi_number_dump(fd, exp->data.n);
241 break;
242
243 case PSI_T_NOT:
244 case PSI_T_TILDE:
245 dprintf(fd, "%s", psi_num_exp_op_tok(exp->op));
246 psi_num_exp_dump(fd, exp->data.u);
247 break;
248
249 case PSI_T_LPAREN:
250 dprintf(fd, "(");
251 psi_num_exp_dump(fd, exp->data.u);
252 dprintf(fd, ")");
253 break;
254
255
256 case PSI_T_OR:
257 case PSI_T_AND:
258
259 case PSI_T_CMP_EQ:
260 case PSI_T_CMP_NE:
261 case PSI_T_CMP_LE:
262 case PSI_T_CMP_GE:
263 case PSI_T_RCHEVR:
264 case PSI_T_LCHEVR:
265
266 case PSI_T_PIPE:
267 case PSI_T_CARET:
268 case PSI_T_AMPERSAND:
269 case PSI_T_LSHIFT:
270 case PSI_T_RSHIFT:
271 case PSI_T_PLUS:
272 case PSI_T_MINUS:
273 case PSI_T_ASTERISK:
274 case PSI_T_SLASH:
275 psi_num_exp_dump(fd, exp->data.b.lhs);
276 dprintf(fd, " %s ", psi_num_exp_op_tok(exp->op));
277 psi_num_exp_dump(fd, exp->data.b.rhs);
278 break;
279
280 default:
281 assert(0);
282 }
283
284 }
285
286 bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp,
287 struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let,
288 struct psi_set_exp *current_set, struct psi_decl_enum *current_enum)
289 {
290 if (exp->op) {
291 switch (exp->op) {
292 case PSI_T_NOT:
293 exp->calc = psi_calc_bool_not;
294 break;
295 case PSI_T_TILDE:
296 exp->calc = psi_calc_bin_not;
297 break;
298
299 case PSI_T_OR:
300 exp->calc = psi_calc_bool_or;
301 break;
302 case PSI_T_AND:
303 exp->calc = psi_calc_bool_and;
304 break;
305 case PSI_T_CMP_EQ:
306 exp->calc = psi_calc_cmp_eq;
307 break;
308 case PSI_T_CMP_NE:
309 exp->calc = psi_calc_cmp_ne;
310 break;
311 case PSI_T_CMP_LE:
312 exp->calc = psi_calc_cmp_le;
313 break;
314 case PSI_T_CMP_GE:
315 exp->calc = psi_calc_cmp_ge;
316 break;
317 case PSI_T_LCHEVR:
318 exp->calc = psi_calc_cmp_lt;
319 break;
320 case PSI_T_RCHEVR:
321 exp->calc = psi_calc_cmp_gt;
322 break;
323
324 case PSI_T_LPAREN:
325 break;
326
327 case PSI_T_PIPE:
328 exp->calc = psi_calc_bin_or;
329 break;
330 case PSI_T_CARET:
331 exp->calc = psi_calc_bin_xor;
332 break;
333 case PSI_T_AMPERSAND:
334 exp->calc = psi_calc_bin_and;
335 break;
336 case PSI_T_LSHIFT:
337 exp->calc = psi_calc_bin_lshift;
338 break;
339 case PSI_T_RSHIFT:
340 exp->calc = psi_calc_bin_rshift;
341 break;
342 case PSI_T_PLUS:
343 exp->calc = psi_calc_add;
344 break;
345 case PSI_T_MINUS:
346 exp->calc = psi_calc_sub;
347 break;
348 case PSI_T_ASTERISK:
349 exp->calc = psi_calc_mul;
350 break;
351 case PSI_T_SLASH:
352 exp->calc = psi_calc_div;
353 break;
354 case PSI_T_MODULO:
355 exp->calc = psi_calc_mod;
356 break;
357 default:
358 data->error(data, exp->token, PSI_WARNING,
359 "Unknown numeric operator (%d)", exp->op);
360 return false;
361 }
362 }
363
364 switch (exp->op) {
365 case 0:
366 return psi_number_validate(data, exp->data.n, impl, cb_decl, current_let, current_set, current_enum);
367
368 case PSI_T_NOT:
369 case PSI_T_TILDE:
370 case PSI_T_LPAREN:
371 return psi_num_exp_validate(data, exp->data.u, impl, cb_decl, current_let, current_set, current_enum);
372 break;
373
374 case PSI_T_OR:
375 case PSI_T_AND:
376
377 case PSI_T_CMP_EQ:
378 case PSI_T_CMP_NE:
379 case PSI_T_CMP_LE:
380 case PSI_T_CMP_GE:
381 case PSI_T_RCHEVR:
382 case PSI_T_LCHEVR:
383
384 case PSI_T_PIPE:
385 case PSI_T_CARET:
386 case PSI_T_AMPERSAND:
387 case PSI_T_LSHIFT:
388 case PSI_T_RSHIFT:
389 case PSI_T_PLUS:
390 case PSI_T_MINUS:
391 case PSI_T_ASTERISK:
392 case PSI_T_SLASH:
393 case PSI_T_MODULO:
394 return psi_num_exp_validate(data, exp->data.b.lhs, impl, cb_decl, current_let, current_set, current_enum)
395 && psi_num_exp_validate(data, exp->data.b.rhs, impl, cb_decl, current_let, current_set, current_enum);
396 default:
397 assert(0);
398 }
399
400 return false;
401 }
402
403 static inline void psi_impl_val_dump(token_t t, impl_val *res,
404 struct psi_call_frame *frame)
405 {
406 switch (t) {
407 case PSI_T_INT8:
408 case PSI_T_UINT8:
409 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi8, res->i8);
410 break;
411 case PSI_T_INT16:
412 case PSI_T_UINT16:
413 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi16, res->i16);
414 break;
415 case PSI_T_INT32:
416 case PSI_T_UINT32:
417 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi32, res->i32);
418 break;
419 case PSI_T_INT64:
420 case PSI_T_UINT64:
421 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
422 break;
423 case PSI_T_FLOAT:
424 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIfval, res->fval);
425 break;
426 case PSI_T_DOUBLE:
427 if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
428 break;
429 default:
430 assert(0);
431 }
432 }
433
434 static inline void psi_num_exp_verify_result(token_t t, impl_val *res, struct psi_call_frame *frame)
435 {
436 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", " = ");
437 psi_impl_val_dump(t, res, frame);
438 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
439 }
440
441 static void psi_num_exp_reduce(struct psi_num_exp *exp, struct psi_plist **output_ptr,
442 struct psi_plist **input_ptr, struct psi_call_frame *frame)
443 {
444 struct psi_plist *output = *output_ptr, *input = *input_ptr;
445 struct element {
446 token_t type;
447 union {
448 impl_val value;
449 psi_calc calc;
450 } data;
451 } entry;
452
453 switch (exp->op) {
454 case 0:
455 entry.type = psi_number_eval(exp->data.n, &entry.data.value, frame);
456 output = psi_plist_add(output, &entry);
457 break;
458
459 case PSI_T_LPAREN:
460 entry.type = exp->op;
461 input = psi_plist_add(input, &entry);
462 psi_num_exp_reduce(exp->data.u, &output, &input, frame);
463 while (psi_plist_pop(input, &entry)) {
464 if (entry.type == PSI_T_LPAREN) {
465 break;
466 }
467 if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
468 output = psi_plist_add(output, &entry);
469 }
470 break;
471
472 case PSI_T_NOT:
473 case PSI_T_TILDE:
474 while (psi_plist_top(input, &entry)) {
475 /* bail out if exp->op >= entry.type */
476 if (psi_calc_oper(exp->op, entry.type) != 1) {
477 break;
478 }
479 psi_plist_pop(input, NULL);
480 if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
481 output = psi_plist_add(output, &entry);
482 }
483 entry.type = exp->op;
484 entry.data.calc = exp->calc;
485 input = psi_plist_add(input, &entry);
486 psi_num_exp_reduce(exp->data.u, &output, &input, frame);
487 break;
488
489 default:
490 psi_num_exp_reduce(exp->data.b.lhs, &output, &input, frame);
491 while (psi_plist_top(input, &entry)) {
492 /* bail out if exp->op > entry.type */
493 if (psi_calc_oper(exp->op, entry.type) == -1) {
494 break;
495 }
496 psi_plist_pop(input, NULL);
497 if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
498 output = psi_plist_add(output, &entry);
499 }
500 entry.type = exp->op;
501 entry.data.calc = exp->calc;
502 input = psi_plist_add(input, &entry);
503 psi_num_exp_reduce(exp->data.b.rhs, &output, &input, frame);
504 break;
505 }
506
507 *output_ptr = output;
508 *input_ptr = input;
509 }
510
511 token_t psi_num_exp_exec(struct psi_num_exp *exp, impl_val *res,
512 struct psi_call_frame *frame)
513 {
514 struct psi_plist *output, *input;
515 struct element {
516 token_t type;
517 union {
518 impl_val value;
519 psi_calc calc;
520 } data;
521 } entry, lhs, rhs;
522
523 output = psi_plist_init_ex(sizeof(entry), NULL);
524 input = psi_plist_init_ex(sizeof(entry), NULL);
525
526 psi_num_exp_reduce(exp, &output, &input, frame);
527
528 while (psi_plist_pop(input, &entry)) {
529 if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
530 output = psi_plist_add(output, &entry);
531 }
532 if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
533
534 while (psi_plist_shift(output, &entry)) {
535 switch (entry.type) {
536 default:
537 input = psi_plist_add(input, &entry);
538 break;
539
540 case PSI_T_NOT:
541 case PSI_T_TILDE:
542 psi_plist_pop(input, &rhs);
543 if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
544 psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
545
546 entry.type = entry.data.calc(rhs.type, &rhs.data.value, 0, NULL, &entry.data.value);
547 input = psi_plist_add(input, &entry);
548 psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
549 break;
550
551 case PSI_T_OR:
552 case PSI_T_AND:
553
554 case PSI_T_CMP_EQ:
555 case PSI_T_CMP_NE:
556 case PSI_T_CMP_LE:
557 case PSI_T_CMP_GE:
558 case PSI_T_RCHEVR:
559 case PSI_T_LCHEVR:
560
561 case PSI_T_PIPE:
562 case PSI_T_CARET:
563 case PSI_T_AMPERSAND:
564 case PSI_T_LSHIFT:
565 case PSI_T_RSHIFT:
566 case PSI_T_MINUS:
567 case PSI_T_PLUS:
568 case PSI_T_ASTERISK:
569 case PSI_T_SLASH:
570 case PSI_T_MODULO:
571 psi_plist_pop(input, &rhs);
572 psi_plist_pop(input, &lhs);
573
574 psi_impl_val_dump(lhs.type, &lhs.data.value, frame);
575 if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
576 psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
577
578 entry.type = entry.data.calc(
579 lhs.type, &lhs.data.value,
580 rhs.type, &rhs.data.value,
581 &entry.data.value);
582 input = psi_plist_add(input, &entry);
583 psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
584 break;
585 }
586
587 if (!psi_plist_count(output)) {
588 break;
589 }
590 }
591
592 psi_plist_free(output);
593 psi_plist_free(input);
594
595 *res = entry.data.value;
596 return entry.type;
597 }
598