Browse Source
Further work on PrismParser and the related PRISM classes...
Further work on PrismParser and the related PRISM classes...
Former-commit-id: be4ae055dd
tempestpy_adaptions
dehnert
11 years ago
23 changed files with 925 additions and 385 deletions
-
98src/parser/PrismParser.cpp
-
35src/parser/PrismParser.h
-
415src/parser/prismparser/PrismGrammar.cpp
-
230src/parser/prismparser/PrismGrammar.h
-
70src/parser/prismparser/PrismParser.cpp
-
36src/parser/prismparser/PrismParser.h
-
4src/storage/expressions/BinaryBooleanFunctionExpression.cpp
-
4src/storage/expressions/Expression.cpp
-
1src/storage/expressions/Expression.h
-
4src/storage/prism/BooleanVariable.h
-
8src/storage/prism/Command.cpp
-
3src/storage/prism/Command.h
-
3src/storage/prism/Constant.cpp
-
2src/storage/prism/IntegerVariable.cpp
-
8src/storage/prism/LocatedInformation.cpp
-
14src/storage/prism/LocatedInformation.h
-
37src/storage/prism/Module.cpp
-
6src/storage/prism/Module.h
-
106src/storage/prism/Program.cpp
-
49src/storage/prism/Program.h
-
15src/storage/prism/Update.cpp
-
5src/storage/prism/Update.h
-
157test/functional/parser/PrismParserTest.cpp
@ -1,98 +0,0 @@ |
|||
#include "src/parser/PrismParser.h"
|
|||
|
|||
#include "src/parser/prismparser/PrismGrammar.h"
|
|||
|
|||
// If the parser fails due to ill-formed data, this exception is thrown.
|
|||
#include "src/exceptions/WrongFormatException.h"
|
|||
|
|||
// Needed for file IO.
|
|||
#include <fstream>
|
|||
#include <iomanip>
|
|||
#include <limits>
|
|||
|
|||
#include "log4cplus/logger.h"
|
|||
#include "log4cplus/loggingmacros.h"
|
|||
#include "log4cplus/consoleappender.h"
|
|||
#include "log4cplus/fileappender.h"
|
|||
log4cplus::Logger logger; |
|||
|
|||
namespace storm { |
|||
namespace parser { |
|||
storm::prism::Program PrismParserFromFile(std::string const& filename) { |
|||
// Open file and initialize result.
|
|||
std::ifstream inputFileStream(filename, std::ios::in); |
|||
storm::prism::Program result; |
|||
|
|||
// Now try to parse the contents of the file.
|
|||
try { |
|||
result = PrismParser(inputFileStream, filename); |
|||
} catch(std::exception& e) { |
|||
// In case of an exception properly close the file before passing exception.
|
|||
inputFileStream.close(); |
|||
throw e; |
|||
} |
|||
|
|||
// Close the stream in case everything went smoothly and return result.
|
|||
inputFileStream.close(); |
|||
return result; |
|||
} |
|||
|
|||
storm::prism::Program PrismParser(std::istream& inputStream, std::string const& filename) { |
|||
// 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<char>(inputStream)), (std::istreambuf_iterator<char>())); |
|||
BaseIteratorType stringIteratorBegin = fileContent.begin(); |
|||
BaseIteratorType stringIteratorEnd = fileContent.end(); |
|||
PositionIteratorType positionIteratorBegin(stringIteratorBegin, stringIteratorEnd, filename); |
|||
PositionIteratorType positionIteratorBegin2(stringIteratorBegin, stringIteratorEnd, filename); |
|||
PositionIteratorType positionIteratorEnd; |
|||
|
|||
// Prepare resulting intermediate representation of input.
|
|||
storm::prism::Program result; |
|||
|
|||
// In order to instantiate the grammar, we have to pass the type of the skipping parser.
|
|||
// As this is more complex, we let Boost figure out the actual type for us.
|
|||
storm::parser::prism::PrismGrammar grammar; |
|||
try { |
|||
// Now parse the content using phrase_parse in order to be able to supply a skipping parser.
|
|||
// First run.
|
|||
LOG4CPLUS_INFO(logger, "Start parsing..."); |
|||
qi::phrase_parse(positionIteratorBegin, positionIteratorEnd, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - qi::eol) >> qi::eol, result); |
|||
LOG4CPLUS_INFO(logger, "Finished parsing, here is the parsed program:" << std::endl << result); |
|||
|
|||
} catch(const qi::expectation_failure<PositionIteratorType>& e) { |
|||
// If the parser expected content different than the one provided, display information
|
|||
// about the location of the error.
|
|||
const boost::spirit::classic::file_position_base<std::string>& pos = e.first.get_position(); |
|||
|
|||
// Construct the error message including a caret display of the position in the
|
|||
// erroneous line.
|
|||
std::stringstream msg; |
|||
std::string line = e.first.get_currentline(); |
|||
while (line.find('\t') != std::string::npos) line.replace(line.find('\t'),1," "); |
|||
msg << pos.file << ", line " << pos.line << ", column " << pos.column |
|||
<< ": parse error: expected " << e.what_ << std::endl << "\t" |
|||
<< line << std::endl << "\t"; |
|||
int i = 0; |
|||
for (i = 1; i < pos.column; ++i) { |
|||
msg << "-"; |
|||
} |
|||
msg << "^"; |
|||
for (; i < 80; ++i) { |
|||
msg << "-"; |
|||
} |
|||
msg << std::endl; |
|||
|
|||
std::cerr << msg.str(); |
|||
|
|||
// Now propagate exception.
|
|||
throw storm::exceptions::WrongFormatException() << msg.str(); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} // namespace parser
|
|||
} // namespace storm
|
@ -1,35 +0,0 @@ |
|||
#ifndef STORM_PARSER_PRISMPARSER_H_ |
|||
#define STORM_PARSER_PRISMPARSER_H_ |
|||
|
|||
// All classes of the intermediate representation are used. |
|||
#include "src/storage/prism/Program.h" |
|||
|
|||
// Used for file input. |
|||
#include <istream> |
|||
|
|||
namespace storm { |
|||
namespace parser { |
|||
using namespace storm::prism; |
|||
using namespace storm::expressions; |
|||
|
|||
/*! |
|||
* Parses the given file into the PRISM storage classes assuming it complies with the PRISM syntax. |
|||
* |
|||
* @param filename the name of the file to parse. |
|||
* @return The resulting PRISM program. |
|||
*/ |
|||
storm::prism::Program PrismParserFromFile(std::string const& filename); |
|||
|
|||
/*! |
|||
* Parses the given input stream into the PRISM storage classes assuming it complies with the PRISM syntax. |
|||
* |
|||
* @param inputStream The input stream to parse. |
|||
* @param filename The name of the file the input stream belongs to. |
|||
* @return The resulting PRISM program. |
|||
*/ |
|||
storm::prism::Program PrismParser(std::istream& inputStream, std::string const& filename); |
|||
|
|||
} // namespace parser |
|||
} // namespace storm |
|||
|
|||
#endif /* STORM_PARSER_PRISMPARSER_H_ */ |
@ -1,153 +1,372 @@ |
|||
// #define BOOST_SPIRIT_DEBUG
|
|||
#include "src/parser/prismparser/PrismGrammar.h"
|
|||
#include "src/exceptions/InvalidArgumentException.h"
|
|||
#include "src/exceptions/WrongFormatException.h"
|
|||
|
|||
namespace storm { |
|||
namespace parser { |
|||
namespace prism { |
|||
PrismGrammar::PrismGrammar() : PrismGrammar::base_type(start) { |
|||
PrismGrammar::PrismGrammar(std::string const& filename, Iterator first) : PrismGrammar::base_type(start), doExpressionGeneration(false), filename(filename), annotate(first) { |
|||
// Parse simple identifier.
|
|||
identifier %= qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')))]]] - keywords_; |
|||
identifier %= qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')))]]][qi::_pass = phoenix::bind(&PrismGrammar::isValidIdentifier, phoenix::ref(*this), qi::_1)]; |
|||
identifier.name("identifier"); |
|||
|
|||
// Parse a composed expression.
|
|||
expression %= (booleanExpression | numericalExpression); |
|||
expression.name("expression"); |
|||
setExpressionGeneration(doExpressionGeneration); |
|||
|
|||
booleanExpression %= orExpression; |
|||
expression.name("boolean expression"); |
|||
|
|||
orExpression = andExpression[qi::_val = qi::_1] >> *(qi::lit("|") >> andExpression)[qi::_val = qi::_val * qi::_1]; |
|||
orExpression.name("boolean expression"); |
|||
|
|||
andExpression = notExpression[qi::_val = qi::_1] >> *(qi::lit("&") >> notExpression)[qi::_val = qi::_val * qi::_1]; |
|||
andExpression.name("boolean expression"); |
|||
|
|||
notExpression = atomicBooleanExpression[qi::_val = qi::_1] | (qi::lit("!") >> atomicBooleanExpression)[qi::_val = !qi::_1]; |
|||
notExpression.name("boolean expression"); |
|||
|
|||
atomicBooleanExpression %= relativeExpression | booleanVariableExpression | qi::lit("(") >> booleanExpression >> qi::lit(")"); |
|||
atomicBooleanExpression.name("boolean expression"); |
|||
|
|||
relativeExpression = ((numericalExpression >> ">") > numericalExpression)[qi::_val = qi::_1 > qi::_2] | ((numericalExpression >> ">=") > numericalExpression)[qi::_val = qi::_1 >= qi::_2] | ((numericalExpression >> "<") > numericalExpression)[qi::_val = qi::_1 < qi::_2] | ((numericalExpression >> "<=") > numericalExpression)[qi::_val = qi::_1 <= qi::_2]; |
|||
relativeExpression.name("relative expression"); |
|||
|
|||
booleanVariableExpression = identifier[qi::_val = phoenix::bind(&storm::expressions::Expression::createBooleanVariable, qi::_1)]; |
|||
booleanVariableExpression.name("boolean variable"); |
|||
|
|||
numericalExpression %= plusExpression; |
|||
numericalExpression.name("numerical expression"); |
|||
|
|||
plusExpression = multiplicationExpression[qi::_val = qi::_1] >> *((qi::lit("+")[qi::_a = true] | qi::lit("-")[qi::_a = false]) >> multiplicationExpression)[phoenix::if_(qi::_a) [qi::_val = qi::_val + qi::_1] .else_ [qi::_val = qi::_val - qi::_1]]; |
|||
plusExpression.name("numerical expression"); |
|||
|
|||
multiplicationExpression = atomicNumericalExpression[qi::_val = qi::_1] >> *(qi::lit("*") >> atomicNumericalExpression[qi::_val = qi::_val * qi::_1]); |
|||
multiplicationExpression.name("numerical expression"); |
|||
|
|||
atomicNumericalExpression %= minMaxExpression | floorCeilExpression | numericalVariableExpression | qi::lit("(") >> numericalExpression >> qi::lit(")"); |
|||
atomicNumericalExpression.name("numerical expression"); |
|||
|
|||
minMaxExpression = ((qi::lit("min")[qi::_a = true] | qi::lit("max")[qi::_a = false]) >> qi::lit("(") >> numericalExpression >> qi::lit(",") >> numericalExpression >> qi::lit(")"))[phoenix::if_(qi::_a) [qi::_val = phoenix::bind(&storm::expressions::Expression::minimum, qi::_1, qi::_2)] .else_ [qi::_val = phoenix::bind(&storm::expressions::Expression::maximum, qi::_1, qi::_2)]]; |
|||
minMaxExpression.name("min/max expression"); |
|||
|
|||
floorCeilExpression = ((qi::lit("floor")[qi::_a = true] | qi::lit("ceil")[qi::_a = false]) >> qi::lit("(") >> numericalExpression >> qi::lit(")"))[phoenix::if_(qi::_a) [qi::_val = phoenix::bind(&storm::expressions::Expression::floor, qi::_1)] .else_ [qi::_val = phoenix::bind(&storm::expressions::Expression::ceil, qi::_1)]]; |
|||
floorCeilExpression.name("integer floor/ceil expression"); |
|||
|
|||
numericalVariableExpression = identifier[qi::_val = phoenix::bind(&storm::expressions::Expression::createDoubleVariable, qi::_1)]; |
|||
numericalVariableExpression.name("numerical variable"); |
|||
|
|||
modelTypeDefinition = modelType_; |
|||
modelTypeDefinition %= modelType_; |
|||
modelTypeDefinition.name("model type"); |
|||
|
|||
undefinedConstantDefinition = (undefinedBooleanConstantDefinition(qi::_r1) | undefinedIntegerConstantDefinition(qi::_r1) | undefinedDoubleConstantDefinition(qi::_r1)); |
|||
undefinedConstantDefinition.name("undefined constant definition"); |
|||
|
|||
undefinedBooleanConstantDefinition = ((qi::lit("const") >> qi::lit("bool")) > identifier > qi::lit(";"))[qi::_pass = phoenix::bind(&PrismGrammar::addUndefinedBooleanConstant, phoenix::bind(&GlobalProgramInformation::undefinedBooleanConstants, qi::_r1), qi::_1)]; |
|||
undefinedBooleanConstantDefinition = ((qi::lit("const") >> qi::lit("bool")) > identifier > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createUndefinedBooleanConstant, phoenix::ref(*this), qi::_1)]; |
|||
undefinedBooleanConstantDefinition.name("undefined boolean constant declaration"); |
|||
|
|||
undefinedIntegerConstantDefinition = ((qi::lit("const") >> qi::lit("int")) > identifier > qi::lit(";"))[qi::_pass = phoenix::bind(&PrismGrammar::addUndefinedIntegerConstant, phoenix::bind(&GlobalProgramInformation::undefinedIntegerConstants, qi::_r1), qi::_1)]; |
|||
undefinedIntegerConstantDefinition = ((qi::lit("const") >> qi::lit("int")) > identifier > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createUndefinedIntegerConstant, phoenix::ref(*this), qi::_1)]; |
|||
undefinedIntegerConstantDefinition.name("undefined integer constant declaration"); |
|||
|
|||
undefinedDoubleConstantDefinition = ((qi::lit("const") >> qi::lit("double")) > identifier > qi::lit(";"))[qi::_pass = phoenix::bind(&PrismGrammar::addUndefinedDoubleConstant, phoenix::bind(&GlobalProgramInformation::undefinedDoubleConstants, qi::_r1), qi::_1)]; |
|||
undefinedDoubleConstantDefinition = ((qi::lit("const") >> qi::lit("double")) > identifier > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createUndefinedDoubleConstant, phoenix::ref(*this), qi::_1)]; |
|||
undefinedDoubleConstantDefinition.name("undefined double constant definition"); |
|||
|
|||
definedConstantDefinition %= (definedBooleanConstantDefinition(qi::_r1) | definedIntegerConstantDefinition(qi::_r1) | definedDoubleConstantDefinition(qi::_r1)); |
|||
definedConstantDefinition.name("defined constant definition"); |
|||
undefinedConstantDefinition = (undefinedBooleanConstantDefinition | undefinedIntegerConstantDefinition | undefinedDoubleConstantDefinition); |
|||
undefinedConstantDefinition.name("undefined constant definition"); |
|||
|
|||
definedBooleanConstantDefinition = ((qi::lit("const") >> qi::lit("bool") >> identifier >> qi::lit("=")) > expression > qi::lit(";"))[qi::_pass = phoenix::bind(&PrismGrammar::addDefinedBooleanConstant, phoenix::bind(&GlobalProgramInformation::definedBooleanConstants, qi::_r1), qi::_1, qi::_2)]; |
|||
definedBooleanConstantDefinition = ((qi::lit("const") >> qi::lit("bool") >> identifier >> qi::lit("=")) > expression > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createDefinedBooleanConstant, phoenix::ref(*this), qi::_1, qi::_2)]; |
|||
definedBooleanConstantDefinition.name("defined boolean constant declaration"); |
|||
|
|||
definedIntegerConstantDefinition = ((qi::lit("const") >> qi::lit("int") >> identifier >> qi::lit("=")) > expression >> qi::lit(";"))[qi::_pass = phoenix::bind(&PrismGrammar::addDefinedIntegerConstant, phoenix::bind(&GlobalProgramInformation::definedIntegerConstants, qi::_r1), qi::_1, qi::_2)]; |
|||
definedIntegerConstantDefinition = ((qi::lit("const") >> qi::lit("int") >> identifier >> qi::lit("=")) > expression >> qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createDefinedIntegerConstant, phoenix::ref(*this), qi::_1, qi::_2)]; |
|||
definedIntegerConstantDefinition.name("defined integer constant declaration"); |
|||
|
|||
definedDoubleConstantDefinition = ((qi::lit("const") >> qi::lit("double") >> identifier >> qi::lit("=")) > expression > qi::lit(";"))[qi::_pass = phoenix::bind(&PrismGrammar::addDefinedDoubleConstant, phoenix::bind(&GlobalProgramInformation::definedDoubleConstants, qi::_r1), qi::_1, qi::_2)]; |
|||
definedDoubleConstantDefinition = ((qi::lit("const") >> qi::lit("double") >> identifier >> qi::lit("=")) > expression > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createDefinedDoubleConstant, phoenix::ref(*this), qi::_1, qi::_2)]; |
|||
definedDoubleConstantDefinition.name("defined double constant declaration"); |
|||
|
|||
formulaDefinition = (qi::lit("formula") > identifier > qi::lit("=") > expression > qi::lit(";"))[qi::_pass = phoenix::bind(&PrismGrammar::addFormula, phoenix::bind(&GlobalProgramInformation::formulas, qi::_r1), qi::_1, qi::_2)]; |
|||
definedConstantDefinition %= (definedBooleanConstantDefinition | definedIntegerConstantDefinition | definedDoubleConstantDefinition); |
|||
definedConstantDefinition.name("defined constant definition"); |
|||
|
|||
formulaDefinition = (qi::lit("formula") > identifier > qi::lit("=") > expression > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createFormula, phoenix::ref(*this), qi::_1, qi::_2)]; |
|||
formulaDefinition.name("formula definition"); |
|||
|
|||
globalVariableDefinition = (qi::lit("global") > (booleanVariableDefinition(phoenix::bind(&GlobalProgramInformation::globalBooleanVariables, qi::_r1)) | integerVariableDefinition(phoenix::bind(&GlobalProgramInformation::globalIntegerVariables, qi::_r1)))); |
|||
booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > ((qi::lit("init") > expression) | qi::attr(storm::expressions::Expression::createFalse())) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_2)]; |
|||
booleanVariableDefinition.name("boolean variable definition"); |
|||
|
|||
integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismGrammar::allowDoubleLiterals, phoenix::ref(*this), false)]) > expression[qi::_a = qi::_1] > qi::lit("..") > expression > qi::lit("]")[phoenix::bind(&PrismGrammar::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expression[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)]; |
|||
integerVariableDefinition.name("integer variable definition"); |
|||
|
|||
variableDefinition = (booleanVariableDefinition[phoenix::push_back(qi::_r1, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_r2, qi::_1)]); |
|||
variableDefinition.name("variable declaration"); |
|||
|
|||
globalVariableDefinition = (qi::lit("global") > (booleanVariableDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::globalBooleanVariables, qi::_r1), qi::_1)] | integerVariableDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::globalIntegerVariables, qi::_r1), qi::_1)])); |
|||
globalVariableDefinition.name("global variable declaration list"); |
|||
|
|||
programHeader = modelTypeDefinition[phoenix::bind(&GlobalProgramInformation::modelType, qi::_r1) = qi::_1] |
|||
> *( undefinedConstantDefinition(qi::_r1) |
|||
| definedConstantDefinition(qi::_r1) |
|||
| formulaDefinition(qi::_r1) |
|||
| globalVariableDefinition(qi::_r1) |
|||
); |
|||
programHeader = modelTypeDefinition[phoenix::bind(&GlobalProgramInformation::modelType, qi::_r1) = qi::_1] |
|||
> *(definedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_r1), qi::_1)] | undefinedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_r1), qi::_1)]) |
|||
> *(formulaDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::formulas, qi::_r1), qi::_1)]) |
|||
> *(globalVariableDefinition(qi::_r1)); |
|||
programHeader.name("program header"); |
|||
|
|||
rewardModelDefinition = (qi::lit("rewards") > qi::lit("\"") > identifier > qi::lit("\"") |
|||
> +( stateRewardDefinition[phoenix::push_back(qi::_a, qi::_1)] |
|||
| transitionRewardDefinition[phoenix::push_back(qi::_b, qi::_1)] |
|||
) |
|||
>> qi::lit("endrewards"))[phoenix::bind(&PrismGrammar::addRewardModel, phoenix::bind(&GlobalProgramInformation::rewardModels, qi::_r1), qi::_1, qi::_a, qi::_b)]; |
|||
rewardModelDefinition.name("reward model definition"); |
|||
|
|||
stateRewardDefinition = (booleanExpression > qi::lit(":") > numericalExpression >> qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createStateReward, qi::_1, qi::_2)]; |
|||
stateRewardDefinition = (expression > qi::lit(":") > plusExpression >> qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createStateReward, phoenix::ref(*this), qi::_1, qi::_2)]; |
|||
stateRewardDefinition.name("state reward definition"); |
|||
|
|||
transitionRewardDefinition = (qi::lit("[") > -(identifier[qi::_a = qi::_1]) > qi::lit("]") > booleanExpression > qi::lit(":") > numericalExpression > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createTransitionReward, qi::_a, qi::_2, qi::_3)]; |
|||
transitionRewardDefinition = (qi::lit("[") > -(identifier[qi::_a = qi::_1]) > qi::lit("]") > expression > qi::lit(":") > plusExpression > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createTransitionReward, phoenix::ref(*this), qi::_a, qi::_2, qi::_3)]; |
|||
transitionRewardDefinition.name("transition reward definition"); |
|||
|
|||
labelDefinition = (qi::lit("label") > -qi::lit("\"") > identifier > -qi::lit("\"") > qi::lit("=") > booleanExpression >> qi::lit(";"))[qi::_pass = phoenix::bind(&PrismGrammar::addLabel, phoenix::bind(&GlobalProgramInformation::labels, qi::_r1), qi::_1, qi::_2)]; |
|||
rewardModelDefinition = (qi::lit("rewards") > qi::lit("\"") > identifier > qi::lit("\"") |
|||
> +( stateRewardDefinition[phoenix::push_back(qi::_a, qi::_1)] |
|||
| transitionRewardDefinition[phoenix::push_back(qi::_b, qi::_1)] |
|||
) |
|||
>> qi::lit("endrewards"))[qi::_val = phoenix::bind(&PrismGrammar::createRewardModel, phoenix::ref(*this), qi::_1, qi::_a, qi::_b)]; |
|||
rewardModelDefinition.name("reward model definition"); |
|||
|
|||
initialStatesConstruct = (qi::lit("init") > expression > qi::lit("endinit"))[qi::_pass = phoenix::bind(&PrismGrammar::addInitialStatesExpression, phoenix::ref(*this), qi::_1, qi::_r1)]; |
|||
initialStatesConstruct.name("initial construct"); |
|||
|
|||
labelDefinition = (qi::lit("label") > -qi::lit("\"") > identifier > -qi::lit("\"") > qi::lit("=") > expression >> qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createLabel, phoenix::ref(*this), qi::_1, qi::_2)]; |
|||
labelDefinition.name("label definition"); |
|||
|
|||
assignmentDefinition = (qi::lit("(") > identifier > qi::lit("'") > qi::lit("=") > expression > qi::lit(")"))[qi::_pass = phoenix::bind(&PrismGrammar::addAssignment, qi::_r1, qi::_1, qi::_2)]; |
|||
assignmentDefinition = (qi::lit("(") > identifier > qi::lit("'") > qi::lit("=") > expression > qi::lit(")"))[qi::_val = phoenix::bind(&PrismGrammar::createAssignment, phoenix::ref(*this), qi::_1, qi::_2)]; |
|||
assignmentDefinition.name("assignment"); |
|||
assignmentDefinitionList = assignmentDefinition(qi::_r1) % "&"; |
|||
assignmentDefinitionList.name("assignment list"); |
|||
|
|||
moduleDefinitionList %= +(moduleDefinition(qi::_r1) | moduleRenaming(qi::_r1)); |
|||
moduleDefinitionList.name("module list"); |
|||
assignmentDefinitionList %= +assignmentDefinition % "&"; |
|||
assignmentDefinitionList.name("assignment list"); |
|||
|
|||
updateDefinition = (((numericalExpression >> qi::lit(":")) | qi::attr(storm::expressions::Expression::createDoubleLiteral(1))) >> assignmentDefinitionList(qi::_a))[qi::_val = phoenix::bind(&PrismGrammar::createUpdate, qi::_1, qi::_a)]; |
|||
updateDefinition = (((plusExpression > qi::lit(":")) | qi::attr(storm::expressions::Expression::createDoubleLiteral(1))) >> assignmentDefinitionList)[qi::_val = phoenix::bind(&PrismGrammar::createUpdate, phoenix::ref(*this), qi::_1, qi::_2, qi::_r1)]; |
|||
updateDefinition.name("update"); |
|||
|
|||
updateListDefinition %= +updateDefinition % "+"; |
|||
updateListDefinition %= +updateDefinition(qi::_r1) % "+"; |
|||
updateListDefinition.name("update list"); |
|||
|
|||
commandDefinition = (qi::lit("[") > -(identifier[qi::_a = qi::_1]) > qi::lit("]") > booleanExpression > qi::lit("->") > updateListDefinition > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createCommand, qi::_a, qi::_2, qi::_3)]; |
|||
commandDefinition = (qi::lit("[") > -(identifier[qi::_a = qi::_1]) > qi::lit("]") > expression > qi::lit("->") > updateListDefinition(qi::_r1) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismGrammar::createCommand, phoenix::ref(*this), qi::_a, qi::_2, qi::_3, qi::_r1)]; |
|||
commandDefinition.name("command definition"); |
|||
|
|||
booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > ((qi::lit("init") > booleanExpression) | qi::attr(storm::expressions::Expression::createFalse())) > qi::lit(";"))[phoenix::bind(&PrismGrammar::addBooleanVariable, qi::_r1, qi::_1, qi::_2)]; |
|||
booleanVariableDefinition.name("boolean variable definition"); |
|||
|
|||
integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")) > numericalExpression[qi::_a = qi::_1] > qi::lit("..") > numericalExpression > qi::lit("]") > -(qi::lit("init") > numericalExpression[qi::_a = qi::_1]) > qi::lit(";"))[phoenix::bind(&PrismGrammar::addIntegerVariable, qi::_r1, qi::_1, qi::_2, qi::_3, qi::_a)]; |
|||
integerVariableDefinition.name("integer variable definition"); |
|||
|
|||
variableDefinition = (booleanVariableDefinition(qi::_r1) | integerVariableDefinition(qi::_r2)); |
|||
variableDefinition.name("variable declaration"); |
|||
|
|||
moduleDefinition = ((qi::lit("module") >> identifier >> *(variableDefinition(qi::_a, qi::_b))) > +commandDefinition > qi::lit("endmodule"))[qi::_val = phoenix::bind(&PrismGrammar::createModule, qi::_1, qi::_a, qi::_b, qi::_2)]; |
|||
moduleDefinition = ((qi::lit("module") >> identifier >> *(variableDefinition(qi::_a, qi::_b))) > +commandDefinition(qi::_r1) > qi::lit("endmodule"))[qi::_val = phoenix::bind(&PrismGrammar::createModule, phoenix::ref(*this), qi::_1, qi::_a, qi::_b, qi::_2, qi::_r1)]; |
|||
moduleDefinition.name("module definition"); |
|||
|
|||
moduleRenaming = ((qi::lit("module") >> identifier >> qi::lit("=")) > identifier > qi::lit("[") |
|||
moduleRenaming = ((qi::lit("module") >> identifier >> qi::lit("=")) > identifier > qi::lit("[") |
|||
> ((identifier > qi::lit("=") > identifier)[phoenix::insert(qi::_a, phoenix::construct<std::pair<std::string,std::string>>(qi::_1, qi::_2))] % ",") > qi::lit("]") |
|||
> qi::lit("endmodule"))[qi::_val = phoenix::bind(&PrismGrammar::createRenamedModule, qi::_1, qi::_2, qi::_a, qi::_r1)]; |
|||
> qi::lit("endmodule"))[qi::_val = phoenix::bind(&PrismGrammar::createRenamedModule, phoenix::ref(*this), qi::_1, qi::_2, qi::_a, qi::_r1)]; |
|||
moduleRenaming.name("module definition via renaming"); |
|||
|
|||
start = (qi::eps > programHeader(qi::_a) > moduleDefinitionList(qi::_a) > *(rewardModelDefinition(qi::_a) | labelDefinition(qi::_a)))[qi::_val = phoenix::bind(&PrismGrammar::createProgram, qi::_a, qi::_1)]; |
|||
moduleDefinitionList %= +(moduleRenaming(qi::_r1) | moduleDefinition(qi::_r1))[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::modules, qi::_r1), qi::_1)]; |
|||
moduleDefinitionList.name("module list"); |
|||
|
|||
start = (qi::eps > programHeader(qi::_a) > moduleDefinitionList(qi::_a) > *(initialStatesConstruct(qi::_a) | rewardModelDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::rewardModels, qi::_a), qi::_1)] | labelDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::labels, qi::_a), qi::_1)]) > qi::eoi)[qi::_val = phoenix::bind(&PrismGrammar::createProgram, phoenix::ref(*this), qi::_a)]; |
|||
start.name("probabilistic program"); |
|||
|
|||
// Enable location tracking for important entities.
|
|||
auto setLocationInfoFunction = this->annotate(qi::_val, qi::_1, qi::_3); |
|||
qi::on_success(undefinedBooleanConstantDefinition, setLocationInfoFunction); |
|||
qi::on_success(undefinedIntegerConstantDefinition, setLocationInfoFunction); |
|||
qi::on_success(undefinedDoubleConstantDefinition, setLocationInfoFunction); |
|||
qi::on_success(definedBooleanConstantDefinition, setLocationInfoFunction); |
|||
qi::on_success(definedIntegerConstantDefinition, setLocationInfoFunction); |
|||
qi::on_success(definedDoubleConstantDefinition, setLocationInfoFunction); |
|||
qi::on_success(booleanVariableDefinition, setLocationInfoFunction); |
|||
qi::on_success(integerVariableDefinition, setLocationInfoFunction); |
|||
qi::on_success(moduleDefinition, setLocationInfoFunction); |
|||
qi::on_success(moduleRenaming, setLocationInfoFunction); |
|||
qi::on_success(formulaDefinition, setLocationInfoFunction); |
|||
qi::on_success(rewardModelDefinition, setLocationInfoFunction); |
|||
qi::on_success(labelDefinition, setLocationInfoFunction); |
|||
qi::on_success(commandDefinition, setLocationInfoFunction); |
|||
qi::on_success(updateDefinition, setLocationInfoFunction); |
|||
qi::on_success(assignmentDefinition, setLocationInfoFunction); |
|||
} |
|||
|
|||
void PrismGrammar::setExpressionGeneration(bool doExpressionGeneration) { |
|||
if (doExpressionGeneration) { |
|||
floorCeilExpression = ((qi::lit("floor")[qi::_a = true] | qi::lit("ceil")[qi::_a = false]) >> qi::lit("(") >> plusExpression >> qi::lit(")"))[phoenix::if_(qi::_a) [qi::_val = phoenix::bind(&storm::expressions::Expression::floor, qi::_1)] .else_ [qi::_val = phoenix::bind(&storm::expressions::Expression::ceil, qi::_1)]]; |
|||
floorCeilExpression.name("floor/ceil expression"); |
|||
|
|||
minMaxExpression = ((qi::lit("min")[qi::_a = true] | qi::lit("max")[qi::_a = false]) >> qi::lit("(") >> plusExpression >> qi::lit(",") >> plusExpression >> qi::lit(")"))[phoenix::if_(qi::_a) [qi::_val = phoenix::bind(&storm::expressions::Expression::minimum, qi::_1, qi::_2)] .else_ [qi::_val = phoenix::bind(&storm::expressions::Expression::maximum, qi::_1, qi::_2)]]; |
|||
minMaxExpression.name("min/max expression"); |
|||
|
|||
identifierExpression = identifier[qi::_val = phoenix::bind(&PrismGrammar::getIdentifierExpression, phoenix::ref(*this), qi::_1)]; |
|||
identifierExpression.name("identifier expression"); |
|||
|
|||
literalExpression = qi::lit("true")[qi::_val = phoenix::bind(&storm::expressions::Expression::createTrue)] | qi::lit("false")[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)] | strict_double[qi::_val = phoenix::bind(&storm::expressions::Expression::createDoubleLiteral, qi::_1)] | qi::int_[qi::_val = phoenix::bind(&storm::expressions::Expression::createIntegerLiteral, qi::_1)]; |
|||
literalExpression.name("literal expression"); |
|||
|
|||
atomicExpression = minMaxExpression | floorCeilExpression | qi::lit("(") >> expression >> qi::lit(")") | literalExpression | identifierExpression; |
|||
atomicExpression.name("atomic expression"); |
|||
|
|||
unaryExpression = atomicExpression[qi::_val = qi::_1] | (qi::lit("!") >> atomicExpression)[qi::_val = !qi::_1] | (qi::lit("-") >> atomicExpression)[qi::_val = -qi::_1]; |
|||
unaryExpression.name("unary expression"); |
|||
|
|||
multiplicationExpression = unaryExpression[qi::_val = qi::_1] >> *((qi::lit("*")[qi::_a = true] | qi::lit("/")[qi::_a = false]) >> unaryExpression[phoenix::if_(qi::_a) [qi::_val = qi::_val * qi::_1] .else_ [qi::_val = qi::_val / qi::_1]]); |
|||
multiplicationExpression.name("multiplication expression"); |
|||
|
|||
plusExpression = multiplicationExpression[qi::_val = qi::_1] >> *((qi::lit("+")[qi::_a = true] | qi::lit("-")[qi::_a = false]) >> multiplicationExpression)[phoenix::if_(qi::_a) [qi::_val = qi::_val + qi::_1] .else_ [qi::_val = qi::_val - qi::_1]]; |
|||
plusExpression.name("plus expression"); |
|||
|
|||
relativeExpression = (plusExpression >> qi::lit(">=") >> plusExpression)[qi::_val = qi::_1 >= qi::_1] | (plusExpression >> qi::lit(">") >> plusExpression)[qi::_val = qi::_1 > qi::_2] | (plusExpression >> qi::lit("<=") >> plusExpression)[qi::_val = qi::_1 <= qi::_2] | (plusExpression >> qi::lit("<") >> plusExpression)[qi::_val = qi::_1 < qi::_2] | (plusExpression >> qi::lit("=") >> plusExpression)[qi::_val = qi::_1 == qi::_2] | (plusExpression >> qi::lit("!=") >> plusExpression)[qi::_val = qi::_1 != qi::_2] | plusExpression[qi::_val = qi::_1]; |
|||
relativeExpression.name("relative expression"); |
|||
|
|||
andExpression = relativeExpression[qi::_val = qi::_1] >> *(qi::lit("&") >> relativeExpression)[qi::_val = qi::_val && qi::_1]; |
|||
andExpression.name("and expression"); |
|||
|
|||
orExpression = andExpression[qi::_val = qi::_1] >> *(qi::lit("|") >> andExpression)[qi::_val = qi::_val || qi::_1]; |
|||
orExpression.name("or expression"); |
|||
|
|||
expression %= orExpression; |
|||
expression.name("expression"); |
|||
} else { |
|||
floorCeilExpression = ((qi::lit("floor") | qi::lit("ceil")) >> qi::lit("(") >> plusExpression >> qi::lit(")"))[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
floorCeilExpression.name("floor/ceil expression"); |
|||
|
|||
minMaxExpression = ((qi::lit("min") | qi::lit("max")) >> qi::lit("(") >> plusExpression >> qi::lit(",") >> plusExpression >> qi::lit(")"))[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
minMaxExpression.name("min/max expression"); |
|||
|
|||
identifierExpression = identifier[qi::_val = phoenix::construct<storm::expressions::Expression>(), qi::_pass = phoenix::bind(&PrismGrammar::isValidIdentifier, phoenix::ref(*this), qi::_1)]; |
|||
identifierExpression.name("identifier expression"); |
|||
|
|||
literalExpression = (qi::lit("true") | qi::lit("false") | strict_double | qi::int_)[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
literalExpression.name("literal expression"); |
|||
|
|||
atomicExpression = (minMaxExpression | floorCeilExpression | qi::lit("(") >> expression >> qi::lit(")") | literalExpression | identifierExpression)[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
atomicExpression.name("atomic expression"); |
|||
|
|||
unaryExpression = (atomicExpression | (qi::lit("!") >> atomicExpression) | (qi::lit("-") >> atomicExpression))[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
unaryExpression.name("unary expression"); |
|||
|
|||
multiplicationExpression = (unaryExpression >> *((qi::lit("*") | qi::lit("/")) >> unaryExpression))[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
multiplicationExpression.name("multiplication expression"); |
|||
|
|||
plusExpression = (multiplicationExpression >> *((qi::lit("+") | qi::lit("-")) >> multiplicationExpression))[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
plusExpression.name("plus expression"); |
|||
|
|||
relativeExpression = ((plusExpression >> qi::lit(">=") >> plusExpression) | (plusExpression >> qi::lit(">") >> plusExpression) | (plusExpression >> qi::lit("<=") >> plusExpression) | (plusExpression >> qi::lit("<") >> plusExpression) | (plusExpression >> qi::lit("=") >> plusExpression) | (plusExpression >> qi::lit("!=") >> plusExpression) | plusExpression)[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
relativeExpression.name("relative expression"); |
|||
|
|||
andExpression = (relativeExpression >> *(qi::lit("&") >> relativeExpression))[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
andExpression.name("and expression"); |
|||
|
|||
orExpression = (andExpression >> *(qi::lit("|") >> andExpression))[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
orExpression.name("or expression"); |
|||
|
|||
expression %= orExpression; |
|||
expression.name("expression"); |
|||
} |
|||
|
|||
// Enable error reporting.
|
|||
qi::on_error<qi::fail>(expression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(orExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(andExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(relativeExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(plusExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(multiplicationExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(unaryExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(atomicExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(literalExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(identifierExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(minMaxExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
qi::on_error<qi::fail>(floorCeilExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4)); |
|||
|
|||
// Finally toggle the internal flag.
|
|||
this->doExpressionGeneration = doExpressionGeneration; |
|||
} |
|||
|
|||
void PrismGrammar::toggleExpressionGeneration() { |
|||
setExpressionGeneration(!doExpressionGeneration); |
|||
} |
|||
|
|||
void PrismGrammar::allowDoubleLiterals(bool flag) { |
|||
if (flag) { |
|||
if (this->doExpressionGeneration) { |
|||
literalExpression = qi::lit("true")[qi::_val = phoenix::bind(&storm::expressions::Expression::createTrue)] | qi::lit("false")[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)] | strict_double[qi::_val = phoenix::bind(&storm::expressions::Expression::createDoubleLiteral, qi::_1)] | qi::int_[qi::_val = phoenix::bind(&storm::expressions::Expression::createIntegerLiteral, qi::_1)]; |
|||
literalExpression.name("literal expression"); |
|||
} else { |
|||
literalExpression = (qi::lit("true") | qi::lit("false") | strict_double | qi::int_)[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
literalExpression.name("literal expression"); |
|||
} |
|||
} else { |
|||
if (this->doExpressionGeneration) { |
|||
literalExpression = qi::lit("true")[qi::_val = phoenix::bind(&storm::expressions::Expression::createTrue)] | qi::lit("false")[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)] | qi::int_[qi::_val = phoenix::bind(&storm::expressions::Expression::createIntegerLiteral, qi::_1)]; |
|||
literalExpression.name("literal expression"); |
|||
} else { |
|||
literalExpression = (qi::lit("true") | qi::lit("false") | qi::int_)[qi::_val = phoenix::bind(&storm::expressions::Expression::createFalse)]; |
|||
literalExpression.name("literal expression"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
std::string const& PrismGrammar::getFilename() const { |
|||
return this->filename; |
|||
} |
|||
|
|||
bool PrismGrammar::isValidIdentifier(std::string const& identifier) { |
|||
if (this->keywords_.find(identifier) != nullptr) { |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
bool PrismGrammar::addInitialStatesExpression(storm::expressions::Expression initialStatesExpression, GlobalProgramInformation& globalProgramInformation) { |
|||
LOG_THROW(!globalProgramInformation.hasInitialStatesExpression, storm::exceptions::InvalidArgumentException, "Program must not define two initial constructs."); |
|||
if (globalProgramInformation.hasInitialStatesExpression) { |
|||
return false; |
|||
} |
|||
globalProgramInformation.hasInitialStatesExpression = true; |
|||
globalProgramInformation.initialStatesExpression = initialStatesExpression; |
|||
return true; |
|||
} |
|||
|
|||
storm::expressions::Expression PrismGrammar::getIdentifierExpression(std::string const& identifier) const { |
|||
storm::expressions::Expression const* expression = this->identifiers_.find(identifier); |
|||
LOG_THROW(expression != nullptr, storm::exceptions::WrongFormatException, "Undeclared identifier '" << identifier << "'."); |
|||
return *expression; |
|||
} |
|||
|
|||
storm::prism::Constant PrismGrammar::createUndefinedBooleanConstant(std::string const& newConstant) const { |
|||
this->identifiers_.add(newConstant, storm::expressions::Expression::createBooleanConstant(newConstant)); |
|||
return storm::prism::Constant(storm::prism::Constant::ConstantType::Bool, newConstant, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Constant PrismGrammar::createUndefinedIntegerConstant(std::string const& newConstant) const { |
|||
this->identifiers_.add(newConstant, storm::expressions::Expression::createIntegerConstant(newConstant)); |
|||
return storm::prism::Constant(storm::prism::Constant::ConstantType::Integer, newConstant, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Constant PrismGrammar::createUndefinedDoubleConstant(std::string const& newConstant) const { |
|||
this->identifiers_.add(newConstant, storm::expressions::Expression::createDoubleConstant(newConstant)); |
|||
return storm::prism::Constant(storm::prism::Constant::ConstantType::Double, newConstant, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Constant PrismGrammar::createDefinedBooleanConstant(std::string const& newConstant, storm::expressions::Expression expression) const { |
|||
this->identifiers_.add(newConstant, storm::expressions::Expression::createBooleanConstant(newConstant)); |
|||
return storm::prism::Constant(storm::prism::Constant::ConstantType::Bool, newConstant, expression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Constant PrismGrammar::createDefinedIntegerConstant(std::string const& newConstant, storm::expressions::Expression expression) const { |
|||
this->identifiers_.add(newConstant, storm::expressions::Expression::createIntegerConstant(newConstant)); |
|||
return storm::prism::Constant(storm::prism::Constant::ConstantType::Integer, newConstant, expression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Constant PrismGrammar::createDefinedDoubleConstant(std::string const& newConstant, storm::expressions::Expression expression) const { |
|||
this->identifiers_.add(newConstant, storm::expressions::Expression::createDoubleConstant(newConstant)); |
|||
return storm::prism::Constant(storm::prism::Constant::ConstantType::Double, newConstant, expression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Formula PrismGrammar::createFormula(std::string const& formulaName, storm::expressions::Expression expression) const { |
|||
this->identifiers_.add(formulaName, expression); |
|||
return storm::prism::Formula(formulaName, expression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Label PrismGrammar::createLabel(std::string const& labelName, storm::expressions::Expression expression) const { |
|||
return storm::prism::Label(labelName, expression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::RewardModel PrismGrammar::createRewardModel(std::string const& rewardModelName, std::vector<storm::prism::StateReward> const& stateRewards, std::vector<storm::prism::TransitionReward> const& transitionRewards) const { |
|||
return storm::prism::RewardModel(rewardModelName, stateRewards, transitionRewards, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::StateReward PrismGrammar::createStateReward(storm::expressions::Expression statePredicateExpression, storm::expressions::Expression rewardValueExpression) const { |
|||
return storm::prism::StateReward(statePredicateExpression, rewardValueExpression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::TransitionReward PrismGrammar::createTransitionReward(std::string const& actionName, storm::expressions::Expression statePredicateExpression, storm::expressions::Expression rewardValueExpression) const { |
|||
return storm::prism::TransitionReward(actionName, statePredicateExpression, rewardValueExpression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Assignment PrismGrammar::createAssignment(std::string const& variableName, storm::expressions::Expression assignedExpression) const { |
|||
return storm::prism::Assignment(variableName, assignedExpression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Update PrismGrammar::createUpdate(storm::expressions::Expression likelihoodExpression, std::vector<storm::prism::Assignment> const& assignments, GlobalProgramInformation& globalProgramInformation) const { |
|||
++globalProgramInformation.currentUpdateIndex; |
|||
return storm::prism::Update(globalProgramInformation.currentUpdateIndex - 1, likelihoodExpression, assignments, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Command PrismGrammar::createCommand(std::string const& actionName, storm::expressions::Expression guardExpression, std::vector<storm::prism::Update> const& updates, GlobalProgramInformation& globalProgramInformation) const { |
|||
++globalProgramInformation.currentCommandIndex; |
|||
return storm::prism::Command(globalProgramInformation.currentCommandIndex - 1, actionName, guardExpression, updates, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::BooleanVariable PrismGrammar::createBooleanVariable(std::string const& variableName, storm::expressions::Expression initialValueExpression) const { |
|||
this->identifiers_.add(variableName, storm::expressions::Expression::createBooleanVariable(variableName)); |
|||
return storm::prism::BooleanVariable(variableName, initialValueExpression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::IntegerVariable PrismGrammar::createIntegerVariable(std::string const& variableName, storm::expressions::Expression lowerBoundExpression, storm::expressions::Expression upperBoundExpression, storm::expressions::Expression initialValueExpression) const { |
|||
this->identifiers_.add(variableName, storm::expressions::Expression::createIntegerVariable(variableName)); |
|||
return storm::prism::IntegerVariable(variableName, lowerBoundExpression, upperBoundExpression, initialValueExpression, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Module PrismGrammar::createModule(std::string const& moduleName, std::vector<storm::prism::BooleanVariable> const& booleanVariables, std::vector<storm::prism::IntegerVariable> const& integerVariables, std::vector<storm::prism::Command> const& commands, GlobalProgramInformation& globalProgramInformation) const { |
|||
globalProgramInformation.moduleToIndexMap[moduleName] = globalProgramInformation.modules.size(); |
|||
return storm::prism::Module(moduleName, booleanVariables, integerVariables, commands, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Module PrismGrammar::createRenamedModule(std::string const& newModuleName, std::string const& oldModuleName, std::map<std::string, std::string> const& renaming, GlobalProgramInformation& globalProgramInformation) const { |
|||
auto const& moduleIndexPair = globalProgramInformation.moduleToIndexMap.find(oldModuleName); |
|||
LOG_THROW(moduleIndexPair != globalProgramInformation.moduleToIndexMap.end(), storm::exceptions::WrongFormatException, "No module named '" << oldModuleName << "' to rename."); |
|||
globalProgramInformation.moduleToIndexMap[newModuleName] = globalProgramInformation.modules.size(); |
|||
uint_fast64_t commandBaseIndex = globalProgramInformation.currentCommandIndex; |
|||
uint_fast64_t updateBaseIndex = globalProgramInformation.currentUpdateIndex; |
|||
storm::prism::Module const& moduleToClone = globalProgramInformation.modules[moduleIndexPair->second]; |
|||
globalProgramInformation.currentCommandIndex += moduleToClone.getNumberOfCommands(); |
|||
globalProgramInformation.currentUpdateIndex += moduleToClone.getNumberOfUpdates(); |
|||
return storm::prism::Module(moduleToClone, newModuleName, commandBaseIndex, updateBaseIndex, renaming, this->getFilename()); |
|||
} |
|||
|
|||
storm::prism::Program PrismGrammar::createProgram(GlobalProgramInformation const& globalProgramInformation) const { |
|||
return storm::prism::Program(globalProgramInformation.modelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, globalProgramInformation.formulas, globalProgramInformation.modules, globalProgramInformation.rewardModels, globalProgramInformation.hasInitialStatesExpression, globalProgramInformation.initialStatesExpression, globalProgramInformation.labels, this->getFilename()); |
|||
} |
|||
} // namespace prism
|
|||
} // namespace parser
|
|||
|
@ -0,0 +1,70 @@ |
|||
#include "src/parser/prismparser/PrismParser.h"
|
|||
#include "src/parser/prismparser/PrismGrammar.h"
|
|||
|
|||
// If the parser fails due to ill-formed data, this exception is thrown.
|
|||
#include "src/exceptions/ExceptionMacros.h"
|
|||
#include "src/exceptions/WrongFormatException.h"
|
|||
|
|||
// Needed for file IO.
|
|||
#include <fstream>
|
|||
#include <iomanip>
|
|||
#include <limits>
|
|||
|
|||
namespace storm { |
|||
namespace parser { |
|||
storm::prism::Program PrismParser::parse(std::string const& filename, bool typeCheck) { |
|||
// Open file and initialize result.
|
|||
std::ifstream inputFileStream(filename, std::ios::in); |
|||
LOG_THROW(inputFileStream.good(), storm::exceptions::WrongFormatException, "Unable to read from file " << filename << "."); |
|||
|
|||
storm::prism::Program result; |
|||
|
|||
// Now try to parse the contents of the file.
|
|||
try { |
|||
std::string fileContent((std::istreambuf_iterator<char>(inputFileStream)), (std::istreambuf_iterator<char>())); |
|||
result = parseFromString(fileContent, filename, typeCheck); |
|||
} catch(std::exception& e) { |
|||
// In case of an exception properly close the file before passing exception.
|
|||
inputFileStream.close(); |
|||
throw e; |
|||
} |
|||
|
|||
// Close the stream in case everything went smoothly and return result.
|
|||
inputFileStream.close(); |
|||
return result; |
|||
} |
|||
|
|||
storm::prism::Program PrismParser::parseFromString(std::string const& input, std::string const& filename, bool typeCheck) { |
|||
PositionIteratorType first(input.begin()); |
|||
PositionIteratorType iter = first; |
|||
PositionIteratorType last(input.end()); |
|||
|
|||
// Create empty result;
|
|||
storm::prism::Program result; |
|||
|
|||
// Create grammar.
|
|||
storm::parser::prism::PrismGrammar grammar(filename, first); |
|||
try { |
|||
// Now parse the content using phrase_parse in order to be able to supply a skipping parser.
|
|||
bool succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - qi::eol) >> qi::eol, result); |
|||
LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Parsing failed in first pass."); |
|||
if (typeCheck) { |
|||
first = PositionIteratorType(input.begin()); |
|||
iter = first; |
|||
last = PositionIteratorType(input.end()); |
|||
grammar.toggleExpressionGeneration(); |
|||
succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - qi::eol) >> qi::eol, result); |
|||
LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Parsing failed in second pass."); |
|||
} |
|||
} catch (qi::expectation_failure<PositionIteratorType> const& e) { |
|||
// If the parser expected content different than the one provided, display information about the location of the error.
|
|||
std::size_t lineNumber = boost::spirit::get_line(e.first); |
|||
|
|||
// Now propagate exception.
|
|||
LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << lineNumber << " of file " << filename << "."); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} // namespace parser
|
|||
} // namespace storm
|
@ -0,0 +1,36 @@ |
|||
#ifndef STORM_PARSER_PRISMPARSER_H_ |
|||
#define STORM_PARSER_PRISMPARSER_H_ |
|||
|
|||
// All classes of the intermediate representation are used. |
|||
#include "src/storage/prism/Program.h" |
|||
|
|||
// Used for file input. |
|||
#include <istream> |
|||
|
|||
namespace storm { |
|||
namespace parser { |
|||
class PrismParser { |
|||
public: |
|||
/*! |
|||
* Parses the given file into the PRISM storage classes assuming it complies with the PRISM syntax. |
|||
* |
|||
* @param filename the name of the file to parse. |
|||
* @param typeCheck Sets whether the expressions are generated and therefore typechecked. |
|||
* @return The resulting PRISM program. |
|||
*/ |
|||
static storm::prism::Program parse(std::string const& filename, bool typeCheck = true); |
|||
|
|||
/*! |
|||
* Parses the given input stream into the PRISM storage classes assuming it complies with the PRISM syntax. |
|||
* |
|||
* @param input The input string to parse. |
|||
* @param filename The name of the file from which the input was read. |
|||
* @param typeCheck Sets whether the expressions are generated and therefore typechecked. |
|||
* @return The resulting PRISM program. |
|||
*/ |
|||
static storm::prism::Program parseFromString(std::string const& input, std::string const& filename, bool typeCheck = true); |
|||
}; |
|||
} // namespace parser |
|||
} // namespace storm |
|||
|
|||
#endif /* STORM_PARSER_PRISMPARSER_H_ */ |
@ -0,0 +1,157 @@ |
|||
#include "gtest/gtest.h"
|
|||
#include "storm-config.h"
|
|||
#include "src/parser/prismparser/PrismParser.h"
|
|||
|
|||
TEST(PrismParser, SimpleParsingOnlyTest) { |
|||
std::string testInput = |
|||
R"(dtmc |
|||
module mod1 |
|||
b : bool; |
|||
[a] true -> 1: (b'=true); |
|||
endmodule)"; |
|||
|
|||
storm::prism::Program result; |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parseFromString(testInput, "testfile", false)); |
|||
EXPECT_EQ(1, result.getNumberOfModules()); |
|||
EXPECT_EQ(storm::prism::Program::ModelType::DTMC, result.getModelType()); |
|||
} |
|||
|
|||
TEST(PrismParser, StandardModelParsingTest) { |
|||
storm::prism::Program result; |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/coin2.nm", false)); |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/crowds5_5.pm", false)); |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/csma2_2.nm", false)); |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/die.pm", false)); |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/firewire.nm", false)); |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/leader3.nm", false)); |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/leader3_5.pm", false)); |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/two_dice.nm", false)); |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/parser/prism/wlan0_collide.nm", false)); |
|||
} |
|||
|
|||
TEST(PrismParser, SimpleFullTest) { |
|||
std::string testInput = |
|||
R"(dtmc |
|||
module mod1 |
|||
b : bool; |
|||
[a] true -> 1: (b'=true); |
|||
endmodule)"; |
|||
|
|||
storm::prism::Program result; |
|||
EXPECT_NO_THROW(result = storm::parser::PrismParser::parseFromString(testInput, "testfile", true)); |
|||
EXPECT_EQ(1, result.getNumberOfModules()); |
|||
EXPECT_EQ(storm::prism::Program::ModelType::DTMC, result.getModelType()); |
|||
} |
|||
|
|||
TEST(PrismParser, ComplexFullTest) { |
|||
std::string testInput = |
|||
R"(ma |
|||
|
|||
const int a; |
|||
const int b = 10; |
|||
const bool c; |
|||
const bool d = true | false; |
|||
const double e; |
|||
const double f = 9; |
|||
|
|||
formula test = a >= 10 & (max(a,b) > floor(e)); |
|||
formula test2 = a+b; |
|||
|
|||
global g : bool init false; |
|||
global h : [0 .. b]; |
|||
|
|||
module mod1 |
|||
i : bool; |
|||
j : bool init c; |
|||
k : [125..a] init a; |
|||
|
|||
[a] test2&false -> (i'=true)&(h'=1+1) + 1 : (j'=floor(a) <= max(k, b) - 1 + k); |
|||
endmodule |
|||
|
|||
module mod2 |
|||
[b] (k > 3) & false & (min(a, 0) < max(h, k)) -> 1-e: (j'=(1-a) * 2 + floor(f)); |
|||
endmodule |
|||
|
|||
module mod3 = mod2 [ x = y ] endmodule |
|||
|
|||
label "mal" = max(a, 10) > 0; |
|||
|
|||
init |
|||
true |
|||
endinit |
|||
|
|||
rewards "testrewards" |
|||
[stateRew] true : a + 7; |
|||
max(f, a) <= 8 : 2*b; |
|||
endrewards |
|||
|
|||
rewards "testrewards2" |
|||
[stateRew] true : a + 7; |
|||
max(f, a) <= 8 : 2*b; |
|||
endrewards)"; |
|||
|
|||
storm::prism::Program result; |
|||
result = storm::parser::PrismParser::parseFromString(testInput, "testfile", true); |
|||
std::cout << result << std::endl; |
|||
EXPECT_EQ(storm::prism::Program::ModelType::MA, result.getModelType()); |
|||
EXPECT_EQ(3, result.getNumberOfModules()); |
|||
EXPECT_EQ(2, result.getNumberOfRewardModels()); |
|||
EXPECT_EQ(1, result.getNumberOfLabels()); |
|||
EXPECT_TRUE(result.definesInitialStatesExpression()); |
|||
} |
|||
|
|||
TEST(PrismParser, ComplexParsingTest) { |
|||
std::string testInput = |
|||
R"(ma |
|||
|
|||
const int a; |
|||
const int b = 10; |
|||
const bool c; |
|||
const bool d = true | false; |
|||
const double e; |
|||
const double f = 9; |
|||
|
|||
formula test = (a >= 10 & (max(a, b) > floor(e))); |
|||
|
|||
global g : bool init false; |
|||
global h : [0 .. b]; |
|||
|
|||
module mod1 |
|||
i : bool; |
|||
j : bool init c; |
|||
k : [125..a] init a; |
|||
[a] true -> (i'=true)&(h'=1+1) + 1 : (j'=floor(a) <= max(k, b) - 1 + k); |
|||
endmodule |
|||
|
|||
module mod2 |
|||
[b] (x > 3) & false & (min(a, b0) < max(as8, b)) -> y: (x'=(1-g) * 2 + a); |
|||
[] s=1 -> (a'=a); |
|||
[read] c<N-1 -> 1 : (c'=floor(c) + 1); |
|||
endmodule |
|||
|
|||
module mod3 = mod2 [ x = y ] endmodule |
|||
|
|||
label "mal" = max(x, i) > 0; |
|||
|
|||
init |
|||
true |
|||
endinit |
|||
|
|||
rewards "testrewards" |
|||
[stateRew] true : a + 7; |
|||
max(z, f) <= 8 : 2*b; |
|||
endrewards |
|||
|
|||
rewards "testrewards2" |
|||
[stateRew] true : a + 7; |
|||
max(z, f) <= 8 : 2*b; |
|||
endrewards)"; |
|||
|
|||
storm::prism::Program result; |
|||
result = storm::parser::PrismParser::parseFromString(testInput, "testfile", false); |
|||
EXPECT_EQ(storm::prism::Program::ModelType::MA, result.getModelType()); |
|||
EXPECT_EQ(3, result.getNumberOfModules()); |
|||
EXPECT_EQ(2, result.getNumberOfRewardModels()); |
|||
EXPECT_EQ(1, result.getNumberOfLabels()); |
|||
EXPECT_TRUE(result.definesInitialStatesExpression()); |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue