Skip to content

Commit 49c68e8

Browse files
committed
Expression engine: added handling of current timestamp; optimizations
1 parent b3535c7 commit 49c68e8

8 files changed

Lines changed: 207 additions & 104 deletions

File tree

src/expression.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ void mpr_expr_set_var_updated(mpr_expr expr, int var_idx)
262262
&& var_idx != expr->mute_ctl);
263263
expr->vars[var_idx].flags |= VAR_SET_EXTERN;
264264
/* Reset expression offset to 0 in case other variables are initialised from this one. */
265-
expr->stack->offset = 0;
265+
expr->stack->init_offset = 0;
266266
return;
267267
}
268268

src/expression/expr_evaluator.h

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
109109
etoken_t *tok = stk->tokens, *end = tok + stk->num_tokens;
110110
int dp = -1, sp = -stk->vec_len, status = 1 | EXPR_EVAL_DONE;
111111
/* Note: signal, history, and vector reduce are currently limited to 255 items here */
112-
uint8_t alive = 1, muted = 0, can_advance = 1, cache = 0, vlen = stk->vec_len;
112+
uint8_t alive = 1, muted = 0, cache = 0, vlen = stk->vec_len;
113113
uint8_t hist_offset = 0, sig_offset = 0, vec_offset = 0;
114114
mpr_value x = NULL;
115115

@@ -118,7 +118,7 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
118118
mpr_type *types = buff->types;
119119

120120
if (v_out && mpr_value_get_num_samps(v_out, inst_idx) > 0) {
121-
tok += stk->offset;
121+
tok += stk->init_offset;
122122
}
123123

124124
if (v_vars) {
@@ -215,15 +215,31 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
215215
if (VAR_Y == tok->var.idx) {
216216
RETURN_ARG_UNLESS(v_out, status);
217217
v = v_out;
218-
can_advance = 0;
219218
#if TRACE_EVAL
220219
printf("[y]");
221220
#endif
222221
}
222+
else if (VAR_NOW == tok->var.idx) {
223+
int i;
224+
double t_d;
225+
RETURN_ARG_UNLESS(time, status);
226+
#if TRACE_EVAL
227+
printf("[now]");
228+
#endif
229+
SET_STACK_PTR(idxp + 1);
230+
t_d = mpr_time_as_dbl(*time);
231+
for (i = sp; i < sp + tok->gen.vec_len; i++)
232+
vals[i].d = t_d;
233+
SET_TYPE(MPR_DBL);
234+
SET_LEN(tok->gen.vec_len);
235+
#if TRACE_EVAL
236+
evalue_print(vals + sp, types[dp], lens[dp], dp);
237+
#endif
238+
break;
239+
}
223240
else if (VAR_NEXT == tok->var.idx) {
224241
RETURN_ARG_UNLESS(v_next, status);
225242
v = v_next;
226-
can_advance = 0;
227243
#if TRACE_EVAL
228244
printf("[next]");
229245
#endif
@@ -259,7 +275,6 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
259275
else
260276
goto error;
261277
}
262-
can_advance = 0;
263278

264279
/* If no instance idx is cached this means that this expression contains a
265280
* non-reducing reference to the variable x, and that mpr_expr_eval() should be
@@ -269,7 +284,6 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
269284
}
270285
else if (v_vars) {
271286
v = v_vars[tok->var.idx];
272-
can_advance = 0;
273287
#if TRACE_EVAL
274288
if (expr->vars && expr->vars[tok->var.idx].name)
275289
printf("[%d:%s]", tok->var.idx, expr->vars[tok->var.idx].name);
@@ -451,7 +465,6 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
451465
goto error;
452466
for (i = 1; i < tok->gen.vec_len; i++)
453467
vals[sp + i].i = vals[sp].i;
454-
can_advance = 0;
455468
#if TRACE_EVAL
456469
evalue_print(vals + sp, types[dp], lens[dp], dp);
457470
#endif
@@ -615,8 +628,6 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
615628
default:
616629
goto error;
617630
}
618-
if (tok->fn.idx > FN_DEL_IDX)
619-
can_advance = 0;
620631
#if TRACE_EVAL
621632
evalue_print(vals + sp, types[dp], lens[dp], dp);
622633
#endif
@@ -894,8 +905,6 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
894905
}
895906
case TOK_ASSIGN:
896907
case TOK_ASSIGN_USE:
897-
if (VAR_Y == tok->var.idx)
898-
can_advance = 0;
899908
case TOK_ASSIGN_CONST: {
900909
mpr_value v;
901910
/* currently only history and vector indices are supported for assignment */
@@ -914,7 +923,6 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
914923
goto assign_done;
915924
}
916925
status |= muted ? EXPR_MUTED_UPDATE : EXPR_UPDATE;
917-
can_advance = 0;
918926
if (!v_out)
919927
return status;
920928
v = v_out;
@@ -1014,30 +1022,16 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
10141022
status |= EXPR_RELEASE_BEFORE_UPDATE;
10151023
}
10161024
alive = vals[sp].i != 0;
1017-
can_advance = 0;
10181025
}
10191026
else if (tok->var.idx == expr->mute_ctl) {
10201027
muted = vals[sp].i != 0;
1021-
can_advance = 0;
10221028
}
10231029
else if (VAR_Y >= tok->var.idx && !hidx) {
10241030
/* inform value struct that it has value */
10251031
mpr_value_set_elements_known(v, inst_idx, vidx, tok->gen.vec_len);
10261032
}
10271033

10281034
assign_done:
1029-
/* If assignment was constant or history initialization, move expr
1030-
* start token pointer so we don't evaluate this section again. */
1031-
1032-
if (can_advance || tok->gen.flags & VAR_HIST_IDX) {
1033-
#if TRACE_EVAL
1034-
printf("\n move start\t%ld\n", tok - stk->tokens + 1);
1035-
#endif
1036-
stk->offset = tok - stk->tokens + 1;
1037-
}
1038-
else
1039-
can_advance = 0;
1040-
10411035
if (tok->gen.flags & CLEAR_STACK)
10421036
dp = -1;
10431037
else if (dp && TOK_ASSIGN_USE != tok->toktype)
@@ -1094,16 +1088,6 @@ int mpr_expr_eval(mpr_expr expr, ebuffer buff, mpr_value *v_in, mpr_value *v_var
10941088
mpr_time_set_dbl(&t, vals[sp].d);
10951089
mpr_value_set_time(v, t, inst_idx, hidx);
10961090

1097-
/* If assignment was constant or history initialization, move expr
1098-
* start token pointer so we don't evaluate this section again. */
1099-
if (can_advance || tok->gen.flags & VAR_HIST_IDX) {
1100-
#if TRACE_EVAL
1101-
printf(" move start\t%ld\n", tok - stk->tokens + 1);
1102-
#endif
1103-
stk->offset = tok - stk->tokens + 1;
1104-
}
1105-
else
1106-
can_advance = 0;
11071091
if (tok->gen.flags & CLEAR_STACK)
11081092
dp = -1;
11091093
else {

src/expression/expr_lexer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ static int var_lookup(etoken tok, const char *s, int len)
1717
s += 2;
1818
len -= 2;
1919
}
20+
if (3 == len && 0 == strncmp(s, "now", 3)) {
21+
tok->var.idx = VAR_NOW;
22+
tok->toktype = TOK_TT;
23+
return 0;
24+
}
2025
if (4 == len && 0 == strncmp(s, "next", 4)) {
2126
tok->var.idx = VAR_NEXT;
2227
tok->toktype = TOK_TT;

src/expression/expr_parser.h

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
315315
break;
316316
}
317317

318-
if (tok.var.idx == VAR_X_NEWEST) {
318+
if (VAR_X_NEWEST == tok.var.idx) {
319319
tok.gen.datatype = type_lo;
320320
tok.gen.casttype = type_hi;
321321
tok.gen.vec_len = out->vec_len;
@@ -330,12 +330,12 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
330330
tok.gen.flags |= (TYPE_LOCKED | VEC_LEN_LOCKED);
331331
is_const = 0;
332332
}
333-
else if (tok.var.idx == VAR_Y) {
333+
else if (VAR_Y == tok.var.idx) {
334334
tok.gen.datatype = dst_types[0];
335335
tok.gen.vec_len = dst_lens[0];
336336
tok.gen.flags |= (TYPE_LOCKED | VEC_LEN_LOCKED);
337337
}
338-
else if (tok.var.idx == VAR_NEXT) {
338+
else if (VAR_NOW == tok.var.idx || VAR_NEXT == tok.var.idx) {
339339
tok.gen.datatype = MPR_DBL;
340340
tok.gen.vec_len = 1;
341341
tok.gen.flags |= (TYPE_LOCKED | VEC_LEN_LOCKED);
@@ -476,6 +476,7 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
476476
}
477477
case TOK_OP_UNARY:
478478
{FAIL_IF( !op->num_tokens
479+
&& tok.op.idx != OP_LOGICAL_NOT
479480
&& tok.op.idx != OP_INCREMENT_PRE
480481
&& tok.op.idx != OP_DECREMENT_PRE, "illegal unary operator at expr start");}
481482
tok.toktype = TOK_OP;
@@ -1872,6 +1873,9 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
18721873
pre = t->op.idx == OP_INCREMENT_PRE || t->op.idx == OP_DECREMENT_PRE,
18731874
var_idx = i - 1,
18741875
flags = t->gen.flags;
1876+
#if TRACE_PARSE
1877+
printf("expanding %sfix %screment operator\n", pre ? "pre" : "post", inc ? "in" : "de");
1878+
#endif
18751879
etoken_t newtok, *vartok = estack_peek(out, var_idx);
18761880
{FAIL_IF(TOK_VAR != vartok->toktype, "misplaced increment or decrement operator");}
18771881
{FAIL_IF(vartok->var.idx >= VAR_X_NEWEST, "cannot assign to variable 'x'");}
@@ -1892,18 +1896,35 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
18921896
case MPR_DBL: t->lit.val.d = 1; break;
18931897
}
18941898

1899+
/* The postfix increment/decrement operators require copying the unaltered variable
1900+
* value to the evaluation stack before incrementing/decrementing so it can be used
1901+
* in further calculations. An exception is made if the variable being incremented
1902+
* is not otherwise assigned, e.g. "a++;" */
18951903
if (!pre) {
1896-
/* need to insert copy token after variable */
1897-
/* newtok.toktype = TOK_COPY_FROM;
1898-
* newtok.con.cache_offset = 0;
1899-
* estack_insert(out, i++, 1, &newtok);
1900-
*/
1901-
1902-
/* above code does not guarantee that variable token will not be cast to another
1903-
* datatype before copy */
1904-
/* for now we will copy variable substack instead of using copy */
1905-
estack_insert(out, i, substack_len, estack_peek(out, var_idx - substack_len + 1));
1906-
i += substack_len;
1904+
/* check if the variable is assigned */
1905+
int top = out->num_tokens - 1, copy_tokens = 1;
1906+
while (top > 0) {
1907+
top -= estack_get_substack_len(out, top);
1908+
if (top == i) {
1909+
copy_tokens = 0;
1910+
break;
1911+
}
1912+
if (top < i)
1913+
break;
1914+
}
1915+
if (copy_tokens) {
1916+
/* need to insert copy token after variable */
1917+
/* newtok.toktype = TOK_COPY_FROM;
1918+
* newtok.con.cache_offset = 0;
1919+
* estack_insert(out, i++, 1, &newtok);
1920+
*/
1921+
1922+
/* above code does not guarantee that variable token will not be cast to another
1923+
* datatype before copy */
1924+
/* for now we will copy variable substack instead of using copy */
1925+
estack_insert(out, i, substack_len, estack_peek(out, var_idx - substack_len + 1));
1926+
i += substack_len;
1927+
}
19071928
}
19081929

19091930
/* add operator */
@@ -1923,6 +1944,18 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
19231944
}
19241945
}
19251946

1947+
/* run checks on VAR_NOW and VAR_NEXT */
1948+
for (i = 0; i < out->num_tokens; i++) {
1949+
etoken t = estack_peek(out, i);
1950+
{FAIL_IF( (TOK_VAR == t->toktype || TOK_ASSIGN == t->toktype)
1951+
&& (VAR_NOW == t->var.idx || VAR_NEXT == t->var.idx),
1952+
"Illegal variable index.");}
1953+
{FAIL_IF(TOK_TT == t->toktype && VAR_NOW == t->var.idx && NUM_VAR_IDXS(t->gen.flags),
1954+
"'now' timestamp does not accept indices.");}
1955+
{FAIL_IF(TOK_ASSIGN_TT == t->toktype && VAR_NOW == t->var.idx,
1956+
"Cannot assign to 'now' timestamp.");}
1957+
}
1958+
19261959
/* check that all used-defined variables were assigned */
19271960
for (i = 0; i < num_var; i++) {
19281961
{FAIL_IF(!(vars[i].flags & VAR_ASSIGNED), "User-defined variable not assigned.");}
@@ -1934,6 +1967,8 @@ int expr_parser_build_stack(mpr_expr expr, const char *str,
19341967
/* replace special constants with their typed values */
19351968
{FAIL_IF(estack_replace_special_constants(out), "Error replacing special constants."); }
19361969

1970+
estack_find_init_offset(out);
1971+
19371972
#if TRACE_PARSE
19381973
estack_print("OUTPUT STACK", out, vars, 0);
19391974
estack_print("OPERATOR STACK", op, vars, 0);

0 commit comments

Comments
 (0)