modified: myjupyterlab.sh
[GalaxyCodeBases.git] / c_cpp / lib / klib / kexpr.c
blob79f110fa2644996c16ed96270104b22cd02e3f3c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <assert.h>
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <math.h>
8 #include "kexpr.h"
10 /***************
11 * Definitions *
12 ***************/
14 #define KEO_NULL 0
15 #define KEO_POS 1
16 #define KEO_NEG 2
17 #define KEO_BNOT 3
18 #define KEO_LNOT 4
19 #define KEO_POW 5
20 #define KEO_MUL 6
21 #define KEO_DIV 7
22 #define KEO_IDIV 8
23 #define KEO_MOD 9
24 #define KEO_ADD 10
25 #define KEO_SUB 11
26 #define KEO_LSH 12
27 #define KEO_RSH 13
28 #define KEO_LT 14
29 #define KEO_LE 15
30 #define KEO_GT 16
31 #define KEO_GE 17
32 #define KEO_EQ 18
33 #define KEO_NE 19
34 #define KEO_BAND 20
35 #define KEO_BXOR 21
36 #define KEO_BOR 22
37 #define KEO_LAND 23
38 #define KEO_LOR 24
40 #define KET_NULL 0
41 #define KET_VAL 1
42 #define KET_OP 2
43 #define KET_FUNC 3
45 #define KEF_NULL 0
46 #define KEF_REAL 1
48 struct ke1_s;
50 typedef struct ke1_s {
51 uint32_t ttype:16, vtype:10, assigned:1, user_func:5; // ttype: token type; vtype: value type
52 int32_t op:8, n_args:24; // op: operator, n_args: number of arguments
53 char *name; // variable name or function name
54 union {
55 void (*builtin)(struct ke1_s *a, struct ke1_s *b); // execution function
56 double (*real_func1)(double);
57 double (*real_func2)(double, double);
58 } f;
59 double r;
60 int64_t i;
61 char *s;
62 } ke1_t;
64 static int ke_op[25] = {
66 1<<1|1, 1<<1|1, 1<<1|1, 1<<1|1, // unary operators
67 2<<1|1, // pow()
68 3<<1, 3<<1, 3<<1, 3<<1, // * / // %
69 4<<1, 4<<1, // + and -
70 5<<1, 5<<1, // << and >>
71 6<<1, 6<<1, 6<<1, 6<<1, // < > <= >=
72 7<<1, 7<<1, // == !=
73 8<<1, // &
74 9<<1, // ^
75 10<<1,// |
76 11<<1,// &&
77 12<<1 // ||
80 static const char *ke_opstr[] = {
81 "",
82 "+(1)", "-(1)", "~", "!",
83 "**",
84 "*", "/", "//", "%",
85 "+", "-",
86 "<<", ">>",
87 "<", "<=", ">", ">=",
88 "==", "!=",
89 "&",
90 "^",
91 "|",
92 "&&",
93 "||"
96 struct kexpr_s {
97 int n;
98 ke1_t *e;
101 /**********************
102 * Operator functions *
103 **********************/
105 #define KE_GEN_CMP(_type, _op) \
106 static void ke_op_##_type(ke1_t *p, ke1_t *q) { \
107 if (p->vtype == KEV_STR && q->vtype == KEV_STR) p->i = (strcmp(p->s, q->s) _op 0); \
108 else p->i = p->vtype == KEV_REAL || q->vtype == KEV_REAL? (p->r _op q->r) : (p->i _op q->i); \
109 p->r = (double)p->i; \
110 p->vtype = KEV_INT; \
113 KE_GEN_CMP(KEO_LT, <)
114 KE_GEN_CMP(KEO_LE, <=)
115 KE_GEN_CMP(KEO_GT, >)
116 KE_GEN_CMP(KEO_GE, >=)
117 KE_GEN_CMP(KEO_EQ, ==)
118 KE_GEN_CMP(KEO_NE, !=)
120 #define KE_GEN_BIN_INT(_type, _op) \
121 static void ke_op_##_type(ke1_t *p, ke1_t *q) { \
122 p->i _op q->i; p->r = (double)p->i; \
123 p->vtype = KEV_INT; \
126 KE_GEN_BIN_INT(KEO_BAND, &=)
127 KE_GEN_BIN_INT(KEO_BOR, |=)
128 KE_GEN_BIN_INT(KEO_BXOR, ^=)
129 KE_GEN_BIN_INT(KEO_LSH, <<=)
130 KE_GEN_BIN_INT(KEO_RSH, >>=)
131 KE_GEN_BIN_INT(KEO_MOD, %=)
132 KE_GEN_BIN_INT(KEO_IDIV, /=)
134 #define KE_GEN_BIN_BOTH(_type, _op) \
135 static void ke_op_##_type(ke1_t *p, ke1_t *q) { \
136 p->i _op q->i; p->r _op q->r; \
137 p->vtype = p->vtype == KEV_REAL || q->vtype == KEV_REAL? KEV_REAL : KEV_INT; \
140 KE_GEN_BIN_BOTH(KEO_ADD, +=)
141 KE_GEN_BIN_BOTH(KEO_SUB, -=)
142 KE_GEN_BIN_BOTH(KEO_MUL, *=)
144 static void ke_op_KEO_DIV(ke1_t *p, ke1_t *q) { p->r /= q->r, p->i = (int64_t)(p->r + .5); p->vtype = KEV_REAL; }
145 static void ke_op_KEO_LAND(ke1_t *p, ke1_t *q) { p->i = (p->i && q->i); p->r = p->i; p->vtype = KEV_INT; }
146 static void ke_op_KEO_LOR(ke1_t *p, ke1_t *q) { p->i = (p->i || q->i); p->r = p->i; p->vtype = KEV_INT; }
147 static void ke_op_KEO_POW(ke1_t *p, ke1_t *q) { p->r = pow(p->r, q->r), p->i = (int64_t)(p->r + .5); p->vtype = p->vtype == KEV_REAL || q->vtype == KEV_REAL? KEV_REAL : KEV_INT; }
148 static void ke_op_KEO_BNOT(ke1_t *p, ke1_t *q) { p->i = ~p->i; p->r = (double)p->i; p->vtype = KEV_INT; }
149 static void ke_op_KEO_LNOT(ke1_t *p, ke1_t *q) { p->i = !p->i; p->r = (double)p->i; p->vtype = KEV_INT; }
150 static void ke_op_KEO_POS(ke1_t *p, ke1_t *q) { } // do nothing
151 static void ke_op_KEO_NEG(ke1_t *p, ke1_t *q) { p->i = -p->i, p->r = -p->r; }
153 static void ke_func1_abs(ke1_t *p, ke1_t *q) { if (p->vtype == KEV_INT) p->i = abs(p->i), p->r = (double)p->i; else p->r = fabs(p->r), p->i = (int64_t)(p->r + .5); }
155 /**********
156 * Parser *
157 **********/
159 static inline char *mystrndup(const char *src, int n)
161 char *dst;
162 dst = (char*)calloc(n + 1, 1);
163 strncpy(dst, src, n);
164 return dst;
167 // parse a token except "(", ")" and ","
168 static ke1_t ke_read_token(char *p, char **r, int *err, int last_is_val) // it doesn't parse parentheses
170 char *q = p;
171 ke1_t e;
172 memset(&e, 0, sizeof(ke1_t));
173 if (isalpha(*p) || *p == '_') { // a variable or a function
174 for (; *p && (*p == '_' || isalnum(*p)); ++p);
175 if (*p == '(') e.ttype = KET_FUNC, e.n_args = 1;
176 else e.ttype = KET_VAL, e.vtype = KEV_REAL;
177 e.name = mystrndup(q, p - q);
178 e.i = 0, e.r = 0.;
179 *r = p;
180 } else if (isdigit(*p) || *p == '.') { // a number
181 long x;
182 double y;
183 char *pp;
184 e.ttype = KET_VAL;
185 y = strtod(q, &p);
186 x = strtol(q, &pp, 0); // FIXME: check int/double parsing errors
187 if (q == p && q == pp) { // parse error
188 *err |= KEE_NUM;
189 } else if (p > pp) { // has "." or "[eE]"; then it is a real number
190 e.vtype = KEV_REAL;
191 e.i = (int64_t)(y + .5), e.r = y;
192 *r = p;
193 } else {
194 e.vtype = KEV_INT;
195 e.i = x, e.r = y;
196 *r = pp;
198 } else if (*p == '"' || *p == '\'') { // a string value
199 int c = *p;
200 for (++p; *p && *p != c; ++p)
201 if (*p == '\\') ++p; // escaping
202 if (*p == c) {
203 e.ttype = KET_VAL, e.vtype = KEV_STR;
204 e.s = mystrndup(q + 1, p - q - 1);
205 *r = p + 1;
206 } else *err |= KEE_UNQU, *r = p;
207 } else { // an operator
208 e.ttype = KET_OP;
209 if (*p == '*' && p[1] == '*') e.op = KEO_POW, e.f.builtin = ke_op_KEO_POW, e.n_args = 2, *r = q + 2;
210 else if (*p == '*') e.op = KEO_MUL, e.f.builtin = ke_op_KEO_MUL, e.n_args = 2, *r = q + 1; // FIXME: NOT working for unary operators
211 else if (*p == '/' && p[1] == '/') e.op = KEO_IDIV, e.f.builtin = ke_op_KEO_IDIV, e.n_args = 2, *r = q + 2;
212 else if (*p == '/') e.op = KEO_DIV, e.f.builtin = ke_op_KEO_DIV, e.n_args = 2, *r = q + 1;
213 else if (*p == '%') e.op = KEO_MOD, e.f.builtin = ke_op_KEO_MOD, e.n_args = 2, *r = q + 1;
214 else if (*p == '+') {
215 if (last_is_val) e.op = KEO_ADD, e.f.builtin = ke_op_KEO_ADD, e.n_args = 2;
216 else e.op = KEO_POS, e.f.builtin = ke_op_KEO_POS, e.n_args = 1;
217 *r = q + 1;
218 } else if (*p == '-') {
219 if (last_is_val) e.op = KEO_SUB, e.f.builtin = ke_op_KEO_SUB, e.n_args = 2;
220 else e.op = KEO_NEG, e.f.builtin = ke_op_KEO_NEG, e.n_args = 1;
221 *r = q + 1;
222 } else if (*p == '=' && p[1] == '=') e.op = KEO_EQ, e.f.builtin = ke_op_KEO_EQ, e.n_args = 2, *r = q + 2;
223 else if (*p == '!' && p[1] == '=') e.op = KEO_NE, e.f.builtin = ke_op_KEO_NE, e.n_args = 2, *r = q + 2;
224 else if (*p == '<' && p[1] == '>') e.op = KEO_NE, e.f.builtin = ke_op_KEO_NE, e.n_args = 2, *r = q + 2;
225 else if (*p == '>' && p[1] == '=') e.op = KEO_GE, e.f.builtin = ke_op_KEO_GE, e.n_args = 2, *r = q + 2;
226 else if (*p == '<' && p[1] == '=') e.op = KEO_LE, e.f.builtin = ke_op_KEO_LE, e.n_args = 2, *r = q + 2;
227 else if (*p == '>' && p[1] == '>') e.op = KEO_RSH, e.f.builtin = ke_op_KEO_RSH, e.n_args = 2, *r = q + 2;
228 else if (*p == '<' && p[1] == '<') e.op = KEO_LSH, e.f.builtin = ke_op_KEO_LSH, e.n_args = 2, *r = q + 2;
229 else if (*p == '>') e.op = KEO_GT, e.f.builtin = ke_op_KEO_GT, e.n_args = 2, *r = q + 1;
230 else if (*p == '<') e.op = KEO_LT, e.f.builtin = ke_op_KEO_LT, e.n_args = 2, *r = q + 1;
231 else if (*p == '|' && p[1] == '|') e.op = KEO_LOR, e.f.builtin = ke_op_KEO_LOR, e.n_args = 2, *r = q + 2;
232 else if (*p == '&' && p[1] == '&') e.op = KEO_LAND, e.f.builtin = ke_op_KEO_LAND, e.n_args = 2, *r = q + 2;
233 else if (*p == '|') e.op = KEO_BOR, e.f.builtin = ke_op_KEO_BOR, e.n_args = 2, *r = q + 1;
234 else if (*p == '&') e.op = KEO_BAND, e.f.builtin = ke_op_KEO_BAND, e.n_args = 2, *r = q + 1;
235 else if (*p == '^') e.op = KEO_BXOR, e.f.builtin = ke_op_KEO_BXOR, e.n_args = 2, *r = q + 1;
236 else if (*p == '~') e.op = KEO_BNOT, e.f.builtin = ke_op_KEO_BNOT, e.n_args = 1, *r = q + 1;
237 else if (*p == '!') e.op = KEO_LNOT, e.f.builtin = ke_op_KEO_LNOT, e.n_args = 1, *r = q + 1;
238 else e.ttype = KET_NULL, *err |= KEE_UNOP;
240 return e;
243 static inline ke1_t *push_back(ke1_t **a, int *n, int *m)
245 if (*n == *m) {
246 int old_m = *m;
247 *m = *m? *m<<1 : 8;
248 *a = (ke1_t*)realloc(*a, *m * sizeof(ke1_t));
249 memset(*a + old_m, 0, (*m - old_m) * sizeof(ke1_t));
251 return &(*a)[(*n)++];
254 static ke1_t *ke_parse_core(const char *_s, int *_n, int *err)
256 char *s, *p, *q;
257 int n_out, m_out, n_op, m_op, last_is_val = 0;
258 ke1_t *out, *op, *t, *u;
260 *err = 0; *_n = 0;
261 s = strdup(_s); // make a copy
262 for (p = q = s; *p; ++p) // squeeze out spaces
263 if (!isspace(*p)) *q++ = *p;
264 *q++ = 0;
266 out = op = 0;
267 n_out = m_out = n_op = m_op = 0;
268 p = s;
269 while (*p) {
270 if (*p == '(') {
271 t = push_back(&op, &n_op, &m_op); // push to the operator stack
272 t->op = -1, t->ttype = KET_NULL; // ->op < 0 for a left parenthsis
273 ++p;
274 } else if (*p == ')') {
275 while (n_op > 0 && op[n_op-1].op >= 0) { // move operators to the output until we see a left parenthesis
276 u = push_back(&out, &n_out, &m_out);
277 *u = op[--n_op];
279 if (n_op == 0) { // error: extra right parenthesis
280 *err |= KEE_UNRP;
281 break;
282 } else --n_op; // pop out '('
283 if (n_op > 0 && op[n_op-1].ttype == KET_FUNC) { // the top of the operator stack is a function
284 u = push_back(&out, &n_out, &m_out); // move it to the output
285 *u = op[--n_op];
286 if (u->n_args == 1 && strcmp(u->name, "abs") == 0) u->f.builtin = ke_func1_abs;
288 ++p;
289 } else if (*p == ',') { // function arguments separator
290 while (n_op > 0 && op[n_op-1].op >= 0) {
291 u = push_back(&out, &n_out, &m_out);
292 *u = op[--n_op];
294 if (n_op < 2 || op[n_op-2].ttype != KET_FUNC) { // we should at least see a function and a left parenthesis
295 *err |= KEE_FUNC;
296 break;
298 ++op[n_op-2].n_args;
299 ++p;
300 } else { // output-able token
301 ke1_t v;
302 v = ke_read_token(p, &p, err, last_is_val);
303 if (*err) break;
304 if (v.ttype == KET_VAL) {
305 u = push_back(&out, &n_out, &m_out);
306 *u = v;
307 last_is_val = 1;
308 } else if (v.ttype == KET_FUNC) {
309 t = push_back(&op, &n_op, &m_op);
310 *t = v;
311 last_is_val = 0;
312 } else if (v.ttype == KET_OP) {
313 int oi = ke_op[v.op];
314 while (n_op > 0 && op[n_op-1].ttype == KET_OP) {
315 int pre = ke_op[op[n_op-1].op]>>1;
316 if (((oi&1) && oi>>1 <= pre) || (!(oi&1) && oi>>1 < pre)) break;
317 u = push_back(&out, &n_out, &m_out);
318 *u = op[--n_op];
320 t = push_back(&op, &n_op, &m_op);
321 *t = v;
322 last_is_val = 0;
327 if (*err == 0) {
328 while (n_op > 0 && op[n_op-1].op >= 0) {
329 u = push_back(&out, &n_out, &m_out);
330 *u = op[--n_op];
332 if (n_op > 0) *err |= KEE_UNLP;
335 if (*err == 0) { // then check if the number of args is correct
336 int i, n;
337 for (i = n = 0; i < n_out; ++i) {
338 ke1_t *e = &out[i];
339 if (e->ttype == KET_VAL) ++n;
340 else n -= e->n_args - 1;
342 if (n != 1) *err |= KEE_ARG;
345 free(op); free(s);
346 if (*err) {
347 free(out);
348 return 0;
350 *_n = n_out;
351 return out;
354 kexpr_t *ke_parse(const char *_s, int *err)
356 int n;
357 ke1_t *e;
358 kexpr_t *ke;
359 e = ke_parse_core(_s, &n, err);
360 if (*err) return 0;
361 ke = (kexpr_t*)calloc(1, sizeof(kexpr_t));
362 ke->n = n, ke->e = e;
363 return ke;
366 int ke_eval(const kexpr_t *ke, int64_t *_i, double *_r, const char **_p, int *ret_type)
368 ke1_t *stack, *p, *q;
369 int i, top = 0, err = 0;
370 *_i = 0, *_r = 0., *ret_type = 0;
371 for (i = 0; i < ke->n; ++i) {
372 ke1_t *e = &ke->e[i];
373 if ((e->ttype == KET_OP || e->ttype == KET_FUNC) && e->f.builtin == 0) err |= KEE_UNFUNC;
374 else if (e->ttype == KET_VAL && e->name && e->assigned == 0) err |= KEE_UNVAR;
376 stack = (ke1_t*)malloc(ke->n * sizeof(ke1_t));
377 for (i = 0; i < ke->n; ++i) {
378 ke1_t *e = &ke->e[i];
379 if (e->ttype == KET_OP || e->ttype == KET_FUNC) {
380 if (e->n_args == 2 && e->f.builtin) {
381 q = &stack[--top], p = &stack[top-1];
382 if (e->user_func) {
383 if (e->user_func == KEF_REAL)
384 p->r = e->f.real_func2(p->r, q->r), p->i = (int64_t)(p->r + .5), p->vtype = KEV_REAL;
385 } else e->f.builtin(p, q);
386 } else if (e->n_args == 1 && e->f.builtin) {
387 p = &stack[top-1];
388 if (e->user_func) {
389 if (e->user_func == KEF_REAL)
390 p->r = e->f.real_func1(p->r), p->i = (int64_t)(p->r + .5), p->vtype = KEV_REAL;
391 } else e->f.builtin(&stack[top-1], 0);
392 } else top -= e->n_args - 1;
393 } else stack[top++] = *e;
395 *ret_type = stack->vtype;
396 *_i = stack->i, *_r = stack->r, *_p = stack->s;
397 free(stack);
398 return err;
401 int64_t ke_eval_int(const kexpr_t *ke, int *err)
403 int int_ret;
404 int64_t i;
405 double r;
406 const char *s;
407 *err = ke_eval(ke, &i, &r, &s, &int_ret);
408 return i;
411 double ke_eval_real(const kexpr_t *ke, int *err)
413 int int_ret;
414 int64_t i;
415 double r;
416 const char *s;
417 *err = ke_eval(ke, &i, &r, &s, &int_ret);
418 return r;
421 void ke_destroy(kexpr_t *ke)
423 int i;
424 if (ke == 0) return;
425 for (i = 0; i < ke->n; ++i) {
426 free(ke->e[i].name);
427 free(ke->e[i].s);
429 free(ke->e); free(ke);
432 int ke_set_int(kexpr_t *ke, const char *var, int64_t y)
434 int i, n = 0;
435 double yy = (double)y;
436 for (i = 0; i < ke->n; ++i) {
437 ke1_t *e = &ke->e[i];
438 if (e->ttype == KET_VAL && e->name && strcmp(e->name, var) == 0)
439 e->i = y, e->r = yy, e->vtype = KEV_INT, e->assigned = 1, ++n;
441 return n;
444 int ke_set_real(kexpr_t *ke, const char *var, double x)
446 int i, n = 0;
447 int64_t xx = (int64_t)(x + .5);
448 for (i = 0; i < ke->n; ++i) {
449 ke1_t *e = &ke->e[i];
450 if (e->ttype == KET_VAL && e->name && strcmp(e->name, var) == 0)
451 e->r = x, e->i = xx, e->vtype = KEV_REAL, e->assigned = 1, ++n;
453 return n;
456 int ke_set_str(kexpr_t *ke, const char *var, const char *x)
458 int i, n = 0;
459 for (i = 0; i < ke->n; ++i) {
460 ke1_t *e = &ke->e[i];
461 if (e->ttype == KET_VAL && e->name && strcmp(e->name, var) == 0) {
462 if (e->vtype == KEV_STR) free(e->s);
463 e->s = strdup(x);
464 e->i = 0, e->r = 0., e->assigned = 1;
465 e->vtype = KEV_STR;
466 ++n;
469 return n;
472 int ke_set_real_func1(kexpr_t *ke, const char *name, double (*func)(double))
474 int i, n = 0;
475 for (i = 0; i < ke->n; ++i) {
476 ke1_t *e = &ke->e[i];
477 if (e->ttype == KET_FUNC && e->n_args == 1 && strcmp(e->name, name) == 0)
478 e->f.real_func1 = func, e->user_func = KEF_REAL, ++n;
480 return n;
483 int ke_set_real_func2(kexpr_t *ke, const char *name, double (*func)(double, double))
485 int i, n = 0;
486 for (i = 0; i < ke->n; ++i) {
487 ke1_t *e = &ke->e[i];
488 if (e->ttype == KET_FUNC && e->n_args == 2 && strcmp(e->name, name) == 0)
489 e->f.real_func2 = func, e->user_func = KEF_REAL, ++n;
491 return n;
494 int ke_set_default_func(kexpr_t *ke)
496 int n = 0;
497 n += ke_set_real_func1(ke, "exp", exp);
498 n += ke_set_real_func1(ke, "log", log);
499 n += ke_set_real_func1(ke, "log10", log10);
500 n += ke_set_real_func1(ke, "sqrt", sqrt);
501 n += ke_set_real_func1(ke, "sin", sin);
502 n += ke_set_real_func1(ke, "cos", cos);
503 n += ke_set_real_func1(ke, "tan", tan);
504 n += ke_set_real_func2(ke, "pow", pow);
505 return n;
508 void ke_unset(kexpr_t *ke)
510 int i;
511 for (i = 0; i < ke->n; ++i) {
512 ke1_t *e = &ke->e[i];
513 if (e->ttype == KET_VAL && e->name) e->assigned = 0;
517 void ke_print(const kexpr_t *ke)
519 int i;
520 if (ke == 0) return;
521 for (i = 0; i < ke->n; ++i) {
522 const ke1_t *u = &ke->e[i];
523 if (i) putchar(' ');
524 if (u->ttype == KET_VAL) {
525 if (u->name) printf("%s", u->name);
526 else if (u->vtype == KEV_REAL) printf("%g", u->r);
527 else if (u->vtype == KEV_INT) printf("%lld", (long long)u->i);
528 else if (u->vtype == KEV_STR) printf("\"%s\"", u->s);
529 } else if (u->ttype == KET_OP) {
530 printf("%s", ke_opstr[u->op]);
531 } else if (u->ttype == KET_FUNC) {
532 printf("%s(%d)", u->name, u->n_args);
535 putchar('\n');
539 #ifdef KE_MAIN
540 #include <unistd.h>
542 int main(int argc, char *argv[])
544 int c, err, to_print = 0, is_int = 0;
545 kexpr_t *ke;
547 while ((c = getopt(argc, argv, "pi")) >= 0) {
548 if (c == 'p') to_print = 1;
549 else if (c == 'i') is_int = 1;
551 if (optind == argc) {
552 fprintf(stderr, "Usage: %s [-pi] <expr>\n", argv[0]);
553 return 1;
555 ke = ke_parse(argv[optind], &err);
556 ke_set_default_func(ke);
557 if (err) {
558 fprintf(stderr, "Parse error: 0x%x\n", err);
559 return 1;
561 if (!to_print) {
562 int64_t vi;
563 double vr;
564 const char *vs;
565 int i, ret_type;
566 if (argc - optind > 1) {
567 for (i = optind + 1; i < argc; ++i) {
568 char *p, *s = argv[i];
569 for (p = s; *p && *p != '='; ++p);
570 if (*p == 0) continue; // not an assignment
571 *p = 0;
572 ke_set_real(ke, s, strtod(p+1, &p));
575 err |= ke_eval(ke, &vi, &vr, &vs, &ret_type);
576 if (err & KEE_UNFUNC)
577 fprintf(stderr, "Evaluation warning: an undefined function returns the first function argument.\n");
578 if (err & KEE_UNVAR) fprintf(stderr, "Evaluation warning: unassigned variables are set to 0.\n");
579 if (ret_type == KEV_INT) printf("%lld\n", (long long)vi);
580 else if (ret_type == KEV_REAL) printf("%g\n", vr);
581 else printf("%s\n", vs);
582 } else ke_print(ke);
583 ke_destroy(ke);
584 return 0;
586 #endif