From 7c5603de3e0f2716235e6719302be9f54a07cd15 Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 2 Aug 2014 19:17:56 +0200 Subject: [PATCH] Improved performance of the expression parser a bit more. Former-commit-id: 7a0ae116c98321f33590f8188cf888e09a40fb32 --- src/exceptions/ExceptionMacros.h | 8 +- src/parser/ExpressionParser.cpp | 123 +++++++-------------- src/parser/ExpressionParser.h | 55 +++++++-- src/storage/expressions/OperatorType.cpp | 33 ++++++ src/storage/expressions/OperatorType.h | 4 + test/functional/parser/PrismParserTest.cpp | 3 +- 6 files changed, 130 insertions(+), 96 deletions(-) create mode 100644 src/storage/expressions/OperatorType.cpp diff --git a/src/exceptions/ExceptionMacros.h b/src/exceptions/ExceptionMacros.h index 09e7058ec..3840928fe 100644 --- a/src/exceptions/ExceptionMacros.h +++ b/src/exceptions/ExceptionMacros.h @@ -22,10 +22,10 @@ extern log4cplus::Logger logger; #define LOG_THROW(cond, exception, message) \ { \ -if (!(cond)) { \ -LOG4CPLUS_ERROR(logger, message); \ -throw exception() << message; \ -} \ +if (!(cond)) { \ +LOG4CPLUS_ERROR(logger, message); \ +throw exception() << message; \ +} \ } while (false) #endif /* STORM_EXCEPTIONS_EXCEPTIONMACROS_H_ */ \ No newline at end of file diff --git a/src/parser/ExpressionParser.cpp b/src/parser/ExpressionParser.cpp index faef55a4c..ed6d1d642 100644 --- a/src/parser/ExpressionParser.cpp +++ b/src/parser/ExpressionParser.cpp @@ -5,26 +5,26 @@ namespace storm { namespace parser { - ExpressionParser::ExpressionParser(qi::symbols const& invalidIdentifiers_) : ExpressionParser::base_type(expression), createExpressions(false), acceptDoubleLiterals(true), identifiers_(nullptr), invalidIdentifiers_(invalidIdentifiers_) { + ExpressionParser::ExpressionParser(qi::symbols const& invalidIdentifiers_) : ExpressionParser::base_type(expression), orOperator_(), andOperator_(), equalityOperator_(), relationalOperator_(), plusOperator_(), multiplicationOperator_(), powerOperator_(), unaryOperator_(), floorCeilOperator_(), minMaxOperator_(), trueFalse_(), createExpressions(false), acceptDoubleLiterals(true), identifiers_(nullptr), invalidIdentifiers_(invalidIdentifiers_) { identifier %= qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')))]]][qi::_pass = phoenix::bind(&ExpressionParser::isValidIdentifier, phoenix::ref(*this), qi::_1)]; identifier.name("identifier"); - floorCeilExpression = ((qi::lit("floor")[qi::_a = true] | qi::lit("ceil")[qi::_a = false]) >> qi::lit("(") >> plusExpression >> qi::lit(")"))[phoenix::if_(qi::_a) [qi::_val = phoenix::bind(&ExpressionParser::createFloorExpression, phoenix::ref(*this), qi::_1)] .else_ [qi::_val = phoenix::bind(&ExpressionParser::createCeilExpression, phoenix::ref(*this), qi::_1)]]; + floorCeilExpression = ((floorCeilOperator_ >> qi::lit("(")) > plusExpression > qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionParser::createFloorCeilExpression, phoenix::ref(*this), qi::_1, qi::_2)]; floorCeilExpression.name("floor/ceil expression"); - minMaxExpression = ((qi::lit("min")[qi::_a = true] | qi::lit("max")[qi::_a = false]) >> qi::lit("(") >> plusExpression >> qi::lit(",") >> plusExpression >> qi::lit(")"))[phoenix::if_(qi::_a) [qi::_val = phoenix::bind(&ExpressionParser::createMinimumExpression, phoenix::ref(*this), qi::_1, qi::_2)] .else_ [qi::_val = phoenix::bind(&ExpressionParser::createMaximumExpression, phoenix::ref(*this), qi::_1, qi::_2)]]; + minMaxExpression = ((minMaxOperator_ >> qi::lit("(")) > plusExpression > qi::lit(",") > plusExpression > qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionParser::createMinimumMaximumExpression, phoenix::ref(*this), qi::_2, qi::_1, qi::_3)]; minMaxExpression.name("min/max expression"); identifierExpression = identifier[qi::_val = phoenix::bind(&ExpressionParser::getIdentifierExpression, phoenix::ref(*this), qi::_1)]; identifierExpression.name("identifier expression"); - literalExpression = qi::lit("true")[qi::_val = phoenix::bind(&ExpressionParser::createTrueExpression, phoenix::ref(*this))] | qi::lit("false")[qi::_val = phoenix::bind(&ExpressionParser::createFalseExpression, phoenix::ref(*this))] | strict_double[qi::_val = phoenix::bind(&ExpressionParser::createDoubleLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1)]; + literalExpression = trueFalse_[qi::_val = qi::_1] | strict_double[qi::_val = phoenix::bind(&ExpressionParser::createDoubleLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1)]; literalExpression.name("literal expression"); - atomicExpression = minMaxExpression | floorCeilExpression | qi::lit("(") >> expression >> qi::lit(")") | literalExpression | identifierExpression; + atomicExpression = floorCeilExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | literalExpression | identifierExpression; atomicExpression.name("atomic expression"); - unaryExpression = atomicExpression[qi::_val = qi::_1] | (qi::lit("!") >> atomicExpression)[qi::_val = phoenix::bind(&ExpressionParser::createNotExpression, phoenix::ref(*this), qi::_1)] | (qi::lit("-") >> atomicExpression)[qi::_val = phoenix::bind(&ExpressionParser::createMinusExpression, phoenix::ref(*this), qi::_1)]; + unaryExpression = (-unaryOperator_ >> atomicExpression)[qi::_val = phoenix::bind(&ExpressionParser::createUnaryExpression, phoenix::ref(*this), qi::_1, qi::_2)]; unaryExpression.name("unary expression"); powerExpression = unaryExpression[qi::_val = qi::_1] > -(powerOperator_ > expression)[qi::_val = phoenix::bind(&ExpressionParser::createPowerExpression, phoenix::ref(*this), qi::_val, qi::_1, qi::_2)]; @@ -97,9 +97,8 @@ namespace storm { } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } storm::expressions::Expression ExpressionParser::createOrExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const { @@ -113,9 +112,8 @@ namespace storm { } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } storm::expressions::Expression ExpressionParser::createAndExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const { @@ -128,9 +126,8 @@ namespace storm { } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } storm::expressions::Expression ExpressionParser::createRelationalExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const { @@ -146,9 +143,8 @@ namespace storm { } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } storm::expressions::Expression ExpressionParser::createEqualsExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const { @@ -162,9 +158,8 @@ namespace storm { } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } storm::expressions::Expression ExpressionParser::createPlusExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const { @@ -178,9 +173,8 @@ namespace storm { } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } storm::expressions::Expression ExpressionParser::createMultExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const { @@ -194,9 +188,8 @@ namespace storm { } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } storm::expressions::Expression ExpressionParser::createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const { @@ -209,47 +202,29 @@ namespace storm { } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } - storm::expressions::Expression ExpressionParser::createNotExpression(storm::expressions::Expression e1) const { - if (this->createExpressions) { - try { - return !e1; - } catch (storm::exceptions::InvalidTypeException const& e) { - LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); - } - } else { - return storm::expressions::Expression::createFalse(); - } - } - - storm::expressions::Expression ExpressionParser::createMinusExpression(storm::expressions::Expression e1) const { + storm::expressions::Expression ExpressionParser::createUnaryExpression(boost::optional const& operatorType, storm::expressions::Expression const& e1) const { if (this->createExpressions) { try { - return -e1; + if (operatorType) { + switch (operatorType.get()) { + case storm::expressions::OperatorType::Not: return !e1; break; + case storm::expressions::OperatorType::Minus: return -e1; break; + default: LOG_ASSERT(false, "Invalid operation."); break; + } + } else { + return e1; + } } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } - } - - storm::expressions::Expression ExpressionParser::createTrueExpression() const { - if (this->createExpressions) { - return storm::expressions::Expression::createTrue(); - } else { - return storm::expressions::Expression::createFalse(); - } - } - - storm::expressions::Expression ExpressionParser::createFalseExpression() const { return storm::expressions::Expression::createFalse(); } - + storm::expressions::Expression ExpressionParser::createDoubleLiteralExpression(double value, bool& pass) const { // If we are not supposed to accept double expressions, we reject it by setting pass to false. if (!this->acceptDoubleLiterals) { @@ -271,52 +246,34 @@ namespace storm { } } - storm::expressions::Expression ExpressionParser::createMinimumExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const { - if (this->createExpressions) { - try { - return storm::expressions::Expression::minimum(e1, e2); - } catch (storm::exceptions::InvalidTypeException const& e) { - LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); - } - } else { - return storm::expressions::Expression::createFalse(); - } - } - - storm::expressions::Expression ExpressionParser::createMaximumExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const { - if (this->createExpressions) { - try { - return storm::expressions::Expression::maximum(e1, e2); - } catch (storm::exceptions::InvalidTypeException const& e) { - LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); - } - } else { - return storm::expressions::Expression::createFalse(); - } - } - - storm::expressions::Expression ExpressionParser::createFloorExpression(storm::expressions::Expression e1) const { + storm::expressions::Expression ExpressionParser::createMinimumMaximumExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2) const { if (this->createExpressions) { try { - return e1.floor(); + switch (operatorType) { + case storm::expressions::OperatorType::Min: return storm::expressions::Expression::minimum(e1, e2); break; + case storm::expressions::OperatorType::Max: return storm::expressions::Expression::maximum(e1, e2); break; + default: LOG_ASSERT(false, "Invalid operation."); break; + } } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } - - storm::expressions::Expression ExpressionParser::createCeilExpression(storm::expressions::Expression e1) const { + + storm::expressions::Expression ExpressionParser::createFloorCeilExpression(storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e1) const { if (this->createExpressions) { try { - return e1.ceil(); + switch (operatorType) { + case storm::expressions::OperatorType::Floor: return e1.floor(); break; + case storm::expressions::OperatorType::Ceil: return e1.ceil(); break; + default: LOG_ASSERT(false, "Invalid operation."); break; + } } catch (storm::exceptions::InvalidTypeException const& e) { LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << get_line(qi::_3) << ": " << e.what()); } - } else { - return storm::expressions::Expression::createFalse(); } + return storm::expressions::Expression::createFalse(); } storm::expressions::Expression ExpressionParser::getIdentifierExpression(std::string const& identifier) const { diff --git a/src/parser/ExpressionParser.h b/src/parser/ExpressionParser.h index 874eba438..423227aa2 100644 --- a/src/parser/ExpressionParser.h +++ b/src/parser/ExpressionParser.h @@ -120,6 +120,50 @@ namespace storm { // A parser used for recognizing the operators at the "power" precedence level. powerOperatorStruct powerOperator_; + struct unaryOperatorStruct : qi::symbols { + 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 { + 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 { + 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 { + trueFalseOperatorStruct() { + add + ("true", storm::expressions::Expression::createTrue()) + ("false", storm::expressions::Expression::createFalse()); + } + }; + + // A parser used for recognizing the literals true and false. + trueFalseOperatorStruct trueFalse_; + // A flag that indicates whether expressions should actually be generated or just a syntax check shall be // performed. bool createExpressions; @@ -164,16 +208,11 @@ namespace storm { 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 createNotExpression(storm::expressions::Expression e1) const; - storm::expressions::Expression createMinusExpression(storm::expressions::Expression e1) const; - storm::expressions::Expression createTrueExpression() const; - storm::expressions::Expression createFalseExpression() const; + storm::expressions::Expression createUnaryExpression(boost::optional 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 createMinimumExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const; - storm::expressions::Expression createMaximumExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const; - storm::expressions::Expression createFloorExpression(storm::expressions::Expression e1) const; - storm::expressions::Expression createCeilExpression(storm::expressions::Expression e1) 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); diff --git a/src/storage/expressions/OperatorType.cpp b/src/storage/expressions/OperatorType.cpp new file mode 100644 index 000000000..a4117d97c --- /dev/null +++ b/src/storage/expressions/OperatorType.cpp @@ -0,0 +1,33 @@ +#include "src/storage/expressions/OperatorType.h" + +namespace storm { + namespace expressions { + std::ostream& operator<<(std::ostream& stream, OperatorType const& operatorType) { + switch (operatorType) { + case OperatorType::And: stream << "&"; break; + case OperatorType::Or: stream << "|"; break; + case OperatorType::Xor: stream << "!="; break; + case OperatorType::Implies: stream << "=>"; break; + case OperatorType::Iff: stream << "<=>"; break; + case OperatorType::Plus: stream << "+"; break; + case OperatorType::Minus: stream << "-"; break; + case OperatorType::Times: stream << "*"; break; + case OperatorType::Divide: stream << "/"; break; + case OperatorType::Min: stream << "min"; break; + case OperatorType::Max: stream << "max"; break; + case OperatorType::Power: stream << "^"; break; + case OperatorType::Equal: stream << "="; break; + case OperatorType::NotEqual: stream << "!="; break; + case OperatorType::Less: stream << "<"; break; + case OperatorType::LessOrEqual: stream << "<="; break; + case OperatorType::Greater: stream << ">"; break; + case OperatorType::GreaterOrEqual: stream << ">="; break; + case OperatorType::Not: stream << "!"; break; + case OperatorType::Floor: stream << "floor"; break; + case OperatorType::Ceil: stream << "ceil"; break; + case OperatorType::Ite: stream << "ite"; break; + } + return stream; + } + } +} \ No newline at end of file diff --git a/src/storage/expressions/OperatorType.h b/src/storage/expressions/OperatorType.h index 8968cf105..5908bf789 100644 --- a/src/storage/expressions/OperatorType.h +++ b/src/storage/expressions/OperatorType.h @@ -1,6 +1,8 @@ #ifndef STORM_STORAGE_EXPRESSIONS_OPERATORTYPE_H_ #define STORM_STORAGE_EXPRESSIONS_OPERATORTYPE_H_ +#include + namespace storm { namespace expressions { // An enum representing all possible operator types. @@ -28,6 +30,8 @@ namespace storm { Ceil, Ite }; + + std::ostream& operator<<(std::ostream& stream, OperatorType const& operatorType); } } diff --git a/test/functional/parser/PrismParserTest.cpp b/test/functional/parser/PrismParserTest.cpp index 3621149b8..c7521fafc 100644 --- a/test/functional/parser/PrismParserTest.cpp +++ b/test/functional/parser/PrismParserTest.cpp @@ -94,7 +94,8 @@ TEST(PrismParser, ComplexTest) { endrewards)"; storm::prism::Program result; - result = storm::parser::PrismParser::parseFromString(testInput, "testfile"); + result = storm::parser::PrismParser::parseFromString(testInput, "testfile"); + EXPECT_NO_THROW(result = storm::parser::PrismParser::parseFromString(testInput, "testfile")); EXPECT_EQ(storm::prism::Program::ModelType::MA, result.getModelType()); EXPECT_EQ(3, result.getNumberOfModules()); EXPECT_EQ(2, result.getNumberOfRewardModels());