1 : // $Id: ExpressionParser.cc 59 2007-07-17 14:43:23Z tb $
2 :
3 : /*
4 : * STX Expression Parser C++ Framework v0.7
5 : * Copyright (C) 2007 Timo Bingmann
6 : *
7 : * This library is free software; you can redistribute it and/or modify it
8 : * under the terms of the GNU Lesser General Public License as published by the
9 : * Free Software Foundation; either version 2.1 of the License, or (at your
10 : * option) any later version.
11 : *
12 : * This library is distributed in the hope that it will be useful, but WITHOUT
13 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15 : * for more details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public License
18 : * along with this library; if not, write to the Free Software Foundation,
19 : * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 : */
21 :
22 : /** \file ExpressionParser.cc
23 : * Implementation of the parser using a boost::spirit grammar and a different
24 : * specializations of ParseNode.
25 : */
26 :
27 : #include "ExpressionParser.h"
28 :
29 : #include <boost/spirit/core.hpp>
30 :
31 : #include <boost/spirit/tree/ast.hpp>
32 : #include <boost/spirit/tree/tree_to_xml.hpp>
33 :
34 : #include <boost/spirit/utility/lists.hpp>
35 : #include <boost/spirit/utility/distinct.hpp>
36 : #include <boost/spirit/utility/escape_char.hpp>
37 : #include <boost/spirit/utility/grammar_def.hpp>
38 :
39 : #include <iostream>
40 : #include <sstream>
41 : #include <cmath>
42 :
43 : // #define STX_DEBUG_PARSER
44 :
45 : namespace stx {
46 :
47 : /// Enclosure for the spirit parser grammar and hidden parse node
48 : /// implementation classes.
49 : namespace Grammar {
50 :
51 : using namespace boost::spirit;
52 :
53 : /// This enum specifies ids for the parse tree nodes created for each rule.
54 : enum parser_ids
55 : {
56 : boolean_const_id = 1,
57 : integer_const_id,
58 : long_const_id,
59 : double_const_id,
60 : string_const_id,
61 : constant_id,
62 :
63 : function_call_id,
64 : function_identifier_id,
65 :
66 : varname_id,
67 :
68 : atom_expr_id,
69 :
70 : unary_expr_id,
71 : mul_expr_id,
72 : add_expr_id,
73 :
74 : cast_expr_id,
75 : cast_spec_id,
76 :
77 : comp_expr_id,
78 : and_expr_id,
79 : or_expr_id,
80 :
81 : expr_id,
82 : exprlist_id,
83 : };
84 :
85 : /// Keyword parser used for matching words with () and spaces as separators.
86 2 : distinct_parser<> keyword_p("a-zA-Z0-9_");
87 :
88 : /// The boost::spirit expression parser grammar
89 : struct ExpressionGrammar : public grammar<ExpressionGrammar>
90 72 : {
91 : /// The boost::spirit expression parser grammar definition (for a specific
92 : /// scanner) with two entry points.
93 : template <typename ScannerT>
94 : struct definition : public grammar_def<rule<ScannerT, parser_context<>, parser_tag<expr_id> >,
95 : rule<ScannerT, parser_context<>, parser_tag<exprlist_id> > >
96 36 : {
97 : /// Real definition function of the grammar.
98 36 : definition(ExpressionGrammar const& /*self*/)
99 36 : {
100 : // *** Constants
101 :
102 36 : constant
103 : = double_const
104 : | integer_const
105 : | long_const
106 : | boolean_const
107 : | string_const
108 : ;
109 :
110 36 : boolean_const
111 : = as_lower_d[keyword_p("true") | keyword_p("false")]
112 : ;
113 :
114 36 : integer_const
115 : = int_p
116 : ;
117 :
118 : // this is needed because spirit's int_parsers don't work with
119 : // these long numbers
120 36 : long_const
121 : = token_node_d[ lexeme_d[ !( ch_p('+') | ch_p('-' ) ) >> +( range_p('0','9') ) ] ]
122 : ;
123 :
124 36 : double_const
125 : = strict_real_p
126 : ;
127 :
128 36 : string_const
129 : = lexeme_d[
130 : token_node_d[ '"' >> *(c_escape_ch_p - '"') >> '"' ]
131 : ]
132 : ;
133 :
134 : // *** Function call and function identifier
135 :
136 36 : function_call
137 : = root_node_d[function_identifier]
138 : >> discard_node_d[ ch_p('(') ] >> exprlist >> discard_node_d[ ch_p(')') ]
139 : ;
140 :
141 36 : function_identifier
142 : = lexeme_d[
143 : token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
144 : ]
145 : ;
146 :
147 : // *** Expression names
148 :
149 36 : varname
150 : = lexeme_d[
151 : token_node_d[ alpha_p >> *(alnum_p | ch_p('_')) ]
152 : ]
153 : ;
154 :
155 : // *** Valid Expressions, from small to large
156 :
157 36 : atom_expr
158 : = constant
159 : | inner_node_d[ ch_p('(') >> expr >> ch_p(')') ]
160 : | function_call
161 : | varname
162 : ;
163 :
164 36 : unary_expr
165 : = !( root_node_d[ as_lower_d[ch_p('+') | ch_p('-') | ch_p('!') | str_p("not")] ] )
166 : >> atom_expr
167 : ;
168 :
169 36 : cast_spec
170 : = discard_node_d[ ch_p('(') ]
171 : >> (
172 : keyword_p("bool") |
173 : keyword_p("char") | keyword_p("short") | keyword_p("int") | keyword_p("integer") | keyword_p("long") |
174 : keyword_p("byte") | keyword_p("word") | keyword_p("dword") | keyword_p("qword") |
175 : keyword_p("float") | keyword_p("double") |
176 : keyword_p("string")
177 : )
178 : >> discard_node_d[ ch_p(')') ]
179 : ;
180 :
181 36 : cast_expr
182 : = root_node_d[ !cast_spec ] >> unary_expr
183 : ;
184 :
185 36 : mul_expr
186 : = cast_expr
187 : >> *( root_node_d[ch_p('*') | ch_p('/')] >> cast_expr )
188 : ;
189 :
190 36 : add_expr
191 : = mul_expr
192 : >> *( root_node_d[ch_p('+') | ch_p('-')] >> mul_expr )
193 : ;
194 :
195 36 : comp_expr
196 : = add_expr
197 : >> *( root_node_d[( str_p("==") | str_p("!=") |
198 : str_p("<=") | str_p(">=") | str_p("=<") | str_p("=>") |
199 : ch_p('=') | ch_p('<') | ch_p('>') )] >> add_expr )
200 : ;
201 :
202 36 : and_expr
203 : = comp_expr
204 : >> *( root_node_d[ as_lower_d[str_p("and") | str_p("&&")] ] >> comp_expr )
205 : ;
206 :
207 36 : or_expr
208 : = and_expr
209 : >> *( root_node_d[ as_lower_d[str_p("or") | str_p("||")] ] >> and_expr )
210 : ;
211 :
212 : // *** Base Expression and List
213 :
214 36 : expr
215 : = or_expr
216 : ;
217 :
218 36 : exprlist
219 : = infix_node_d[ !list_p(expr, ch_p(',')) ]
220 : ;
221 :
222 : // Special spirit feature to declare multiple grammar entry points
223 36 : this->start_parsers(expr, exprlist);
224 :
225 : #ifdef STX_DEBUG_PARSER
226 : BOOST_SPIRIT_DEBUG_RULE(constant);
227 :
228 : BOOST_SPIRIT_DEBUG_RULE(boolean_const);
229 : BOOST_SPIRIT_DEBUG_RULE(integer_const);
230 : BOOST_SPIRIT_DEBUG_RULE(long_const);
231 : BOOST_SPIRIT_DEBUG_RULE(double_const);
232 : BOOST_SPIRIT_DEBUG_RULE(string_const);
233 :
234 : BOOST_SPIRIT_DEBUG_RULE(function_call);
235 : BOOST_SPIRIT_DEBUG_RULE(function_identifier);
236 :
237 : BOOST_SPIRIT_DEBUG_RULE(varname);
238 :
239 : BOOST_SPIRIT_DEBUG_RULE(atom_expr);
240 :
241 : BOOST_SPIRIT_DEBUG_RULE(unary_expr);
242 : BOOST_SPIRIT_DEBUG_RULE(mul_expr);
243 : BOOST_SPIRIT_DEBUG_RULE(add_expr);
244 :
245 : BOOST_SPIRIT_DEBUG_RULE(cast_spec);
246 : BOOST_SPIRIT_DEBUG_RULE(cast_expr);
247 :
248 : BOOST_SPIRIT_DEBUG_RULE(comp_expr);
249 : BOOST_SPIRIT_DEBUG_RULE(and_expr);
250 : BOOST_SPIRIT_DEBUG_RULE(or_expr);
251 :
252 : BOOST_SPIRIT_DEBUG_RULE(expr);
253 : BOOST_SPIRIT_DEBUG_RULE(exprlist);
254 : #endif
255 : }
256 :
257 : /// Rule for a constant: one of the three scalar types integer_const,
258 : /// double_const or string_const
259 : rule<ScannerT, parser_context<>, parser_tag<constant_id> > constant;
260 :
261 : /// Boolean value constant rule: "true" or "false"
262 : rule<ScannerT, parser_context<>, parser_tag<boolean_const_id> > boolean_const;
263 : /// Integer constant rule: "1234"
264 : rule<ScannerT, parser_context<>, parser_tag<integer_const_id> > integer_const;
265 : /// Long integer constant rule: "12345452154"
266 : rule<ScannerT, parser_context<>, parser_tag<long_const_id> > long_const;
267 : /// Float constant rule: "1234.3"
268 : rule<ScannerT, parser_context<>, parser_tag<double_const_id> > double_const;
269 : /// String constant rule: with quotes "abc"
270 : rule<ScannerT, parser_context<>, parser_tag<string_const_id> > string_const;
271 :
272 : /// Function call rule: func1(a,b,c) where a,b,c is a list of exprs
273 : rule<ScannerT, parser_context<>, parser_tag<function_call_id> > function_call;
274 : /// Function rule to match a function identifier: alphanumeric and _
275 : /// are allowed.
276 : rule<ScannerT, parser_context<>, parser_tag<function_identifier_id> > function_identifier;
277 :
278 : /// Rule to match a variable name: alphanumeric with _
279 : rule<ScannerT, parser_context<>, parser_tag<varname_id> > varname;
280 :
281 : /// Helper rule which implements () bracket grouping.
282 : rule<ScannerT, parser_context<>, parser_tag<atom_expr_id> > atom_expr;
283 :
284 : /// Unary operator rule: recognizes + - ! and "not".
285 : rule<ScannerT, parser_context<>, parser_tag<unary_expr_id> > unary_expr;
286 : /// Binary operator rule taking precedent before add_expr:
287 : /// recognizes * and /
288 : rule<ScannerT, parser_context<>, parser_tag<mul_expr_id> > mul_expr;
289 : /// Binary operator rule: recognizes + and -
290 : rule<ScannerT, parser_context<>, parser_tag<add_expr_id> > add_expr;
291 :
292 : /// Match all the allowed cast types: short, double, etc.
293 : rule<ScannerT, parser_context<>, parser_tag<cast_spec_id> > cast_spec;
294 : /// Cast operator written like in C: (short)
295 : rule<ScannerT, parser_context<>, parser_tag<cast_expr_id> > cast_expr;
296 :
297 : /// Comparison operator: recognizes == = != <= >= < > => =<
298 : rule<ScannerT, parser_context<>, parser_tag<comp_expr_id> > comp_expr;
299 : /// Boolean operator: recognizes && and "and" and works only on boolean
300 : /// values
301 : rule<ScannerT, parser_context<>, parser_tag<and_expr_id> > and_expr;
302 : /// Boolean operator: recognizes || and "or" and works only on boolean
303 : /// values
304 : rule<ScannerT, parser_context<>, parser_tag<or_expr_id> > or_expr;
305 :
306 : /// Base rule to match an expression
307 : rule<ScannerT, parser_context<>, parser_tag<expr_id> > expr;
308 : /// Base rule to match a comma-separated list of expressions (used for
309 : /// function arguments and lists of expressions)
310 : rule<ScannerT, parser_context<>, parser_tag<exprlist_id> > exprlist;
311 : };
312 : };
313 :
314 : // *** Classes representing the nodes in the resulting parse tree, these need
315 : // *** not be publicly available via the header file.
316 :
317 : /// Constant value nodes of the parse tree. This class holds any of the three
318 : /// constant types in the enclosed AnyScalar object.
319 : class PNConstant : public ParseNode
320 132 : {
321 : private:
322 : /// The constant parsed value.
323 : class AnyScalar value;
324 :
325 : public:
326 : /// Assignment from the string received from the parser.
327 86 : PNConstant(AnyScalar::attrtype_t type, std::string strvalue)
328 86 : : ParseNode(), value(type)
329 : {
330 : // check whether to dequote the incoming string.
331 86 : if (type == AnyScalar::ATTRTYPE_STRING)
332 6 : value.setStringQuoted(strvalue);
333 : else
334 80 : value.setString(strvalue); // not a string, but an integer or double or boolean value
335 86 : }
336 :
337 : /// constructor for folded constant values.
338 46 : PNConstant(const AnyScalar &_value)
339 46 : : value(_value)
340 : {
341 46 : }
342 :
343 : /// Easiest evaluation: return the constant.
344 24 : virtual AnyScalar evaluate(const class SymbolTable &) const
345 : {
346 24 : return value;
347 : }
348 :
349 : /// Returns true, because value is constant
350 176 : virtual bool evaluate_const(AnyScalar *dest) const
351 : {
352 176 : if (dest) *dest = value;
353 176 : return true;
354 : }
355 :
356 : /// String representation of the constant AnyScalar value.
357 48 : virtual std::string toString() const
358 : {
359 48 : if (value.getType() == AnyScalar::ATTRTYPE_STRING) {
360 4 : return value.getStringQuoted();
361 : }
362 44 : return value.getString();
363 : }
364 : };
365 :
366 : /// Parse tree node representing a variable place-holder. It is filled when
367 : /// parameterized by a symbol table.
368 : class PNVariable : public ParseNode
369 8 : {
370 : private:
371 : /// String name of the variable
372 : std::string varname;
373 :
374 : public:
375 : /// Constructor from the string received from the parser.
376 8 : PNVariable(std::string _varname)
377 8 : : ParseNode(), varname(_varname)
378 : {
379 8 : }
380 :
381 : /// Check the given symbol table for the actual value of this variable.
382 4 : virtual AnyScalar evaluate(const class SymbolTable &st) const
383 : {
384 4 : return st.lookupVariable(varname);
385 : }
386 :
387 : /// Returns false, because value isn't constant.
388 8 : virtual bool evaluate_const(AnyScalar *) const
389 : {
390 8 : return false;
391 : }
392 :
393 : /// Nothing but the variable name.
394 8 : virtual std::string toString() const
395 : {
396 8 : return varname;
397 : }
398 : };
399 :
400 : /// Parse tree node representing a function place-holder. It is filled when
401 : /// parameterized by a symbol table.
402 : class PNFunction : public ParseNode
403 : {
404 : public:
405 : /// Type of sequence of subtrees to evaluate as function parameters.
406 : typedef std::vector<const class ParseNode*> paramlist_type;
407 :
408 : private:
409 : /// String name of the function
410 : std::string funcname;
411 :
412 : /// The array of function parameter subtrees
413 : paramlist_type paramlist;
414 :
415 : public:
416 : /// Constructor from the string received from the parser.
417 12 : PNFunction(std::string _funcname, const paramlist_type& _paramlist)
418 12 : : ParseNode(), funcname(_funcname), paramlist(_paramlist)
419 : {
420 12 : }
421 :
422 : /// Delete the paramlist
423 12 : ~PNFunction()
424 12 : {
425 26 : for(unsigned int i = 0; i < paramlist.size(); ++i)
426 14 : delete paramlist[i];
427 12 : }
428 :
429 : /// Check the given symbol table for the actual value of this variable.
430 6 : virtual AnyScalar evaluate(const class SymbolTable &st) const
431 : {
432 6 : std::vector<AnyScalar> paramvalues;
433 :
434 13 : for(unsigned int i = 0; i < paramlist.size(); ++i)
435 : {
436 7 : paramvalues.push_back( paramlist[i]->evaluate(st) );
437 : }
438 :
439 6 : return st.processFunction(funcname, paramvalues);
440 : }
441 :
442 : /// Returns false, because value isn't constant.
443 6 : virtual bool evaluate_const(AnyScalar *) const
444 : {
445 6 : return false;
446 : }
447 :
448 : /// Nothing but the function and its parameters
449 12 : virtual std::string toString() const
450 : {
451 12 : std::string str = funcname + "(";
452 26 : for(unsigned int i = 0; i < paramlist.size(); ++i)
453 : {
454 14 : if (i != 0) str += ",";
455 14 : str += paramlist[i]->toString();
456 : }
457 12 : return str + ")";
458 : }
459 : };
460 :
461 : /// Parse tree node representing an unary operator: '+', '-', '!' or
462 : /// "not". This node has one child.
463 : class PNUnaryArithmExpr : public ParseNode
464 : {
465 : private:
466 : /// Pointer to the single operand
467 : const ParseNode *operand;
468 :
469 : /// Arithmetic operation to perform: either '+', '-' or '!'. Further
470 : /// optimization would be to create an extra class for each op
471 : char op;
472 :
473 : public:
474 : /// Constructor from the parser: operand subnode and operator id.
475 8 : PNUnaryArithmExpr(const ParseNode* _operand, char _op)
476 8 : : ParseNode(), operand(_operand), op(_op)
477 : {
478 8 : if (op == 'n' || op == 'N') op = '!';
479 8 : }
480 :
481 : /// Recursively delete the parse tree.
482 8 : virtual ~PNUnaryArithmExpr()
483 8 : {
484 8 : delete operand;
485 8 : }
486 :
487 : /// Applies the operator to the recursively calculated value.
488 1 : virtual AnyScalar evaluate(const class SymbolTable &st) const
489 : {
490 1 : AnyScalar dest = operand->evaluate(st);
491 :
492 1 : if (op == '-') {
493 1 : dest = -dest;
494 : }
495 0 : else if (op == '!')
496 : {
497 : // This should not happend, as types are constant in the parse tree
498 0 : if (dest.getType() != AnyScalar::ATTRTYPE_BOOL)
499 0 : throw(BadSyntaxException("Invalid operand for !. Operand must be of type bool."));
500 :
501 0 : dest = -dest;
502 : }
503 : else {
504 0 : assert(op == '+');
505 : }
506 :
507 0 : return dest;
508 : }
509 :
510 : /// Calculates subnodes and returns result if the operator can be applied.
511 8 : virtual bool evaluate_const(AnyScalar *dest) const
512 : {
513 8 : if (!dest) return false;
514 :
515 6 : bool b = operand->evaluate_const(dest);
516 :
517 6 : if (op == '-') {
518 4 : *dest = -(*dest);
519 : }
520 2 : else if (op == '!')
521 : {
522 2 : if (dest->getType() != AnyScalar::ATTRTYPE_BOOL)
523 0 : throw(BadSyntaxException("Invalid operand for !. Operand must be of type bool."));
524 :
525 2 : *dest = -(*dest);
526 : }
527 : else {
528 0 : assert(op == '+');
529 : }
530 :
531 6 : return b;
532 : }
533 :
534 : /// Return the subnode's string with this operator prepended.
535 2 : virtual std::string toString() const
536 : {
537 2 : return std::string("(") + op + " " + operand->toString() + ")";
538 : }
539 : };
540 :
541 : /// Parse tree node representing a binary operators: +, -, * and / for numeric
542 : /// values. This node has two children.
543 : class PNBinaryArithmExpr : public ParseNode
544 : {
545 : private:
546 : /// Pointers to the left of the two child parse trees.
547 : const ParseNode *left;
548 :
549 : /// Pointers to the right of the two child parse trees.
550 : const ParseNode *right;
551 :
552 : /// Arithmetic operation to perform: left op right.
553 : /// Further optimization would be to create an extra class for each op
554 : char op;
555 :
556 : public:
557 : /// Constructor from the parser: both operand subnodes and the operator id.
558 : PNBinaryArithmExpr(const ParseNode* _left,
559 : const ParseNode* _right,
560 28 : char _op)
561 : : ParseNode(),
562 28 : left(_left), right(_right), op(_op)
563 28 : { }
564 :
565 : /// Recursively delete parse tree.
566 28 : virtual ~PNBinaryArithmExpr()
567 28 : {
568 28 : delete left;
569 28 : delete right;
570 28 : }
571 :
572 : /// Applies the operator to the two recursive calculated values. The actual
573 : /// switching between types is handled by AnyScalar's operators.
574 8 : virtual AnyScalar evaluate(const class SymbolTable &st) const
575 : {
576 8 : AnyScalar vl = left->evaluate(st);
577 8 : AnyScalar vr = right->evaluate(st);
578 :
579 5 : if (op == '+') {
580 3 : return (vl + vr);
581 : }
582 2 : else if (op == '-') {
583 0 : return (vl - vr);
584 : }
585 2 : else if (op == '*') {
586 1 : return (vl * vr);
587 : }
588 1 : else if (op == '/') {
589 1 : return (vl / vr);
590 : }
591 :
592 0 : assert(0);
593 0 : return 0;
594 : }
595 :
596 : /// Returns false because this node isn't always constant. Tries to
597 : /// calculate a constant subtree's value.
598 20 : virtual bool evaluate_const(AnyScalar *dest) const
599 : {
600 20 : if (!dest) return false;
601 :
602 12 : AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
603 :
604 12 : bool bl = left->evaluate_const(&vl);
605 12 : bool br = right->evaluate_const(&vr);
606 :
607 12 : if (op == '+') {
608 7 : *dest = vl + vr;
609 : }
610 5 : else if (op == '-') {
611 1 : *dest = vl - vr;
612 : }
613 4 : else if (op == '*') {
614 4 : *dest = vl * vr;
615 : }
616 0 : else if (op == '/') {
617 0 : *dest = vl / vr;
618 : }
619 :
620 12 : return (bl && br);
621 : }
622 :
623 : /// String representing (operandA op operandB)
624 16 : virtual std::string toString() const
625 : {
626 16 : return std::string("(") + left->toString() + " " + op + " " + right->toString() + ")";
627 : }
628 : };
629 :
630 : /// Parse tree node handling type conversions within the tree.
631 : class PNCastExpr : public ParseNode
632 : {
633 : private:
634 : /// Child tree of which the return value should be casted.
635 : const ParseNode* operand;
636 :
637 : /// AnyScalar type to cast the value to.
638 : AnyScalar::attrtype_t type;
639 :
640 : public:
641 : /// Constructor from the parser: operand subnode and the cast type as
642 : /// recognized by AnyScalar.
643 4 : PNCastExpr(const ParseNode* _operand, AnyScalar::attrtype_t _type)
644 : : ParseNode(),
645 4 : operand(_operand), type(_type)
646 4 : { }
647 :
648 : /// Recursively delete parse tree.
649 4 : virtual ~PNCastExpr()
650 4 : {
651 4 : delete operand;
652 4 : }
653 :
654 : /// Recursive calculation of the value and subsequent casting via
655 : /// AnyScalar's convertType method.
656 1 : virtual AnyScalar evaluate(const class SymbolTable &st) const
657 : {
658 1 : AnyScalar val = operand->evaluate(st);
659 1 : val.convertType(type);
660 0 : return val;
661 : }
662 :
663 : /// Returns false because this node isn't always constant.
664 2 : virtual bool evaluate_const(AnyScalar *dest) const
665 : {
666 2 : if (!dest) return false;
667 :
668 2 : bool b = operand->evaluate_const(dest);
669 2 : dest->convertType(type);
670 2 : return b;
671 : }
672 :
673 : /// c-like representation of the cast
674 2 : virtual std::string toString() const
675 : {
676 2 : return std::string("((") + AnyScalar::getTypeString(type) + ")" + operand->toString() + ")";
677 : }
678 : };
679 :
680 : /// Parse tree node representing a binary comparison operator: ==, =, !=, <, >,
681 : /// >=, <=, =>, =<. This node has two children.
682 : class PNBinaryComparisonExpr : public ParseNode
683 : {
684 : private:
685 : /// Pointers to the left of the two child parse trees.
686 : const ParseNode *left;
687 :
688 : /// Pointers to the right of the two child parse trees.
689 : const ParseNode *right;
690 :
691 : /// Comparison operation to perform: left op right
692 : enum { EQUAL, NOTEQUAL, LESS, GREATER, LESSEQUAL, GREATEREQUAL } op;
693 :
694 : /// String saved for toString()
695 : std::string opstr;
696 :
697 : public:
698 : /// Constructor from the parser: both operand subnodes and the operator id.
699 : PNBinaryComparisonExpr(const ParseNode* _left,
700 : const ParseNode* _right,
701 17 : std::string _op)
702 : : ParseNode(),
703 17 : left(_left), right(_right), opstr(_op)
704 : {
705 17 : if (_op == "==" || _op == "=")
706 7 : op = EQUAL;
707 10 : else if (_op == "!=")
708 1 : op = NOTEQUAL;
709 9 : else if (_op == "<")
710 1 : op = LESS;
711 8 : else if (_op == ">")
712 2 : op = GREATER;
713 6 : else if (_op == "<=" || _op == "=<")
714 3 : op = LESSEQUAL;
715 3 : else if (_op == ">=" || _op == "=>")
716 3 : op = GREATEREQUAL;
717 : else
718 0 : throw(BadSyntaxException("Program Error: invalid binary comparision operator."));
719 17 : }
720 :
721 : /// Recursively delete parse tree.
722 17 : virtual ~PNBinaryComparisonExpr()
723 17 : {
724 17 : delete left;
725 17 : delete right;
726 17 : }
727 :
728 : /// Applies the operator to the two recursive calculated values. The actual
729 : /// switching between types is handled by AnyScalar's operators. This
730 : /// result type of this processing node is always bool.
731 2 : virtual AnyScalar evaluate(const class SymbolTable &st) const
732 : {
733 2 : AnyScalar vl = left->evaluate(st);
734 2 : AnyScalar vr = right->evaluate(st);
735 :
736 2 : AnyScalar dest(AnyScalar::ATTRTYPE_BOOL);
737 :
738 2 : switch(op)
739 : {
740 : case EQUAL:
741 2 : dest = AnyScalar( vl.equal_to(vr) );
742 2 : break;
743 :
744 : case NOTEQUAL:
745 0 : dest = AnyScalar( vl.not_equal_to(vr) );
746 0 : break;
747 :
748 : case LESS:
749 0 : dest = AnyScalar( vl.less(vr) );
750 0 : break;
751 :
752 : case GREATER:
753 0 : dest = AnyScalar( vl.greater(vr) );
754 0 : break;
755 :
756 : case LESSEQUAL:
757 0 : dest = AnyScalar( vl.less_equal(vr) );
758 0 : break;
759 :
760 : case GREATEREQUAL:
761 0 : dest = AnyScalar( vl.greater_equal(vr) );
762 0 : break;
763 :
764 : default:
765 0 : assert(0);
766 : }
767 :
768 2 : return dest;
769 : }
770 :
771 : /// Returns false because this node isn't always constant.
772 13 : virtual bool evaluate_const(AnyScalar *dest) const
773 : {
774 13 : if (!dest) return false;
775 :
776 13 : AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
777 :
778 13 : bool bl = left->evaluate_const(&vl);
779 13 : bool br = right->evaluate_const(&vr);
780 :
781 13 : switch(op)
782 : {
783 : case EQUAL:
784 3 : *dest = AnyScalar( vl.equal_to(vr) );
785 3 : break;
786 :
787 : case NOTEQUAL:
788 1 : *dest = AnyScalar( vl.not_equal_to(vr) );
789 1 : break;
790 :
791 : case LESS:
792 1 : *dest = AnyScalar( vl.less(vr) );
793 1 : break;
794 :
795 : case GREATER:
796 2 : *dest = AnyScalar( vl.greater(vr) );
797 2 : break;
798 :
799 : case LESSEQUAL:
800 3 : *dest = AnyScalar( vl.less_equal(vr) );
801 3 : break;
802 :
803 : case GREATEREQUAL:
804 3 : *dest = AnyScalar( vl.greater_equal(vr) );
805 3 : break;
806 :
807 : default:
808 0 : assert(0);
809 : }
810 :
811 13 : return (bl && br);
812 : }
813 :
814 : /// String (operandA op operandB)
815 4 : virtual std::string toString() const
816 : {
817 4 : return std::string("(") + left->toString() + " " + opstr + " " + right->toString() + ")";
818 : }
819 : };
820 :
821 : /// Parse tree node representing a binary logic operator: and, or, &&, ||. This
822 : /// node has two children.
823 : class PNBinaryLogicExpr : public ParseNode
824 : {
825 : private:
826 : /// Pointers to the left of the two child parse trees.
827 : ParseNode* left;
828 :
829 : /// Pointers to the right of the two child parse trees.
830 : ParseNode* right;
831 :
832 : /// Comparison operation to perform: left op right
833 : enum { OP_AND, OP_OR } op;
834 :
835 : public:
836 : /// Constructor from the parser: both operand subnodes and the operator id.
837 : PNBinaryLogicExpr(ParseNode* _left,
838 : ParseNode* _right,
839 13 : std::string _op)
840 : : ParseNode(),
841 13 : left(_left), right(_right)
842 : {
843 13 : if (_op == "and" || _op == "&&")
844 10 : op = OP_AND;
845 3 : else if (_op == "or" || _op == "||")
846 3 : op = OP_OR;
847 : else
848 0 : throw(BadSyntaxException("Program Error: invalid binary logic operator."));
849 13 : }
850 :
851 : /// Recursively delete parse tree.
852 13 : virtual ~PNBinaryLogicExpr()
853 13 : {
854 13 : if (left) delete left;
855 13 : if (right) delete right;
856 13 : }
857 :
858 : /// Calculate the operator
859 13 : inline bool do_operator(bool left, bool right) const
860 : {
861 13 : if (op == OP_AND)
862 10 : return left && right;
863 3 : else if (op == OP_OR)
864 3 : return left || right;
865 : else
866 0 : return false;
867 : }
868 :
869 : /// Return the string of this operator
870 0 : inline std::string get_opstr() const
871 : {
872 0 : return (op == OP_AND) ? "&&" : "||";
873 : }
874 :
875 : /// Applies the operator to the two recursive calculated values. The actual
876 : /// switching between types is handled by AnyScalar's operators.
877 0 : virtual AnyScalar evaluate(const class SymbolTable &st) const
878 : {
879 0 : AnyScalar vl = left->evaluate(st);
880 0 : AnyScalar vr = right->evaluate(st);
881 :
882 : // these should never happen.
883 0 : if (vl.getType() != AnyScalar::ATTRTYPE_BOOL)
884 0 : throw(BadSyntaxException(std::string("Invalid left operand for ") + get_opstr() + ". Both operands must be of type bool."));
885 0 : if (vr.getType() != AnyScalar::ATTRTYPE_BOOL)
886 0 : throw(BadSyntaxException(std::string("Invalid right operand for ") + get_opstr() + ". Both operands must be of type bool."));
887 :
888 0 : int bvl = vl.getInteger();
889 0 : int bvr = vr.getInteger();
890 :
891 0 : return AnyScalar( do_operator(bvl, bvr) );
892 : }
893 :
894 : /// Applies the operator to the two recursive calculated const
895 : /// values. Determining if this node is constant is somewhat more tricky
896 : /// than with the other parse nodes: AND with a false operand is always
897 : /// false. OR with a true operand is always true.
898 13 : virtual bool evaluate_const(AnyScalar *dest) const
899 : {
900 13 : if (!dest) return false; // returns false because this node isn't always constant
901 :
902 13 : AnyScalar vl(AnyScalar::ATTRTYPE_INVALID), vr(AnyScalar::ATTRTYPE_INVALID);
903 :
904 13 : bool bl = left->evaluate_const(&vl);
905 13 : bool br = right->evaluate_const(&vr);
906 :
907 13 : if (vl.getType() != AnyScalar::ATTRTYPE_BOOL)
908 0 : throw(BadSyntaxException(std::string("Invalid left operand for ") + get_opstr() + ". Both operands must be of type bool."));
909 13 : if (vr.getType() != AnyScalar::ATTRTYPE_BOOL)
910 0 : throw(BadSyntaxException(std::string("Invalid right operand for ") + get_opstr() + ". Both operands must be of type bool."));
911 :
912 13 : int bvl = vl.getInteger();
913 13 : int bvr = vr.getInteger();
914 :
915 13 : *dest = AnyScalar( do_operator(bvl, bvr) );
916 :
917 13 : if (op == OP_AND)
918 : {
919 : // true if either both ops are themselves constant, or if either of
920 : // the ops are constant and evaluates to false.
921 23 : return (bl && br) || (bl && !bvl) || (br && !bvr);
922 : }
923 3 : else if (op == OP_OR)
924 : {
925 : // true if either both ops are themselves constant, or if either of
926 : // the ops is constant and evaluates to true.
927 3 : return (bl && br) || (bl && bvl) || (br && bvr);
928 : }
929 : else {
930 0 : assert(0);
931 : return false;
932 0 : }
933 : }
934 :
935 : /// String (operandA op operandB)
936 0 : virtual std::string toString() const
937 : {
938 0 : return std::string("(") + left->toString() + " " + get_opstr() + " " + right->toString() + ")";
939 : }
940 :
941 : /// Detach left node
942 0 : inline ParseNode* detach_left()
943 : {
944 0 : ParseNode *n = left;
945 0 : left = NULL;
946 0 : return n;
947 : }
948 :
949 : /// Detach right node
950 0 : inline ParseNode* detach_right()
951 : {
952 0 : ParseNode *n = right;
953 0 : right = NULL;
954 0 : return n;
955 : }
956 : };
957 :
958 : // *** Functions which translate the resulting parse tree into our expression
959 : // *** tree, simultaneously folding constants.
960 :
961 : /// Iterator type used by spirit's parsers.
962 : typedef std::string::const_iterator InputIterT;
963 :
964 : /// Resulting match tree after parsing
965 : typedef tree_match<InputIterT> ParseTreeMatchT;
966 :
967 : /// The iterator of the match tree used in build_expr()
968 : typedef ParseTreeMatchT::const_tree_iterator TreeIterT;
969 :
970 : /// Build_expr is the constructor method to create a parse tree from the
971 : /// AST-tree returned by the spirit parser.
972 176 : static ParseNode* build_expr(TreeIterT const& i)
973 : {
974 : #ifdef STX_DEBUG_PARSER
975 : std::cout << "In build_expr. i->value = " <<
976 : std::string(i->value.begin(), i->value.end()) <<
977 : " i->children.size() = " << i->children.size() <<
978 : " i->value.id = " << i->value.id().to_long() << std::endl;
979 : #endif
980 :
981 176 : switch(i->value.id().to_long())
982 : {
983 : // *** Constant node cases
984 :
985 : case boolean_const_id:
986 : {
987 : return new PNConstant(AnyScalar::ATTRTYPE_BOOL,
988 7 : std::string(i->value.begin(), i->value.end()));
989 : }
990 :
991 : case integer_const_id:
992 : {
993 : return new PNConstant(AnyScalar::ATTRTYPE_INTEGER,
994 63 : std::string(i->value.begin(), i->value.end()));
995 : }
996 :
997 : case long_const_id:
998 : {
999 : return new PNConstant(AnyScalar::ATTRTYPE_LONG,
1000 0 : std::string(i->value.begin(), i->value.end()));
1001 : }
1002 :
1003 : case double_const_id:
1004 : {
1005 : return new PNConstant(AnyScalar::ATTRTYPE_DOUBLE,
1006 10 : std::string(i->value.begin(), i->value.end()));
1007 : }
1008 :
1009 : case string_const_id:
1010 : {
1011 : return new PNConstant(AnyScalar::ATTRTYPE_STRING,
1012 6 : std::string(i->value.begin(), i->value.end()));
1013 : }
1014 :
1015 : // *** Arithmetic node cases
1016 :
1017 : case unary_expr_id:
1018 : {
1019 8 : char arithop = *i->value.begin();
1020 8 : assert(i->children.size() == 1);
1021 :
1022 8 : const ParseNode *val = build_expr(i->children.begin());
1023 :
1024 8 : if (val->evaluate_const(NULL))
1025 : {
1026 : // construct a constant node
1027 6 : PNUnaryArithmExpr tmpnode(val, arithop);
1028 6 : AnyScalar constval(AnyScalar::ATTRTYPE_INVALID);
1029 :
1030 6 : tmpnode.evaluate_const(&constval);
1031 :
1032 6 : return new PNConstant(constval);
1033 : }
1034 : else
1035 : {
1036 : // calculation node
1037 2 : return new PNUnaryArithmExpr(val, arithop);
1038 : }
1039 : }
1040 :
1041 : case add_expr_id:
1042 : case mul_expr_id:
1043 : {
1044 28 : char arithop = *i->value.begin();
1045 28 : assert(i->children.size() == 2);
1046 :
1047 : // auto_ptr needed because of possible parse exceptions in build_expr.
1048 :
1049 28 : std::auto_ptr<const ParseNode> left( build_expr(i->children.begin()) );
1050 28 : std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1) );
1051 :
1052 28 : if (left->evaluate_const(NULL) && right->evaluate_const(NULL))
1053 : {
1054 : // construct a constant node
1055 12 : PNBinaryArithmExpr tmpnode(left.release(), right.release(), arithop);
1056 12 : AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
1057 :
1058 12 : tmpnode.evaluate_const(&both);
1059 :
1060 : // left and right are deleted by tmpnode's deconstructor
1061 :
1062 40 : return new PNConstant(both);
1063 : }
1064 : else
1065 : {
1066 : // calculation node
1067 16 : return new PNBinaryArithmExpr(left.release(), right.release(), arithop);
1068 0 : }
1069 : }
1070 :
1071 : // *** Cast node case
1072 :
1073 : case cast_spec_id:
1074 : {
1075 4 : assert(i->children.size() == 1);
1076 :
1077 4 : std::string tname(i->value.begin(), i->value.end());
1078 8 : AnyScalar::attrtype_t at = AnyScalar::stringToType(tname);
1079 :
1080 4 : const ParseNode *val = build_expr(i->children.begin());
1081 :
1082 4 : if (val->evaluate_const(NULL))
1083 : {
1084 : // construct a constant node
1085 2 : PNCastExpr tmpnode(val, at);
1086 :
1087 2 : AnyScalar constval(AnyScalar::ATTRTYPE_INVALID);
1088 :
1089 2 : tmpnode.evaluate_const(&constval);
1090 :
1091 6 : return new PNConstant(constval);
1092 : }
1093 : else
1094 : {
1095 2 : return new PNCastExpr(val, at);
1096 0 : }
1097 : }
1098 :
1099 : // *** Binary Comparison Operator
1100 :
1101 : case comp_expr_id:
1102 : {
1103 17 : assert(i->children.size() == 2);
1104 :
1105 17 : std::string arithop(i->value.begin(), i->value.end());
1106 :
1107 : // we need auto_ptr because of possible parse exceptions in build_expr.
1108 :
1109 34 : std::auto_ptr<const ParseNode> left( build_expr(i->children.begin()) );
1110 17 : std::auto_ptr<const ParseNode> right( build_expr(i->children.begin()+1) );
1111 :
1112 17 : if (left->evaluate_const(NULL) && right->evaluate_const(NULL))
1113 : {
1114 : // construct a constant node
1115 13 : PNBinaryComparisonExpr tmpnode(left.release(), right.release(), arithop);
1116 13 : AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
1117 :
1118 13 : tmpnode.evaluate_const(&both);
1119 :
1120 : // left and right are deleted by tmpnode's deconstructor
1121 :
1122 30 : return new PNConstant(both);
1123 : }
1124 : else
1125 : {
1126 : // calculation node
1127 4 : return new PNBinaryComparisonExpr(left.release(), right.release(), arithop);
1128 0 : }
1129 : }
1130 :
1131 : // *** Binary Logic Operator
1132 :
1133 : case and_expr_id:
1134 : case or_expr_id:
1135 : {
1136 13 : assert(i->children.size() == 2);
1137 :
1138 13 : std::string logicop(i->value.begin(), i->value.end());
1139 26 : std::transform(logicop.begin(), logicop.end(), logicop.begin(), tolower);
1140 :
1141 : // auto_ptr needed because of possible parse exceptions in build_expr.
1142 :
1143 13 : std::auto_ptr<ParseNode> left( build_expr(i->children.begin()) );
1144 13 : std::auto_ptr<ParseNode> right( build_expr(i->children.begin()+1) );
1145 :
1146 13 : bool constleft = left->evaluate_const(NULL);
1147 13 : bool constright = right->evaluate_const(NULL);
1148 :
1149 : // a logical node is constant if one of the two ops is constant. so we
1150 : // construct a calculation node and check later.
1151 13 : std::auto_ptr<PNBinaryLogicExpr> node( new PNBinaryLogicExpr(left.release(), right.release(), logicop) );
1152 :
1153 13 : if (constleft || constright)
1154 : {
1155 13 : AnyScalar both(AnyScalar::ATTRTYPE_INVALID);
1156 :
1157 : // test if the node is really const.
1158 13 : if (node->evaluate_const(&both))
1159 : {
1160 : // return a constant node instead, node will be deleted by
1161 : // auto_ptr, left,right by node's destructor.
1162 26 : return new PNConstant(both);
1163 0 : }
1164 : }
1165 0 : if (constleft)
1166 : {
1167 : // left node is constant, but the evaluation is not
1168 : // -> only right node is meaningful.
1169 0 : return node->detach_right();
1170 : }
1171 0 : if (constright)
1172 : {
1173 : // right node is constant, but the evaluation is not
1174 : // -> only left node is meaningful.
1175 0 : return node->detach_left();
1176 : }
1177 :
1178 0 : return node.release();
1179 : }
1180 :
1181 : // *** Variable and Function name place-holder
1182 :
1183 : case varname_id:
1184 : {
1185 8 : assert(i->children.size() == 0);
1186 :
1187 8 : std::string varname(i->value.begin(), i->value.end());
1188 :
1189 16 : return new PNVariable(varname);
1190 : }
1191 :
1192 : case function_identifier_id:
1193 : {
1194 12 : std::string funcname(i->value.begin(), i->value.end());
1195 24 : std::vector<const class ParseNode*> paramlist;
1196 :
1197 24 : if (i->children.size() > 0)
1198 : {
1199 10 : TreeIterT const& paramlistchild = i->children.begin();
1200 :
1201 10 : if (paramlistchild->value.id().to_long() == exprlist_id)
1202 : {
1203 : try
1204 : {
1205 12 : for(TreeIterT ci = paramlistchild->children.begin(); ci != paramlistchild->children.end(); ++ci)
1206 : {
1207 8 : const ParseNode *pas = build_expr(ci);
1208 8 : paramlist.push_back(pas);
1209 : }
1210 : }
1211 0 : catch (...) // need to clean-up
1212 : {
1213 0 : for(unsigned int i = 0; i < paramlist.size(); ++i)
1214 0 : delete paramlist[i];
1215 0 : throw;
1216 : }
1217 : }
1218 : else
1219 : {
1220 : // just one subnode and its not a full expression list
1221 6 : paramlist.push_back( build_expr(paramlistchild) );
1222 : }
1223 : }
1224 :
1225 12 : return new PNFunction(funcname, paramlist);
1226 : }
1227 :
1228 : default:
1229 0 : throw(ExpressionParserException("Unknown AST parse tree node found. This should never happen."));
1230 : }
1231 : }
1232 :
1233 : /// build_exprlist constructs the vector holding the ParseNode parse tree for
1234 : /// each parse tree.
1235 0 : ParseTreeList build_exprlist(TreeIterT const &i)
1236 : {
1237 : #ifdef STX_DEBUG_PARSER
1238 : std::cout << "In build_exprlist. i->value = " <<
1239 : std::string(i->value.begin(), i->value.end()) <<
1240 : " i->children.size() = " << i->children.size() <<
1241 : " i->value.id = " << i->value.id().to_long() << std::endl;
1242 : #endif
1243 :
1244 0 : ParseTreeList ptlist;
1245 :
1246 0 : for(TreeIterT ci = i->children.begin(); ci != i->children.end(); ++ci)
1247 : {
1248 0 : ParseNode *vas = build_expr(ci);
1249 :
1250 0 : ptlist.push_back( ParseTree(vas) );
1251 : }
1252 :
1253 0 : return ptlist;
1254 : }
1255 :
1256 : /// Uses boost::spirit function to convert the parse tree into a XML document.
1257 1 : static inline void tree_dump_xml(std::ostream &os, const std::string &input, const tree_parse_info<InputIterT> &info)
1258 : {
1259 : // map used by the xml dumper to label the nodes
1260 :
1261 1 : std::map<parser_id, std::string> rule_names;
1262 :
1263 1 : rule_names[boolean_const_id] = "boolean_const";
1264 1 : rule_names[integer_const_id] = "integer_const";
1265 1 : rule_names[long_const_id] = "long_const";
1266 1 : rule_names[double_const_id] = "double_const";
1267 1 : rule_names[string_const_id] = "string_const";
1268 1 : rule_names[constant_id] = "constant";
1269 :
1270 1 : rule_names[function_call_id] = "function_call";
1271 1 : rule_names[function_identifier_id] = "function_identifier";
1272 :
1273 1 : rule_names[varname_id] = "varname";
1274 :
1275 1 : rule_names[unary_expr_id] = "unary_expr";
1276 1 : rule_names[mul_expr_id] = "mul_expr";
1277 1 : rule_names[add_expr_id] = "add_expr";
1278 :
1279 1 : rule_names[cast_expr_id] = "cast_expr";
1280 1 : rule_names[cast_spec_id] = "cast_spec";
1281 :
1282 1 : rule_names[comp_expr_id] = "comp_expr";
1283 1 : rule_names[and_expr_id] = "and_expr";
1284 1 : rule_names[or_expr_id] = "or_expr";
1285 :
1286 1 : rule_names[expr_id] = "expr";
1287 1 : rule_names[exprlist_id] = "exprlist";
1288 :
1289 1 : tree_to_xml(os, info.trees, input.c_str(), rule_names);
1290 1 : }
1291 :
1292 : } // namespace Grammar
1293 :
1294 35 : const ParseTree parseExpression(const std::string &input)
1295 : {
1296 : // instance of the grammar
1297 35 : Grammar::ExpressionGrammar g;
1298 :
1299 : #ifdef STX_DEBUG_PARSER
1300 : BOOST_SPIRIT_DEBUG_GRAMMAR(g);
1301 : #endif
1302 :
1303 : Grammar::tree_parse_info<Grammar::InputIterT> info =
1304 : boost::spirit::ast_parse(input.begin(), input.end(),
1305 : g.use_parser<0>(), // use first entry point: expr
1306 35 : boost::spirit::space_p);
1307 :
1308 35 : if (!info.full)
1309 : {
1310 1 : std::ostringstream oss;
1311 : oss << "Syntax error at position "
1312 : << static_cast<int>(info.stop - input.begin())
1313 : << " near "
1314 1 : << std::string(info.stop, input.end());
1315 :
1316 2 : throw(BadSyntaxException(oss.str()));
1317 : }
1318 :
1319 34 : return ParseTree( Grammar::build_expr(info.trees.begin()) );
1320 : }
1321 :
1322 1 : std::string parseExpressionXML(const std::string &input)
1323 : {
1324 : // instance of the grammar
1325 1 : Grammar::ExpressionGrammar g;
1326 :
1327 : #ifdef STX_DEBUG_PARSER
1328 : BOOST_SPIRIT_DEBUG_GRAMMAR(g);
1329 : #endif
1330 :
1331 : Grammar::tree_parse_info<Grammar::InputIterT> info =
1332 : boost::spirit::ast_parse(input.begin(), input.end(),
1333 : g.use_parser<0>(), // use first entry point: expr
1334 1 : boost::spirit::space_p);
1335 :
1336 1 : if (!info.full)
1337 : {
1338 0 : std::ostringstream oss;
1339 : oss << "Syntax error at position "
1340 : << static_cast<int>(info.stop - input.begin())
1341 : << " near "
1342 0 : << std::string(info.stop, input.end());
1343 :
1344 0 : throw(BadSyntaxException(oss.str()));
1345 : }
1346 :
1347 1 : std::ostringstream oss;
1348 1 : Grammar::tree_dump_xml(oss, input, info);
1349 1 : return oss.str();
1350 : }
1351 :
1352 0 : ParseTreeList parseExpressionList(const std::string &input)
1353 : {
1354 : // instance of the grammar
1355 0 : Grammar::ExpressionGrammar g;
1356 :
1357 : #ifdef STX_DEBUG_PARSER
1358 : BOOST_SPIRIT_DEBUG_GRAMMAR(g);
1359 : #endif
1360 :
1361 : Grammar::tree_parse_info<Grammar::InputIterT> info =
1362 : boost::spirit::ast_parse(input.begin(), input.end(),
1363 : g.use_parser<1>(), // use second entry point: exprlist
1364 0 : boost::spirit::space_p);
1365 :
1366 0 : if (!info.full)
1367 : {
1368 0 : std::ostringstream oss;
1369 : oss << "Syntax error at position "
1370 : << static_cast<int>(info.stop - input.begin())
1371 : << " near "
1372 0 : << std::string(info.stop, input.end());
1373 :
1374 0 : throw(BadSyntaxException(oss.str()));
1375 : }
1376 :
1377 0 : return Grammar::build_exprlist(info.trees.begin());
1378 : }
1379 :
1380 0 : std::vector<AnyScalar> ParseTreeList::evaluate(const class SymbolTable &st) const
1381 : {
1382 0 : std::vector<AnyScalar> vl;
1383 :
1384 0 : for(parent_type::const_iterator i = parent_type::begin(); i != parent_type::end(); i++)
1385 : {
1386 0 : vl.push_back( i->evaluate(st) );
1387 : }
1388 :
1389 0 : return vl;
1390 : }
1391 :
1392 0 : std::string ParseTreeList::toString() const
1393 : {
1394 0 : std::string sl;
1395 :
1396 0 : for(parent_type::const_iterator i = parent_type::begin(); i != parent_type::end(); i++)
1397 : {
1398 0 : if (i != parent_type::begin()) {
1399 0 : sl += ", ";
1400 : }
1401 :
1402 0 : sl += i->toString();
1403 : }
1404 :
1405 0 : return sl;
1406 : }
1407 :
1408 : /// *** SymbolTable, EmptySymbolTable and BasicSymbolTable implementation
1409 :
1410 17 : SymbolTable::~SymbolTable()
1411 : {
1412 17 : }
1413 :
1414 0 : EmptySymbolTable::~EmptySymbolTable()
1415 : {
1416 0 : }
1417 :
1418 0 : AnyScalar EmptySymbolTable::lookupVariable(const std::string &varname) const
1419 : {
1420 0 : throw(UnknownSymbolException(std::string("Unknown variable ") + varname));
1421 : }
1422 :
1423 : AnyScalar EmptySymbolTable::processFunction(const std::string &funcname,
1424 0 : const paramlist_type &) const
1425 : {
1426 0 : throw(UnknownSymbolException(std::string("Unknown function ") + funcname + "()"));
1427 : }
1428 :
1429 17 : BasicSymbolTable::BasicSymbolTable()
1430 : {
1431 17 : addStandardFunctions();
1432 17 : }
1433 :
1434 17 : BasicSymbolTable::~BasicSymbolTable()
1435 : {
1436 17 : }
1437 :
1438 34 : void BasicSymbolTable::setVariable(const std::string& varname, const AnyScalar &value)
1439 : {
1440 34 : std::string vn = varname;
1441 34 : std::transform(vn.begin(), vn.end(), vn.begin(), tolower);
1442 :
1443 34 : variablemap[vn] = value;
1444 34 : }
1445 :
1446 153 : void BasicSymbolTable::setFunction(const std::string& funcname, int arguments, functionptr_type funcptr)
1447 : {
1448 153 : std::string fn = funcname;
1449 153 : std::transform(fn.begin(), fn.end(), fn.begin(), toupper);
1450 :
1451 153 : functionmap[fn] = FunctionInfo(arguments, funcptr);
1452 153 : }
1453 :
1454 0 : void BasicSymbolTable::clearVariables()
1455 : {
1456 0 : variablemap.clear();
1457 0 : }
1458 :
1459 0 : void BasicSymbolTable::clearFunctions()
1460 : {
1461 0 : functionmap.clear();
1462 0 : }
1463 :
1464 0 : AnyScalar BasicSymbolTable::funcPI(const paramlist_type &)
1465 : {
1466 0 : return AnyScalar(3.14159265358979323846);
1467 : }
1468 :
1469 0 : AnyScalar BasicSymbolTable::funcSIN(const paramlist_type ¶mlist)
1470 : {
1471 0 : return AnyScalar( std::sin(paramlist[0].getDouble()) );
1472 : }
1473 :
1474 0 : AnyScalar BasicSymbolTable::funcCOS(const paramlist_type ¶mlist)
1475 : {
1476 0 : return AnyScalar( std::cos(paramlist[0].getDouble()) );
1477 : }
1478 :
1479 0 : AnyScalar BasicSymbolTable::funcTAN(const paramlist_type ¶mlist)
1480 : {
1481 0 : return AnyScalar( std::tan(paramlist[0].getDouble()) );
1482 : }
1483 :
1484 0 : AnyScalar BasicSymbolTable::funcABS(const paramlist_type ¶mlist)
1485 : {
1486 0 : if (paramlist[0].isIntegerType()) {
1487 0 : return AnyScalar( std::abs(paramlist[0].getInteger()) );
1488 : }
1489 0 : else if (paramlist[0].isFloatingType()) {
1490 0 : return AnyScalar( std::fabs(paramlist[0].getDouble()) );
1491 : }
1492 : else {
1493 0 : throw(BadFunctionCallException("Function ABS() takes exactly one parameter"));
1494 : }
1495 : }
1496 :
1497 1 : AnyScalar BasicSymbolTable::funcEXP(const paramlist_type ¶mlist)
1498 : {
1499 1 : return AnyScalar( std::exp(paramlist[0].getDouble()) );
1500 : }
1501 :
1502 1 : AnyScalar BasicSymbolTable::funcLOGN(const paramlist_type ¶mlist)
1503 : {
1504 1 : return AnyScalar( std::log(paramlist[0].getDouble()) );
1505 : }
1506 :
1507 1 : AnyScalar BasicSymbolTable::funcPOW(const paramlist_type ¶mlist)
1508 : {
1509 1 : return AnyScalar( std::pow(paramlist[0].getDouble(), paramlist[1].getDouble()) );
1510 : }
1511 :
1512 1 : AnyScalar BasicSymbolTable::funcSQRT(const paramlist_type ¶mlist)
1513 : {
1514 1 : return AnyScalar( std::sqrt(paramlist[0].getDouble()) );
1515 : }
1516 :
1517 17 : void BasicSymbolTable::addStandardFunctions()
1518 : {
1519 17 : setFunction("PI", 0, funcPI);
1520 :
1521 34 : setFunction("SIN", 1, funcSIN);
1522 34 : setFunction("COS", 1, funcCOS);
1523 34 : setFunction("TAN", 1, funcTAN);
1524 :
1525 34 : setFunction("ABS", 1, funcABS);
1526 34 : setFunction("EXP", 1, funcEXP);
1527 34 : setFunction("LOGN", 1, funcLOGN);
1528 34 : setFunction("POW", 2, funcPOW);
1529 34 : setFunction("SQRT", 1, funcSQRT);
1530 17 : }
1531 :
1532 4 : AnyScalar BasicSymbolTable::lookupVariable(const std::string &_varname) const
1533 : {
1534 4 : std::string varname = _varname;
1535 4 : std::transform(varname.begin(), varname.end(), varname.begin(), tolower);
1536 :
1537 4 : variablemap_type::const_iterator fi = variablemap.find(varname);
1538 :
1539 4 : if (fi != variablemap.end())
1540 : {
1541 3 : return fi->second;
1542 : }
1543 :
1544 3 : throw(UnknownSymbolException(std::string("Unknown variable ") + varname));
1545 : }
1546 :
1547 : AnyScalar BasicSymbolTable::processFunction(const std::string &_funcname,
1548 6 : const paramlist_type ¶mlist) const
1549 : {
1550 6 : std::string funcname = _funcname;
1551 6 : std::transform(funcname.begin(), funcname.end(), funcname.begin(), toupper);
1552 :
1553 6 : functionmap_type::const_iterator fi = functionmap.find(funcname);
1554 :
1555 6 : if (fi != functionmap.end())
1556 : {
1557 5 : if (fi->second.arguments >= 0)
1558 : {
1559 5 : if (fi->second.arguments == 0 && paramlist.size() != 0)
1560 : {
1561 0 : throw(BadFunctionCallException(std::string("Function ") + funcname + "() does not take any parameter."));
1562 : }
1563 5 : else if (fi->second.arguments == 1 && paramlist.size() != 1)
1564 : {
1565 1 : throw(BadFunctionCallException(std::string("Function ") + funcname + "() takes exactly one parameter."));
1566 : }
1567 4 : else if (static_cast<unsigned int>(fi->second.arguments) != paramlist.size())
1568 : {
1569 0 : std::ostringstream oss;
1570 0 : oss << "Function " << funcname << "() takes exactly " << fi->second.arguments << " parameters.";
1571 0 : throw(BadFunctionCallException(oss.str()));
1572 : }
1573 : }
1574 4 : return fi->second.func(paramlist);
1575 : }
1576 :
1577 4 : throw(UnknownSymbolException(std::string("Unknown function ") + funcname + "()"));
1578 : }
1579 0 :
1580 2 : } // namespace stx
|