diff --git a/src/formula/Formulas.h b/src/formula/Formulas.h index 70ed03c75..38c607771 100644 --- a/src/formula/Formulas.h +++ b/src/formula/Formulas.h @@ -8,6 +8,8 @@ #ifndef STORM_FORMULA_FORMULAS_H_ #define STORM_FORMULA_FORMULAS_H_ +#include "modelChecker/ForwardDeclarations.h" + #include "And.h" #include "Ap.h" #include "BoundedUntil.h" @@ -30,4 +32,6 @@ #include "RewardBoundOperator.h" #include "RewardNoBoundOperator.h" +#include "modelChecker/DtmcPrctlModelChecker.h" + #endif /* STORM_FORMULA_FORMULAS_H_ */ diff --git a/src/formula/NoBoundOperator.h b/src/formula/NoBoundOperator.h index 204c102a8..4c4113f49 100644 --- a/src/formula/NoBoundOperator.h +++ b/src/formula/NoBoundOperator.h @@ -11,6 +11,8 @@ #include "PctlFormula.h" #include "PctlPathFormula.h" +#include "modelChecker/ForwardDeclarations.h" + namespace storm { namespace formula { diff --git a/src/formula/PctlPathFormula.h b/src/formula/PctlPathFormula.h index f929c642a..eaebd087e 100644 --- a/src/formula/PctlPathFormula.h +++ b/src/formula/PctlPathFormula.h @@ -9,7 +9,7 @@ #define STORM_FORMULA_PCTLPATHFORMULA_H_ #include "PctlFormula.h" -#include "modelChecker/DtmcPrctlModelChecker.h" + #include namespace storm { @@ -62,4 +62,6 @@ public: } //namespace storm + + #endif /* STORM_FORMULA_PCTLPATHFORMULA_H_ */ diff --git a/src/formula/PctlStateFormula.h b/src/formula/PctlStateFormula.h index bfd035e4d..eb7424d3f 100644 --- a/src/formula/PctlStateFormula.h +++ b/src/formula/PctlStateFormula.h @@ -10,7 +10,6 @@ #include "PctlFormula.h" #include "storage/BitVector.h" -#include "modelChecker/DtmcPrctlModelChecker.h" namespace storm { @@ -62,5 +61,4 @@ public: } //namespace storm - #endif /* STORM_FORMULA_PCTLSTATEFORMULA_H_ */ diff --git a/src/modelChecker/DtmcPrctlModelChecker.h b/src/modelChecker/DtmcPrctlModelChecker.h index 60a88adce..6204605af 100644 --- a/src/modelChecker/DtmcPrctlModelChecker.h +++ b/src/modelChecker/DtmcPrctlModelChecker.h @@ -8,25 +8,13 @@ #ifndef STORM_MODELCHECKER_DTMCPRCTLMODELCHECKER_H_ #define STORM_MODELCHECKER_DTMCPRCTLMODELCHECKER_H_ -namespace storm { - -namespace modelChecker { - -/* The formula classes need to reference a model checker for the check function, - * which is used to infer the correct type of formula, - * so the model checker class is declared here already. - * - */ -template -class DtmcPrctlModelChecker; -} -} #include "src/formula/PctlPathFormula.h" #include "src/formula/PctlStateFormula.h" #include "src/formula/Formulas.h" +#include "src/utility/Vector.h" #include "src/models/Dtmc.h" #include "src/storage/BitVector.h" @@ -192,6 +180,7 @@ public: if (!this->getModel().hasAtomicProposition(formula.getAp())) { throw storm::exceptions::InvalidPropertyException() << "Atomic proposition '" << formula.getAp() << "' is invalid."; + return nullptr; } return new storm::storage::BitVector(*this->getModel().getLabeledStates(formula.getAp())); diff --git a/src/parser/PrctlParser.cpp b/src/parser/PrctlParser.cpp index 9c0850ca5..b3bd6d06f 100644 --- a/src/parser/PrctlParser.cpp +++ b/src/parser/PrctlParser.cpp @@ -1,147 +1,140 @@ +#include "src/storage/SparseMatrix.h" #include "src/parser/PrctlParser.h" +#include "src/utility/OsDetection.h" +#include "src/utility/ConstTemplates.h" -#include -#include -//#include +// If the parser fails due to ill-formed data, this exception is thrown. +#include "src/exceptions/WrongFileFormatException.h" -#include -#include -#include +// Used for Boost spirit. +#include #include -#include -#include +#include -#include +// Include headers for spirit iterators. Needed for diagnostics and input stream iteration. +#include +#include -namespace bs = boost::spirit; +// Needed for file IO. +#include +#include -namespace -{ - using namespace bs; - using namespace bs::qi; - using namespace bs::standard; - - struct SpiritParser : public grammar< char const* > - { - typedef rule< char const* > rule_none; - typedef rule< char const*, double() > rule_double; - typedef rule< char const*, std::string() > rule_string; - - /*! - * @brief Generic Nonterminals. - */ - rule_none ws; - rule_string variable; - rule_double value; - - /*! - * @brief Nonterminals for file header. - */ - rule< char const* > varDef; - rule_none type; - - /*! - * @brief Nonterminals for formula. - */ - rule_none formula, opP; - - /*! - * @brief Nonterminals for high-level file structure. - */ - rule_none file, header; - - /*! - * @brief Variable assignments. - */ - std::map variables; - - /*! - * @brief Resulting formula. - */ - storm::formula::PctlFormula* result; - - struct dump - { - void print(double const& i, std::string& s) - { - std::cout << s << " = " << i << std::endl; - } - void operator()(double const& a, unused_type, unused_type) const - { - std::cout << a << std::endl; - } - void operator()(std::string const& a, unused_type, unused_type) const - { - std::cout << a << std::endl; - } - void operator()(utree const& a, unused_type, unused_type) const - { - std::cout << &a << std::endl; - } - }; - - SpiritParser() : SpiritParser::base_type(file, "PRCTL parser") - { - variable %= alnum; - ws = *( space ); - value %= ( double_ | int_ ); // double_ must be *before* int_ - type = string("int") | string("double"); - - /* - * Todo: - * Use two arguments at one point in the code, e.g. do something like - * this->variables[ variable ] = value - * - * You can have local variables in rules, but somehow does not work. - * You can also (somehow) let a rule return some arbitrary class and let boost magically collect the arguments for the constructor. - * No idea how this can possibly work, did not get this to work. - * You can also generate a syntax tree and do this manually (-> utree)... somehow. - * - * Attention: spirit had some major upgrades in the last few releases. 1.48 already lacks some features that might be useful. - * - * The rules parse the const definitions of - * http://www.prismmodelchecker.org/manual/PropertySpecification/PropertiesFiles - * We actually do not need them, but the problems I described above are fairly generic. - * We will not be able to parse the formulas if we don't solve them... - * - * Example input: - * const int k = 7; - * const double T = 9; - * const double p = 0.01; - * - * Parser can be run via ./storm --test-prctl foo bar - * foo and bar are necessary, otherwise the option parser fails... - */ - - varDef = - string("const") >> ws >> - type >> ws >> - variable >> ws >> - string("=") >> ws >> - value >> ws >> - string(";"); - - header = +( varDef >> ws ); - - file = header; - } - - - }; -} +// Some typedefs and namespace definitions to reduce code size. +typedef std::istreambuf_iterator base_iterator_type; +typedef boost::spirit::multi_pass forward_iterator_type; +typedef boost::spirit::classic::position_iterator2 pos_iterator_type; +namespace qi = boost::spirit::qi; +namespace phoenix = boost::phoenix; -storm::parser::PrctlParser::PrctlParser(const char* filename) -{ - SpiritParser p; - storm::parser::MappedFile file(filename); - - char* data = file.data; - if (bs::qi::parse< char const* >(data, file.dataend, p)) - { - std::cout << "File was parsed" << std::endl; - std::string rest(data, file.dataend); - std::cout << "Rest: " << rest << std::endl; - this->formula = p.result; +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 = ("(" << stateFormula << "&" << stateFormula << ")")[qi::_val = + phoenix::new_>(qi::_1, qi::_2)]; + orFormula = ('(' << 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_>(qi::_1, qi::_1, qi::_2)] | + ("P[" << qi::double_ << qi::double_ << ']' << '[' << pathFormula << ']')[qi::_val = + phoenix::new_ >(qi::_1, qi::_2, qi::_3)] | + ("P>=" << qi::double_ << '[' << pathFormula << ']')[qi::_val = + phoenix::new_ >(qi::_1, 1, qi::_2)] | + ("P<=" << qi::double_ << '[' << pathFormula << ']')[qi::_val = + phoenix::new_ >(0, qi::_1, qi::_2)] + ); + rewardBoundOperator = ( + ("R=" << qi::double_ << '[' << pathFormula << ']') [qi::_val = + phoenix::new_ >(qi::_1, qi::_1, qi::_2)] | + ("R[" << qi::double_ << qi::double_ << ']' << '[' << pathFormula << ']')[qi::_val = + phoenix::new_ >(qi::_1, qi::_2, qi::_3)] | + ("R>=" << qi::double_ << '[' << pathFormula << ']')[qi::_val = + phoenix::new_ >(qi::_1, storm::utility::constGetInfinity(), qi::_2)] | + ("R<=" << qi::double_ << '[' << pathFormula << ']')[qi::_val = + phoenix::new_ >(0, 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' << pathFormula)[qi::_val = + phoenix::new_ >(qi::_1)]; + boundedEventually = ("F<=" << qi::double_ << pathFormula)[qi::_val = + phoenix::new_>(qi::_2, qi::_1)]; + globally = ('G' << pathFormula)[qi::_val = + phoenix::new_ >(qi::_1)]; + until = (stateFormula << 'U' << stateFormula)[qi::_val = + phoenix::new_>(qi::_1, qi::_2)]; + boundedUntil = (stateFormula << "U<=" << qi::double_ << stateFormula)[qi::_val = + phoenix::new_>(qi::_1, qi::_3, qi::_2)]; + + start %= (stateFormula | noBoundOperator); } - else this->formula = NULL; + + 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. + base_iterator_type in_begin(inputFileStream); + forward_iterator_type fwd_begin = boost::spirit::make_default_multi_pass(in_begin); + forward_iterator_type fwd_end; + pos_iterator_type position_begin(fwd_begin, fwd_end, filename); + pos_iterator_type position_end; + + // Prepare resulting intermediate representation of input. + storm::formula::PctlFormula* result_pointer; + + PrctlGrammar grammar; + + qi::phrase_parse(position_begin, position_end, grammar, boost::spirit::ascii::space, result_pointer); + + } diff --git a/src/parser/PrctlParser.h b/src/parser/PrctlParser.h index 79c2e81c7..29f16aa18 100644 --- a/src/parser/PrctlParser.h +++ b/src/parser/PrctlParser.h @@ -1,9 +1,11 @@ #ifndef STORM_PARSER_PRCTLPARSER_H_ #define STORM_PARSER_PRCTLPARSER_H_ -#include "src/formula/PctlFormula.h" #include "src/parser/Parser.h" +#include "src/formula/Formulas.h" +#include + namespace storm { namespace parser { @@ -13,18 +15,20 @@ namespace parser { class PrctlParser : Parser { public: - PrctlParser(const char * filename); + PrctlParser(std::string filename); /*! * @brief return formula object parsed from file. */ - storm::formula::PctlFormula* getFormula() + std::shared_ptr> getFormula() { return this->formula; } private: - storm::formula::PctlFormula* formula; + std::shared_ptr> formula; + template + struct PrctlGrammar; }; } // namespace parser diff --git a/src/utility/Vector.h b/src/utility/Vector.h index 187d3c5e2..0add7457f 100644 --- a/src/utility/Vector.h +++ b/src/utility/Vector.h @@ -9,7 +9,7 @@ #define STORM_UTILITY_VECTOR_H_ #include "Eigen/src/Core/Matrix.h" - +#include "ConstTemplates.h" #include namespace storm {