|
@@ -4,6 +4,7 @@
|
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
#include <string.h>
|
|
|
#include <time.h>
|
|
#include <time.h>
|
|
|
|
|
+#include <math.h>
|
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
#define ON_WINDOWS
|
|
#define ON_WINDOWS
|
|
@@ -5130,6 +5131,14 @@ node_t *mexpr_negate(node_t *a)
|
|
|
|
|
|
|
|
node_t *mexpr_add(node_t *a, node_t *b)
|
|
node_t *mexpr_add(node_t *a, node_t *b)
|
|
|
{
|
|
{
|
|
|
|
|
+ if (IS_STRING(a) && IS_STRING(b)) {
|
|
|
|
|
+ char *buf = malloc(strlen(a->t->text) + strlen(b->t->text) + 1);
|
|
|
|
|
+ strcpy(buf, a->t->text);
|
|
|
|
|
+ strcat(buf, b->t->text);
|
|
|
|
|
+
|
|
|
|
|
+ return nodet(N_LITERAL, token(T_STRING, buf));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (!IS_NUMBER(a))
|
|
if (!IS_NUMBER(a))
|
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
|
@@ -5161,6 +5170,17 @@ node_t *mexpr_mul(node_t *a, node_t *b)
|
|
|
return make_number(TO_DOUBLE(a) * TO_DOUBLE(b));
|
|
return make_number(TO_DOUBLE(a) * TO_DOUBLE(b));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+node_t *mexpr_pow(node_t *a, node_t *b)
|
|
|
|
|
+{
|
|
|
|
|
+ if (!IS_NUMBER(a))
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ if (!IS_NUMBER(b))
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ return make_number(pow(TO_DOUBLE(a), TO_DOUBLE(b)));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
node_t *mexpr_div(node_t *a, node_t *b)
|
|
node_t *mexpr_div(node_t *a, node_t *b)
|
|
|
{
|
|
{
|
|
|
if (!IS_NUMBER(a))
|
|
if (!IS_NUMBER(a))
|
|
@@ -5176,6 +5196,21 @@ node_t *mexpr_div(node_t *a, node_t *b)
|
|
|
return make_number(TO_DOUBLE(a) * x);
|
|
return make_number(TO_DOUBLE(a) * x);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+node_t *mexpr_mod(node_t *a, node_t *b)
|
|
|
|
|
+{
|
|
|
|
|
+ if (!IS_NUMBER(a))
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ if (!IS_NUMBER(b))
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ double x = TO_DOUBLE(b);
|
|
|
|
|
+ if (x == 0)
|
|
|
|
|
+ return make_number(0);
|
|
|
|
|
+
|
|
|
|
|
+ return make_number(fmod(TO_DOUBLE(a), x));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
int mexpr_equals(node_t *a, node_t *b)
|
|
int mexpr_equals(node_t *a, node_t *b)
|
|
|
{
|
|
{
|
|
|
if (!a && !b)
|
|
if (!a && !b)
|
|
@@ -5226,136 +5261,244 @@ macro_t *find_macro(char *name, size_t argc, int *res);
|
|
|
node_t *run_macro(macro_t *macro, list_t *args);
|
|
node_t *run_macro(macro_t *macro, list_t *args);
|
|
|
node_t *expand_mvars(node_t *node, node_t *_node, int expr);
|
|
node_t *expand_mvars(node_t *node, node_t *_node, int expr);
|
|
|
|
|
|
|
|
-node_t *mexpr_eval(node_t *n)
|
|
|
|
|
|
|
+int mdepth = 0;
|
|
|
|
|
+size_t macro_rlimit = 100;
|
|
|
|
|
+
|
|
|
|
|
+node_t *mexpr_eval(node_t *node)
|
|
|
{
|
|
{
|
|
|
- if (n)
|
|
|
|
|
- switch (n->tag)
|
|
|
|
|
|
|
+ if (mdepth >= macro_rlimit) {
|
|
|
|
|
+ COMPILE_ERROR("max. recursion depth (%d) reached while evaluating constant expression", macro_rlimit);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ mdepth++;
|
|
|
|
|
+
|
|
|
|
|
+ if (node)
|
|
|
|
|
+ switch (node->tag)
|
|
|
{
|
|
{
|
|
|
case N_LITERAL:
|
|
case N_LITERAL:
|
|
|
- if (n->t->tag == T_NAME)
|
|
|
|
|
|
|
+ if (node->t->tag == T_NAME)
|
|
|
{
|
|
{
|
|
|
- node_t *v = const_get(n->t->text);
|
|
|
|
|
|
|
+ node_t *v = const_get(node->t->text);
|
|
|
if (v)
|
|
if (v)
|
|
|
- return mexpr_eval(v);
|
|
|
|
|
|
|
+ node = mexpr_eval(v);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case N_UNARY_PLUS:
|
|
case N_UNARY_PLUS:
|
|
|
- return mexpr_eval(n->a);
|
|
|
|
|
|
|
+ node = mexpr_eval(node->a);
|
|
|
break;
|
|
break;
|
|
|
|
|
+
|
|
|
case N_NEGATE:
|
|
case N_NEGATE:
|
|
|
{
|
|
{
|
|
|
- node_t *a = mexpr_eval(n->a);
|
|
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
|
|
|
- return mexpr_negate(a);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ node = mexpr_negate(a);
|
|
|
|
|
+ } break;
|
|
|
|
|
+
|
|
|
|
|
+ case N_EQUALS:
|
|
|
|
|
+ {
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
+ node_t *b = mexpr_eval(node->b);
|
|
|
|
|
+
|
|
|
|
|
+ node = mexpr_equals(a, b)? nodet(N_LITERAL, token(T_TRUE, "true")): nodet(N_LITERAL, token(T_FALSE, "false"));
|
|
|
|
|
+ } break;
|
|
|
|
|
+
|
|
|
|
|
+ case N_NOTEQUALS:
|
|
|
|
|
+ {
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
+ node_t *b = mexpr_eval(node->b);
|
|
|
|
|
+
|
|
|
|
|
+ node = !mexpr_equals(a, b)? nodet(N_LITERAL, token(T_TRUE, "true")): nodet(N_LITERAL, token(T_FALSE, "false"));
|
|
|
|
|
+ } break;
|
|
|
|
|
|
|
|
case N_ADD:
|
|
case N_ADD:
|
|
|
{
|
|
{
|
|
|
- node_t *a = mexpr_eval(n->a);
|
|
|
|
|
- node_t *b = mexpr_eval(n->b);
|
|
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
+ node_t *b = mexpr_eval(node->b);
|
|
|
|
|
|
|
|
- if (!IS_NUMBER(a) && IS_NUMBER(b))
|
|
|
|
|
- return node2(N_ADD, n->a, b);
|
|
|
|
|
|
|
+ if (IS_STRING(a) && IS_STRING(b)) {
|
|
|
|
|
+ node = mexpr_add(a, b);
|
|
|
|
|
|
|
|
- if (IS_NUMBER(a) && !IS_NUMBER(b))
|
|
|
|
|
- return node2(N_ADD, a, n->b);
|
|
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return mexpr_add(a, b);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!IS_NUMBER(a) && IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_ADD, node->a, b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (IS_NUMBER(a) && !IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_ADD, a, node->b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ node = mexpr_add(a, b);
|
|
|
|
|
+ } break;
|
|
|
|
|
|
|
|
case N_SUB:
|
|
case N_SUB:
|
|
|
{
|
|
{
|
|
|
- node_t *a = mexpr_eval(n->a);
|
|
|
|
|
- node_t *b = mexpr_eval(n->b);
|
|
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
+ node_t *b = mexpr_eval(node->b);
|
|
|
|
|
+
|
|
|
|
|
+ if (!IS_NUMBER(a) && IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_SUB, node->a, b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (!IS_NUMBER(a) && IS_NUMBER(b))
|
|
|
|
|
- return node2(N_SUB, n->a, b);
|
|
|
|
|
|
|
+ if (IS_NUMBER(a) && !IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_SUB, a, node->b);
|
|
|
|
|
|
|
|
- if (IS_NUMBER(a) && !IS_NUMBER(b))
|
|
|
|
|
- return node2(N_SUB, a, n->b);
|
|
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return mexpr_sub(a, b);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ node = mexpr_sub(a, b);
|
|
|
|
|
+ } break;
|
|
|
|
|
|
|
|
case N_MUL:
|
|
case N_MUL:
|
|
|
{
|
|
{
|
|
|
- node_t *a = mexpr_eval(n->a);
|
|
|
|
|
- node_t *b = mexpr_eval(n->b);
|
|
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
+ node_t *b = mexpr_eval(node->b);
|
|
|
|
|
|
|
|
- if (!IS_NUMBER(a) && IS_NUMBER(b))
|
|
|
|
|
- return node2(N_MUL, n->a, b);
|
|
|
|
|
|
|
+ if (!IS_NUMBER(a) && IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_MUL, node->a, b);
|
|
|
|
|
|
|
|
- if (IS_NUMBER(a) && !IS_NUMBER(b))
|
|
|
|
|
- return node2(N_MUL, a, n->b);
|
|
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return mexpr_mul(a, b);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (IS_NUMBER(a) && !IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_MUL, a, node->b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ node = mexpr_mul(a, b);
|
|
|
|
|
+ } break;
|
|
|
|
|
+
|
|
|
|
|
+ case N_POW:
|
|
|
|
|
+ {
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
+ node_t *b = mexpr_eval(node->b);
|
|
|
|
|
+
|
|
|
|
|
+ if (!IS_NUMBER(a) && IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_POW, node->a, b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (IS_NUMBER(a) && !IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_POW, a, node->b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ node = mexpr_pow(a, b);
|
|
|
|
|
+ } break;
|
|
|
|
|
|
|
|
case N_DIV:
|
|
case N_DIV:
|
|
|
{
|
|
{
|
|
|
- node_t *a = mexpr_eval(n->a);
|
|
|
|
|
- node_t *b = mexpr_eval(n->b);
|
|
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
+ node_t *b = mexpr_eval(node->b);
|
|
|
|
|
|
|
|
- if (!IS_NUMBER(a) && IS_NUMBER(b))
|
|
|
|
|
- return node2(N_DIV, n->a, b);
|
|
|
|
|
|
|
+ if (!IS_NUMBER(a) && IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_DIV, node->a, b);
|
|
|
|
|
|
|
|
- if (IS_NUMBER(a) && !IS_NUMBER(b))
|
|
|
|
|
- return node2(N_DIV, a, n->b);
|
|
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return mexpr_div(a, b);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (IS_NUMBER(a) && !IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_DIV, a, node->b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ node = mexpr_div(a, b);
|
|
|
|
|
+ } break;
|
|
|
|
|
+
|
|
|
|
|
+ case N_MOD:
|
|
|
|
|
+ {
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
+ node_t *b = mexpr_eval(node->b);
|
|
|
|
|
+
|
|
|
|
|
+ if (!IS_NUMBER(a) && IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_MOD, node->a, b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (IS_NUMBER(a) && !IS_NUMBER(b)) {
|
|
|
|
|
+ node = node2(N_MOD, a, node->b);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ node = mexpr_mod(a, b);
|
|
|
|
|
+ } break;
|
|
|
|
|
|
|
|
case N_IFEXPR:
|
|
case N_IFEXPR:
|
|
|
{
|
|
{
|
|
|
- node_t *a = mexpr_eval(n->a);
|
|
|
|
|
|
|
+ node_t *a = mexpr_eval(node->a);
|
|
|
|
|
|
|
|
if (a)
|
|
if (a)
|
|
|
- return mexpr_eval(n->b);
|
|
|
|
|
-
|
|
|
|
|
- return mexpr_eval(n->c);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ node = mexpr_eval(node->b);
|
|
|
|
|
+ else
|
|
|
|
|
+ node = mexpr_eval(node->c);
|
|
|
|
|
+ } break;
|
|
|
|
|
|
|
|
case N_TUPLE:
|
|
case N_TUPLE:
|
|
|
case N_LIST:
|
|
case N_LIST:
|
|
|
{
|
|
{
|
|
|
|
|
+ int f = 0;
|
|
|
list_t *l = list_new();
|
|
list_t *l = list_new();
|
|
|
|
|
|
|
|
- for (size_t i = 0; i < n->l->length; i++)
|
|
|
|
|
|
|
+ for (size_t i = 0; i < node->l->length; i++)
|
|
|
{
|
|
{
|
|
|
- node_t *a = mexpr_eval(n->l->data[i]);
|
|
|
|
|
|
|
+ node_t *a = mexpr_eval(node->l->data[i]);
|
|
|
|
|
|
|
|
- if (!IS_EXPR(a))
|
|
|
|
|
- return NULL;
|
|
|
|
|
|
|
+ if (!IS_EXPR(a)) {
|
|
|
|
|
+ f = 1; break;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
list_push(l, a);
|
|
list_push(l, a);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return nodel(n->tag, l);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (f) break;
|
|
|
|
|
+
|
|
|
|
|
+ node = nodel(node->tag, l);
|
|
|
|
|
+ } break;
|
|
|
|
|
|
|
|
case N_COMMA:
|
|
case N_COMMA:
|
|
|
- return mexpr_eval(list_index(n->l, -1));
|
|
|
|
|
|
|
+ node = mexpr_eval(list_index(node->l, -1));
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
case N_MACRO_CALL:
|
|
case N_MACRO_CALL:
|
|
|
{
|
|
{
|
|
|
list_t *args = list_new();
|
|
list_t *args = list_new();
|
|
|
|
|
|
|
|
- for (size_t i = 0; i < n->l->length; i++)
|
|
|
|
|
- list_push(args, mexpr_eval(n->l->data[i]));
|
|
|
|
|
|
|
+ for (size_t i = 0; i < node->l->length; i++)
|
|
|
|
|
+ list_push(args, mexpr_eval(node->l->data[i]));
|
|
|
|
|
|
|
|
- macro_t *m = find_macro(n->t->text, args->length, NULL);
|
|
|
|
|
- if (!m)
|
|
|
|
|
- return n;
|
|
|
|
|
|
|
+ macro_t *m = find_macro(node->t->text, args->length, NULL);
|
|
|
|
|
+ if (m) {
|
|
|
|
|
+ list_push(MVARS, table_new());
|
|
|
|
|
|
|
|
- return mexpr_eval(expand_mvars(n, run_macro(m, args), 1));
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ node_t *r = run_macro(m, args);
|
|
|
|
|
+
|
|
|
|
|
+ list_pop(MVARS);
|
|
|
|
|
+
|
|
|
|
|
+ node = mexpr_eval(expand_mvars(node, r, 1));
|
|
|
|
|
+ }
|
|
|
|
|
+ } break;
|
|
|
|
|
|
|
|
default:
|
|
default:
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return n;
|
|
|
|
|
|
|
+ mdepth--;
|
|
|
|
|
+
|
|
|
|
|
+ return node;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
node_t *mf_isExpr(list_t *t)
|
|
node_t *mf_isExpr(list_t *t)
|
|
@@ -5614,7 +5757,13 @@ node_t *run_mexpr(node_t *node)
|
|
|
if (!m)
|
|
if (!m)
|
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
|
|
- return run_macro(m, args);
|
|
|
|
|
|
|
+ list_push(MVARS, table_new());
|
|
|
|
|
+
|
|
|
|
|
+ node_t *r = run_macro(m, args);
|
|
|
|
|
+
|
|
|
|
|
+ list_pop(MVARS);
|
|
|
|
|
+
|
|
|
|
|
+ return r;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; METAFUNCS[i].name; i++)
|
|
for (size_t i = 0; METAFUNCS[i].name; i++)
|
|
@@ -5662,6 +5811,14 @@ node_t *run_mexpr(node_t *node)
|
|
|
return mexpr_mul(a, b);
|
|
return mexpr_mul(a, b);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ case N_POW:
|
|
|
|
|
+ {
|
|
|
|
|
+ node_t *a = run_mexpr(node->a);
|
|
|
|
|
+ node_t *b = run_mexpr(node->b);
|
|
|
|
|
+
|
|
|
|
|
+ return mexpr_pow(a, b);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
case N_DIV:
|
|
case N_DIV:
|
|
|
{
|
|
{
|
|
|
node_t *a = run_mexpr(node->a);
|
|
node_t *a = run_mexpr(node->a);
|
|
@@ -5670,6 +5827,14 @@ node_t *run_mexpr(node_t *node)
|
|
|
return mexpr_div(a, b);
|
|
return mexpr_div(a, b);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ case N_MOD:
|
|
|
|
|
+ {
|
|
|
|
|
+ node_t *a = run_mexpr(node->a);
|
|
|
|
|
+ node_t *b = run_mexpr(node->b);
|
|
|
|
|
+
|
|
|
|
|
+ return mexpr_mod(a, b);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
case N_EQUALS:
|
|
case N_EQUALS:
|
|
|
{
|
|
{
|
|
|
node_t *a = run_mexpr(node->a);
|
|
node_t *a = run_mexpr(node->a);
|
|
@@ -5678,6 +5843,14 @@ node_t *run_mexpr(node_t *node)
|
|
|
return mexpr_equals(a, b) ? YES : NULL;
|
|
return mexpr_equals(a, b) ? YES : NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ case N_NOTEQUALS:
|
|
|
|
|
+ {
|
|
|
|
|
+ node_t *a = run_mexpr(node->a);
|
|
|
|
|
+ node_t *b = run_mexpr(node->b);
|
|
|
|
|
+
|
|
|
|
|
+ return !mexpr_equals(a, b) ? YES : NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
case N_LT:
|
|
case N_LT:
|
|
|
{
|
|
{
|
|
|
node_t *a = run_mexpr(node->a);
|
|
node_t *a = run_mexpr(node->a);
|
|
@@ -5797,7 +5970,6 @@ node_t *run_mnode(node_t *node)
|
|
|
|
|
|
|
|
list_t *macro_stk;
|
|
list_t *macro_stk;
|
|
|
size_t expand_depth = 0;
|
|
size_t expand_depth = 0;
|
|
|
-size_t macro_rlimit = 100;
|
|
|
|
|
|
|
|
|
|
node_t *run_macro(macro_t *macro, list_t *args)
|
|
node_t *run_macro(macro_t *macro, list_t *args)
|
|
|
{
|
|
{
|