136 lines
6.9 KiB

  1. #include "src/storage/SparseMatrix.h"
  2. #include "src/parser/PrctlParser.h"
  3. #include "src/utility/OsDetection.h"
  4. #include "src/utility/ConstTemplates.h"
  5. // If the parser fails due to ill-formed data, this exception is thrown.
  6. #include "src/exceptions/WrongFileFormatException.h"
  7. // Used for Boost spirit.
  8. #include <boost/typeof/typeof.hpp>
  9. #include <boost/spirit/include/qi.hpp>
  10. #include <boost/spirit/include/phoenix.hpp>
  11. // Include headers for spirit iterators. Needed for diagnostics and input stream iteration.
  12. #include <boost/spirit/include/classic_position_iterator.hpp>
  13. #include <boost/spirit/include/support_multi_pass.hpp>
  14. // Needed for file IO.
  15. #include <fstream>
  16. #include <iomanip>
  17. // Some typedefs and namespace definitions to reduce code size.
  18. typedef std::string::const_iterator BaseIteratorType;
  19. typedef boost::spirit::classic::position_iterator2<BaseIteratorType> PositionIteratorType;
  20. namespace qi = boost::spirit::qi;
  21. namespace phoenix = boost::phoenix;
  22. namespace storm {
  23. namespace parser {
  24. template<typename Iterator, typename Skipper>
  25. struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::formula::PctlFormula<double>*(), Skipper> {
  26. PrctlGrammar() : PrctlGrammar::base_type(start) {
  27. freeIdentifierName = qi::lexeme[(qi::alpha | qi::char_('_'))];
  28. //This block defines rules for parsing state formulas
  29. stateFormula %= (andFormula | atomicProposition | orFormula | notFormula | probabilisticBoundOperator | rewardBoundOperator);
  30. andFormula = (qi::lit("(") >> stateFormula >> qi::lit("&") >> stateFormula >> qi::lit(")"))[
  31. qi::_val = phoenix::new_<storm::formula::And<double>>(qi::_1, qi::_2)];
  32. orFormula = (qi::lit("(") >> stateFormula >> '|' >> stateFormula >> ')')[qi::_val =
  33. phoenix::new_<storm::formula::Or<double>>(qi::_1, qi::_2)];
  34. notFormula = ('!' >> stateFormula)[qi::_val =
  35. phoenix::new_<storm::formula::Not<double>>(qi::_1)];
  36. atomicProposition = (freeIdentifierName)[qi::_val =
  37. phoenix::new_<storm::formula::Ap<double>>(qi::_1)];
  38. probabilisticBoundOperator = (
  39. ("P>=" >> qi::double_ >> '[' >> pathFormula >> ']')[qi::_val =
  40. phoenix::new_<storm::formula::ProbabilisticBoundOperator<double> >(storm::formula::BoundOperator<double>::GREATER_EQUAL, qi::_1, qi::_2)] |
  41. ("P<=" >> qi::double_ >> '[' >> pathFormula >> ']')[qi::_val =
  42. phoenix::new_<storm::formula::ProbabilisticBoundOperator<double> >(storm::formula::BoundOperator<double>::LESS_EQUAL, qi::_1, qi::_2)]
  43. );
  44. rewardBoundOperator = (
  45. ("R>=" >> qi::double_ >> '[' >> pathFormula >> ']')[qi::_val =
  46. phoenix::new_<storm::formula::RewardBoundOperator<double> >(storm::formula::BoundOperator<double>::GREATER_EQUAL, qi::_1, qi::_2)] |
  47. ("R<=" >> qi::double_ >> '[' >> pathFormula >> ']')[qi::_val =
  48. phoenix::new_<storm::formula::RewardBoundOperator<double> >(storm::formula::BoundOperator<double>::LESS_EQUAL, qi::_1, qi::_2)]
  49. );
  50. //This block defines rules for parsing formulas with noBoundOperators
  51. noBoundOperator %= (probabilisticNoBoundOperator | rewardNoBoundOperator);
  52. probabilisticNoBoundOperator = ("P=?[" >> pathFormula >> ']')[qi::_val =
  53. phoenix::new_<storm::formula::ProbabilisticNoBoundOperator<double> >(qi::_1)];
  54. rewardNoBoundOperator = ("R=?[" >> pathFormula >> ']')[qi::_val =
  55. phoenix::new_<storm::formula::RewardNoBoundOperator<double> >(qi::_1)];
  56. //This block defines rules for parsing path formulas
  57. pathFormula %= (eventually | boundedEventually | globally | boundedUntil | until);
  58. eventually = ('F' >> stateFormula)[qi::_val =
  59. phoenix::new_<storm::formula::Eventually<double> >(qi::_1)];
  60. boundedEventually = ("F<=" >> qi::int_ >> stateFormula)[qi::_val =
  61. phoenix::new_<storm::formula::BoundedEventually<double>>(qi::_2, qi::_1)];
  62. globally = ('G' >> stateFormula)[qi::_val =
  63. phoenix::new_<storm::formula::Globally<double> >(qi::_1)];
  64. until = (stateFormula >> 'U' >> stateFormula)[qi::_val =
  65. phoenix::new_<storm::formula::Until<double>>(qi::_1, qi::_2)];
  66. boundedUntil = (stateFormula >> "U<=" >> qi::int_ >> stateFormula)[qi::_val =
  67. phoenix::new_<storm::formula::BoundedUntil<double>>(qi::_1, qi::_3, qi::_2)];
  68. start %= (stateFormula | noBoundOperator);
  69. }
  70. qi::rule<Iterator, storm::formula::PctlFormula<double>*(), Skipper> start;
  71. qi::rule<Iterator, storm::formula::PctlStateFormula<double>*(), Skipper> stateFormula;
  72. qi::rule<Iterator, storm::formula::And<double>*(), Skipper> andFormula;
  73. qi::rule<Iterator, storm::formula::Ap<double>*(), Skipper> atomicProposition;
  74. qi::rule<Iterator, storm::formula::PctlStateFormula<double>*(), Skipper> orFormula;
  75. qi::rule<Iterator, storm::formula::PctlStateFormula<double>*(), Skipper> notFormula;
  76. qi::rule<Iterator, storm::formula::PctlStateFormula<double>*(), Skipper> probabilisticBoundOperator;
  77. qi::rule<Iterator, storm::formula::PctlStateFormula<double>*(), Skipper> rewardBoundOperator;
  78. qi::rule<Iterator, storm::formula::NoBoundOperator<double>*(), Skipper> noBoundOperator;
  79. qi::rule<Iterator, storm::formula::NoBoundOperator<double>*(), Skipper> probabilisticNoBoundOperator;
  80. qi::rule<Iterator, storm::formula::NoBoundOperator<double>*(), Skipper> rewardNoBoundOperator;
  81. qi::rule<Iterator, storm::formula::PctlPathFormula<double>*(), Skipper> pathFormula;
  82. qi::rule<Iterator, storm::formula::PctlPathFormula<double>*(), Skipper> boundedEventually;
  83. qi::rule<Iterator, storm::formula::PctlPathFormula<double>*(), Skipper> eventually;
  84. qi::rule<Iterator, storm::formula::PctlPathFormula<double>*(), Skipper> globally;
  85. qi::rule<Iterator, storm::formula::PctlPathFormula<double>*(), Skipper> boundedUntil;
  86. qi::rule<Iterator, storm::formula::PctlPathFormula<double>*(), Skipper> until;
  87. qi::rule<Iterator, std::string(), Skipper> freeIdentifierName;
  88. };
  89. } //namespace storm
  90. } //namespace parser
  91. storm::parser::PrctlParser::PrctlParser(std::string filename) {
  92. // Open file and initialize result.
  93. std::ifstream inputFileStream(filename, std::ios::in);
  94. // Prepare iterators to input.
  95. // TODO: Right now, this parses the whole contents of the file into a string first.
  96. // While this is usually not necessary, because there exist adapters that make an input stream
  97. // iterable in both directions without storing it into a string, using the corresponding
  98. // Boost classes gives an awful output under valgrind and is thus disabled for the time being.
  99. std::string fileContent((std::istreambuf_iterator<char>(inputFileStream)), (std::istreambuf_iterator<char>()));
  100. BaseIteratorType stringIteratorBegin = fileContent.begin();
  101. BaseIteratorType stringIteratorEnd = fileContent.end();
  102. PositionIteratorType positionIteratorBegin(stringIteratorBegin, stringIteratorEnd, filename);
  103. PositionIteratorType positionIteratorEnd;
  104. // Prepare resulting intermediate representation of input.
  105. storm::formula::PctlFormula<double>* result_pointer = nullptr;
  106. PrctlGrammar<PositionIteratorType, BOOST_TYPEOF(boost::spirit::ascii::space)> grammar;
  107. qi::phrase_parse(positionIteratorBegin, positionIteratorEnd, grammar, boost::spirit::ascii::space, result_pointer);
  108. }