📄 expressionparser.cpp
字号:
comma = expect_comma( ch_p(',') ); close_brace = expect_close( ch_p(')') ); expression = ifthenelseexp; // We parse expressions without regard of the types. First we // parse the expressions, then we worry about whether what the // user says is actually valid. You can try to add up two // booleans, and the parser will parse it, but it will notice // you're writing bogus when it tries to pass it to an operator // structure from Operators.hpp // TODO: implement the ifthenelse operator ? ifthenelseexp = andexp; andexp = orexp >> *( ( str_p( "&&" ) | "and" ) >> orexp[ bind( &ExpressionParser::seen_binary, this, "&&" ) ] ); orexp = notequalexp >> *( ( str_p( "||" ) | "or" ) >> notequalexp[ bind( &ExpressionParser::seen_binary, this, "||" ) ] ); notequalexp = equalexp >> *( "!=" >> equalexp[ bind( &ExpressionParser::seen_binary, this, "!=" ) ] ); equalexp = greatereqexp >> *( "==" >> greatereqexp[ bind( &ExpressionParser::seen_binary, this, "==" ) ] ); greatereqexp = greaterexp >> *( ">=" >> greaterexp[ bind( &ExpressionParser::seen_binary, this, ">=" ) ] ); greaterexp = smallereqexp >> *( '>' >> smallereqexp[ bind( &ExpressionParser::seen_binary, this, ">" ) ] ); smallereqexp = smallerexp >> *( "<=" >> smallerexp[ bind( &ExpressionParser::seen_binary, this, "<=" ) ] ); smallerexp = minusexp >> *( '<' >> minusexp[ bind( &ExpressionParser::seen_binary, this, "<" ) ] ); minusexp = plusexp >> *( '-' >> plusexp[ bind( &ExpressionParser::seen_binary, this, "-" ) ] ); plusexp = modexp >> *( '+' >> modexp[ bind( &ExpressionParser::seen_binary, this, "+" ) ] ); modexp = divexp >> *( '%' >> divexp[ bind( &ExpressionParser::seen_binary, this, "%" ) ] ); divexp = multexp >> *( '/' >> multexp[ bind( &ExpressionParser::seen_binary, this, "/" ) ] ); multexp = unaryplusexp >> *( '*' >> unaryplusexp[ bind( &ExpressionParser::seen_binary, this, "*" ) ] ); unaryplusexp = '+' >> unaryminusexp[ bind( &ExpressionParser::seen_unary, this, "+" ) ] | unaryminusexp; unaryminusexp = '-' >> unarynotexp[ bind( &ExpressionParser::seen_unary, this, "-" ) ] | unarynotexp; unarynotexp = ( str_p( "not" ) | '!' ) >> atomicexpression[ bind( &ExpressionParser::seen_unary, this, "!" ) ] | atomicexpression; // note the order is important: commonparser.identifier throws a // useful "cannot use x as identifier" error if it fails, so we // must first show all non-identifier rules. atomicexpression = ( // A parenthesis group. groupexp // or a time expression | time_expression // or a constant or user-defined value.. | my_guard( valueparser.parser())[ &handle_no_value ] [ bind( &ExpressionParser::seenvalue, this ) ] | my_guard( datacallparser.parser() )[&handle_no_datacall] [bind( &ExpressionParser::seendatacall, this ) ] // or an index or dot expression ) >> ! dotexp >> !indexexp; // take index of an atomicexpression indexexp = (ch_p('[') >> expression[bind(&ExpressionParser::seen_binary, this, "[]")] >> expect_close( ch_p( ']') ) ); dotexp = +( ch_p('.') >> commonparser.identifier[ bind(&ExpressionParser::seen_dotmember, this, _1, _2)]); // needs no semantic action, its result is already on top of // the stack, where it should be.. groupexp = '(' >> expression >> close_brace; // the day i find a clean way to temporarily disable 'eol' skipping, a lot of // grammar will look better... time_expression = (str_p("time")>>eps_p(~commonparser.identchar | eol_p | end_p ))[bind(&ExpressionParser::seentimeexpr, this)] | ( (eps_p[boost::lambda::var(eol_skip_functor::skipeol) = false] >> uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ] >> (str_p( "s" ) | "ms" | "us" | "ns" )[boost::lambda::var(eol_skip_functor::skipeol) = true][bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ]) | (eps_p[boost::lambda::var(eol_skip_functor::skipeol) = true] >> nothing_p) // eps_p succeeds always, then fail. ) ; // enable skipeol.// >> expect_timespec( (( str_p( ">=" ) | ">" )// |// (str_p("<=") | "<")[bind( &ExpressionParser::inverttime, this)])// >> time_spec);// time_spec =// ( uint_p[ bind( &ExpressionParser::seentimespec, this, _1 ) ]// >>// ( str_p( "s" ) | "ms" | "us" | "ns" )[// bind( &ExpressionParser::seentimeunit, this, _1, _2 ) ] ) | expression[bind(&ExpressionParser::seentimeexpr, this)]; }; void ExpressionParser::inverttime() { _invert_time = true; } void ExpressionParser::seentimeexpr() { parsestack.push( new DataSourceTime() );// DataSourceBase::shared_ptr res = parsestack.top();// parsestack.pop();// DataSource<double>::shared_ptr dres = dynamic_cast<DataSource<double>*>( res.get() );// if ( !dres )// throw parse_exception_semantic_error("Expected time in seconds but expression is not a floating point number.");// DataSourceBase::shared_ptr dsb( new DataSourceCondition( new ConditionDSDuration( dres, _invert_time ) ) );// _invert_time = false;// parsestack.push( dsb ); } void ExpressionParser::seentimeunit( iter_t begin, iter_t end) { // the string starting at begin, ending at end is either ms, us, // ns or s, so we only need to check the first letter... // Convert to seconds... TimeService::Seconds total = 0; switch( *begin ) { case 's': total = tsecs; break; case 'm': total = tsecs / 1000.0; break; case 'u': total = tsecs / 1000000.0; break; case 'n': total = tsecs / 1000000000.0; break; default: std::string arg(begin, end); throw parse_exception_semantic_error("Expected time expression 's', 'ms', 'us' or 'ns' after integer value, got "+arg); }; parsestack.push( new ConstantDataSource<double>( total ) ); // DataSourceBase::shared_ptr dsb( new DataSourceCondition(// new ConditionDuration( total, _invert_time ) ) );// _invert_time = false;// parsestack.push( dsb ); } void ExpressionParser::seentimespec( int n ) { tsecs = n; } void ExpressionParser::seenvalue() { DataSourceBase::shared_ptr ds = valueparser.lastParsed(); parsestack.push( ds ); } void ExpressionParser::seendatacall() { DataSourceBase::shared_ptr n( datacallparser.getParseResult() ); parsestack.push( n ); } ExpressionParser::~ExpressionParser() { // if parsestack is not empty, then something went wrong, someone // threw an exception, so we clean up.. while ( !parsestack.empty() ) parsestack.pop(); } rule_t& ExpressionParser::parser() { return expression; } DataSourceBase::shared_ptr ExpressionParser::getResult() { assert( !parsestack.empty() ); return parsestack.top(); } void ExpressionParser::seen_unary( const std::string& op ) { DataSourceBase::shared_ptr arg( parsestack.top() ); parsestack.pop(); DataSourceBase::shared_ptr ret = opreg->applyUnary( op, arg.get() ); if ( ! ret ) throw parse_exception_fatal_semantic_error( "Cannot apply unary operator \"" + op + "\" to " + arg->getType() +"." ); parsestack.push( ret ); }; void ExpressionParser::seen_dotmember( iter_t s, iter_t f ) { std::string member(s,f); // inspirired on seen_unary DataSourceBase::shared_ptr arg( parsestack.top() ); parsestack.pop(); DataSourceBase::shared_ptr ret = opreg->applyDot( member, arg.get() ); if ( ! ret ) throw parse_exception_fatal_semantic_error( arg->getType() + " does not have member \"" + member + "\"." ); parsestack.push( ret ); }; void ExpressionParser::seen_binary( const std::string& op ) { DataSourceBase::shared_ptr arg1( parsestack.top() ); parsestack.pop(); DataSourceBase::shared_ptr arg2( parsestack.top() ); parsestack.pop(); // Arg2 is the first (!) argument, as it was pushed on the stack // first. DataSourceBase::shared_ptr ret = opreg->applyBinary( op, arg2.get(), arg1.get() ); if ( ! ret ) throw parse_exception_fatal_semantic_error( "Cannot apply binary operation "+ arg2->getType() +" " + op + " "+arg1->getType() +"." ); parsestack.push( ret ); }; void ExpressionParser::dropResult() { parsestack.pop(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -