Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseItemLabelingParser.cpp
Go to the documentation of this file.
2
3#include <cstring>
4#include <iostream>
5#include <string>
6
9
13
14namespace storm {
15namespace parser {
16
17using namespace storm::utility::cstring;
18
20 MappedFile file(filename.c_str());
21 checkSyntax(filename, file);
22
23 // Create labeling object with given node and label count.
24 storm::models::sparse::StateLabeling labeling(stateCount);
25
26 // initialize the buffer
27 char const* buf = file.getData();
28
29 // add the labels to the labeling
30 parseLabelNames(filename, labeling, buf);
31
32 // Now parse the assignments of labels to states.
33 parseDeterministicLabelAssignments(filename, labeling, buf);
34
35 return labeling;
36}
37
39 uint_fast64_t choiceCount, std::string const& filename, boost::optional<std::vector<uint_fast64_t>> const& nondeterministicChoiceIndices) {
40 MappedFile file(filename.c_str());
41 checkSyntax(filename, file);
42
43 // Create labeling object with given node and label count.
44 storm::models::sparse::ChoiceLabeling labeling(choiceCount);
45
46 // initialize the buffer
47 char const* buf = file.getData();
48
49 // add the labels to the labeling
50 parseLabelNames(filename, labeling, buf);
51
52 // Now parse the assignments of labels to states.
53 if (nondeterministicChoiceIndices) {
54 parseNonDeterministicLabelAssignments(filename, labeling, nondeterministicChoiceIndices.get(), buf);
55 } else {
56 parseDeterministicLabelAssignments(filename, labeling, buf);
57 }
58
59 return labeling;
60}
61
62void SparseItemLabelingParser::checkSyntax(std::string const& filename, storm::parser::MappedFile const& file) {
63 char const* buf = file.getData();
64
65 // First pass: Count the number of propositions.
66 bool foundDecl = false, foundEnd = false;
67 size_t cnt = 0;
68
69 // Iterate over tokens until we hit #END or the end of the file.
70 while (buf[0] != '\0') {
71 // Move the buffer to the beginning of the next word.
72 buf += cnt;
73 buf = trimWhitespaces(buf);
74
75 // Get the number of characters until the next separator.
76 cnt = skipWord(buf) - buf;
77 if (cnt > 0) {
78 // If the next token is #DECLARATION: Just skip it.
79 // If the next token is #END: Stop the search.
80 // Otherwise increase proposition_count.
81 if (strncmp(buf, "#DECLARATION", cnt) == 0) {
82 foundDecl = true;
83 continue;
84 } else if (strncmp(buf, "#END", cnt) == 0) {
85 foundEnd = true;
86 break;
87 }
88 }
89 }
90
91 // If #DECLARATION or #END have not been found, the file format is wrong.
92 STORM_LOG_THROW(foundDecl, storm::exceptions::WrongFormatException,
93 "Error while parsing " << filename << ": File header is corrupted (Token #DECLARATION missing - case sensitive).");
94 STORM_LOG_THROW(foundEnd, storm::exceptions::WrongFormatException,
95 "Error while parsing " << filename << ": File header is corrupted (Token #END missing - case sensitive).");
96}
97
98void SparseItemLabelingParser::parseLabelNames(std::string const& filename, storm::models::sparse::ItemLabeling& labeling, char const*& buf) {
99 // Prepare a buffer for proposition names.
100 char proposition[128];
101 size_t cnt = 0;
102
103 // Parse proposition names.
104 // As we already checked the file header, we know that #DECLARATION and #END are tokens in the character stream.
105 while (buf[0] != '\0') {
106 // Move the buffer to the beginning of the next word.
107 buf += cnt;
108 buf = trimWhitespaces(buf);
109
110 // Get the number of characters until the next separator.
111 cnt = skipWord(buf) - buf;
112
113 if (cnt >= sizeof(proposition)) {
114 // if token is longer than our buffer, the following strncpy code might get risky...
115 STORM_LOG_ERROR("Error while parsing " << filename << ": Atomic proposition with length > " << (sizeof(proposition) - 1) << " was found.");
116 throw storm::exceptions::WrongFormatException()
117 << "Error while parsing " << filename << ": Atomic proposition with length > " << (sizeof(proposition) - 1) << " was found.";
118
119 } else if (cnt > 0) {
120 // If the next token is #DECLARATION: Just skip it.
121 if (strncmp(buf, "#DECLARATION", cnt) == 0)
122 continue;
123
124 // If the next token is #END: Stop the search.
125 if (strncmp(buf, "#END", cnt) == 0)
126 break;
127
128 // Otherwise copy the token to the buffer, append a trailing null byte and hand it to labeling.
129 strncpy(proposition, buf, cnt);
130 proposition[cnt] = '\0';
131 labeling.addLabel(proposition);
132 }
133 }
134
135 // At this point, the pointer buf is still pointing to our last token, i.e. to #END.
136 // We want to skip it.
137 buf += 4;
138
139 // Now eliminate remaining whitespaces such as empty lines and start parsing.
140 buf = trimWhitespaces(buf);
141}
142
143void SparseItemLabelingParser::parseDeterministicLabelAssignments(std::string const& filename, storm::models::sparse::ItemLabeling& labeling,
144 char const*& buf) {
145 uint_fast64_t state = 0;
146 uint_fast64_t lastState = (uint_fast64_t)-1;
147 uint_fast64_t const startIndexComparison = lastState;
148 size_t cnt = 0;
149 char proposition[128];
150
151 while (buf[0] != '\0') {
152 // Parse the state number and iterate over its labels (atomic propositions).
153 // Stop at the end of the line.
154 state = checked_strtol(buf, &buf);
155
156 // If the state has already been read or skipped once there might be a problem with the file (doubled lines, or blocks).
157 if (state <= lastState && lastState != startIndexComparison) {
158 STORM_LOG_ERROR("Error while parsing " << filename << ": State " << state << " was found but has already been read or skipped previously.");
159 throw storm::exceptions::WrongFormatException()
160 << "Error while parsing " << filename << ": State " << state << " was found but has already been read or skipped previously.";
161 }
162
163 while ((buf[0] != '\r') && (buf[0] != '\n') && (buf[0] != '\0')) {
164 cnt = skipWord(buf) - buf;
165 if (cnt == 0) {
166 // The next character is a separator.
167 // If it is a line separator, we continue with next node.
168 // Otherwise, we skip it and try again.
169 if (buf[0] == '\n' || buf[0] == '\r')
170 break;
171 buf++;
172 } else {
173 // Copy the label to the buffer, null terminate it and add it to labeling.
174 strncpy(proposition, buf, cnt);
175 proposition[cnt] = '\0';
176
177 // Has the label been declared in the header?
178 if (!labeling.containsLabel(proposition)) {
179 STORM_LOG_ERROR("Error while parsing " << filename << ": Atomic proposition" << proposition << " was found but not declared.");
180 throw storm::exceptions::WrongFormatException()
181 << "Error while parsing " << filename << ": Atomic proposition" << proposition << " was found but not declared.";
182 }
183 if (labeling.isStateLabeling()) {
184 labeling.asStateLabeling().addLabelToState(proposition, state);
185 } else {
186 STORM_LOG_ASSERT(labeling.isChoiceLabeling(), "Unexpected labeling type");
187 labeling.asChoiceLabeling().addLabelToChoice(proposition, state);
188 }
189 buf += cnt;
190 }
191 }
192 buf = trimWhitespaces(buf);
193 lastState = state;
194 }
195}
196
197void SparseItemLabelingParser::parseNonDeterministicLabelAssignments(std::string const& filename, storm::models::sparse::ChoiceLabeling& labeling,
198 std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, char const*& buf) {
199 uint_fast64_t const startIndexComparison = (uint_fast64_t)-1;
200 uint_fast64_t state = 0;
201 uint_fast64_t lastState = startIndexComparison;
202 uint_fast64_t localChoice = 0;
203 uint_fast64_t lastLocalChoice = startIndexComparison;
204 size_t cnt = 0;
205 char proposition[128];
206
207 while (buf[0] != '\0') {
208 // Parse the state and choice number and iterate over its labels (atomic propositions).
209 // Stop at the end of the line.
210 state = checked_strtol(buf, &buf);
211 localChoice = checked_strtol(buf, &buf);
212
213 // If we see this state for the first time, reset the last choice
214 if (state != lastState) {
215 lastLocalChoice = startIndexComparison;
216 }
217
218 // If the state-choice pair has already been read or skipped once there might be a problem with the file (doubled lines, or blocks).
219 STORM_LOG_THROW(state >= lastState || lastState == startIndexComparison, storm::exceptions::WrongFormatException,
220 "Error while parsing " << filename << ": State " << state << " and Choice " << localChoice
221 << " were found but the state has already been read or skipped previously.");
222 STORM_LOG_THROW(state != lastState || localChoice > lastLocalChoice || lastLocalChoice == startIndexComparison, storm::exceptions::WrongFormatException,
223 "Error while parsing " << filename << ": State " << state << " and Choice " << localChoice
224 << " were found but the choice has already been read or skipped previously.");
225
226 uint_fast64_t const globalChoice = nondeterministicChoiceIndices[state] + localChoice;
227 STORM_LOG_THROW(globalChoice < nondeterministicChoiceIndices[state + 1], storm::exceptions::WrongFormatException,
228 "Error while parsing " << filename << ": Invalid choice index " << localChoice << " at state " << state << ".");
229
230 while ((buf[0] != '\r') && (buf[0] != '\n') && (buf[0] != '\0')) {
231 cnt = skipWord(buf) - buf;
232 if (cnt == 0) {
233 // The next character is a separator.
234 // If it is a line separator, we continue with next node.
235 // Otherwise, we skip it and try again.
236 if (buf[0] == '\n' || buf[0] == '\r')
237 break;
238 buf++;
239 } else {
240 // Copy the label to the buffer, null terminate it and add it to labeling.
241 strncpy(proposition, buf, cnt);
242 proposition[cnt] = '\0';
243
244 // Has the label been declared in the header?
245 STORM_LOG_THROW(labeling.containsLabel(proposition), storm::exceptions::WrongFormatException,
246 "Error while parsing " << filename << ": Atomic proposition" << proposition << " was found but not declared.");
247
248 labeling.addLabelToChoice(proposition, globalChoice);
249 buf += cnt;
250 }
251 }
252 buf = trimWhitespaces(buf);
253 lastState = state;
254 lastLocalChoice = localChoice;
255 }
256}
257
258} // namespace parser
259} // namespace storm
This class manages the labeling of the choice space with a number of (atomic) labels.
void addLabelToChoice(std::string const &label, uint64_t choice)
Adds a label to a given choice.
A base class managing the labeling of items with a number of (atomic) labels.
virtual bool isChoiceLabeling() const
void addLabel(std::string const &label)
Adds a new label to the labelings.
ChoiceLabeling const & asChoiceLabeling() const
bool containsLabel(std::string const &label) const
Checks whether a label is registered within this labeling.
StateLabeling const & asStateLabeling() const
This class manages the labeling of the state space with a number of (atomic) labels.
void addLabelToState(std::string const &label, storm::storage::sparse::state_type state)
Adds a label to a given state.
Opens a file and maps it to memory providing a char* containing the file content.
Definition MappedFile.h:33
char const * getData() const
Returns a pointer to the beginning of the mapped file data.
static storm::models::sparse::ChoiceLabeling parseChoiceLabeling(uint_fast64_t choiceCount, std::string const &filename, boost::optional< std::vector< uint_fast64_t > > const &nondeterministicChoiceIndices=boost::none)
Parses the given file and returns the resulting choice labeling.
static storm::models::sparse::StateLabeling parseAtomicPropositionLabeling(uint_fast64_t stateCount, std::string const &filename)
Parses the given file and returns the resulting state labeling.
#define STORM_LOG_ERROR(message)
Definition logging.h:31
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
char const * skipWord(char const *buf)
Skips all numbers, letters and special characters.
Definition cstring.cpp:55
uint_fast64_t checked_strtol(char const *str, char const **end)
Calls strtol() internally and checks if the new pointer is different from the original one,...
Definition cstring.cpp:21
char const * trimWhitespaces(char const *buf)
Skips spaces, tabs, newlines and carriage returns.
Definition cstring.cpp:66
LabParser.cpp.
Definition cli.cpp:18