#include "src/parser/PrctlParser.h" #include <iostream> #include <map> //#include <pair> #include <boost/spirit/include/classic_core.hpp> #include <boost/spirit/include/qi_grammar.hpp> #include <boost/spirit/include/qi_rule.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/spirit/include/qi_char_class.hpp> #include <boost/bind.hpp> namespace bs = boost::spirit; 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<std::string, double> variables; /*! * @brief Resulting formula. */ storm::formula::PctlFormula<double>* 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 <filename> 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; } }; } 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; } else this->formula = NULL; }