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
55 void (*builtin
)(struct ke1_s
*a
, struct ke1_s
*b
); // execution function
56 double (*real_func1
)(double);
57 double (*real_func2
)(double, double);
64 static int ke_op
[25] = {
66 1<<1|1, 1<<1|1, 1<<1|1, 1<<1|1, // unary operators
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, // < > <= >=
80 static const char *ke_opstr
[] = {
82 "+(1)", "-(1)", "~", "!",
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); }
159 static inline char *mystrndup(const char *src
, int n
)
162 dst
= (char*)calloc(n
+ 1, 1);
163 strncpy(dst
, src
, n
);
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
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
);
180 } else if (isdigit(*p
) || *p
== '.') { // a number
186 x
= strtol(q
, &pp
, 0); // FIXME: check int/double parsing errors
187 if (q
== p
&& q
== pp
) { // parse error
189 } else if (p
> pp
) { // has "." or "[eE]"; then it is a real number
191 e
.i
= (int64_t)(y
+ .5), e
.r
= y
;
198 } else if (*p
== '"' || *p
== '\'') { // a string value
200 for (++p
; *p
&& *p
!= c
; ++p
)
201 if (*p
== '\\') ++p
; // escaping
203 e
.ttype
= KET_VAL
, e
.vtype
= KEV_STR
;
204 e
.s
= mystrndup(q
+ 1, p
- q
- 1);
206 } else *err
|= KEE_UNQU
, *r
= p
;
207 } else { // an operator
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;
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;
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
;
243 static inline ke1_t
*push_back(ke1_t
**a
, int *n
, int *m
)
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
)
257 int n_out
, m_out
, n_op
, m_op
, last_is_val
= 0;
258 ke1_t
*out
, *op
, *t
, *u
;
261 s
= strdup(_s
); // make a copy
262 for (p
= q
= s
; *p
; ++p
) // squeeze out spaces
263 if (!isspace(*p
)) *q
++ = *p
;
267 n_out
= m_out
= n_op
= m_op
= 0;
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
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
);
279 if (n_op
== 0) { // error: extra right parenthesis
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
286 if (u
->n_args
== 1 && strcmp(u
->name
, "abs") == 0) u
->f
.builtin
= ke_func1_abs
;
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
);
294 if (n_op
< 2 || op
[n_op
-2].ttype
!= KET_FUNC
) { // we should at least see a function and a left parenthesis
300 } else { // output-able token
302 v
= ke_read_token(p
, &p
, err
, last_is_val
);
304 if (v
.ttype
== KET_VAL
) {
305 u
= push_back(&out
, &n_out
, &m_out
);
308 } else if (v
.ttype
== KET_FUNC
) {
309 t
= push_back(&op
, &n_op
, &m_op
);
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
);
320 t
= push_back(&op
, &n_op
, &m_op
);
328 while (n_op
> 0 && op
[n_op
-1].op
>= 0) {
329 u
= push_back(&out
, &n_out
, &m_out
);
332 if (n_op
> 0) *err
|= KEE_UNLP
;
335 if (*err
== 0) { // then check if the number of args is correct
337 for (i
= n
= 0; i
< n_out
; ++i
) {
339 if (e
->ttype
== KET_VAL
) ++n
;
340 else n
-= e
->n_args
- 1;
342 if (n
!= 1) *err
|= KEE_ARG
;
354 kexpr_t
*ke_parse(const char *_s
, int *err
)
359 e
= ke_parse_core(_s
, &n
, err
);
361 ke
= (kexpr_t
*)calloc(1, sizeof(kexpr_t
));
362 ke
->n
= n
, ke
->e
= e
;
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];
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
) {
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
;
401 int64_t ke_eval_int(const kexpr_t
*ke
, int *err
)
407 *err
= ke_eval(ke
, &i
, &r
, &s
, &int_ret
);
411 double ke_eval_real(const kexpr_t
*ke
, int *err
)
417 *err
= ke_eval(ke
, &i
, &r
, &s
, &int_ret
);
421 void ke_destroy(kexpr_t
*ke
)
425 for (i
= 0; i
< ke
->n
; ++i
) {
429 free(ke
->e
); free(ke
);
432 int ke_set_int(kexpr_t
*ke
, const char *var
, int64_t y
)
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
;
444 int ke_set_real(kexpr_t
*ke
, const char *var
, double x
)
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
;
456 int ke_set_str(kexpr_t
*ke
, const char *var
, const char *x
)
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
);
464 e
->i
= 0, e
->r
= 0., e
->assigned
= 1;
472 int ke_set_real_func1(kexpr_t
*ke
, const char *name
, double (*func
)(double))
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
;
483 int ke_set_real_func2(kexpr_t
*ke
, const char *name
, double (*func
)(double, double))
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
;
494 int ke_set_default_func(kexpr_t
*ke
)
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
);
508 void ke_unset(kexpr_t
*ke
)
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
)
521 for (i
= 0; i
< ke
->n
; ++i
) {
522 const ke1_t
*u
= &ke
->e
[i
];
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
);
542 int main(int argc
, char *argv
[])
544 int c
, err
, to_print
= 0, is_int
= 0;
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]);
555 ke
= ke_parse(argv
[optind
], &err
);
556 ke_set_default_func(ke
);
558 fprintf(stderr
, "Parse error: 0x%x\n", err
);
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
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
);