Skip to content

Commit 39edc1f

Browse files
committed
Refactoring expression engine: use bitflags for tracking assignment flavours
1 parent c857577 commit 39edc1f

6 files changed

Lines changed: 224 additions & 211 deletions

File tree

src/expression/expr_evaluator.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
182182
feclearexcept(FE_ALL_EXCEPT);
183183
errno = 0;
184184

185-
switch (tok->toktype) {
185+
switch (tok->toktype & TOKEN_MASK) {
186186
case TOK_LITERAL:
187187
case TOK_VLITERAL:
188188
INCR_STACK_PTR(1);
@@ -244,6 +244,7 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
244244
SET_TYPE(MPR_DBL);
245245
SET_LEN(tok->gen.vec_len);
246246
#if TRACE_EVAL
247+
printf("\r\t\t\t\t\t");
247248
evalue_print(vals + sp, types[dp], lens[dp], dp);
248249
#endif
249250
break;
@@ -914,9 +915,7 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
914915
#endif
915916
break;
916917
}
917-
case TOK_ASSIGN:
918-
case TOK_ASSIGN_USE:
919-
case TOK_ASSIGN_CONST: {
918+
case TOK_ASSIGN: {
920919
mpr_value v;
921920
/* currently only history and vector indices are supported for assignment */
922921
int idxp, hidx = tok->gen.flags & VAR_HIST_IDX, vidx = tok->gen.flags & VAR_VEC_IDX;
@@ -1045,7 +1044,7 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
10451044
assign_done:
10461045
if (tok->gen.flags & CLEAR_STACK)
10471046
dp = -1;
1048-
else if (dp && TOK_ASSIGN_USE != tok->toktype)
1047+
else if (dp && !(tok->toktype & ASSIGN_KEEP_ARG))
10491048
--dp;
10501049
sp = dp * vlen;
10511050
break;

src/expression/expr_lexer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ static expr_op_t op_lookup(etoken t, const char *s)
1616
if (strncmp(s, name, len) == 0) {
1717
/* check for augmented assignment operator */
1818
if (op_tbl[i].assignment && ('=' == s[len])) {
19-
t->toktype = TOK_ASSIGN_OP;
19+
t->toktype = TOK_ASSIGN | ASSIGN_COMPOUND;
2020
t->var.op_idx = i;
2121
return len + 1;
2222
}
@@ -191,7 +191,7 @@ static int expr_lex(const char *str, int idx, etoken tok)
191191
tok->op.idx = OP_DECREMENT_PRE;
192192
return idx + 1;
193193
case '=':
194-
tok->toktype = TOK_ASSIGN_OP;
194+
tok->toktype = TOK_ASSIGN | ASSIGN_COMPOUND;
195195
tok->var.op_idx = OP_SUBTRACT;
196196
return idx + 1;
197197
default:

src/expression/expr_parser.h

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ int push_vfn_token(estack op, estack out, etoken tok, expr_var_t *vars, int *p_n
7575

7676
for (i = 0; i < memory; i++) {
7777
/* add assignment token */
78-
newtok.toktype = (i == 0) ? TOK_ASSIGN_USE : TOK_ASSIGN;
78+
newtok.toktype = TOK_ASSIGN;
79+
if (i == 0)
80+
newtok.toktype |= ASSIGN_KEEP_ARG;
7981
newtok.var.idx = num_var;
8082
#if TRACE_PARSE
8183
printf("vfn memory: adding assign(vars[%d]) to op stack\n", num_var);
@@ -215,7 +217,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
215217
goto error;
216218
}
217219
}
218-
switch (tok.toktype) {
220+
switch (tok.toktype & TOKEN_MASK) {
219221
case TOK_LITERAL:
220222
/* push to output stack */
221223
estack_push(out, &tok);
@@ -248,6 +250,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
248250
#endif
249251
{FAIL_IF(!found_in->loop_start_pos,
250252
"local input variable used before lambda token.");}
253+
/* find offset of the value to be copied on the evaluation stack */
251254
i = found_in->loop_start_pos + 1;
252255
while (i < out->num_tokens) {
253256
if (out->tokens[i].toktype <= TOK_MOVE)
@@ -919,7 +922,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
919922
var_cache->loop_start_pos = 0;
920923

921924
GET_NEXT_TOKEN(tok);
922-
if (TOK_ASSIGN == tok.toktype) {
925+
if (TOK_ASSIGN == (tok.toktype & TOKEN_MASK)) {
923926
/* expression contains accumulator variable initialization */
924927
lambda_allowed = 1;
925928
}
@@ -1383,7 +1386,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
13831386
/* move assignment tokens */
13841387
for (; memory > 0; memory--) {
13851388
etoken tmp = estack_pop(op);
1386-
{FAIL_IF(tmp->toktype != TOK_ASSIGN && tmp->toktype != TOK_ASSIGN_USE,
1389+
{FAIL_IF(!(tmp->toktype & TOK_ASSIGN),
13871390
"VFN missing memory assignment tokens.");}
13881391
/* copy datatype and vector length from vfn token */
13891392
tmp->gen.datatype = t->gen.datatype;
@@ -1431,8 +1434,10 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
14311434
estack_push(out, &tok);
14321435
reduce_types &= ~(tok.con.flags & REDUCE_TYPE_MASK);
14331436
}
1434-
/* special case: if top of stack is tok_assign_use, pop to output */
1435-
if (op->num_tokens && (estack_peek(op, ESTACK_TOP))->toktype == TOK_ASSIGN_USE) {
1437+
/* special case: if top of stack is tok_assign with keep_arg flag, pop to output */
1438+
if (op->num_tokens
1439+
&& (estack_peek(op, ESTACK_TOP))->toktype & TOK_ASSIGN
1440+
&& (estack_peek(op, ESTACK_TOP))->toktype & ASSIGN_KEEP_ARG) {
14361441
estack_push(out, estack_pop(op));
14371442
{FAIL_IF(!estack_check_type(out, vars, 1), "Malformed expression (16).");}
14381443
}
@@ -1558,11 +1563,11 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
15581563
if ((op->num_tokens == 1) && op_top->toktype < TOK_ASSIGN)
15591564
{FAIL("Malformed expression (22)");}
15601565
estack_push(out, estack_pop(op));
1561-
if ( TOK_ASSIGN_USE == (estack_peek(out, ESTACK_TOP))->toktype
1566+
if ( ASSIGN_KEEP_ARG & op_top->toktype
15621567
&& estack_check_assign_type_and_len(out, vars) == -1)
15631568
{FAIL("Malformed expression (23)");}
1564-
if (!is_const && TOK_ASSIGN_CONST == estack_peek(out, ESTACK_TOP)->toktype)
1565-
estack_peek(out, ESTACK_TOP)->toktype = TOK_ASSIGN;
1569+
if (!is_const && ASSIGN_CONSTANT & op_top->toktype)
1570+
estack_peek(out, ESTACK_TOP)->toktype &= ~ASSIGN_CONSTANT;
15661571
}
15671572
/* mark last assignment token to clear eval stack */
15681573
(estack_peek(out, ESTACK_TOP))->gen.flags |= CLEAR_STACK;
@@ -1583,13 +1588,13 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
15831588
}
15841589
else {
15851590
etoken t = estack_peek(out, ESTACK_TOP - substack_len);
1586-
switch (t->toktype) {
1591+
switch (t->toktype & TOKEN_MASK) {
15871592
case TOK_OP:
15881593
if (t->op.idx < OP_INCREMENT_PRE || t->op.idx > OP_DECREMENT_POST)
15891594
{FAIL("misplaced increment or decrement operator");}
1595+
break;
15901596
case TOK_ASSIGN:
15911597
case TOK_ASSIGN_TT:
1592-
case TOK_ASSIGN_CONST:
15931598
out_top->gen.flags |= (TYPE_LOCKED | CLEAR_STACK);
15941599
break;
15951600
default:
@@ -1721,6 +1726,8 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
17211726
}
17221727
else {
17231728
/* we are retrieving signal instance index */
1729+
/* evaluator will keep track of local instance being processed, so we don't
1730+
* need to know which variable is being addressed */
17241731
GET_NEXT_TOKEN(tok);
17251732
{FAIL_IF(tok.toktype != TOK_VAR, "Misplaced instance index query.");}
17261733
tok.toktype = TOK_VAR_INST_IDX;
@@ -1739,8 +1746,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
17391746

17401747
allow_toktype = OBJECT_TOKENS & ~TOK_NEGATE;
17411748
break;
1742-
case TOK_ASSIGN:
1743-
case TOK_ASSIGN_OP: {
1749+
case TOK_ASSIGN: {
17441750
etoken out_top = estack_peek(out, ESTACK_TOP);
17451751
/* assignment to variable */
17461752
{FAIL_IF(!assigning, "Misplaced assignment operator.");}
@@ -1769,12 +1775,13 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
17691775
vars[var].flags |= VAR_ASSIGNED;
17701776
i = estack_get_substack_len(out, ESTACK_TOP);
17711777
/* nothing extraordinary, continue as normal */
1772-
if (TOK_ASSIGN_OP == tok.toktype) {
1773-
out_top->toktype = TOK_ASSIGN_OP;
1778+
out_top->toktype = TOK_ASSIGN;
1779+
if (ASSIGN_COMPOUND & tok.toktype) {
1780+
out_top->toktype |= ASSIGN_COMPOUND;
17741781
out_top->var.op_idx = tok.var.op_idx;
17751782
}
1776-
else {
1777-
out_top->toktype = is_const ? TOK_ASSIGN_CONST : TOK_ASSIGN;
1783+
if (is_const) {
1784+
out_top->toktype |= ASSIGN_CONSTANT;
17781785
}
17791786
out_top->var.offset = 0;
17801787
while (i > 0) {
@@ -1791,13 +1798,11 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
17911798
{FAIL_IF(out_top->var.idx == VAR_Y && !(out_top->gen.flags & VAR_HIST_IDX),
17921799
"Only past samples of output timetag are writable.");}
17931800
i = estack_get_substack_len(out, ESTACK_TOP);
1794-
if (TOK_ASSIGN_OP == tok.toktype) {
1795-
out_top->toktype = TOK_ASSIGN_TT_OP;
1801+
out_top->toktype = TOK_ASSIGN_TT;
1802+
if (ASSIGN_COMPOUND & tok.toktype) {
1803+
out_top->toktype |= ASSIGN_COMPOUND;
17961804
out_top->var.op_idx = tok.var.op_idx;
17971805
}
1798-
else {
1799-
out_top->toktype = TOK_ASSIGN_TT;
1800-
}
18011806
out_top->gen.datatype = MPR_DBL;
18021807
while (i > 0) {
18031808
estack_push(op, estack_pop(out));
@@ -1807,8 +1812,9 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
18071812
else if (out_top->toktype == TOK_VECTORIZE) {
18081813
int var, j, arity = out_top->fn.arity;
18091814

1810-
/* out token is vectorizer */
1815+
/* remove vectorizer token from output */
18111816
estack_pop(out);
1817+
18121818
out_top = estack_peek(out, ESTACK_TOP);
18131819
{FAIL_IF(out_top->toktype != TOK_VAR, "Bad token left of assignment. (1)");}
18141820
var = out_top->var.idx;
@@ -1828,12 +1834,13 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
18281834
else if (out_top->var.idx != var)
18291835
{FAIL("Cannot mix variables in vector assignment.");}
18301836
j = estack_get_substack_len(out, ESTACK_TOP);
1831-
if (TOK_ASSIGN_OP == tok.toktype) {
1832-
out_top->toktype = TOK_ASSIGN_OP;
1837+
out_top->toktype = TOK_ASSIGN;
1838+
if (ASSIGN_COMPOUND & tok.toktype) {
1839+
out_top->toktype |= ASSIGN_COMPOUND;
18331840
out_top->var.op_idx = tok.var.op_idx;
18341841
}
1835-
else {
1836-
out_top->toktype = is_const ? TOK_ASSIGN_CONST : TOK_ASSIGN;
1842+
if (is_const) {
1843+
out_top->toktype |= ASSIGN_CONSTANT;
18371844
}
18381845
while (j-- > 0)
18391846
estack_push(op, estack_pop(out));
@@ -1883,7 +1890,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
18831890
#endif
18841891
for (i = 0; i < out->num_tokens; i++) {
18851892
etoken t = estack_peek(out, i);
1886-
if (TOK_ASSIGN_OP == t->toktype || TOK_ASSIGN_TT_OP == t->toktype) {
1893+
if ((TOK_ASSIGN & t->toktype) && (ASSIGN_COMPOUND & t->toktype)) {
18871894
/* include variable indexes/indexing subexpressions but not the value to be assigned */
18881895
int j, assign_len = 1, arg_substack_len, var_substack_len = estack_get_substack_len(out, i) - 1;
18891896
etoken_t newtok;
@@ -1924,10 +1931,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
19241931
etoken a = estack_peek(out, j);
19251932
if (!(TOK_ASSIGN & a->toktype))
19261933
break;
1927-
if (TOK_ASSIGN_OP == a->toktype)
1928-
a->toktype = TOK_ASSIGN;
1929-
else if (TOK_ASSIGN_TT_OP == a->toktype)
1930-
a->toktype = TOK_ASSIGN_TT;
1934+
a->toktype &= ~ASSIGN_COMPOUND;
19311935
--j;
19321936
}
19331937

@@ -1943,10 +1947,11 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
19431947
/* we have inserted a token but i still points to the old assignment token position */
19441948
for (j = 0; j < var_substack_len; j++) {
19451949
etoken a = estack_peek(out, i - arg_substack_len - j);
1946-
if (TOK_ASSIGN == a->toktype)
1947-
a->toktype = TOK_VAR;
1948-
else if (TOK_ASSIGN_TT == a->toktype)
1949-
a->toktype = TOK_TT;
1950+
switch (a->toktype & TOKEN_MASK) {
1951+
case TOK_ASSIGN: a->toktype = TOK_VAR; break;
1952+
case TOK_ASSIGN_TT: a->toktype = TOK_TT; break;
1953+
default: break;
1954+
}
19501955
}
19511956

19521957
/* 6) if there are more than 1 assignment tokens we also need a TOK_VECTORIZE */
@@ -2027,10 +2032,12 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
20272032
newtok.gen.vec_len = 1;
20282033
estack_insert(out, ++i, 1, &newtok);
20292034

2030-
/* add var substack and convert to assign_use */
2035+
/* add var substack and convert to assign with keep_arg flag */
20312036
t = estack_insert(out, ++i, substack_len, estack_peek(out, var_idx - substack_len + 1));
20322037
{FAIL_IF(t->toktype != TOK_VAR, "error!");}
2033-
t->toktype = pre ? TOK_ASSIGN_USE : TOK_ASSIGN;
2038+
t->toktype = TOK_ASSIGN;
2039+
if (pre)
2040+
t->toktype |= ASSIGN_KEEP_ARG;
20342041
t->gen.flags |= flags;
20352042
if (t->var.idx < VAR_Y) {
20362043
vars[t->var.idx].flags |= VAR_ASSIGNED;
@@ -2048,13 +2055,22 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
20482055
/* run checks on VAR_NOW and VAR_NEXT */
20492056
for (i = 0; i < out->num_tokens; i++) {
20502057
etoken t = estack_peek(out, i);
2051-
{FAIL_IF( (TOK_VAR == t->toktype || TOK_ASSIGN == t->toktype)
2052-
&& (VAR_NOW == t->var.idx || VAR_NEXT == t->var.idx),
2053-
"Illegal variable index.");}
2054-
{FAIL_IF(TOK_TT == t->toktype && VAR_NOW == t->var.idx && NUM_VAR_IDXS(t->gen.flags),
2055-
"'now' timestamp does not accept indices.");}
2056-
{FAIL_IF(TOK_ASSIGN_TT == t->toktype && VAR_NOW == t->var.idx,
2057-
"Cannot assign to 'now' timestamp.");}
2058+
switch (t->toktype & TOKEN_MASK) {
2059+
case TOK_VAR:
2060+
case TOK_ASSIGN:
2061+
{FAIL_IF(VAR_NOW == t->var.idx || VAR_NEXT == t->var.idx, "Illegal variable index.");}
2062+
break;
2063+
case TOK_TT:
2064+
{FAIL_IF(VAR_NOW == t->var.idx && NUM_VAR_IDXS(t->gen.flags),
2065+
"'now' timestamp does not accept indices.");}
2066+
break;
2067+
case TOK_ASSIGN_TT:
2068+
{FAIL_IF(VAR_NOW == t->var.idx, "Cannot assign to 'now' timestamp.");}
2069+
break;
2070+
default:
2071+
break;
2072+
2073+
}
20582074
}
20592075

20602076
/* check that all used-defined variables were assigned */

0 commit comments

Comments
 (0)