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