fix gdbinit; postprocessing macros
[m6w6/ext-psi] / src / types / num_exp.c
index d2fcc1a62befe02b6681c4262370b53e547d97f1..9388ad3dcc2d12d4365cf9575951c0bb5b94ce79 100644 (file)
@@ -5,11 +5,11 @@
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
 
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
 
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*******************************************************************************/
+ *******************************************************************************/
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+#include "php_psi_stdinc.h"
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
 #include <assert.h>
 
 #include "data.h"
+#include "context.h"
+#include "call.h"
 #include "calc.h"
 
-num_exp *init_num_exp(token_t t, void *num) {
-       num_exp *exp = calloc(1, sizeof(*exp));
-       switch (exp->t = t) {
-       case PSI_T_NUMBER:
-       case PSI_T_NSNAME:
-               exp->u.numb = strdup(num);
-               break;
-       case PSI_T_NAME:
-               exp->u.dvar = num;
-               break;
-       default:
-               assert(0);
-       }
+struct psi_num_exp *psi_num_exp_init_ternary(token_t op,
+               struct psi_num_exp *cond, struct psi_num_exp *truthy,
+               struct psi_num_exp *falsy)
+{
+       struct psi_num_exp *exp = pecalloc(1, sizeof(*exp), 1);
+
+       exp->op = op;
+       exp->data.t.cond = cond;
+       exp->data.t.truthy = truthy;
+       exp->data.t.falsy = falsy;
+
        return exp;
 }
 
-num_exp *copy_num_exp(num_exp *exp) {
-       decl_var *dvar;
-       num_exp *num = calloc(1, sizeof(*num));
-       memcpy(num, exp, sizeof(*num));
-       if (num->token) {
-               num->token = psi_token_copy(num->token);
-       }
-       if (num->operand) {
-               num->operand = copy_num_exp(num->operand);
-       }
-       switch (num->t) {
-       case PSI_T_NUMBER:
-       case PSI_T_NSNAME:
-               num->u.numb = strdup(num->u.numb);
-               break;
-       case PSI_T_NAME:
-               dvar = init_decl_var(num->u.dvar->name, num->u.dvar->pointer_level,
-                               num->u.dvar->array_size);
-               dvar->arg = num->u.dvar->arg;
-               if (num->u.dvar->token) {
-                       dvar->token = psi_token_copy(num->u.dvar->token);
-               }
-               num->u.dvar = dvar;
-               break;
-       default:
-               assert(0);
-       }
-       return num;
+struct psi_num_exp *psi_num_exp_init_binary(token_t op,
+               struct psi_num_exp *lhs, struct psi_num_exp *rhs)
+{
+       struct psi_num_exp *exp = pecalloc(1, sizeof(*exp), 1);
+
+       exp->op = op;
+       exp->data.b.lhs = lhs;
+       exp->data.b.rhs = rhs;
+
+       return exp;
 }
 
-void free_num_exp(num_exp *exp) {
-       if (exp->token) {
-               free(exp->token);
+struct psi_num_exp *psi_num_exp_init_unary(token_t op,
+               struct psi_num_exp *u)
+{
+       struct psi_num_exp *exp = pecalloc(1, sizeof(*exp), 1);
+
+       exp->op = op;
+       exp->data.u = u;
+
+       return exp;
+}
+
+struct psi_num_exp *psi_num_exp_init_num(struct psi_number *n)
+{
+       struct psi_num_exp *exp = pecalloc(1, sizeof(*exp), 1);
+
+       exp->op = PSI_T_NUMBER;
+       exp->data.n = n;
+
+       return exp;
+}
+
+struct psi_num_exp *psi_num_exp_init_cast(struct psi_decl_type *typ,
+               struct psi_num_exp *num)
+{
+       struct psi_num_exp *exp = pecalloc(1, sizeof(*exp), 1);
+
+       exp->op = PSI_T_CAST;
+       exp->data.c.typ = typ;
+       exp->data.c.num = num;
+
+       return exp;
+}
+
+struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp)
+{
+       struct psi_num_exp *cpy;
+
+       if (!exp) {
+               return NULL;
        }
-       switch (exp->t) {
+
+       cpy = pemalloc(sizeof(*cpy), 1);
+       *cpy = *exp;
+
+       switch (exp->op) {
        case PSI_T_NUMBER:
-               free(exp->u.numb);
+               cpy->data.n = psi_number_copy(exp->data.n);
                break;
-       case PSI_T_NSNAME:
+
+       case PSI_T_CAST:
+               cpy->data.c.typ = psi_decl_type_copy(exp->data.c.typ);
+               cpy->data.c.num = psi_num_exp_copy(exp->data.c.num);
                break;
-       case PSI_T_NAME:
-               free_decl_var(exp->u.dvar);
+
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+       case PSI_T_LPAREN:
+               cpy->data.u = psi_num_exp_copy(exp->data.u);
                break;
-       case PSI_T_ENUM:
+
+       case PSI_T_OR:
+       case PSI_T_AND:
+
+       case PSI_T_CMP_EQ:
+       case PSI_T_CMP_NE:
+       case PSI_T_CMP_LE:
+       case PSI_T_CMP_GE:
+       case PSI_T_RCHEVR:
+       case PSI_T_LCHEVR:
+
+       case PSI_T_PIPE:
+       case PSI_T_CARET:
+       case PSI_T_AMPERSAND:
+       case PSI_T_LSHIFT:
+       case PSI_T_RSHIFT:
+       case PSI_T_PLUS:
+       case PSI_T_MINUS:
+       case PSI_T_ASTERISK:
+       case PSI_T_SLASH:
+       case PSI_T_MODULO:
+               cpy->data.b.lhs = psi_num_exp_copy(exp->data.b.lhs);
+               cpy->data.b.rhs = psi_num_exp_copy(exp->data.b.rhs);
                break;
+
+       case PSI_T_IIF:
+               cpy->data.t.cond = psi_num_exp_copy(exp->data.t.cond);
+               cpy->data.t.truthy = psi_num_exp_copy(exp->data.t.truthy);
+               cpy->data.t.falsy = psi_num_exp_copy(exp->data.t.falsy);
+               break;
+
        default:
                assert(0);
        }
-       if (exp->operand) {
-               free_num_exp(exp->operand);
+
+       if (exp->token) {
+               cpy->token = psi_token_copy(exp->token);
        }
-       free(exp);
+
+       return cpy;
+}
+
+void psi_num_exp_copy_ctor(struct psi_num_exp **exp_ptr)
+{
+       *exp_ptr = psi_num_exp_copy(*exp_ptr);
 }
 
-void dump_num_exp(int fd, num_exp *exp) {
-       while (exp) {
-               switch (exp->t) {
+void psi_num_exp_free(struct psi_num_exp **c_ptr)
+{
+       if (*c_ptr) {
+               struct psi_num_exp *c = *c_ptr;
+
+               *c_ptr = NULL;
+
+               switch (c->op) {
                case PSI_T_NUMBER:
-                       dprintf(fd, "%s", exp->u.numb);
+                       psi_number_free(&c->data.n);
                        break;
-               case PSI_T_NSNAME:
-                       dprintf(fd, "%s", exp->u.cnst->name);
+
+               case PSI_T_CAST:
+                       psi_decl_type_free(&c->data.c.typ);
+                       psi_num_exp_free(&c->data.c.num);
                        break;
-               case PSI_T_NAME:
-                       dump_decl_var(fd, exp->u.dvar);
+
+               case PSI_T_NOT:
+               case PSI_T_TILDE:
+               case PSI_T_LPAREN:
+                       psi_num_exp_free(&c->data.u);
                        break;
-               case PSI_T_ENUM:
-                       dprintf(fd, "%s", exp->u.enm->name);
+
+               case PSI_T_OR:
+               case PSI_T_AND:
+
+               case PSI_T_CMP_EQ:
+               case PSI_T_CMP_NE:
+               case PSI_T_CMP_LE:
+               case PSI_T_CMP_GE:
+               case PSI_T_RCHEVR:
+               case PSI_T_LCHEVR:
+
+               case PSI_T_PIPE:
+               case PSI_T_CARET:
+               case PSI_T_AMPERSAND:
+               case PSI_T_LSHIFT:
+               case PSI_T_RSHIFT:
+               case PSI_T_PLUS:
+               case PSI_T_MINUS:
+               case PSI_T_ASTERISK:
+               case PSI_T_SLASH:
+               case PSI_T_MODULO:
+                       psi_num_exp_free(&c->data.b.lhs);
+                       psi_num_exp_free(&c->data.b.rhs);
                        break;
+
+               case PSI_T_IIF:
+                       psi_num_exp_free(&c->data.t.cond);
+                       psi_num_exp_free(&c->data.t.truthy);
+                       psi_num_exp_free(&c->data.t.falsy);
+                       break;
+
                default:
                        assert(0);
                }
-               if (exp->operand) {
-                       char op;
-
-                       switch (exp->operator) {
-                       case PSI_T_PLUS:        op = '+'; break;
-                       case PSI_T_MINUS:       op = '-'; break;
-                       case PSI_T_ASTERISK:op = '*'; break;
-                       case PSI_T_SLASH:       op = '/'; break;
-                       default:
-                               assert(0);
-                       }
-                       dprintf(fd, " %c ", op);
-               }
-               exp = exp->operand;
+
+               psi_token_free(&c->token);
+
+               free(c);
        }
 }
 
-static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) {
-       size_t i;
+static inline const char *psi_num_exp_op_tok(token_t op)
+{
+       switch (op) {
+       case PSI_T_NOT:
+               return "!";
+       case PSI_T_TILDE:
+               return "~";
+       case PSI_T_LPAREN:
+               return "(";
+       case PSI_T_CAST:
+               return "(cast)";
 
-       for (i = 0; i < consts->count; ++i) {
-               constant *cnst = consts->list[i];
+       case PSI_T_PIPE:
+               return "|";
+       case PSI_T_CARET:
+               return "^";
+       case PSI_T_AMPERSAND:
+               return "&";
 
-               if (!strcmp(cnst->name, exp->u.numb)) {
-                       free(exp->u.numb);
-                       return exp->u.cnst = cnst;
-               }
-       }
+       case PSI_T_LSHIFT:
+               return "<<";
+       case PSI_T_RSHIFT:
+               return ">>";
+
+       case PSI_T_PLUS:
+               return "+";
+       case PSI_T_MINUS:
+               return "-";
+
+       case PSI_T_ASTERISK:
+               return "*";
+       case PSI_T_SLASH:
+               return "/";
+       case PSI_T_MODULO:
+               return "%";
 
-       return NULL;
+       case PSI_T_OR:
+               return "||";
+       case PSI_T_AND:
+               return "&&";
+
+       case PSI_T_CMP_EQ:
+               return "==";
+       case PSI_T_CMP_NE:
+               return "!=";
+       case PSI_T_CMP_LE:
+               return "<=";
+       case PSI_T_CMP_GE:
+               return ">=";
+       case PSI_T_RCHEVR:
+               return ">";
+       case PSI_T_LCHEVR:
+               return "<";
+
+       case PSI_T_IIF:
+               return "?";
+
+       default:
+               assert(0);
+       }
+       return 0;
 }
-static inline decl_enum_item *locate_num_exp_enum_item_ex(num_exp *exp, decl_enum *e) {
-       size_t k;
 
-       if (e) for (k = 0; k < e->items->count; ++k) {
-               decl_enum_item *i = e->items->list[k];
+struct psi_plist *psi_num_exp_tokens(struct psi_num_exp *exp,
+               struct psi_plist *list)
+{
+       struct psi_token *ntoken;
+
+       if (!list) {
+               list = psi_plist_init((psi_plist_dtor) psi_token_free);
+       }
+
+       switch (exp->op) {
+       case PSI_T_NUMBER:
+               list = psi_number_tokens(exp->data.n, list);
+               break;
+
+       case PSI_T_CAST:
+               ntoken = exp->data.c.typ->token;
+               ntoken = psi_token_init(PSI_T_LPAREN, "(", 1, ntoken->col-1, ntoken->line, ntoken->file);
+               list = psi_plist_add(list, &ntoken);
+               ntoken = psi_token_copy(exp->data.c.typ->token);
+               list = psi_plist_add(list, &ntoken);
+               ntoken = psi_token_init(PSI_T_RPAREN, ")", 1, ntoken->col+ntoken->text->len, ntoken->line, ntoken->file);
+               list = psi_plist_add(list, &ntoken);
+               break;
+
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+       unary:
+               ntoken = psi_token_copy(exp->token);
+               list = psi_plist_add(list, &ntoken);
+               list = psi_num_exp_tokens(exp->data.u, list);
+               break;
+
+       case PSI_T_LPAREN:
+               ntoken = psi_token_copy(exp->token);
+               list = psi_plist_add(list, &ntoken);
+               list = psi_num_exp_tokens(exp->data.u, list);
+               psi_plist_top(list, &ntoken);
+               ntoken = psi_token_init(PSI_T_RPAREN, ")", 1, ntoken->col+ntoken->text->len, ntoken->line, ntoken->file);
+               list = psi_plist_add(list, &ntoken);
+               break;
 
-               if (!strcmp(i->name, exp->u.dvar->name)) {
-                       free_decl_var(exp->u.dvar);
-                       exp->t = PSI_T_ENUM;
-                       exp->u.enm = i;
-                       return i;
+       case PSI_T_PLUS:
+       case PSI_T_MINUS:
+               if (!exp->data.b.rhs) {
+                       goto unary;
                }
+               /* no break */
+       case PSI_T_PIPE:
+       case PSI_T_CARET:
+       case PSI_T_AMPERSAND:
+       case PSI_T_LSHIFT:
+       case PSI_T_RSHIFT:
+       case PSI_T_ASTERISK:
+       case PSI_T_SLASH:
+
+       case PSI_T_OR:
+       case PSI_T_AND:
+
+       case PSI_T_CMP_EQ:
+       case PSI_T_CMP_NE:
+       case PSI_T_CMP_LE:
+       case PSI_T_CMP_GE:
+       case PSI_T_RCHEVR:
+       case PSI_T_LCHEVR:
+
+               list = psi_num_exp_tokens(exp->data.b.lhs, list);
+               ntoken = psi_token_copy(exp->token);
+               list = psi_plist_add(list, &ntoken);
+               list = psi_num_exp_tokens(exp->data.b.rhs, list);
+               break;
+
+       case PSI_T_IIF:
+               list = psi_num_exp_tokens(exp->data.t.cond, list);
+               ntoken = psi_token_copy(exp->token);
+               list = psi_plist_add(list, &ntoken);
+               list = psi_num_exp_tokens(exp->data.t.truthy, list);
+               psi_plist_top(list, &ntoken);
+               ntoken = psi_token_init(PSI_T_COLON, ":", 1, ntoken->col+ntoken->text->len, ntoken->line, ntoken->file);
+               list = psi_plist_add(list, &ntoken);
+               list = psi_plist_add(list, &ntoken);
+               list = psi_num_exp_tokens(exp->data.t.falsy, list);
+               break;
+
+       default:
+               assert(0);
        }
-       return NULL;
+
+       return list;
 }
-static inline decl_enum_item *locate_num_exp_enum_item(num_exp *exp, decl_enums *enums) {
-       size_t j;
 
-       if (enums) for (j = 0; j < enums->count; ++j) {
-               decl_enum *e = enums->list[j];
-               decl_enum_item *i = locate_num_exp_enum_item_ex(exp, e);
+void psi_num_exp_dump(struct psi_dump *dump, struct psi_num_exp *exp)
+{
+       switch (exp->op) {
+       case PSI_T_NUMBER:
+               psi_number_dump(dump, exp->data.n);
+               break;
 
-               if (i) {
-                       return i;
+       case PSI_T_CAST:
+               PSI_DUMP(dump, "(");
+               psi_decl_type_dump(dump, exp->data.c.typ, 0);
+               PSI_DUMP(dump, ")");
+               break;
+
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+       unary:
+               PSI_DUMP(dump, "%s", psi_num_exp_op_tok(exp->op));
+               psi_num_exp_dump(dump, exp->data.u);
+               break;
+
+       case PSI_T_LPAREN:
+               PSI_DUMP(dump, "(");
+               psi_num_exp_dump(dump, exp->data.u);
+               PSI_DUMP(dump, ")");
+               break;
+
+       case PSI_T_PLUS:
+       case PSI_T_MINUS:
+               if (!exp->data.b.rhs) {
+                       goto unary;
                }
+               /* no break */
+       case PSI_T_PIPE:
+       case PSI_T_CARET:
+       case PSI_T_AMPERSAND:
+       case PSI_T_LSHIFT:
+       case PSI_T_RSHIFT:
+       case PSI_T_ASTERISK:
+       case PSI_T_SLASH:
+
+       case PSI_T_OR:
+       case PSI_T_AND:
+
+       case PSI_T_CMP_EQ:
+       case PSI_T_CMP_NE:
+       case PSI_T_CMP_LE:
+       case PSI_T_CMP_GE:
+       case PSI_T_RCHEVR:
+       case PSI_T_LCHEVR:
+               psi_num_exp_dump(dump, exp->data.b.lhs);
+               PSI_DUMP(dump, " %s ", psi_num_exp_op_tok(exp->op));
+               psi_num_exp_dump(dump, exp->data.b.rhs);
+               break;
+
+       case PSI_T_IIF:
+               psi_num_exp_dump(dump, exp->data.t.cond);
+               PSI_DUMP(dump, " ? ");
+               psi_num_exp_dump(dump, exp->data.t.truthy);
+               PSI_DUMP(dump, " : ");
+               psi_num_exp_dump(dump, exp->data.t.falsy);
+               break;
+
+       default:
+               assert(0);
        }
-       return NULL;
+
 }
 
-int validate_num_exp(struct psi_data *data, num_exp *exp, decl_args *dargs, decl_arg *func, decl_enum *enm) {
-       if (exp->operand) {
-               switch (exp->operator) {
+bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp,
+               struct psi_validate_scope *scope)
+{
+       if (exp->op && exp->op != PSI_T_NUMBER) {
+               switch (exp->op) {
+               case PSI_T_NOT:
+                       exp->calc = psi_calc_bool_not;
+                       break;
+               case PSI_T_TILDE:
+                       exp->calc = psi_calc_bin_not;
+                       break;
+
+               case PSI_T_OR:
+                       exp->calc = psi_calc_bool_or;
+                       break;
+               case PSI_T_AND:
+                       exp->calc = psi_calc_bool_and;
+                       break;
+               case PSI_T_CMP_EQ:
+                       exp->calc = psi_calc_cmp_eq;
+                       break;
+               case PSI_T_CMP_NE:
+                       exp->calc = psi_calc_cmp_ne;
+                       break;
+               case PSI_T_CMP_LE:
+                       exp->calc = psi_calc_cmp_le;
+                       break;
+               case PSI_T_CMP_GE:
+                       exp->calc = psi_calc_cmp_ge;
+                       break;
+               case PSI_T_LCHEVR:
+                       exp->calc = psi_calc_cmp_lt;
+                       break;
+               case PSI_T_RCHEVR:
+                       exp->calc = psi_calc_cmp_gt;
+                       break;
+
+               case PSI_T_CAST:
+               case PSI_T_LPAREN:
+               case PSI_T_IIF:
+                       break;
+
+               case PSI_T_PIPE:
+                       exp->calc = psi_calc_bin_or;
+                       break;
+               case PSI_T_CARET:
+                       exp->calc = psi_calc_bin_xor;
+                       break;
+               case PSI_T_AMPERSAND:
+                       exp->calc = psi_calc_bin_and;
+                       break;
+               case PSI_T_LSHIFT:
+                       exp->calc = psi_calc_bin_lshift;
+                       break;
+               case PSI_T_RSHIFT:
+                       exp->calc = psi_calc_bin_rshift;
+                       break;
                case PSI_T_PLUS:
-                       exp->calculator = psi_calc_add;
+                       if (exp->data.b.rhs) {
+                               exp->calc = psi_calc_add;
+                       }
                        break;
                case PSI_T_MINUS:
-                       exp->calculator = psi_calc_sub;
+                       if (exp->data.b.rhs) {
+                               exp->calc = psi_calc_sub;
+                       } else {
+                               exp->calc = psi_calc_minus;
+                       }
                        break;
                case PSI_T_ASTERISK:
-                       exp->calculator = psi_calc_mul;
+                       exp->calc = psi_calc_mul;
                        break;
                case PSI_T_SLASH:
-                       exp->calculator = psi_calc_div;
+                       exp->calc = psi_calc_div;
+                       break;
+               case PSI_T_MODULO:
+                       exp->calc = psi_calc_mod;
                        break;
                default:
-                       assert(0);
+                       data->error(data, exp->token, PSI_WARNING,
+                                       "Unknown numeric operator (%d)", exp->op);
+                       return false;
                }
-               if (!validate_num_exp(data, exp->operand, dargs, func, enm)) {
-                       return 0;
+       }
+
+       switch (exp->op) {
+       case PSI_T_NUMBER:
+               return psi_number_validate(data, exp->data.n, scope);
+
+       case PSI_T_CAST:
+               return psi_num_exp_validate(data, exp->data.c.num, scope)
+                               && psi_decl_type_validate(data, exp->data.c.typ, NULL, scope);
+               break;
+
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+       case PSI_T_LPAREN:
+       unary:
+               return psi_num_exp_validate(data, exp->data.u, scope);
+               break;
+
+       case PSI_T_PLUS:
+       case PSI_T_MINUS:
+               if (!exp->data.b.rhs) {
+                       goto unary;
                }
+               /* no break */
+       case PSI_T_PIPE:
+       case PSI_T_CARET:
+       case PSI_T_AMPERSAND:
+       case PSI_T_LSHIFT:
+       case PSI_T_RSHIFT:
+       case PSI_T_ASTERISK:
+       case PSI_T_SLASH:
+       case PSI_T_MODULO:
+
+       case PSI_T_OR:
+       case PSI_T_AND:
+
+       case PSI_T_CMP_EQ:
+       case PSI_T_CMP_NE:
+       case PSI_T_CMP_LE:
+       case PSI_T_CMP_GE:
+       case PSI_T_RCHEVR:
+       case PSI_T_LCHEVR:
+               return psi_num_exp_validate(data, exp->data.b.lhs, scope)
+                               && psi_num_exp_validate(data, exp->data.b.rhs, scope);
+
+       case PSI_T_IIF:
+               return psi_num_exp_validate(data, exp->data.t.cond, scope)
+                               && psi_num_exp_validate(data, exp->data.t.truthy, scope)
+                               && psi_num_exp_validate(data, exp->data.t.falsy, scope);
+
+       default:
+               assert(0);
        }
-       switch (exp->t) {
-       case PSI_T_NAME:
-               if (!locate_decl_var_arg(exp->u.dvar, dargs, func)) {
-                       if (!locate_num_exp_enum_item(exp, data->enums) && !locate_num_exp_enum_item_ex(exp, enm)) {
-                               data->error(data, exp->token, PSI_WARNING, "Unknown variable '%s' in numeric expression",
-                                               exp->u.dvar->name);
-                               return 0;
+
+       return false;
+}
+
+static inline void psi_impl_val_dump(token_t t, impl_val *res,
+               struct psi_call_frame *frame)
+{
+       switch (t) {
+       case PSI_T_INT8:
+       case PSI_T_UINT8:
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi8, res->i8);
+               break;
+       case PSI_T_INT16:
+       case PSI_T_UINT16:
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi16, res->i16);
+               break;
+       case PSI_T_INT32:
+       case PSI_T_UINT32:
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi32, res->i32);
+               break;
+       case PSI_T_INT64:
+       case PSI_T_UINT64:
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIi64, res->i64);
+               break;
+       case PSI_T_FLOAT:
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIfval, res->fval);
+               break;
+       case PSI_T_DOUBLE:
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIdval, res->dval);
+               break;
+#if HAVE_LONG_DOUBLE
+       case PSI_T_LONG_DOUBLE:
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %" PRIldval, res->ldval);
+               break;
+#endif
+               default:
+               assert(0);
+       }
+}
+
+static inline void psi_num_exp_verify_result(token_t t, impl_val *res, struct psi_call_frame *frame)
+{
+       if (frame) PSI_DEBUG_PRINT(frame->context, "%s", " = ");
+       psi_impl_val_dump(t, res, frame);
+       if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
+}
+
+static void psi_num_exp_reduce(struct psi_num_exp *exp, struct psi_plist **output_ptr,
+               struct psi_plist **input_ptr, struct psi_call_frame *frame, struct psi_cpp *cpp)
+{
+       struct psi_plist *output = *output_ptr, *input = *input_ptr;
+       struct element {
+               token_t type;
+               union {
+                       impl_val value;
+                       psi_calc calc;
+                       struct psi_decl_type *cast;
+               } data;
+       } entry;
+
+       switch (exp->op) {
+       case PSI_T_NUMBER:
+               entry.type = psi_number_eval(exp->data.n, &entry.data.value, frame, cpp, exp);
+               output = psi_plist_add(output, &entry);
+               break;
+
+       case PSI_T_LPAREN:
+               entry.type = exp->op;
+               input = psi_plist_add(input, &entry);
+               psi_num_exp_reduce(exp->data.u, &output, &input, frame, cpp);
+               while (psi_plist_pop(input, &entry)) {
+                       if (entry.type == PSI_T_LPAREN) {
+                               break;
                        }
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+                       output = psi_plist_add(output, &entry);
                }
-               return 1;
-       case PSI_T_NSNAME:
-               if (!locate_num_exp_constant(exp, data->consts)) {
-                       data->error(data, exp->token, PSI_WARNING, "Unknown constant '%s' in numeric expression",
-                                       exp->u.numb);
-                       return 0;
+               break;
+
+       case PSI_T_CAST:
+               while (psi_plist_top(input, &entry)) {
+                       /* bail out if exp->op >= entry.type */
+                       if (psi_calc_oper(exp->op, entry.type) != 1) {
+                               break;
+                       }
+                       psi_plist_pop(input, NULL);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+                       output = psi_plist_add(output, &entry);
                }
-               return 1;
-       case PSI_T_NUMBER:
-       case PSI_T_ENUM:
-               return 1;
+               entry.type = exp->op;
+               entry.data.cast = exp->data.c.typ;
+               input = psi_plist_add(input, &entry);
+               psi_num_exp_reduce(exp->data.c.num, &output, &input, frame, cpp);
+               break;
+
+       case PSI_T_NOT:
+       case PSI_T_TILDE:
+               while (psi_plist_top(input, &entry)) {
+                       /* bail out if exp->op >= entry.type */
+                       if (psi_calc_oper(exp->op, entry.type) != 1) {
+                               break;
+                       }
+                       psi_plist_pop(input, NULL);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+                       output = psi_plist_add(output, &entry);
+               }
+               entry.type = exp->op;
+               entry.data.calc = exp->calc;
+               input = psi_plist_add(input, &entry);
+               psi_num_exp_reduce(exp->data.u, &output, &input, frame, cpp);
+               break;
+
+       case PSI_T_IIF:
+               {
+                       impl_val cond_val = {0};
+                       token_t cond_typ = psi_num_exp_exec(exp->data.t.cond, &cond_val, frame, cpp);
+
+                       psi_calc_bool_not(cond_typ, &cond_val, 0, NULL, &cond_val);
+                       if (cond_val.u8) {
+                               psi_num_exp_reduce(exp->data.t.falsy, &output, &input, frame, cpp);
+                       } else {
+                               psi_num_exp_reduce(exp->data.t.truthy, &output, &input, frame, cpp);
+                       }
+               }
+               break;
+
+       case PSI_T_MINUS:
+       case PSI_T_PLUS:
+               /* unary */
+               if (!exp->data.b.rhs) {
+                       entry.type = psi_num_exp_exec(exp->data.b.lhs, &entry.data.value, frame, cpp);
+
+                       if (exp->calc) {
+                               entry.type = exp->calc(entry.type, &entry.data.value, 0, NULL, &entry.data.value);
+                       }
+                       output = psi_plist_add(output, &entry);
+                       break;
+               }
+               /* no break */
        default:
-               return 0;
+               psi_num_exp_reduce(exp->data.b.lhs, &output, &input, frame, cpp);
+               while (psi_plist_top(input, &entry)) {
+                       /* bail out if exp->op > entry.type */
+                       if (psi_calc_oper(exp->op, entry.type) == -1) {
+                               break;
+                       }
+                       psi_plist_pop(input, NULL);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+                       output = psi_plist_add(output, &entry);
+               }
+               entry.type = exp->op;
+               entry.data.calc = exp->calc;
+               input = psi_plist_add(input, &entry);
+               psi_num_exp_reduce(exp->data.b.rhs, &output, &input, frame, cpp);
+               break;
+       }
+
+       *output_ptr = output;
+       *input_ptr = input;
+}
+
+token_t psi_num_exp_exec(struct psi_num_exp *exp, impl_val *res,
+               struct psi_call_frame *frame, struct psi_cpp *cpp)
+{
+       struct psi_plist *output, *input;
+       struct element {
+               token_t type;
+               union {
+                       impl_val value;
+                       psi_calc calc;
+                       struct psi_decl_type *cast;
+               } data;
+       } entry, lhs, rhs;
+
+       output = psi_plist_init_ex(sizeof(entry), NULL);
+       input = psi_plist_init_ex(sizeof(entry), NULL);
+
+       psi_num_exp_reduce(exp, &output, &input, frame, cpp);
+
+       while (psi_plist_pop(input, &entry)) {
+               if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+               output = psi_plist_add(output, &entry);
        }
+       if (frame) PSI_DEBUG_PRINT(frame->context, "%s", "\n");
+
+       while (psi_plist_shift(output, &entry)) {
+               switch (entry.type) {
+               default:
+                       input = psi_plist_add(input, &entry);
+                       break;
+
+               case PSI_T_CAST:
+                       psi_plist_pop(input, &rhs);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+                       psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
+
+                       entry.type = psi_decl_type_get_real(entry.data.cast)->type;
+                       psi_calc_cast(rhs.type, &rhs.data.value, entry.type, &entry.data.value);
+                       input = psi_plist_add(input, &entry);
+                       psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
+                       break;
+
+               case PSI_T_NOT:
+               case PSI_T_TILDE:
+                       psi_plist_pop(input, &rhs);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+                       psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
+
+                       entry.type = entry.data.calc(rhs.type, &rhs.data.value, 0, NULL, &entry.data.value);
+                       input = psi_plist_add(input, &entry);
+                       psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
+                       break;
+
+               case PSI_T_OR:
+               case PSI_T_AND:
+
+               case PSI_T_CMP_EQ:
+               case PSI_T_CMP_NE:
+               case PSI_T_CMP_LE:
+               case PSI_T_CMP_GE:
+               case PSI_T_RCHEVR:
+               case PSI_T_LCHEVR:
+
+               case PSI_T_PIPE:
+               case PSI_T_CARET:
+               case PSI_T_AMPERSAND:
+               case PSI_T_LSHIFT:
+               case PSI_T_RSHIFT:
+               case PSI_T_MINUS:
+               case PSI_T_PLUS:
+               case PSI_T_ASTERISK:
+               case PSI_T_SLASH:
+               case PSI_T_MODULO:
+                       psi_plist_pop(input, &rhs);
+                       psi_plist_pop(input, &lhs);
+
+                       psi_impl_val_dump(lhs.type, &lhs.data.value, frame);
+                       if (frame) PSI_DEBUG_PRINT(frame->context, " %s", psi_num_exp_op_tok(entry.type));
+                       psi_impl_val_dump(rhs.type, &rhs.data.value, frame);
+
+                       entry.type = entry.data.calc(
+                                       lhs.type, &lhs.data.value,
+                                       rhs.type, &rhs.data.value,
+                                       &entry.data.value);
+                       input = psi_plist_add(input, &entry);
+                       psi_num_exp_verify_result(entry.type, &entry.data.value, frame);
+                       break;
+               }
+
+               if (!psi_plist_count(output)) {
+                       break;
+               }
+       }
+
+       psi_plist_free(output);
+       psi_plist_free(input);
+
+       *res = entry.data.value;
+       return entry.type;
 }
+