cgv
Loading...
Searching...
No Matches
expression_processor.cxx
1#include "variables.h"
2#include "expression_processor.h"
3#include "ph_processor.h"
4
5#include <iostream>
6
7#include <cgv/utils/scan.h>
8#include <cgv/utils/tokenizer.h>
9#include <cgv/utils/convert.h>
10
11using namespace cgv::utils;
12
13namespace cgv {
14 namespace ppp {
15
16 bool check_cyclic_reference(const variant* v)
17 {
18 std::vector<const variant*> s;
19 s.push_back(v);
20 do {
21 const variant* v1;
22 if (v->get_type() == REFERENCE_VALUE)
23 v1 = v->get_reference();
24 else if (v->get_type() == NAME_VALUE)
25 v1 = find_variable(v->get_name());
26 else
27 return false;
28
29 for (unsigned i = 0; i < s.size(); ++i) {
30 if (s[i] == v1)
31 return true;
32 }
33 s.push_back(v1);
34 v = v1;
35 } while (true);
36 return false;
37 }
38
39 expression_processor::expression_processor()
40 {
41 /* debug_parse = true;
42 debug_evaluate = true;
43 found_error = true;*/
44
45 debug_parse = false;
46 debug_evaluate = false;
47 found_error = false;
48 issued_error = false;
49 }
50
51 unsigned int expression_processor::get_nr_comma_separated_expressions(
52 std::vector<expr_stack_entry>& expression_stack,
53 std::vector<ExpressionPart>& parenthesis_stack,
54 std::stack<variant>& value_stack) const
55 {
56 unsigned int i = (unsigned int)expression_stack.size();
57 if (i == 0)
58 return 0;
59 --i;
60 unsigned int n = 1;
61 if (value_stack.size() <= expression_stack.back().first)
62 n = 0;
63 while (parenthesis_stack[i] == EP_COMMA) {
64 ++n;
65 if (i == 0)
66 return n;
67 --i;
68 }
69 return n;
70 }
71
72 ExpressionPart expression_processor::find_last_parenthesis(std::vector<expr_stack_entry>& expression_stack,
73 std::vector<ExpressionPart>& parenthesis_stack) const
74 {
75 unsigned int i = (unsigned int)expression_stack.size();
76 if (i == 0)
77 return EP_VALUE;
78 --i;
79 while (parenthesis_stack[i] == EP_COMMA) {
80 if (i == 0)
81 return EP_VALUE;
82 --i;
83 }
84 return parenthesis_stack[i];
85 }
86
87 bool expression_processor::parse(const token& input_token)
88 {
89 expression_tokens.clear();
90
91 std::vector<token> input_tokens;
92 bite_all(tokenizer(input_token).set_sep(std::string(operator_characters) + "()[],", false).
93 set_skip("\"'", "\"'"), input_tokens);
94
95 unsigned int i;
96 for (i = 0; i < input_tokens.size(); ++i) {
97 const token& tok = input_tokens[i];
98 if (*tok.begin == '"' || *tok.begin == '\'') {
99 variant v(interpret_special(to_string(tok).substr(1, tok.get_length() - 2)));
100 expression_tokens.push_back(expression_token(tok, v));
101 if (debug_parse)
102 std::cout << i << " : string token '" << v.get_str() << "'" << std::endl;
103 }
104 else if (to_string(tok) == "(") {
105 expression_tokens.push_back(expression_token(tok, EP_OPEN));
106 if (debug_parse)
107 std::cout << i << " : open token" << std::endl;
108 }
109 else if (to_string(tok) == ")") {
110 expression_tokens.push_back(expression_token(tok, EP_CLOSE));
111 if (debug_parse)
112 std::cout << i << " : close token" << std::endl;
113 }
114 else if (to_string(tok) == "[") {
115 expression_tokens.push_back(expression_token(tok, EP_LIST_OPEN));
116 if (debug_parse)
117 std::cout << i << " : open list token" << std::endl;
118 }
119 else if (to_string(tok) == "]") {
120 expression_tokens.push_back(expression_token(tok, EP_LIST_CLOSE));
121 if (debug_parse)
122 std::cout << i << " : close list token" << std::endl;
123 }
124 else if (to_string(tok) == ",") {
125 expression_tokens.push_back(expression_token(tok, EP_COMMA));
126 if (debug_parse)
127 std::cout << i << " : comma token" << std::endl;
128 }
129 else {
130 OperatorType ot = OT_LAST;
131 // check for operator token
132 if (tok.size() == 1 && is_element(*tok.begin, operator_characters)) {
133 // try to extend to two character operator
134 token op_tok = tok;
135 if (i + 1 < input_tokens.size() && input_tokens[i + 1].size() == 1 &&
136 is_element(*input_tokens[i + 1].begin, operator_characters)) {
137 ot = get_operator_type(to_string(tok) + to_string(input_tokens[i + 1]));
138 if (ot != OT_LAST) {
139 ++i;
140 op_tok.end = input_tokens[i].end;
141 }
142 }
143 if (ot == OT_LAST)
144 ot = get_operator_type(to_string(tok));
145 if (ot != OT_LAST) {
146 expression_tokens.push_back(expression_token(op_tok, ot));
147 if (debug_parse)
148 std::cout << i << " : operator " << get_operator_word(ot) << std::endl;
149 }
150 }
151 if (ot == OT_LAST) {
152 int vi;
153 double d;
154 token dbl_tok = tok;
155 unsigned j = i + 1;
156 bool considered_dot = false;
157 bool considered_exp = false;
158 bool considered_sign = false;
159 while (j < input_tokens.size()) {
160 bool can_extend = true;
161 for (const char* p = dbl_tok.end; p < input_tokens[j].end; ++p) {
162 if (!considered_dot && *p == '.')
163 considered_dot = true;
164 else if (!considered_exp && (*p == 'E' || *p == 'e'))
165 considered_exp = true;
166 else if (!considered_sign && (*p == '+' || *p == '-'))
167 considered_sign = true;
168 else if (*p < '0' || *p > '9') {
169 can_extend = false;
170 break;
171 }
172 }
173 if (can_extend) {
174 dbl_tok.end = input_tokens[j].end;
175 ++j;
176 }
177 else
178 break;
179 }
180 bool rather_int = !considered_dot && !considered_exp && !considered_sign;
181 if (!rather_int && dbl_tok[0] >= '0' && dbl_tok[0] <= '9' && is_double(to_string(dbl_tok), d)) {
182 std::string t = to_string(dbl_tok);
183 expression_tokens.push_back(expression_token(dbl_tok, variant(d)));
184 if (debug_parse)
185 std::cout << i << "-" << j - 1 << " : double tokens = " << d << std::endl;
186 i = j - 1;
187 }
188 else if (is_integer(to_string(tok), vi)) {
189 expression_tokens.push_back(expression_token(tok, variant(vi)));
190 if (debug_parse)
191 std::cout << i << " : int token = " << vi << std::endl;
192 }
193 else {
194 variant v(NAME_VALUE, to_string(tok));
195 expression_tokens.push_back(expression_token(tok, v));
196 if (debug_parse)
197 std::cout << i << " : variable >" << to_string(tok) << "< = " <<
198 v.get_str() << std::endl;
199 }
200 }
201 }
202 }
203 return true;
204 }
205
206 void expression_processor::prepare()
207 {
208 found_error = false;
209 issued_error = false;
210 // expression_stack.clear();
211 // parenthesis_stack.clear();
212 // while (!value_stack.empty()) value_stack.pop();
213 // while (!operator_stack.empty()) operator_stack.pop();
214 }
215
216 void expression_processor::extract_begins(std::vector<unsigned>& begins, unsigned i0, unsigned ie) const
217 {
218 if (ie == -1)
219 ie = (unsigned)expression_tokens.size();
220 int parenthesis = 0;
221 if (expression_tokens.size() > i0)
222 begins.push_back(i0);
223 for (unsigned i = i0; i < ie; ++i) {
224 const expression_token& et = expression_tokens[i];
225 switch (et.ep) {
226 case EP_VALUE:
227 case EP_OPERATOR:
228 break;
229 case EP_OPEN:
230 case EP_FUNC:
231 case EP_LIST_OPEN:
232 case EP_LIST_ACCESS:
233 ++parenthesis;
234 break;
235 case EP_CLOSE:
236 case EP_LIST_CLOSE:
237 --parenthesis;
238 break;
239 case EP_COMMA:
240 if (parenthesis == 0 && i + 1 < ie)
241 begins.push_back(i + 1);
242 break;
243 }
244 }
245 }
246
247 int expression_processor::classify_call(unsigned closing_i) const
248 {
249 unsigned opening_i = closing_i - 1;
250 unsigned parenthesis = 1;
251 do {
252 const expression_token& et = expression_tokens[opening_i];
253 switch (et.ep) {
254 case EP_OPEN:
255 case EP_FUNC:
256 case EP_LIST_OPEN:
257 case EP_LIST_ACCESS:
258 --parenthesis;
259 break;
260 case EP_CLOSE:
261 case EP_LIST_CLOSE:
262 ++parenthesis;
263 break;
264 default:
265 break;
266 }
267 if (parenthesis == 0)
268 break;
269 --opening_i;
270 } while (true);
271 std::vector<unsigned> begins;
272 extract_begins(begins, opening_i + 1, closing_i);
273 unsigned nr_special = 0;
274 for (unsigned i = 0; i < begins.size(); ++i) {
275 unsigned j = begins[i];
276 if (expression_tokens[j].ep != EP_OPERATOR || expression_tokens[j].ot != OT_MAP_DOWN)
277 continue;
278 ++j;
279 if (j >= expression_tokens.size() || expression_tokens[j].ep != EP_VALUE || expression_tokens[j].value.get_type() != NAME_VALUE)
280 continue;
281 ++j;
282 if (j >= expression_tokens.size() || expression_tokens[j].ep != EP_OPERATOR || (expression_tokens[j].ot != OT_ASSIGN && expression_tokens[j].ot != OT_ASSIGN_REF))
283 continue;
284 ++nr_special;
285 }
286 if (nr_special == begins.size())
287 return 1;
288 if (nr_special == 0)
289 return 0;
290 return -1;
291 }
292
293 bool expression_processor::assign_func_decl(const std::vector<variant>& values) const
294 {
295 std::vector<unsigned> begins;
296 extract_begins(begins);
297 if (values.size() > begins.size()) {
298 last_error = "function called with more parameters than declared by the function";
299 last_error_token = expression_tokens.back();
300 return false;
301 }
302 for (unsigned i = 0; i < values.size(); ++i) {
303 variant& v = ref_variable(expression_tokens[begins[i] + 1].value.get_name(), true);
304 v = values[i];
305 if (check_cyclic_reference(&v)) {
306 last_error = "a call to this function generated cyclic reference to variable ";
307 if (v.is_name())
308 last_error += v.get_name();
309 last_error += ". Make sure to use map down operator <:";
310 if (v.is_name())
311 last_error += v.get_name();
312 last_error += " to mark special function call syntax in the function call referenced in the next error message.";
313 last_error_token = expression_tokens.back();
314 return false;
315 }
316 }
317 return true;
318 }
319
320
321 bool expression_processor::is_func_decl() const
322 {
323 std::vector<unsigned> begins;
324 extract_begins(begins);
325 for (unsigned i = 0; i < begins.size(); ++i) {
326 unsigned j = begins[i];
327 if (expression_tokens[j].ep != EP_OPERATOR || expression_tokens[j].ot != OT_MAP_UP) {
328 last_error = "function declaration expression must be a comma separated list of expressions of the form ':>var_name=...' or ':>var_name=&...' (:> missing)";
329 last_error_token = expression_tokens[j];
330 return false;
331 }
332 ++j;
333 if (j >= expression_tokens.size() || expression_tokens[j].ep != EP_VALUE || expression_tokens[j].value.get_type() != NAME_VALUE) {
334 last_error = "function declaration expression must be a comma separated list of expressions of the form ':>var_name=...' or ':>var_name=&...' (var_name missing)";
335 if (j < expression_tokens.size())
336 last_error_token = expression_tokens[j];
337 else
338 last_error_token = expression_tokens.back();
339 return false;
340 }
341 ++j;
342 if (j >= expression_tokens.size() || expression_tokens[j].ep != EP_OPERATOR || (expression_tokens[j].ot != OT_ASSIGN && expression_tokens[j].ot != OT_ASSIGN_REF)) {
343 last_error = "function declaration expression must be a comma separated list of expressions of the form ':>var_name=...' or ':>var_name=&...' (= or =& missing)";
344 if (j < expression_tokens.size())
345 last_error_token = expression_tokens[j];
346 else
347 last_error_token = expression_tokens.back();
348 return false;
349 }
350 }
351 return true;
352 }
353
354 bool expression_processor::validate(bool allow_several_values)
355 {
356 if (expression_tokens.size() == 0)
357 return true;
358 prepare();
359
361 std::vector<expr_stack_entry> expression_stack;
363 std::vector<ExpressionPart> parenthesis_stack;
365 std::stack<variant> value_stack;
367 std::stack<OperatorType> operator_stack;
368
369 bool left_of_operand = true;
370 unsigned int i;
371 for (i = 0; i < expression_tokens.size(); ++i) {
372 expression_token& et = expression_tokens[i];
373 switch (et.ep) {
374 case EP_VALUE:
375 if (left_of_operand) {
376 value_stack.push(et.value);
377 left_of_operand = false;
378 }
379 else {
380 last_error = "two successive values in expression without operator";
381 last_error_token = expression_tokens[i];
382 return false;
383 }
384 break;
385 case EP_OPERATOR:
386 // correct binary sub to unary if necessary
387 if (get_operator_arity(et.ot) == 2 && left_of_operand && et.ot == OT_SUB)
388 et.ot = OT_NEGATE;
389 // correct binary map to unary if necessary
390 if (get_operator_arity(et.ot) == 2 && left_of_operand && et.ot == OT_BINARY_MAP)
391 et.ot = OT_UNARY_MAP;
392
393 if (get_operator_arity(et.ot) == 1) {
394 if (get_operator_location(et.ot) == OL_PREFIX) {
395 if (left_of_operand) {
396 operator_stack.push(et.ot);
397 }
398 else {
399 last_error = std::string("unary prefix operator ") +
400 get_operator_word(et.ot) +
401 " cannot follow operand";
402 last_error_token = expression_tokens[i];
403 return false;
404 }
405 }
406 else {
407 if (left_of_operand) {
408 last_error = std::string("unary postfix operator ") +
409 get_operator_word(et.ot) +
410 " cannot preceed operand";
411 last_error_token = expression_tokens[i];
412 return false;
413 }
414 else {
415 operator_stack.push(et.ot);
416 }
417 }
418 }
419 else {
420 if (left_of_operand) {
421 last_error = std::string("binary operator ") +
422 get_operator_word(et.ot) +
423 " is missing left argument";
424 last_error_token = expression_tokens[i];
425 return false;
426 }
427 else {
428 if (!compress_stack_validate(get_operator_priority(et.ot), expression_stack, parenthesis_stack, value_stack, operator_stack))
429 return false;
430 operator_stack.push(et.ot);
431 left_of_operand = true;
432 }
433 }
434 break;
435 case EP_OPEN:
436 case EP_FUNC:
437 expression_stack.push_back(expr_stack_entry((unsigned int)value_stack.size(), (unsigned int)operator_stack.size()));
438 if (left_of_operand) {
439 parenthesis_stack.push_back(EP_OPEN);
440 }
441 else {
442 if (!compress_stack_validate(get_operator_priority(OT_MAP_UP), expression_stack, parenthesis_stack, value_stack, operator_stack))
443 return false;
444 expression_tokens[i].ep = EP_FUNC;
445 parenthesis_stack.push_back(EP_FUNC);
446 left_of_operand = true;
447 }
448 break;
449 case EP_CLOSE:
450 {
451 ExpressionPart last_parenthesis = find_last_parenthesis(expression_stack, parenthesis_stack);
452 if (last_parenthesis == EP_OPEN && left_of_operand) {
453 last_error = "closing paranthesis cannot init term";
454 last_error_token = expression_tokens[i];
455 return false;
456 }
457 if (last_parenthesis != EP_OPEN && last_parenthesis != EP_FUNC) {
458 last_error = "wrongly or not matched parenthesis )";
459 last_error_token = expression_tokens[i];
460 return false;
461 }
462 if (!left_of_operand) {
463 if (!compress_stack_validate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack)) {
464 last_error_token = expression_tokens[i];
465 return false;
466 }
467 if ((last_parenthesis != EP_FUNC) && (value_stack.size() <= expression_stack.back().first)) {
468 last_error = "no resulting value in expression";
469 last_error_token = expression_tokens[i];
470 return false;
471 }
472 // if more than one comma separated expressions are defined, only leave last value on the value stack
473 while (get_nr_comma_separated_expressions(expression_stack, parenthesis_stack, value_stack) > 1) {
474 variant tmp = value_stack.top();
475 value_stack.pop();
476 value_stack.pop();
477 value_stack.push(tmp);
478 expression_stack.pop_back();
479 parenthesis_stack.pop_back();
480 }
481 if (last_parenthesis == EP_FUNC)
482 value_stack.pop();
483 }
484 else
485 left_of_operand = false;
486 expression_stack.pop_back();
487 parenthesis_stack.pop_back();
488 }
489 break;
490 case EP_LIST_ACCESS:
491 case EP_LIST_OPEN:
492 expression_stack.push_back(expr_stack_entry((unsigned int)value_stack.size(), (unsigned int)operator_stack.size()));
493 if (left_of_operand)
494 parenthesis_stack.push_back(EP_LIST_OPEN);
495 else {
496 if (!compress_stack_validate(get_operator_priority(OT_MAP_UP), expression_stack, parenthesis_stack, value_stack, operator_stack))
497 return false;
498 expression_tokens[i].ep = EP_LIST_ACCESS;
499 parenthesis_stack.push_back(EP_LIST_ACCESS);
500 left_of_operand = true;
501 }
502 break;
503 case EP_LIST_CLOSE:
504 {
505 if (left_of_operand) {
506 if (i == 0 || expression_tokens[i - 1].ep != EP_LIST_OPEN) {
507 last_error = "closing paranthesis ] cannot init a term";
508 last_error_token = expression_tokens[i];
509 return false;
510 }
511 left_of_operand = false;
512 }
513 ExpressionPart last_parenthesis = find_last_parenthesis(expression_stack, parenthesis_stack);
514 if (last_parenthesis != EP_LIST_OPEN &&
515 last_parenthesis != EP_LIST_ACCESS) {
516 last_error = "wrongly or not matched parenthesis ]";
517 last_error_token = expression_tokens[i];
518 return false;
519 }
520 if (!compress_stack_validate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack)) {
521 last_error_token = expression_tokens[i];
522 return false;
523 }
524 if (last_parenthesis == EP_LIST_OPEN) {
525 unsigned int n = get_nr_comma_separated_expressions(expression_stack, parenthesis_stack, value_stack);
526 variant v = variant(variant::list_type());
527 if (n > 0) {
528 std::vector<variant> tmp;
529 tmp.resize(n);
530 unsigned int i;
531 for (i = 0; i < n; ++i) {
532 tmp[n - i - 1] = value_stack.top();
533 value_stack.pop();
534 expression_stack.pop_back();
535 parenthesis_stack.pop_back();
536 }
537 for (i = 0; i < n; ++i)
538 v.append_to_list(tmp[i]);
539 }
540 else {
541 expression_stack.pop_back();
542 parenthesis_stack.pop_back();
543 }
544 value_stack.push(v);
545 }
546 else {
547 unsigned int n = get_nr_comma_separated_expressions(expression_stack, parenthesis_stack, value_stack);
548 if (n != 1) {
549 last_error = "list access only with exactly one value allowed";
550 last_error_token = expression_tokens[i];
551 return false;
552 }
553 value_stack.pop();
554 expression_stack.pop_back();
555 parenthesis_stack.pop_back();
556 if (value_stack.empty()) {
557 last_error = "applied list access operator to empty value stack";
558 last_error_token = expression_tokens[i];
559 return false;
560 }
561 value_stack.pop();
562 value_stack.push(variant());
563 }
564 }
565 break;
566 case EP_COMMA:
567 if (left_of_operand) {
568 last_error = "comma cannot init a term";
569 last_error_token = expression_tokens[i];
570 return false;
571 }
572 if (!compress_stack_validate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack)) {
573 last_error_token = expression_tokens[i];
574 return false;
575 }
576 expression_stack.push_back(expr_stack_entry((unsigned int)value_stack.size(), (unsigned int)operator_stack.size()));
577 parenthesis_stack.push_back(EP_COMMA);
578 left_of_operand = true;
579 break;
580 }
581 }
582 if (!compress_stack_validate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack))
583 return false;
584 if (value_stack.empty()) {
585 last_error = "expression did not yield a value";
586 last_error_token = token(expression_tokens.front().begin, expression_tokens.back().end);
587 return false;
588 }
589 if (!allow_several_values && value_stack.size() > 1) {
590 last_error = "expression yielded more than one value";
591 last_error_token = token(expression_tokens.front().begin, expression_tokens.back().end);
592 return false;
593 }
594 return true;
595 }
596
597
599 {
600 if (expression_tokens.size() == 0) {
601 // value_stack.push(variant(0));
602 return true;
603 }
604 prepare();
605
607 std::vector<expr_stack_entry> expression_stack;
609 std::vector<ExpressionPart> parenthesis_stack;
611 std::stack<variant> value_stack;
613 std::stack<OperatorType> operator_stack;
614
615 unsigned int i;
616 bool empty_func_arg = false;
617 for (i = 0; i < expression_tokens.size(); ++i) {
618 expression_token& et = expression_tokens[i];
619 switch (et.ep) {
620 case EP_VALUE:
621 value_stack.push(et.value);
622 empty_func_arg = false;
623 break;
624 case EP_OPERATOR:
625 empty_func_arg = false;
626 if (get_operator_arity(et.ot) == 1) {
627 operator_stack.push(et.ot);
628 }
629 else {
630 compress_stack_evaluate(get_operator_priority(et.ot), expression_stack, parenthesis_stack, value_stack, operator_stack);
631 operator_stack.push(et.ot);
632 }
633 break;
634 case EP_OPEN:
635 expression_stack.push_back(expr_stack_entry((unsigned int)value_stack.size(), (unsigned int)operator_stack.size()));
636 parenthesis_stack.push_back(EP_OPEN);
637 break;
638 case EP_FUNC:
639 compress_stack_evaluate(get_operator_priority(OT_MAP_UP), expression_stack, parenthesis_stack, value_stack, operator_stack);
640 empty_func_arg = true;
641 expression_stack.push_back(expr_stack_entry((unsigned int)value_stack.size(), (unsigned int)operator_stack.size()));
642 parenthesis_stack.push_back(EP_FUNC);
643 if (value_stack.top().is_name() || value_stack.top().is_str() || value_stack.top().is_func()) {
644 variant* func_var;
645 if (value_stack.top().is_func())
646 func_var = &value_stack.top().ref_value();
647 else {
648 std::string func_name = (value_stack.top().is_str() ? value_stack.top().get_str() : value_stack.top().get_name());
649 func_var = &ref_variable(func_name);
650 }
651 if (func_var->is_func()) {
652 func_type& func = func_var->ref_func();
653 push_namespace(0, func.ns);
654 ref_variable("return", true);
655 variant tmp;
656 if (func.ph_proc->commands[func.block_begin - 1].expressions.size() == 2) {
657 ph_proc->swap_output(*func.ph_proc);
658 expression_processor& ep = func.ph_proc->commands[func.block_begin - 1].expressions[1];
659 if (!ep.evaluate(tmp, ph_proc)) {
660 if (!ep.issued_error) {
661 ph_proc->error(ep.last_error, ep.last_error_token);
662 ep.issued_error = true;
663 }
664 ph_proc->swap_output(*func.ph_proc);
665 last_error = "previous error was generated while evaluating this expression";
666 last_error_token = expression_tokens[i];
667 found_error = true;
668 return false;
669 }
670 ph_proc->swap_output(*func.ph_proc);
671 if (func.ph_proc->exit_code != 0) {
672 ph_proc->exit_code = func.ph_proc->exit_code;
673 return true;
674 }
675 }
676 goto_parent_namespace();
677 }
678 else {
679 last_error = "function call on variable not of type func";
680 last_error_token = expression_tokens[i];
681 found_error = true;
682 return false;
683 }
684 }
685 else {
686 last_error = "function call on non name or string expression";
687 last_error_token = expression_tokens[i];
688 found_error = true;
689 return false;
690 }
691 break;
692 case EP_CLOSE:
693 {
694 ExpressionPart last_parenthesis = find_last_parenthesis(expression_stack, parenthesis_stack);
695 if (last_parenthesis != EP_FUNC) {
696 if (!compress_stack_evaluate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack)) {
697 last_error_token = expression_tokens[i];
698 found_error = true;
699 return false;
700 }
701 // if more than one comma separated expressions are defined, only leave last value on the value stack
702 while (get_nr_comma_separated_expressions(expression_stack, parenthesis_stack, value_stack) > 1) {
703 variant tmp = value_stack.top();
704 value_stack.pop();
705 value_stack.pop();
706 value_stack.push(tmp);
707 expression_stack.pop_back();
708 parenthesis_stack.pop_back();
709 }
710 expression_stack.pop_back();
711 parenthesis_stack.pop_back();
712 }
713 else { // function call
714 std::vector<variant> arguments;
715 if (!empty_func_arg) {
716 if (!compress_stack_evaluate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack)) {
717 last_error_token = expression_tokens[i];
718 found_error = true;
719 return false;
720 }
721 unsigned argc = get_nr_comma_separated_expressions(expression_stack, parenthesis_stack, value_stack);
722 int cc = classify_call(i);
723 if (cc == -1) {
724 last_error = "error calling a function mixing special and standard syntax";
725 last_error_token = et;
726 found_error = true;
727 return false;
728 }
729 if (cc == 0) {
730 arguments.resize(argc);
731 for (unsigned i = 0; i < argc; ++i) {
732 arguments[argc - 1 - i] = value_stack.top();
733 if (arguments[argc - 1 - i].get_type() == NAME_VALUE) {
734 arguments[argc - 1 - i] = variant(&ref_variable(arguments[argc - 1 - i].get_name()));
735 }
736 value_stack.pop();
737 expression_stack.pop_back();
738 parenthesis_stack.pop_back();
739 }
740 }
741 else {
742 for (unsigned i = 0; i < argc; ++i) {
743 value_stack.pop();
744 expression_stack.pop_back();
745 parenthesis_stack.pop_back();
746 }
747 }
748 }
749 else {
750 expression_stack.pop_back();
751 parenthesis_stack.pop_back();
752 }
753 if (value_stack.top().is_name() || value_stack.top().is_str() || value_stack.top().is_func()) {
754 variant* func_var;
755 if (value_stack.top().is_func())
756 func_var = &value_stack.top().ref_value();
757 else {
758 std::string func_name = (value_stack.top().is_str() ? value_stack.top().get_str() : value_stack.top().get_name());
759 variant* func_var = &ref_variable(func_name);
760 }
761 if (func_var->is_func()) {
762 goto_child_namespace();
763 func_type& func = func_var->ref_func();
764 ph_proc->swap_output(*func.ph_proc);
765 if (arguments.size() > 0 && func.ph_proc->commands[func.block_begin - 1].expressions.size() == 2) {
766 const expression_processor& ep = func.ph_proc->commands[func.block_begin - 1].expressions[1];
767 if (!ep.assign_func_decl(arguments)) {
768 func.ph_proc->error(ep.get_last_error(), ep.get_last_error_token());
769 ph_proc->swap_output(*func.ph_proc);
770 last_error = "error appeared in the following function call:";
771 last_error_token = et;
772 found_error = true;
773 return false;
774 }
775 }
776 else if (arguments.size() > 0) {
777 ph_proc->swap_output(*func.ph_proc);
778 last_error = "error calling a function without arguments passing values";
779 last_error_token = et;
780 found_error = true;
781 return false;
782 }
783 if (!func.ph_proc->process(func.block_begin, func.block_end)) {
784 ph_proc->swap_output(*func.ph_proc);
785 last_error = "error in function call";
786 last_error_token = expression_tokens[i];
787 found_error = true;
788 return false;
789 }
790 ph_proc->swap_output(*func.ph_proc);
791 value_stack.pop();
792 value_stack.push(ref_variable("return", true));
793 pop_namespace();
794 }
795 else {
796 last_error = "function call on variable not of type proc";
797 last_error_token = expression_tokens[i];
798 found_error = true;
799 return false;
800 }
801 }
802 else {
803 last_error = "function call on non name or string expression";
804 last_error_token = expression_tokens[i];
805 found_error = true;
806 return false;
807 }
808 }
809 empty_func_arg = false;
810 }
811 break;
812 case EP_LIST_OPEN:
813 expression_stack.push_back(expr_stack_entry((unsigned int)value_stack.size(), (unsigned int)operator_stack.size()));
814 parenthesis_stack.push_back(EP_LIST_OPEN);
815 break;
816 case EP_LIST_ACCESS:
817 compress_stack_evaluate(get_operator_priority(OT_MAP_UP), expression_stack, parenthesis_stack, value_stack, operator_stack);
818 expression_stack.push_back(expr_stack_entry((unsigned int)value_stack.size(), (unsigned int)operator_stack.size()));
819 parenthesis_stack.push_back(EP_LIST_ACCESS);
820 break;
821 case EP_LIST_CLOSE:
822 {
823 ExpressionPart last_parenthesis = find_last_parenthesis(expression_stack, parenthesis_stack);
824 if (!compress_stack_evaluate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack)) {
825 last_error_token = expression_tokens[i];
826 found_error = true;
827 return false;
828 }
829 if (last_parenthesis == EP_LIST_OPEN) {
830 unsigned int n = get_nr_comma_separated_expressions(expression_stack, parenthesis_stack, value_stack);
831 variant v = variant(variant::list_type());
832 if (n > 0) {
833 std::vector<variant> tmp;
834 tmp.resize(n);
835 unsigned int i;
836 for (i = 0; i < n; ++i) {
837 tmp[n - i - 1] = value_stack.top();
838 value_stack.pop();
839 expression_stack.pop_back();
840 parenthesis_stack.pop_back();
841 }
842 for (i = 0; i < n; ++i)
843 v.append_to_list(tmp[i].get_value());
844 }
845 else {
846 expression_stack.pop_back();
847 parenthesis_stack.pop_back();
848 }
849 value_stack.push(v);
850 }
851 else {
852 variant var_idx = value_stack.top();
853 value_stack.pop();
854 expression_stack.pop_back();
855 parenthesis_stack.pop_back();
856 if (value_stack.top().is_map()) {
857 std::string var_name;
858 if (var_idx.is_int()) {
859 var_name = value_stack.top().get_element_name(var_idx.get_int());
860 value_stack.pop();
861 value_stack.push(var_name);
862 }
863 else {
864 if (var_idx.is_str())
865 var_name = var_idx.get_str();
866 else {
867 last_error = "map access key evaluate to name or string";
868 last_error_token = expression_tokens[i];
869 found_error = true;
870 return false;
871 }
872 variant tmp;
873 if (value_stack.top().is_reference()) {
874 tmp = variant(&value_stack.top().ref_element(var_name));
875 }
876 else
877 tmp = value_stack.top().get_element(var_name);
878 value_stack.pop();
879 value_stack.push(tmp);
880 }
881 }
882 else {
883 int idx = var_idx.get_int();
884 if (value_stack.top().is_list()) {
885 if (idx < 0)
886 idx += (int)value_stack.top().get_size();
887 if (idx < 0 || idx >= (int)value_stack.top().get_size()) {
888 last_error = "list access with index ";
889 last_error += to_string(idx) + " out of valid range [0," +
890 to_string(value_stack.top().get_size()) + "]";
891 last_error_token = expression_tokens[i];
892 found_error = true;
893 return false;
894 }
895 variant tmp;
896 if (value_stack.top().is_reference()) {
897 tmp = variant(&value_stack.top().ref_element(idx));
898 }
899 else
900 tmp = value_stack.top().get_element(idx);
901 value_stack.pop();
902 value_stack.push(tmp);
903 }
904 else if (value_stack.top().is_str()) {
905 int n = (int)value_stack.top().get_str().size();
906 if (idx < 0)
907 idx += n;
908 if (idx < 0 || idx >= n) {
909 last_error = "string access with index ";
910 last_error += to_string(idx) + " out of valid range [" +
911 to_string(-n) + "," + to_string(n - 1) + "]";
912 last_error_token = expression_tokens[i];
913 found_error = true;
914 return false;
915 }
916 variant tmp(std::string(1, value_stack.top().get_str()[idx]));
917 value_stack.pop();
918 value_stack.push(tmp);
919 }
920 else {
921 last_error = "applied list access operator to non list type";
922 last_error_token = expression_tokens[i];
923 found_error = true;
924 return false;
925 }
926 }
927 }
928 }
929 break;
930 case EP_COMMA:
931 if (!compress_stack_evaluate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack)) {
932 last_error_token = expression_tokens[i];
933 found_error = true;
934 return false;
935 }
936 expression_stack.push_back(expr_stack_entry((unsigned int)value_stack.size(), (unsigned int)operator_stack.size()));
937 parenthesis_stack.push_back(EP_COMMA);
938 break;
939 }
940 }
941 if (!compress_stack_evaluate(-1, expression_stack, parenthesis_stack, value_stack, operator_stack)) {
942 last_error_token = token(expression_tokens.front().begin, expression_tokens.back().end);
943 found_error = true;
944 return false;
945 }
946 result = value_stack.top();
947 if (debug_evaluate)
948 std::cout << "expression evaluated to " << result.get_str() << std::endl;
949 return true;
950 }
951
952 bool expression_processor::compress_stack_evaluate(int priority, std::vector<expr_stack_entry>& expression_stack,
953 std::vector<ExpressionPart>& parenthesis_stack,
954 std::stack<variant>& value_stack, std::stack<OperatorType>& operator_stack)
955 {
956 while (!found_error && !operator_stack.empty()) {
957 OperatorType ot = operator_stack.top();
958 if (priority > get_operator_priority(ot))
959 return true;
960 if (priority == get_operator_priority(ot) &&
961 get_operator_precedence(ot) == OP_RIGHT)
962 return true;
963 switch (get_operator_arity(ot)) {
964 case 1:
965 if (!expression_stack.empty() && operator_stack.size() <= expression_stack.back().second)
966 return true;
967 if (!value_stack.top().unary_check_defined(operator_stack.top())) {
968 last_error = std::string("applied unary operator ") +
969 get_operator_word(operator_stack.top()) + " to undefined value";
970 found_error = true;
971 }
972 else if (!value_stack.top().is_unary_applicable(operator_stack.top())) {
973 last_error = std::string("could not apply unary operator ") +
974 get_operator_word(ot);
975 found_error = true;
976 }
977 else {
978 value_stack.top().apply_unary(operator_stack.top());
979 if (check_cyclic_reference(&value_stack.top())) {
980 last_error = std::string("generated cyclic reference");
981 found_error = true;
982 }
983 if (debug_evaluate)
984 std::cout << "applied unary operator " << get_operator_word(operator_stack.top()) << std::endl;
985 }
986 operator_stack.pop();
987 break;
988 case 2:
989 if (!expression_stack.empty() && operator_stack.size() <= expression_stack.back().second)
990 return true;
991 else {
992 variant v2 = value_stack.top();
993 value_stack.pop();
994 if (!value_stack.top().is_binary_applicable(operator_stack.top(), v2)) {
995 last_error = std::string("could not apply binary operator ") +
996 get_operator_word(ot);
997 found_error = true;
998 }
999 if (!value_stack.top().binary_check_defined(operator_stack.top(), v2)) {
1000 last_error = std::string("applied binary operator ") +
1001 get_operator_word(operator_stack.top()) + " to undefined value";
1002 found_error = true;
1003 }
1004 value_stack.top().apply_binary(operator_stack.top(), v2);
1005 if (check_cyclic_reference(&value_stack.top())) {
1006 last_error = std::string("generated cyclic reference");
1007 found_error = true;
1008 }
1009 if (debug_evaluate)
1010 std::cout << "applied binary operator " << get_operator_word(operator_stack.top()) << std::endl;
1011 operator_stack.pop();
1012 break;
1013 }
1014 }
1015 }
1016 return !found_error;
1017 }
1018
1019 bool expression_processor::compress_stack_validate(int priority, std::vector<expr_stack_entry>& expression_stack,
1020 std::vector<ExpressionPart>& parenthesis_stack,
1021 std::stack<variant>& value_stack, std::stack<OperatorType>& operator_stack)
1022 {
1023 while (!operator_stack.empty()) {
1024 OperatorType ot = operator_stack.top();
1025 if (priority > get_operator_priority(ot))
1026 return true;
1027 if (priority == get_operator_priority(ot) &&
1028 get_operator_precedence(ot) == OP_RIGHT)
1029 return true;
1030 switch (get_operator_arity(ot)) {
1031 case 1:
1032 if (!expression_stack.empty() && operator_stack.size() <= expression_stack.back().second)
1033 return true;
1034 if (value_stack.empty()) {
1035 last_error = std::string("no value to apply unary operator ") +
1036 get_operator_word(ot);
1037 return false;
1038 }
1039 operator_stack.pop();
1040 break;
1041 case 2:
1042 if (!expression_stack.empty() && operator_stack.size() <= expression_stack.back().second)
1043 return true;
1044 if (value_stack.size() < 2) {
1045 last_error = std::string("no 2 values to apply binary operator ") +
1046 get_operator_word(ot);
1047 return false;
1048 }
1049 else {
1050 variant v2 = value_stack.top();
1051 value_stack.pop();
1052 operator_stack.pop();
1053 break;
1054 }
1055 }
1056 }
1057 return true;
1058 }
1059
1060 const std::string& expression_processor::get_last_error() const
1061 {
1062 return last_error;
1063 }
1064
1065 const token& expression_processor::get_last_error_token() const
1066 {
1067 return last_error_token;
1068 }
1069
1070 }
1071}
bool evaluate(variant &result, ph_processor *ph_proc)
bool validate(bool allow_several_values=false)
the pre header processor parses a pre header file and converts it to a header file or uses the inform...
std::string get_str() const
lookup names and follow references and convert to string
const std::string & get_element_name(unsigned int i) const
return the name of the i-th element in a map
bool is_int() const
lookup names and follow references and return whether variant is int
int get_int() const
lookup names and follow references and convert to int: undef ... -1, bool ... 0 or 1,...
func_type & ref_func()
access to func value
bool is_func() const
lookup names and follow references and return whether variant is func
variant & ref_value()
lookup names and follow references and return reference to the reached variant
const variant & get_element(unsigned int i) const
return a const reference to the i-th element in a list or map
bool is_str() const
lookup names and follow references and return whether variant is string
the tokenizer allows to split text into tokens in a convenient way.
Definition tokenizer.h:68
namespace that holds tools that dont fit any other namespace
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
std::string interpret_special(const std::string &s)
interprets the C++ special characters \a, \b, \f, \n, \r, \t, \v, \\', \", \\, \?,...
Definition scan.cxx:227
bool is_integer(const char *begin, const char *end, int &value)
check if the text range (begin,end( defines an integer value. If yes, store the value in the passed r...
Definition scan.cxx:367
void bite_all(tokenizer &t, std::vector< token > &result)
bite all tokens into a token vector
Definition tokenizer.h:121
bool is_double(const char *begin, const char *end, double &value)
check if the text range (begin,end( defines a double value. If yes, store the value in the passed ref...
Definition scan.cxx:426
bool is_element(char c, const std::string &s)
check if char c arises in string s
Definition scan.cxx:291
the cgv namespace
Definition print.h:11
Helper functions to process strings.
representation of a token in a text by two pointers begin and end, that point to the first character ...
Definition token.h:18