You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

254 lines
10 KiB

  1. #include "storm-parsers/parser/SparseItemLabelingParser.h"
  2. #include <cstring>
  3. #include <string>
  4. #include <iostream>
  5. #include "storm-parsers/util/cstring.h"
  6. #include "storm-parsers/parser/MappedFile.h"
  7. #include "storm/utility/macros.h"
  8. #include "storm/exceptions/WrongFormatException.h"
  9. #include "storm/exceptions/FileIoException.h"
  10. namespace storm {
  11. namespace parser {
  12. using namespace storm::utility::cstring;
  13. storm::models::sparse::StateLabeling SparseItemLabelingParser::parseAtomicPropositionLabeling(uint_fast64_t stateCount, std::string const & filename) {
  14. MappedFile file(filename.c_str());
  15. checkSyntax(filename, file);
  16. // Create labeling object with given node and label count.
  17. storm::models::sparse::StateLabeling labeling(stateCount);
  18. // initialize the buffer
  19. char const* buf = file.getData();
  20. // add the labels to the labeling
  21. parseLabelNames(filename, labeling, buf);
  22. // Now parse the assignments of labels to states.
  23. parseDeterministicLabelAssignments(filename, labeling, buf);
  24. return labeling;
  25. }
  26. storm::models::sparse::ChoiceLabeling SparseItemLabelingParser::parseChoiceLabeling(uint_fast64_t choiceCount, std::string const& filename, boost::optional<std::vector<uint_fast64_t>> const& nondeterministicChoiceIndices) {
  27. MappedFile file(filename.c_str());
  28. checkSyntax(filename, file);
  29. // Create labeling object with given node and label count.
  30. storm::models::sparse::ChoiceLabeling labeling(choiceCount);
  31. // initialize the buffer
  32. char const* buf = file.getData();
  33. // add the labels to the labeling
  34. parseLabelNames(filename, labeling, buf);
  35. // Now parse the assignments of labels to states.
  36. if (nondeterministicChoiceIndices) {
  37. parseNonDeterministicLabelAssignments(filename, labeling, nondeterministicChoiceIndices.get(), buf);
  38. } else {
  39. parseDeterministicLabelAssignments(filename, labeling, buf);
  40. }
  41. return labeling;
  42. }
  43. void SparseItemLabelingParser::checkSyntax(std::string const & filename, storm::parser::MappedFile const& file) {
  44. char const* buf = file.getData();
  45. // First pass: Count the number of propositions.
  46. bool foundDecl = false, foundEnd = false;
  47. size_t cnt = 0;
  48. // Iterate over tokens until we hit #END or the end of the file.
  49. while(buf[0] != '\0') {
  50. //Move the buffer to the beginning of the next word.
  51. buf += cnt;
  52. buf = trimWhitespaces(buf);
  53. // Get the number of characters until the next separator.
  54. cnt = skipWord(buf) - buf;
  55. if (cnt > 0) {
  56. // If the next token is #DECLARATION: Just skip it.
  57. // If the next token is #END: Stop the search.
  58. // Otherwise increase proposition_count.
  59. if (strncmp(buf, "#DECLARATION", cnt) == 0) {
  60. foundDecl = true;
  61. continue;
  62. } else if (strncmp(buf, "#END", cnt) == 0) {
  63. foundEnd = true;
  64. break;
  65. }
  66. }
  67. }
  68. // If #DECLARATION or #END have not been found, the file format is wrong.
  69. STORM_LOG_THROW(foundDecl, storm::exceptions::WrongFormatException, "Error while parsing " << filename << ": File header is corrupted (Token #DECLARATION missing - case sensitive).");
  70. STORM_LOG_THROW(foundEnd, storm::exceptions::WrongFormatException, "Error while parsing " << filename << ": File header is corrupted (Token #END missing - case sensitive).");
  71. }
  72. void SparseItemLabelingParser::parseLabelNames(std::string const & filename, storm::models::sparse::ItemLabeling& labeling, char const*& buf) {
  73. // Prepare a buffer for proposition names.
  74. char proposition[128];
  75. size_t cnt = 0;
  76. // Parse proposition names.
  77. // As we already checked the file header, we know that #DECLARATION and #END are tokens in the character stream.
  78. while(buf[0] != '\0') {
  79. //Move the buffer to the beginning of the next word.
  80. buf += cnt;
  81. buf = trimWhitespaces(buf);
  82. // Get the number of characters until the next separator.
  83. cnt = skipWord(buf) - buf;
  84. if (cnt >= sizeof(proposition)) {
  85. // if token is longer than our buffer, the following strncpy code might get risky...
  86. STORM_LOG_ERROR("Error while parsing " << filename << ": Atomic proposition with length > " << (sizeof(proposition) - 1) << " was found.");
  87. throw storm::exceptions::WrongFormatException() << "Error while parsing " << filename << ": Atomic proposition with length > " << (sizeof(proposition) - 1) << " was found.";
  88. } else if (cnt > 0) {
  89. // If the next token is #DECLARATION: Just skip it.
  90. if (strncmp(buf, "#DECLARATION", cnt) == 0) continue;
  91. // If the next token is #END: Stop the search.
  92. if (strncmp(buf, "#END", cnt) == 0) break;
  93. // Otherwise copy the token to the buffer, append a trailing null byte and hand it to labeling.
  94. strncpy(proposition, buf, cnt);
  95. proposition[cnt] = '\0';
  96. labeling.addLabel(proposition);
  97. }
  98. }
  99. // At this point, the pointer buf is still pointing to our last token, i.e. to #END.
  100. // We want to skip it.
  101. buf += 4;
  102. // Now eliminate remaining whitespaces such as empty lines and start parsing.
  103. buf = trimWhitespaces(buf);
  104. }
  105. void SparseItemLabelingParser::parseDeterministicLabelAssignments(std::string const & filename, storm::models::sparse::ItemLabeling& labeling, char const*& buf) {
  106. uint_fast64_t state = 0;
  107. uint_fast64_t lastState = (uint_fast64_t)-1;
  108. uint_fast64_t const startIndexComparison = lastState;
  109. size_t cnt = 0;
  110. char proposition[128];
  111. while (buf[0] != '\0') {
  112. // Parse the state number and iterate over its labels (atomic propositions).
  113. // Stop at the end of the line.
  114. state = checked_strtol(buf, &buf);
  115. // If the state has already been read or skipped once there might be a problem with the file (doubled lines, or blocks).
  116. if (state <= lastState && lastState != startIndexComparison) {
  117. STORM_LOG_ERROR("Error while parsing " << filename << ": State " << state << " was found but has already been read or skipped previously.");
  118. throw storm::exceptions::WrongFormatException() << "Error while parsing " << filename << ": State " << state << " was found but has already been read or skipped previously.";
  119. }
  120. while ((buf[0] != '\r') && (buf[0] != '\n') && (buf[0] != '\0')) {
  121. cnt = skipWord(buf) - buf;
  122. if (cnt == 0) {
  123. // The next character is a separator.
  124. // If it is a line separator, we continue with next node.
  125. // Otherwise, we skip it and try again.
  126. if (buf[0] == '\n' || buf[0] == '\r') break;
  127. buf++;
  128. } else {
  129. // Copy the label to the buffer, null terminate it and add it to labeling.
  130. strncpy(proposition, buf, cnt);
  131. proposition[cnt] = '\0';
  132. // Has the label been declared in the header?
  133. if(!labeling.containsLabel(proposition)) {
  134. STORM_LOG_ERROR("Error while parsing " << filename << ": Atomic proposition" << proposition << " was found but not declared.");
  135. throw storm::exceptions::WrongFormatException() << "Error while parsing " << filename << ": Atomic proposition" << proposition << " was found but not declared.";
  136. }
  137. if (labeling.isStateLabeling()) {
  138. labeling.asStateLabeling().addLabelToState(proposition, state);
  139. } else {
  140. STORM_LOG_ASSERT(labeling.isChoiceLabeling(), "Unexpected labeling type");
  141. labeling.asChoiceLabeling().addLabelToChoice(proposition, state);
  142. }
  143. buf += cnt;
  144. }
  145. }
  146. buf = trimWhitespaces(buf);
  147. lastState = state;
  148. }
  149. }
  150. void SparseItemLabelingParser::parseNonDeterministicLabelAssignments(std::string const & filename, storm::models::sparse::ChoiceLabeling& labeling, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, char const*& buf) {
  151. uint_fast64_t const startIndexComparison = (uint_fast64_t)-1;
  152. uint_fast64_t state = 0;
  153. uint_fast64_t lastState = startIndexComparison;
  154. uint_fast64_t localChoice = 0;
  155. uint_fast64_t lastLocalChoice = startIndexComparison;
  156. size_t cnt = 0;
  157. char proposition[128];
  158. while (buf[0] != '\0') {
  159. // Parse the state and choice number and iterate over its labels (atomic propositions).
  160. // Stop at the end of the line.
  161. state = checked_strtol(buf, &buf);
  162. localChoice = checked_strtol(buf, &buf);
  163. // If we see this state for the first time, reset the last choice
  164. if (state != lastState) {
  165. lastLocalChoice = startIndexComparison;
  166. }
  167. // If the state-choice pair has already been read or skipped once there might be a problem with the file (doubled lines, or blocks).
  168. STORM_LOG_THROW(state >= lastState || lastState == startIndexComparison, storm::exceptions::WrongFormatException, "Error while parsing " << filename << ": State " << state << " and Choice " << localChoice << " were found but the state has already been read or skipped previously.");
  169. STORM_LOG_THROW(state != lastState || localChoice > lastLocalChoice || lastLocalChoice == startIndexComparison, storm::exceptions::WrongFormatException, "Error while parsing " << filename << ": State " << state << " and Choice " << localChoice << " were found but the choice has already been read or skipped previously.");
  170. uint_fast64_t const globalChoice = nondeterministicChoiceIndices[state] + localChoice;
  171. STORM_LOG_THROW(globalChoice < nondeterministicChoiceIndices[state + 1], storm::exceptions::WrongFormatException, "Error while parsing " << filename << ": Invalid choice index " << localChoice << " at state " << state << ".");
  172. while ((buf[0] != '\r') && (buf[0] != '\n') && (buf[0] != '\0')) {
  173. cnt = skipWord(buf) - buf;
  174. if (cnt == 0) {
  175. // The next character is a separator.
  176. // If it is a line separator, we continue with next node.
  177. // Otherwise, we skip it and try again.
  178. if (buf[0] == '\n' || buf[0] == '\r') break;
  179. buf++;
  180. } else {
  181. // Copy the label to the buffer, null terminate it and add it to labeling.
  182. strncpy(proposition, buf, cnt);
  183. proposition[cnt] = '\0';
  184. // Has the label been declared in the header?
  185. STORM_LOG_THROW(labeling.containsLabel(proposition), storm::exceptions::WrongFormatException, "Error while parsing " << filename << ": Atomic proposition" << proposition << " was found but not declared.");
  186. labeling.addLabelToChoice(proposition, globalChoice);
  187. buf += cnt;
  188. }
  189. }
  190. buf = trimWhitespaces(buf);
  191. lastState = state;
  192. lastLocalChoice = localChoice;
  193. }
  194. }
  195. } // namespace parser
  196. } // namespace storm