/* * PrismParser.h * * Created on: Jan 3, 2013 * Author: Christian Dehnert */ #ifndef PRISMPARSER_H_ #define PRISMPARSER_H_ #include #include #include #include #include #include #include #include "src/ir/IR.h" #include #include #include namespace storm { namespace parser { namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace phoenix = boost::phoenix; class PrismParser { public: void test(std::string const& fileName) { std::ifstream inputFileStream(fileName, std::ios::in); getProgram(inputFileStream, fileName); inputFileStream.close(); } void getProgram(std::istream& inputStream, std::string const& fileName) { typedef std::istreambuf_iterator base_iterator_type; base_iterator_type in_begin(inputStream); typedef boost::spirit::multi_pass forward_iterator_type; forward_iterator_type fwd_begin = boost::spirit::make_default_multi_pass(in_begin); forward_iterator_type fwd_end; typedef boost::spirit::classic::position_iterator2 pos_iterator_type; pos_iterator_type position_begin(fwd_begin, fwd_end, fileName); pos_iterator_type position_end; storm::ir::Program result; prismGrammar> *(qi::char_ - qi::eol) >> qi::eol)> grammar; try { phrase_parse(position_begin, position_end, grammar, ascii::space | qi::lit("//") >> *(qi::char_ - qi::eol) >> qi::eol, result); } catch(const qi::expectation_failure& e) { const boost::spirit::classic::file_position_base& pos = e.first.get_position(); std::stringstream msg; msg << "parse error at file '" << pos.file << "' line " << pos.line << " column " << pos.column << std::endl << "'" << e.first.get_currentline() << "'" << std::endl << std::setw(pos.column + 1) << " " << "^------- here"; std::cout << msg.str() << std::endl; throw storm::exceptions::WrongFileFormatException() << msg.str(); } std::cout << result.toString(); } private: template struct prismGrammar : qi::grammar>, std::map>, std::map>, std::map>, Skipper> { prismGrammar() : prismGrammar::base_type(start) { freeIdentifierName %= qi::lexeme[qi::alpha >> *(qi::alnum | qi::char_('_'))] - allVariables_ - allConstants_; booleanLiteralExpression = qi::bool_[qi::_val = phoenix::construct>(phoenix::new_(qi::_1))]; integerLiteralExpression = qi::int_[qi::_val = phoenix::construct>(phoenix::new_(qi::_1))]; doubleLiteralExpression = qi::double_[qi::_val = phoenix::construct>(phoenix::new_(qi::_1))]; literalExpression %= (booleanLiteralExpression | integerLiteralExpression | doubleLiteralExpression); integerVariableExpression = integerVariables_; booleanVariableExpression = booleanVariables_; variableExpression = (integerVariableExpression | booleanVariableExpression); booleanConstantExpression %= (booleanConstants_ | booleanLiteralExpression); integerConstantExpression %= (integerConstants_ | integerLiteralExpression); doubleConstantExpression %= (doubleConstants_ | doubleLiteralExpression); constantExpression %= (booleanConstantExpression | integerConstantExpression | doubleConstantExpression); atomicIntegerExpression %= (integerVariableExpression | qi::lit("(") >> integerExpression >> qi::lit(")") | integerConstantExpression); integerMultExpression %= atomicIntegerExpression[qi::_val = qi::_1] >> *(qi::lit("*") >> atomicIntegerExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryNumericalFunctionExpression::TIMES))]; integerPlusExpression = integerMultExpression[qi::_val = qi::_1] >> *(qi::lit("+") >> integerMultExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryNumericalFunctionExpression::PLUS))]; integerExpression %= integerPlusExpression; constantAtomicIntegerExpression %= (qi::lit("(") >> constantIntegerExpression >> qi::lit(")") | integerConstantExpression); constantIntegerMultExpression %= constantAtomicIntegerExpression[qi::_val = qi::_1] >> *(qi::lit("*") >> constantAtomicIntegerExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryNumericalFunctionExpression::TIMES))]; constantIntegerPlusExpression = constantIntegerMultExpression[qi::_val = qi::_1] >> *(qi::lit("+") >> constantIntegerMultExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryNumericalFunctionExpression::PLUS))]; constantIntegerExpression %= constantIntegerPlusExpression; // This block defines all expressions of type double that are by syntax constant. That is, they are evaluable given the values for all constants. constantAtomicDoubleExpression %= (qi::lit("(") >> constantDoubleExpression >> qi::lit(")") | doubleConstantExpression); constantDoubleMultExpression %= constantAtomicDoubleExpression[qi::_val = qi::_1] >> *(qi::lit("*") >> constantAtomicDoubleExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryNumericalFunctionExpression::TIMES))]; constantDoublePlusExpression %= constantDoubleMultExpression[qi::_val = qi::_1] >> *(qi::lit("+") >> constantDoubleMultExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryNumericalFunctionExpression::PLUS))]; constantDoubleExpression %= constantDoublePlusExpression; // This block defines all expressions of type boolean. relativeExpression = (integerExpression >> relations_ >> integerExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_1, qi::_3, qi::_2))]; atomicBooleanExpression %= (relativeExpression | booleanVariableExpression | qi::lit("(") >> booleanExpression >> qi::lit(")") | booleanConstantExpression); notExpression = atomicBooleanExpression[qi::_val = qi::_1] | (qi::lit("!") >> atomicBooleanExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_1, storm::ir::expressions::UnaryBooleanFunctionExpression::FunctorType::NOT))]; andExpression = notExpression[qi::_val = qi::_1] >> *(qi::lit("&") >> notExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryBooleanFunctionExpression::AND))]; orExpression = andExpression[qi::_val = qi::_1] >> *(qi::lit("|") >> andExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryBooleanFunctionExpression::OR))]; booleanExpression %= orExpression; // This block defines all expressions of type boolean that are by syntax constant. That is, they are evaluable given the values for all constants. constantRelativeExpression = (constantIntegerExpression >> relations_ >> constantIntegerExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_1, qi::_3, qi::_2))]; constantAtomicBooleanExpression %= (constantRelativeExpression | qi::lit("(") >> constantBooleanExpression >> qi::lit(")") | booleanLiteralExpression | booleanConstantExpression); constantNotExpression = constantAtomicBooleanExpression[qi::_val = qi::_1] | (qi::lit("!") >> constantAtomicBooleanExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_1, storm::ir::expressions::UnaryBooleanFunctionExpression::FunctorType::NOT))]; constantAndExpression = constantNotExpression[qi::_val = qi::_1] >> *(qi::lit("&") >> constantNotExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryBooleanFunctionExpression::AND))]; constantOrExpression = constantAndExpression[qi::_val = qi::_1] >> *(qi::lit("|") >> constantAndExpression)[qi::_val = phoenix::construct>(phoenix::new_(qi::_val, qi::_1, storm::ir::expressions::BinaryBooleanFunctionExpression::OR))]; constantBooleanExpression %= constantOrExpression; // This block defines the general root of all expressions. Most of the time, however, you may want to start with a more specialized rule. expression %= (booleanExpression | integerExpression | constantDoubleExpression); stateRewardDefinition = (booleanExpression > qi::lit(":") > constantDoubleExpression >> qi::lit(";"))[qi::_val = phoenix::construct(qi::_1, qi::_2)]; transitionRewardDefinition = (qi::lit("[") > -(commandName[qi::_a = qi::_1]) > qi::lit("]") > booleanExpression > qi::lit(":") > constantDoubleExpression > qi::lit(";"))[qi::_val = phoenix::construct(qi::_a, qi::_2, qi::_3)]; rewardDefinition = (qi::lit("rewards") > qi::lit("\"") > freeIdentifierName > qi::lit("\"") > +(stateRewardDefinition[phoenix::push_back(qi::_a, qi::_1)] | transitionRewardDefinition[phoenix::push_back(qi::_b, qi::_1)]) > qi::lit("endrewards"))[phoenix::insert(qi::_r1, phoenix::construct>(qi::_1, phoenix::construct(qi::_1, qi::_a, qi::_b)))]; rewardDefinitionList = *rewardDefinition(qi::_r1); // This block defines auxiliary entities that are used to check whether a certain variable exist. integerVariableName %= integerVariableNames_; booleanVariableName %= booleanVariableNames_; commandName %= commandNames_; // This block defines all entities that are needed for parsing a single command. assignmentDefinition = (qi::lit("(") >> integerVariableName > qi::lit("'") > qi::lit("=") > integerExpression > qi::lit(")"))[qi::_val = phoenix::construct(qi::_1, qi::_2)] | (qi::lit("(") > booleanVariableName > qi::lit("'") > qi::lit("=") > booleanExpression > qi::lit(")"))[qi::_val = phoenix::construct(qi::_1, qi::_2)]; assignmentDefinitionList %= assignmentDefinition % "&"; updateDefinition = (constantDoubleExpression > qi::lit(":") > assignmentDefinitionList)[qi::_val = phoenix::construct(qi::_1, qi::_2)]; updateListDefinition = +updateDefinition % "+"; commandDefinition = (qi::lit("[") > -((freeIdentifierName[phoenix::bind(commandNames_.add, qi::_1, qi::_1)] | commandName)[qi::_a = qi::_1]) > qi::lit("]") > booleanExpression > qi::lit("->") > updateListDefinition > qi::lit(";"))[qi::_val = phoenix::construct(qi::_a, qi::_2, qi::_3)]; // This block defines all entities that are neede for parsing variable definitions. booleanVariableDefinition = (freeIdentifierName >> qi::lit(":") >> qi::lit("bool") > -(qi::lit("init") > constantBooleanExpression[qi::_b = phoenix::construct>(qi::_1)]) > qi::lit(";"))[qi::_val = phoenix::construct(qi::_1, qi::_b), qi::_a = phoenix::construct>(phoenix::new_(qi::_1)), phoenix::bind(booleanVariables_.add, qi::_1, qi::_a), phoenix::bind(booleanVariableNames_.add, qi::_1, qi::_1), phoenix::bind(allVariables_.add, qi::_1, qi::_a), phoenix::bind(booleanVariableInfo_.add, qi::_1, qi::_val)]; integerVariableDefinition = (freeIdentifierName > qi::lit(":") > qi::lit("[") > constantIntegerExpression > qi::lit("..") > constantIntegerExpression > qi::lit("]") > -(qi::lit("init") > constantIntegerExpression[qi::_b = phoenix::construct>(qi::_1)]) > qi::lit(";"))[qi::_val = phoenix::construct(qi::_1, qi::_2, qi::_3, qi::_b), qi::_a = phoenix::construct>(phoenix::new_(qi::_1)), phoenix::bind(integerVariables_.add, qi::_1, qi::_a), phoenix::bind(integerVariableNames_.add, qi::_1, qi::_1), phoenix::bind(allVariables_.add, qi::_1, qi::_a), phoenix::bind(integerVariableInfo_.add, qi::_1, qi::_val)]; variableDefinition = (booleanVariableDefinition | integerVariableDefinition); // This block defines all entities that are needed for parsing a module. moduleDefinition = (qi::lit("module") > freeIdentifierName > *(booleanVariableDefinition[phoenix::push_back(qi::_a, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_b, qi::_1)]) > +commandDefinition > qi::lit("endmodule"))[qi::_val = phoenix::construct(qi::_1, qi::_a, qi::_b, qi::_3)]; moduleDefinitionList %= +moduleDefinition; // This block defines all entities that are needed for parsing constant definitions. definedBooleanConstantDefinition = (qi::lit("const") >> qi::lit("bool") >> freeIdentifierName >> qi::lit("=") > booleanLiteralExpression > qi::lit(";"))[phoenix::bind(booleanConstants_.add, qi::_1, qi::_2), phoenix::bind(allConstants_.add, qi::_1, qi::_2), qi::_val = qi::_2]; definedIntegerConstantDefinition = (qi::lit("const") >> qi::lit("int") >> freeIdentifierName >> qi::lit("=") > integerLiteralExpression > qi::lit(";"))[phoenix::bind(integerConstants_.add, qi::_1, qi::_2), phoenix::bind(allConstants_.add, qi::_1, qi::_2), qi::_val = qi::_2]; definedDoubleConstantDefinition = (qi::lit("const") >> qi::lit("double") >> freeIdentifierName >> qi::lit("=") > doubleLiteralExpression > qi::lit(";"))[phoenix::bind(doubleConstants_.add, qi::_1, qi::_2), phoenix::bind(allConstants_.add, qi::_1, qi::_2), qi::_val = qi::_2]; undefinedBooleanConstantDefinition = (qi::lit("const") >> qi::lit("bool") > freeIdentifierName > qi::lit(";"))[qi::_a = phoenix::construct>(phoenix::new_(qi::_1)), phoenix::insert(qi::_r1, phoenix::construct>>(qi::_1, qi::_a)), phoenix::bind(booleanConstantInfo_.add, qi::_1, qi::_a), phoenix::bind(booleanConstants_.add, qi::_1, qi::_a), phoenix::bind(allConstants_.add, qi::_1, qi::_a)]; undefinedIntegerConstantDefinition = (qi::lit("const") >> qi::lit("int") > freeIdentifierName > qi::lit(";"))[qi::_a = phoenix::construct>(phoenix::new_(qi::_1)), phoenix::insert(qi::_r1, phoenix::construct>>(qi::_1, qi::_a)), phoenix::bind(integerConstantInfo_.add, qi::_1, qi::_a), phoenix::bind(integerConstants_.add, qi::_1, qi::_a), phoenix::bind(allConstants_.add, qi::_1, qi::_a)]; undefinedDoubleConstantDefinition = (qi::lit("const") >> qi::lit("double") > freeIdentifierName > qi::lit(";"))[qi::_a = phoenix::construct>(phoenix::new_(qi::_1)), phoenix::insert(qi::_r1, phoenix::construct>>(qi::_1, qi::_a)), phoenix::bind(doubleConstantInfo_.add, qi::_1, qi::_a), phoenix::bind(doubleConstants_.add, qi::_1, qi::_a), phoenix::bind(allConstants_.add, qi::_1, qi::_a)]; definedConstantDefinition %= (definedBooleanConstantDefinition | definedIntegerConstantDefinition | definedDoubleConstantDefinition); undefinedConstantDefinition = (undefinedBooleanConstantDefinition(qi::_r1) | undefinedIntegerConstantDefinition(qi::_r2) | undefinedDoubleConstantDefinition(qi::_r3)); constantDefinitionList = *(definedConstantDefinition | undefinedConstantDefinition(qi::_r1, qi::_r2, qi::_r3)); // This block defines all entities that are needed for parsing a program. modelTypeDefinition = modelType_; start = (modelTypeDefinition > constantDefinitionList(qi::_a, qi::_b, qi::_c) > moduleDefinitionList > rewardDefinitionList(qi::_d))[qi::_val = phoenix::construct(qi::_1, qi::_a, qi::_b, qi::_c, qi::_2, qi::_d)]; } // The starting point of the grammar. qi::rule>, std::map>, std::map>, std::map>, Skipper> start; qi::rule modelTypeDefinition; qi::rule>&, std::map>&, std::map>&), Skipper> constantDefinitionList; qi::rule(), Skipper> moduleDefinitionList; qi::rule, std::vector>, Skipper> moduleDefinition; qi::rule variableDefinition; qi::rule, std::shared_ptr>, Skipper> booleanVariableDefinition; qi::rule, std::shared_ptr>, Skipper> integerVariableDefinition; qi::rule, Skipper> commandDefinition; qi::rule(), Skipper> updateListDefinition; qi::rule updateDefinition; qi::rule(), Skipper> assignmentDefinitionList; qi::rule assignmentDefinition; qi::rule integerVariableName; qi::rule booleanVariableName; qi::rule commandName; qi::rule&), Skipper> rewardDefinitionList; qi::rule&), qi::locals, std::vector>, Skipper> rewardDefinition; qi::rule stateRewardDefinition; qi::rule, Skipper> transitionRewardDefinition; qi::rule(), Skipper> constantDefinition; qi::rule>&, std::map>&, std::map>&), Skipper> undefinedConstantDefinition; qi::rule(), Skipper> definedConstantDefinition; qi::rule>&), qi::locals>, Skipper> undefinedBooleanConstantDefinition; qi::rule>&), qi::locals>, Skipper> undefinedIntegerConstantDefinition; qi::rule>&), qi::locals>, Skipper> undefinedDoubleConstantDefinition; qi::rule(), Skipper> definedBooleanConstantDefinition; qi::rule(), Skipper> definedIntegerConstantDefinition; qi::rule(), Skipper> definedDoubleConstantDefinition; qi::rule freeIdentifierName; // The starting point for arbitrary expressions. qi::rule(), Skipper> expression; // Rules with boolean result type. qi::rule(), Skipper> booleanExpression; qi::rule(), Skipper> orExpression; qi::rule(), Skipper> andExpression; qi::rule(), Skipper> notExpression; qi::rule(), Skipper> atomicBooleanExpression; qi::rule(), Skipper> relativeExpression; qi::rule(), Skipper> constantBooleanExpression; qi::rule(), Skipper> constantOrExpression; qi::rule(), Skipper> constantAndExpression; qi::rule(), Skipper> constantNotExpression; qi::rule(), Skipper> constantAtomicBooleanExpression; qi::rule(), Skipper> constantRelativeExpression; // Rules with integer result type. qi::rule(), Skipper> integerExpression; qi::rule(), Skipper> integerPlusExpression; qi::rule(), Skipper> integerMultExpression; qi::rule(), Skipper> atomicIntegerExpression; qi::rule(), Skipper> constantIntegerExpression; qi::rule(), Skipper> constantIntegerPlusExpression; qi::rule(), Skipper> constantIntegerMultExpression; qi::rule(), Skipper> constantAtomicIntegerExpression; // Rules with double result type. qi::rule(), Skipper> constantDoubleExpression; qi::rule(), Skipper> constantDoublePlusExpression; qi::rule(), Skipper> constantDoubleMultExpression; qi::rule(), Skipper> constantAtomicDoubleExpression; // Rules for variable recognition. qi::rule(), Skipper> variableExpression; qi::rule(), Skipper> booleanVariableExpression; qi::rule(), Skipper> integerVariableExpression; // Rules for constant recognition. qi::rule(), Skipper> constantExpression; qi::rule(), Skipper> booleanConstantExpression; qi::rule(), Skipper> integerConstantExpression; qi::rule(), Skipper> doubleConstantExpression; // Rules for literal recognition. qi::rule(), Skipper> literalExpression; qi::rule(), Skipper> booleanLiteralExpression; qi::rule(), Skipper> integerLiteralExpression; qi::rule(), Skipper> doubleLiteralExpression; struct keywordsStruct : qi::symbols { keywordsStruct() { add ("dtmc", 1) ("ctmc", 2) ("mdp", 3) ("ctmdp", 4) ("const", 5) ("int", 6) ("bool", 7) ("module", 8) ("endmodule", 9) ("rewards", 10) ("endrewards", 11) ("true", 12) ("false", 13) ; } } keywords_; struct modelTypeStruct : qi::symbols { modelTypeStruct() { add ("dtmc", storm::ir::Program::ModelType::DTMC) ("ctmc", storm::ir::Program::ModelType::CTMC) ("mdp", storm::ir::Program::ModelType::MDP) ("ctmdp", storm::ir::Program::ModelType::CTMDP) ; } } modelType_; struct relationalOperatorStruct : qi::symbols { relationalOperatorStruct() { add ("=", storm::ir::expressions::BinaryRelationExpression::EQUAL) ("<", storm::ir::expressions::BinaryRelationExpression::LESS) ("<=", storm::ir::expressions::BinaryRelationExpression::LESS_OR_EQUAL) (">", storm::ir::expressions::BinaryRelationExpression::GREATER) (">=", storm::ir::expressions::BinaryRelationExpression::GREATER_OR_EQUAL) ; } } relations_; struct variablesStruct : qi::symbols> { // Intentionally left empty. This map is filled during parsing. } integerVariables_, booleanVariables_, allVariables_; struct entityNamesStruct : qi::symbols { // Intentionally left empty. This map is filled during parsing. } integerVariableNames_, booleanVariableNames_, commandNames_; struct booleanVariableTypesStruct : qi::symbols { // Intentionally left empty. This map is filled during parsing. } booleanVariableInfo_; struct integerVariableTypesStruct : qi::symbols { // Intentionally left empty. This map is filled during parsing. } integerVariableInfo_; struct constantsStruct : qi::symbols> { // Intentionally left empty. This map is filled during parsing. } integerConstants_, booleanConstants_, doubleConstants_, allConstants_; struct undefinedBooleanConstantsTypesStruct : qi::symbols> { // Intentionally left empty. This map is filled during parsing. } booleanConstantInfo_; struct undefinedIntegerConstantsTypesStruct : qi::symbols> { // Intentionally left empty. This map is filled during parsing. } integerConstantInfo_; struct undefinedDoubleConstantsTypesStruct : qi::symbols> { // Intentionally left empty. This map is filled during parsing. } doubleConstantInfo_; struct modulesStruct : qi::symbols { // Intentionally left empty. This map is filled during parsing. } modules_; }; }; } // namespace parser } // namespace storm #endif /* PRISMPARSER_H_ */