#include "src/storage/SparseMatrix.h" #include "src/parser/PrctlParser.h" #include "src/utility/OsDetection.h" #include "src/utility/ConstTemplates.h" // If the parser fails due to ill-formed data, this exception is thrown. #include "src/exceptions/WrongFileFormatException.h" // Used for Boost spirit. #include #include #include // Include headers for spirit iterators. Needed for diagnostics and input stream iteration. #include #include // Needed for file IO. #include #include // Some typedefs and namespace definitions to reduce code size. typedef std::string::const_iterator BaseIteratorType; typedef boost::spirit::classic::position_iterator2 PositionIteratorType; namespace qi = boost::spirit::qi; namespace phoenix = boost::phoenix; namespace storm { namespace parser { template struct PrctlParser::PrctlGrammar : qi::grammar*(), Skipper> { PrctlGrammar() : PrctlGrammar::base_type(start) { freeIdentifierName = qi::lexeme[(qi::alpha | qi::char_('_'))]; //This block defines rules for parsing state formulas stateFormula %= (andFormula | atomicProposition | orFormula | notFormula | probabilisticBoundOperator | rewardBoundOperator); andFormula = (qi::lit("(") >> stateFormula >> qi::lit("&") >> stateFormula >> qi::lit(")"))[ qi::_val = phoenix::new_>(qi::_1, qi::_2)]; orFormula = (qi::lit("(") >> stateFormula >> '|' >> stateFormula >> ')')[qi::_val = phoenix::new_>(qi::_1, qi::_2)]; notFormula = ('!' >> stateFormula)[qi::_val = phoenix::new_>(qi::_1)]; atomicProposition = (freeIdentifierName)[qi::_val = phoenix::new_>(qi::_1)]; probabilisticBoundOperator = ( ("P>=" >> qi::double_ >> '[' >> pathFormula >> ']')[qi::_val = phoenix::new_ >(storm::formula::BoundOperator::GREATER_EQUAL, qi::_1, qi::_2)] | ("P<=" >> qi::double_ >> '[' >> pathFormula >> ']')[qi::_val = phoenix::new_ >(storm::formula::BoundOperator::LESS_EQUAL, qi::_1, qi::_2)] ); rewardBoundOperator = ( ("R>=" >> qi::double_ >> '[' >> pathFormula >> ']')[qi::_val = phoenix::new_ >(storm::formula::BoundOperator::GREATER_EQUAL, qi::_1, qi::_2)] | ("R<=" >> qi::double_ >> '[' >> pathFormula >> ']')[qi::_val = phoenix::new_ >(storm::formula::BoundOperator::LESS_EQUAL, qi::_1, qi::_2)] ); //This block defines rules for parsing formulas with noBoundOperators noBoundOperator %= (probabilisticNoBoundOperator | rewardNoBoundOperator); probabilisticNoBoundOperator = ("P=?[" >> pathFormula >> ']')[qi::_val = phoenix::new_ >(qi::_1)]; rewardNoBoundOperator = ("R=?[" >> pathFormula >> ']')[qi::_val = phoenix::new_ >(qi::_1)]; //This block defines rules for parsing path formulas pathFormula %= (eventually | boundedEventually | globally | boundedUntil | until); eventually = ('F' >> stateFormula)[qi::_val = phoenix::new_ >(qi::_1)]; boundedEventually = ("F<=" >> qi::int_ >> stateFormula)[qi::_val = phoenix::new_>(qi::_2, qi::_1)]; globally = ('G' >> stateFormula)[qi::_val = phoenix::new_ >(qi::_1)]; until = (stateFormula >> 'U' >> stateFormula)[qi::_val = phoenix::new_>(qi::_1, qi::_2)]; boundedUntil = (stateFormula >> "U<=" >> qi::int_ >> stateFormula)[qi::_val = phoenix::new_>(qi::_1, qi::_3, qi::_2)]; start %= (stateFormula | noBoundOperator); } qi::rule*(), Skipper> start; qi::rule*(), Skipper> stateFormula; qi::rule*(), Skipper> andFormula; qi::rule*(), Skipper> atomicProposition; qi::rule*(), Skipper> orFormula; qi::rule*(), Skipper> notFormula; qi::rule*(), Skipper> probabilisticBoundOperator; qi::rule*(), Skipper> rewardBoundOperator; qi::rule*(), Skipper> noBoundOperator; qi::rule*(), Skipper> probabilisticNoBoundOperator; qi::rule*(), Skipper> rewardNoBoundOperator; qi::rule*(), Skipper> pathFormula; qi::rule*(), Skipper> boundedEventually; qi::rule*(), Skipper> eventually; qi::rule*(), Skipper> globally; qi::rule*(), Skipper> boundedUntil; qi::rule*(), Skipper> until; qi::rule freeIdentifierName; }; } //namespace storm } //namespace parser storm::parser::PrctlParser::PrctlParser(std::string filename) { // Open file and initialize result. std::ifstream inputFileStream(filename, std::ios::in); // Prepare iterators to input. // TODO: Right now, this parses the whole contents of the file into a string first. // While this is usually not necessary, because there exist adapters that make an input stream // iterable in both directions without storing it into a string, using the corresponding // Boost classes gives an awful output under valgrind and is thus disabled for the time being. std::string fileContent((std::istreambuf_iterator(inputFileStream)), (std::istreambuf_iterator())); BaseIteratorType stringIteratorBegin = fileContent.begin(); BaseIteratorType stringIteratorEnd = fileContent.end(); PositionIteratorType positionIteratorBegin(stringIteratorBegin, stringIteratorEnd, filename); PositionIteratorType positionIteratorEnd; // Prepare resulting intermediate representation of input. storm::formula::PctlFormula* result_pointer = nullptr; PrctlGrammar grammar; qi::phrase_parse(positionIteratorBegin, positionIteratorEnd, grammar, boost::spirit::ascii::space, result_pointer); }