#ifndef STORM_PARSER_EXPRESSIONPARSER_H_ #define STORM_PARSER_EXPRESSIONPARSER_H_ #include <sstream> #include "src/parser/SpiritParserDefinitions.h" #include "src/storage/expressions/Expression.h" #include "src/storage/expressions/ExpressionManager.h" #include "src/utility/macros.h" #include "src/exceptions/WrongFormatException.h" namespace storm { namespace parser { class ExpressionParser : public qi::grammar<Iterator, storm::expressions::Expression(), Skipper> { public: /*! * Creates an expression parser. Initially the parser is set to a mode in which it will not generate the * actual expressions but only perform a syntax check and return the expression "false". To make the parser * generate the actual expressions, a mapping of valid identifiers to their expressions need to be provided * later. * * @param manager The manager responsible for the expressions. * @param invalidIdentifiers_ A symbol table of identifiers that are to be rejected. * @param allowBacktracking A flag that indicates whether or not the parser is supposed to backtrack beyond * points it would typically allow. This can, for example, be used to prevent errors if the outer grammar * also parses boolean conjuncts that are erroneously consumed by the expression parser. */ ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols<char, uint_fast64_t> const& invalidIdentifiers_, bool allowBacktracking = false); /*! * Sets an identifier mapping that is used to determine valid variables in the expression. The mapped-to * expressions will be substituted wherever the key value appears in the parsed expression. After setting * this, the parser will generate expressions. * * @param identifiers_ A pointer to a mapping from identifiers to expressions. */ void setIdentifierMapping(qi::symbols<char, storm::expressions::Expression> const* identifiers_); /*! * Unsets a previously set identifier mapping. This will make the parser not generate expressions any more * but merely check for syntactic correctness of an expression. */ void unsetIdentifierMapping(); /*! * Sets whether double literals are to be accepted or not. * * @param flag If set to true, double literals are accepted. */ void setAcceptDoubleLiterals(bool flag); private: struct orOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { orOperatorStruct() { add ("|", storm::expressions::OperatorType::Or) ("=>", storm::expressions::OperatorType::Implies); } }; // A parser used for recognizing the operators at the "or" precedence level. orOperatorStruct orOperator_; struct andOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { andOperatorStruct() { add ("&", storm::expressions::OperatorType::And); } }; // A parser used for recognizing the operators at the "and" precedence level. andOperatorStruct andOperator_; struct equalityOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { equalityOperatorStruct() { add ("=", storm::expressions::OperatorType::Equal) ("!=", storm::expressions::OperatorType::NotEqual); } }; // A parser used for recognizing the operators at the "equality" precedence level. equalityOperatorStruct equalityOperator_; struct relationalOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { relationalOperatorStruct() { add (">=", storm::expressions::OperatorType::GreaterOrEqual) (">", storm::expressions::OperatorType::Greater) ("<=", storm::expressions::OperatorType::LessOrEqual) ("<", storm::expressions::OperatorType::Less); } }; // A parser used for recognizing the operators at the "relational" precedence level. relationalOperatorStruct relationalOperator_; struct plusOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { plusOperatorStruct() { add ("+", storm::expressions::OperatorType::Plus) ("-", storm::expressions::OperatorType::Minus); } }; // A parser used for recognizing the operators at the "plus" precedence level. plusOperatorStruct plusOperator_; struct multiplicationOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { multiplicationOperatorStruct() { add ("*", storm::expressions::OperatorType::Times) ("/", storm::expressions::OperatorType::Divide); } }; // A parser used for recognizing the operators at the "multiplication" precedence level. multiplicationOperatorStruct multiplicationOperator_; struct powerOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { powerOperatorStruct() { add ("^", storm::expressions::OperatorType::Power); } }; // A parser used for recognizing the operators at the "power" precedence level. powerOperatorStruct powerOperator_; struct unaryOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { unaryOperatorStruct() { add ("!", storm::expressions::OperatorType::Not) ("-", storm::expressions::OperatorType::Minus); } }; // A parser used for recognizing the operators at the "unary" precedence level. unaryOperatorStruct unaryOperator_; struct floorCeilOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { floorCeilOperatorStruct() { add ("floor", storm::expressions::OperatorType::Floor) ("ceil", storm::expressions::OperatorType::Ceil); } }; // A parser used for recognizing the operators at the "floor/ceil" precedence level. floorCeilOperatorStruct floorCeilOperator_; struct minMaxOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { minMaxOperatorStruct() { add ("min", storm::expressions::OperatorType::Min) ("max", storm::expressions::OperatorType::Max); } }; // A parser used for recognizing the operators at the "min/max" precedence level. minMaxOperatorStruct minMaxOperator_; struct trueFalseOperatorStruct : qi::symbols<char, storm::expressions::Expression> { trueFalseOperatorStruct(storm::expressions::ExpressionManager const& manager) { add ("true", manager.boolean(true)) ("false", manager.boolean(false)); } }; // A parser used for recognizing the literals true and false. trueFalseOperatorStruct trueFalse_; // The manager responsible for the expressions. storm::expressions::ExpressionManager const& manager; // A flag that indicates whether expressions should actually be generated or just a syntax check shall be // performed. bool createExpressions; // A flag that indicates whether double literals are accepted. bool acceptDoubleLiterals; // The currently used mapping of identifiers to expressions. This is used if the parser is set to create // expressions. qi::symbols<char, storm::expressions::Expression> const* identifiers_; // The symbol table of invalid identifiers. qi::symbols<char, uint_fast64_t> const& invalidIdentifiers_; // Rules for parsing a composed expression. qi::rule<Iterator, storm::expressions::Expression(), Skipper> expression; qi::rule<Iterator, storm::expressions::Expression(), Skipper> iteExpression; qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> orExpression; qi::rule<Iterator, storm::expressions::Expression(), Skipper> andExpression; qi::rule<Iterator, storm::expressions::Expression(), Skipper> relativeExpression; qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> equalityExpression; qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> plusExpression; qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> multiplicationExpression; qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> powerExpression; qi::rule<Iterator, storm::expressions::Expression(), Skipper> unaryExpression; qi::rule<Iterator, storm::expressions::Expression(), Skipper> atomicExpression; qi::rule<Iterator, storm::expressions::Expression(), Skipper> literalExpression; qi::rule<Iterator, storm::expressions::Expression(), Skipper> identifierExpression; qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> minMaxExpression; qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> floorCeilExpression; qi::rule<Iterator, std::string(), Skipper> identifier; // Parser that is used to recognize doubles only (as opposed to Spirit's double_ parser). boost::spirit::qi::real_parser<double, boost::spirit::qi::strict_real_policies<double>> strict_double; // Helper functions to create expressions. storm::expressions::Expression createIteExpression(storm::expressions::Expression e1, storm::expressions::Expression e2, storm::expressions::Expression e3) const; storm::expressions::Expression createOrExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const; storm::expressions::Expression createAndExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const; storm::expressions::Expression createRelationalExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const; storm::expressions::Expression createEqualsExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const; storm::expressions::Expression createPlusExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const; storm::expressions::Expression createMultExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const; storm::expressions::Expression createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const; storm::expressions::Expression createUnaryExpression(boost::optional<storm::expressions::OperatorType> const& operatorType, storm::expressions::Expression const& e1) const; storm::expressions::Expression createDoubleLiteralExpression(double value, bool& pass) const; storm::expressions::Expression createIntegerLiteralExpression(int value) const; storm::expressions::Expression createMinimumMaximumExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const; storm::expressions::Expression createFloorCeilExpression(storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e1) const; storm::expressions::Expression getIdentifierExpression(std::string const& identifier) const; bool isValidIdentifier(std::string const& identifier); // Functor used for displaying error information. struct ErrorHandler { typedef qi::error_handler_result result_type; template<typename T1, typename T2, typename T3, typename T4> qi::error_handler_result operator()(T1 b, T2 e, T3 where, T4 const& what) const { std::stringstream whatAsString; whatAsString << what; STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(where) << ": " << " expecting " << whatAsString.str() << "."); return qi::fail; } }; // An error handler function. phoenix::function<ErrorHandler> handler; }; } // namespace parser } // namespace storm #endif /* STORM_PARSER_EXPRESSIONPARSER_H_ */