libutap  0.93
Uppaal Timed Automata Parser
xmlreader.cpp
Go to the documentation of this file.
1 // -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 
3 /* libutap - Uppaal Timed Automata Parser.
4  Copyright (C) 2002-2006 Uppsala University and Aalborg University.
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public License
8  as published by the Free Software Foundation; either version 2.1 of
9  the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  USA
20  */
21 
22 #include "libparser.h"
23 #ifdef ENABLE_SBML
24 #include "utap/sbmlconverter.h"
25 #endif
26 
27 #include "utap/position.h"
28 
29 #include <libxml/xmlreader.h>
30 #include <libxml/xpath.h>
31 #include <libxml/parser.h>
32 #include <libxml/xmlstring.h>
33 #include <stdexcept>
34 #include <cstdarg>
35 #include <cctype>
36 #include <cstring>
37 #include <cassert>
38 #include <algorithm>
39 #include <list>
40 #include <vector>
41 #include <map>
42 #include <sstream>
43 
44 using std::map;
45 using std::vector;
46 using std::list;
47 using std::ostringstream;
48 using std::string;
49 
50 namespace UTAP {
51 
57  enum tag_t {
63  // LSC
68  // SBML
70  // QUERIES
72  };
73 
74 #include "tags.cc"
75 
80  static bool isempty(string str) {
81  const char *p = str.c_str();
82  while (*p) {
83  if (!isspace((unsigned char)*p)) {
84  return false;
85  }
86  p++;
87  }
88  return true;
89  }
90 
91  static bool isAlpha(unsigned char c) {
92  return isalpha(c) || c == '_';
93  }
94 
95  static bool isIdChr(unsigned char c) {
96  return isalnum(c) || c == '_' || c == '$' || c == '#';
97  }
98 
107  static string symbol(const char *str) {
108  if (str == NULL) {
109  throw "Identifier expected";
110  }
111  while (isspace((unsigned char)*str)) {
112  str++;
113  }
114  if (*str == 0) {
115  throw "Identifier expected";
116  }
117  if (!isAlpha(*str)) {
118  throw "Invalid identifier";
119  }
120  const char *end = str;
121  while (isIdChr(*end)) end++;
122  const char *p = end;
123  while (isspace((unsigned char)*p)) {
124  p++;
125  }
126  if (*p) {
127  throw "Invalid identifier";
128  }
129  return string(str, end - str);
130  }
131 
135  struct compare_str {
136 
137  bool operator()(const xmlChar* x, const xmlChar * y) const {
138  return (strcmp((const char*) x, (const char*) y) < 0);
139  }
140  };
141 
149  class Path {
150  private:
151  list<vector<tag_t> > path;
152  public:
153  Path();
154  void push(tag_t);
155  tag_t pop();
156  string get(tag_t tag = TAG_NONE) const;
157  };
158 
159  Path::Path() {
160  path.push_back(vector<tag_t > ());
161  }
162 
163  void Path::push(tag_t tag) {
164  path.back().push_back(tag);
165  path.push_back(vector<tag_t > ());
166  }
167 
168  tag_t Path::pop() {
169  path.pop_back();
170  return path.back().back();
171  }
172 
174  string Path::get(tag_t tag) const {
175  ostringstream str;
176  list<vector<tag_t> >::const_iterator i;
177  for (i = path.begin(); !i->empty() && i != path.end(); i++) {
178  switch (i->back()) {
179  case TAG_NTA:
180  str << "/nta";
181  break;
182  case TAG_IMPORTS:
183  str << "/imports";
184  break;
185  case TAG_DECLARATION:
186  str << "/declaration";
187  break;
188  case TAG_TEMPLATE:
189  str << "/template[" <<
190  std::count(i->begin(), i->end(), TAG_TEMPLATE) << "]";
191  break;
192  case TAG_INSTANTIATION:
193  str << "/instantiation";
194  break;
195  case TAG_SYSTEM:
196  str << "/system";
197  break;
198  case TAG_NAME:
199  str << "/name";
200  break;
201  case TAG_PARAMETER:
202  str << "/parameter";
203  break;
204  case TAG_LOCATION:
205  str << "/location["
206  << std::count(i->begin(), i->end(), TAG_LOCATION) << "]";
207  break;
208  case TAG_BRANCHPOINT:
209  str << "/branchpoint["
210  << std::count(i->begin(), i->end(), TAG_BRANCHPOINT) << "]";
211  break;
212  case TAG_INIT:
213  str << "/init";
214  break;
215  case TAG_TRANSITION:
216  str << "/transition[" <<
217  std::count(i->begin(), i->end(), TAG_TRANSITION) << "]";
218  break;
219  case TAG_LABEL:
220  str << "/label[" <<
221  std::count(i->begin(), i->end(), TAG_LABEL) << "]";
222  break;
223  case TAG_URGENT:
224  str << "/urgent";
225  break;
226  case TAG_COMMITTED:
227  str << "/committed";
228  break;
229  case TAG_SOURCE:
230  str << "/source";
231  break;
232  case TAG_TARGET:
233  str << "/target";
234  break;
235  case TAG_NAIL:
236  str << "/nail["
237  << std::count(i->begin(), i->end(), TAG_NAIL) << "]";
238  break;
239  case TAG_PROJECT:
240  str << "/project";
241  break;
242  case TAG_LSC:
243  str << "/lscTemplate[" <<
244  std::count(i->begin(), i->end(), TAG_LSC) << "]";
245  break;
246  case TAG_TYPE:
247  str << "/type";
248  break;
249  case TAG_MODE:
250  str << "/mode";
251  break;
252  case TAG_YLOCCOORD:
253  str << "/ylocoord[" <<
254  std::count(i->begin(), i->end(), TAG_YLOCCOORD) << "]";
255  break;
256  case TAG_LSCLOCATION:
257  str << "/lsclocation";
258  break;
259  case TAG_PRECHART:
260  str << "/prechart";
261  break;
262  case TAG_INSTANCE:
263  str << "/instance["
264  << std::count(i->begin(), i->end(), TAG_INSTANCE) << "]";
265  break;
266  case TAG_TEMPERATURE:
267  str << "/temperature["
268  << std::count(i->begin(), i->end(), TAG_TEMPERATURE) << "]";
269  break;
270  case TAG_MESSAGE:
271  str << "/message["
272  << std::count(i->begin(), i->end(), TAG_MESSAGE) << "]";
273  break;
274  case TAG_CONDITION:
275  str << "/condition["
276  << std::count(i->begin(), i->end(), TAG_CONDITION) << "]";
277  break;
278  case TAG_UPDATE:
279  str << "/update["
280  << std::count(i->begin(), i->end(), TAG_UPDATE) << "]";
281  break;
282  case TAG_ANCHOR:
283  str << "/anchor["
284  << std::count(i->begin(), i->end(), TAG_ANCHOR) << "]";
285  break;
286  case TAG_SBML:
287  str << "/sbml["
288  << std::count(i->begin(), i->end(), TAG_SBML) << "]";
289  break;
290  case TAG_QUERIES:
291  str << "/queries";
292  break;
293  case TAG_QUERY:
294  str << "/query["
295  << std::count(i->begin(), i->end(), TAG_QUERY) << "]";
296  break;
297  case TAG_FORMULA:
298  str << "/formula";
299  break;
300  default:
301  /* Strange tag on stack */
302  throw std::logic_error("XPath is corrupted");
303  }
304  if (i->back() == tag) {
305  break;
306  }
307  }
308  return str.str();
309  }
310 
315  class XMLReader {
316  private:
317  typedef map<xmlChar*, string, compare_str> elementmap_t;
318 
319  xmlTextReaderPtr reader;
320  elementmap_t names;
321  ParserBuilder *parser;
322  bool newxta;
323  Path path;
324  bool nta;
325  int bottomPrechart;
326  string currentType;
327  string currentMode;
329  tag_t getElement();
330  bool isEmpty();
331  int getNodeType();
332  void read();
333  bool begin(tag_t, bool skipEmpty = true);
334  bool end(tag_t);
335 
336  const string getName(const xmlChar *id);
337  int parse(const xmlChar *, xta_part_t syntax);
338 
339  bool declaration();
340  bool label(bool required = false, string kind = "");
341  int invariant();
342  bool committed();
343  bool urgent();
344  bool location();
345  bool branchpoint();
346  bool init();
347  string name(bool instanceLine = false);
348  string readString(tag_t tag, bool instanceLine = false);
349  string readText(bool instanceLine = false);
350  int readNumber();
351  string source();
352  string target();
353  bool transition();
354  bool templ();
355  int parameter();
356  bool instantiation();
357  void system();
358  string reference(string attributeName);
359 
360  // LSC elements:
361  bool lscTempl();
362  string anchor();
363  vector<char*> anchors();
364  string type();
365  string mode();
366  int lscLocation();
367  string temperature();
368  bool yloccoord();
369  bool instance();
370  bool prechart();
371  bool message();
372  bool condition();
373  bool update();
374 
375  // integrated query elements:
376  bool queries();
377  bool query();
378  bool formula();
379  bool comment();
380 
381  public:
382  XMLReader(
383  xmlTextReaderPtr reader, ParserBuilder *parser, bool newxta);
384  virtual ~XMLReader();
385  void project();
386  };
387 
388  XMLReader::XMLReader(
389  xmlTextReaderPtr reader, ParserBuilder *parser, bool newxta)
390  : reader(reader), parser(parser), newxta(newxta) {
391  read();
392  }
393 
394  XMLReader::~XMLReader() {
395  elementmap_t::iterator i;
396  for (i = names.begin(); i != names.end(); ++i) {
397  xmlFree(i->first);
398  }
399  xmlFreeTextReader(reader);
400  }
401 
403  int XMLReader::getNodeType() {
404  return xmlTextReaderNodeType(reader);
405  }
406 
411  tag_t XMLReader::getElement() {
412  const char *element = (const char *) xmlTextReaderConstLocalName(reader);
413  const Tag *tag = Tags::in_word_set(element, strlen(element));
414  if (tag == NULL) {
415  /* Unknown element. */
416  throw std::runtime_error("Unknown tag in XML file");
417  }
418  return tag->tag;
419  }
420 
422  bool XMLReader::isEmpty() {
423  return xmlTextReaderIsEmptyElement(reader);
424  }
425 
431  bool XMLReader::begin(tag_t tag, bool skipEmpty) {
432  for (;;) {
433  while (getNodeType() != XML_READER_TYPE_ELEMENT) {
434  read();
435  }
436  if (getElement() != tag) {
437  return false;
438  }
439 
440  if (!skipEmpty || !isEmpty()) {
441  return true;
442  }
443  read();
444  }
445  }
452  bool UTAP::XMLReader::end(UTAP::tag_t tag) {
453  //Ignore whitespace
454  while (getNodeType() == XML_READER_TYPE_WHITESPACE
455  || getNodeType() == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) {
456  read();
457  }
458  // </...> tag found
459  return getNodeType() == XML_READER_TYPE_END_ELEMENT && getElement() == tag;
460  }
464  void XMLReader::read() {
465  if ((getNodeType() == XML_READER_TYPE_END_ELEMENT)
466  || (getNodeType() == XML_READER_TYPE_ELEMENT && isEmpty())) {
467  if (path.pop() != getElement()) {
468  /* Path is corrupted */
469  throw std::runtime_error("Invalid nesting in XML document");
470  }
471  }
472  if (xmlTextReaderRead(reader) != 1) {
473  /* Premature end of document. */
474  throw std::runtime_error("Unexpected end of XML document");
475  }
476 
477  if (getNodeType() == XML_READER_TYPE_ELEMENT) {
478  path.push(getElement());
479  }
480  }
481 
483  const string XMLReader::getName(const xmlChar *id) {
484  if (id) {
485  elementmap_t::iterator l = names.find((xmlChar*) id);
486  if (l != names.end()) {
487  return l->second;
488  }
489  }
490  throw std::runtime_error("Missing reference");
491  }
492 
494  int XMLReader::parse(const xmlChar *text, xta_part_t syntax) {
495  return parseXTA((const char*) text, parser, newxta, syntax, path.get());
496  }
497 
499  bool XMLReader::declaration() {
500  if (begin(TAG_DECLARATION)) {
501  read();
502  if (getNodeType() == XML_READER_TYPE_TEXT) {
503  parse(xmlTextReaderConstValue(reader), S_DECLARATION);
504  }
505  return true;
506  }
507  return false;
508  }
509 
511  bool XMLReader::label(bool required, string s_kind) {
512  xmlChar *kind;
513 
514  if (begin(TAG_LABEL)) {
515  /* Get kind attribute. */
516  kind = xmlTextReaderGetAttribute(reader, (const xmlChar *) "kind");
517  read();
518 
519  /* Read the text and push it to the parser. */
520  if (getNodeType() == XML_READER_TYPE_TEXT) {
521  const xmlChar *text = xmlTextReaderConstValue(reader);
522 
523  if (strcmp((char*) kind, "invariant") == 0) {
524  parse(text, S_INVARIANT);
525  } else if (strcmp((char*) kind, "select") == 0) {
526  parse(text, S_SELECT);
527  } else if (strcmp((char*) kind, "guard") == 0) {
528  parse(text, S_GUARD);
529  } else if (strcmp((char*) kind, "synchronisation") == 0) {
530  parse(text, S_SYNC);
531  } else if (strcmp((char*) kind, "assignment") == 0) {
532  parse(text, S_ASSIGN);
533  } else if (strcmp((char*) kind, "probability") == 0) {
534  parse(text, S_PROBABILITY);
535  } else if (strcmp((char*) kind, "message") == 0)//LSC
536  {
537  parse(text, S_MESSAGE);
538  } else if (strcmp((char*) kind, "update") == 0)//LSC
539  {
540  parse(text, S_UPDATE);
541  } else if (strcmp((char*) kind, "condition") == 0)//LSC
542  {
543  parse(text, S_CONDITION);
544  }
545  }
546  xmlFree(kind);
547  return true;
548  } else if (required) {
549  PositionTracker::setPath(parser, path.get());
550  if (strcmp(s_kind.c_str(), "message") == 0)
551  parser->handleError("$Message_label_is_required");
552  else if (strcmp(s_kind.c_str(), "update") == 0)
553  parser->handleError("$Update_label_is_required");
554  else if (strcmp(s_kind.c_str(), "condition") == 0)
555  parser->handleError("$Condition_label_is_required");
556  }
557  return false;
558  }
559 
560  int XMLReader::invariant() {
561  int result = -1;
562  xmlChar *kind;
563 
564  if (begin(TAG_LABEL)) {
565  /* Get kind attribute. */
566  kind = xmlTextReaderGetAttribute(reader, (const xmlChar *) "kind");
567  read();
568 
569  /* Read the text and push it to the parser. */
570  if (getNodeType() == XML_READER_TYPE_TEXT) {
571  const xmlChar *text = xmlTextReaderConstValue(reader);
572 
573  // This is a terrible mess but it's too badly designed
574  // to fix at this moment.
575 
576  if (strcmp((char*) kind, "invariant") == 0) {
577  if (parse(text, S_INVARIANT) == 0) {
578  result = 0;
579  }
580  } else if (strcmp((char*) kind, "exponentialrate") == 0) {
581  if (parse(text, S_EXPONENTIALRATE) == 0) {
582  result = 1;
583  }
584  }
585  }
586  xmlFree(kind);
587  }
588  return result;
589  }
590 
592  string XMLReader::name(bool instanceLine) {
593  string text = readString(TAG_NAME, instanceLine);
594  if (instanceLine && strcmp(text.c_str(), "") == 0)
595  parser->handleError("$Instance_name_is_required");
596  return text;
597  }
598 
599  string XMLReader::readText(bool instanceLine) {
600  if (getNodeType() == XML_READER_TYPE_TEXT)//text content of a node
601  {
602  xmlChar *text = xmlTextReaderValue(reader);
603  PositionTracker::setPath(parser, path.get());
604  PositionTracker::increment(parser, strlen((char*) text));
605  try {
606  string id = (instanceLine) ? (char*) text : symbol((char*) text);
607  if (!isKeyword(id.c_str(), SYNTAX_OLD | SYNTAX_PROPERTY)) {
608  xmlFree(text);
609  return id;
610  }
611  parser->handleError("$Keywords_are_not_allowed_here");
612  } catch (const char *str) {
613  parser->handleError(str);
614  }
615  xmlFree(text);
616  }
617  return "";
618  }
619 
620  int XMLReader::readNumber() {
621  read();
622  if (getNodeType() == XML_READER_TYPE_TEXT)//text content of a node
623  {
624  xmlChar *text = xmlTextReaderValue(reader);
625  PositionTracker::setPath(parser, path.get());
626  PositionTracker::increment(parser, strlen((char*) text));
627  try {
628  string id = (char*) text;
629  xmlFree(text);
630  return atoi(id.c_str());
631  } catch (const char *str) {
632  parser->handleError(str);
633  }
634  xmlFree(text);
635  }
636  return -1;
637  }
638 
639  string XMLReader::readString(tag_t tag, bool instanceLine) {
640  if (begin(tag)) {
641  read();
642  return readText(instanceLine);
643  }
644  return "";
645  }
646 
648  string XMLReader::type() {
649  return readString(TAG_TYPE);
650  }
651 
653  string XMLReader::mode() {
654  return readString(TAG_MODE);
655  }
656 
660  int XMLReader::lscLocation() {
661  int n = -1;
662  if (begin(TAG_LSCLOCATION)) {
663  n = readNumber();
664  }
665  if (n == -1)
666  throw std::runtime_error("Missing LSC location");
667  return n;
668  }
669 
671  bool XMLReader::committed() {
672  if (begin(TAG_COMMITTED, false)) {
673  read();
674  return true;
675  }
676  return false;
677  }
678 
680  bool XMLReader::urgent() {
681  if (begin(TAG_URGENT, false)) {
682  read();
683  return true;
684  }
685  return false;
686  }
687 
689  bool XMLReader::location() {
690  string l_name;
691  xmlChar *l_id = NULL;
692  bool l_committed = false;
693  bool l_urgent = false;
694  bool l_invariant = false;
695  bool l_exponentialRate = false;
696 
697  if (begin(TAG_LOCATION, false)) {
698  try {
699  string l_path = path.get(TAG_LOCATION);
700 
701  /* Extract ID attribute.
702  */
703  l_id = xmlTextReaderGetAttribute(reader, (const xmlChar*) "id");
704 
705  read();
706 
707  /* Get name of the location.
708  */
709  l_name = name();
710 
711  /* Read the invariant.
712  */
713  while (begin(TAG_LABEL)) {
714  int res = invariant();
715  l_invariant |= res == 0;
716  l_exponentialRate |= res == 1;
717  }
718 
719  /* Is the location urgent or committed?
720  */
721  l_urgent = urgent();
722  l_committed = committed();
723 
724  /* In case of anonymous locations we assign an
725  * internal name based on the ID of the
726  * location. FIXME: Is it ok to use an underscore
727  * here?
728  */
729  if (isempty(l_name)) {
730  l_name = string("_") + (char*) l_id;
731  }
732 
733  /* Remember the mapping from id to name
734  */
735  names[l_id] = l_name;
736 
737  /* Any error messages generated by any of the
738  * procStateXXX calls must be attributed to the state
739  * element. To do this, we add a dummy position of
740  * length 1.
741  */
742  PositionTracker::setPath(parser, l_path);
743  PositionTracker::increment(parser, 1);
744 
745  /* Push location to parser builder.
746  */
747  parser->procState(l_name.c_str(), l_invariant, l_exponentialRate);
748  if (l_committed) {
749  parser->procStateCommit(l_name.c_str());
750  }
751  if (l_urgent) {
752  parser->procStateUrgent(l_name.c_str());
753  }
754  } catch (TypeException &e) {
755  parser->handleError(e.what());
756  }
757  return true;
758  }
759  return false;
760  }
761 
763  bool XMLReader::instance() {
764  string i_name;
765  xmlChar *i_id = NULL;
766 
767  if (begin(TAG_INSTANCE, false)) {
768  try {
769  string i_path = path.get(TAG_INSTANCE);
770 
771  /* Extract ID attribute.
772  */
773  i_id = xmlTextReaderGetAttribute(reader, (const xmlChar*) "id");
774  read();
775 
776  /* Get name of the instance.
777  */
778  PositionTracker::setPath(parser, i_path);
779  PositionTracker::increment(parser, 1);
780 
781  i_name = name(true);
782 
783  /* Remember the mapping from id to name
784  */
785  names[i_id] = i_name;
786 
787  /* Any error messages generated by the
788  * procInstanceLine call must be attributed to the
789  * instance line element. To do this, we add a dummy
790  * position of length 1.
791  */
792  PositionTracker::setPath(parser, i_path);
793  PositionTracker::increment(parser, 1);
794  /* Push instance to parser builder.
795  */
796  parser->procInstanceLine();
797  parse((xmlChar*) i_name.c_str(), S_INSTANCELINE);
798 
799  } catch (TypeException &e) {
800  parser->handleError(e.what());
801  }
802  return true;
803  }
804  return false;
805  }
806 
808  bool XMLReader::yloccoord() {
809  if (begin(TAG_YLOCCOORD, false)) {
810  read(); //used only for the GUI
811  return true;
812  }
813  return false;
814  }
815 
816  string XMLReader::temperature() {
817  if (begin(TAG_TEMPERATURE, false)) {
818  read();
819  /* Get the temperature of the condition
820  */
821  return readText();
822  }
823  throw std::runtime_error("Missing temperature");
824  }
825 
826  bool XMLReader::prechart() {
827  if (begin(TAG_PRECHART, false)) {
828  try {
829  string p_path = path.get(TAG_PRECHART);
830 
831  /* Get the bottom location number
832  */
833  read();
834  bottomPrechart = lscLocation();
835  if (strcasecmp(currentType.c_str(), "existential") == 0) {
836  PositionTracker::setPath(parser, p_path);
837  PositionTracker::increment(parser, 1);
838  parser->handleError("$Existential_charts_must_not_have_prechart");
839  }
840  parser->hasPrechart(true);
841  } catch (TypeException &e) {
842  parser->handleError(e.what());
843  }
844  return true;
845  } else {
846  bottomPrechart = -1;
847  parser->hasPrechart(false);
848  }
849  return false;
850  }
851 
852  bool XMLReader::message() {
853  if (begin(TAG_MESSAGE)) {
854  string from;
855  string to;
856  int location;
857 
858  /* Add dummy position mapping to the message element.
859  */
860  try {
861  string m_path = path.get(TAG_MESSAGE);
862  read();
863  from = source();
864  to = target();
865  location = lscLocation();
866  bool pch = (location < bottomPrechart);
867  PositionTracker::setPath(parser, m_path);
868  PositionTracker::increment(parser, 1);
869  parser->procMessage(from.c_str(), to.c_str(), location, pch);
870  PositionTracker::setPath(parser, m_path);
871  PositionTracker::increment(parser, 1);
872  label(true, "message");
873  } catch (TypeException &e) {
874  parser->handleError(e.what());
875  }
876 
877  return true;
878  }
879  return false;
880  }
881 
882  bool XMLReader::condition() {
883  if (begin(TAG_CONDITION)) {
884  vector<char*> instance_anchors;
885  int location;
886  string temp;
887  bool pch, hot;
888 
889  try {
890  string c_path = path.get(TAG_CONDITION);
891  read();
892 
893  instance_anchors = anchors();
894  location = lscLocation();
895  pch = (location < bottomPrechart);
896 
897  PositionTracker::setPath(parser, c_path);
898  PositionTracker::increment(parser, 1);
899  temp = temperature();
900  hot = (temp == "hot");
901  parser->procCondition(instance_anchors, location, pch, hot);
902 
903  label(true, "condition");
904  } catch (TypeException &e) {
905  parser->handleError(e.what());
906  }
907 
908  return true;
909  }
910  return false;
911  }
912 
913  bool XMLReader::update() {
914  if (begin(TAG_UPDATE)) {
915  string instance_anchor;
916  int location;
917  bool pch;
918 
919  try {
920  string u_path = path.get(TAG_UPDATE);
921  //location = atoi((char*)xmlTextReaderGetAttribute(reader, (const xmlChar*)"y"));
922  //pch = (location < bottomPrechart);
923  read();
924 
925  instance_anchor = anchor();
926  location = lscLocation();
927  pch = (location < bottomPrechart);
928 
929  PositionTracker::setPath(parser, u_path);
930  PositionTracker::increment(parser, 1);
931  parser->procLscUpdate(instance_anchor.c_str(), location, pch);
932  label(true, "update");
933  } catch (TypeException &e) {
934  parser->handleError(e.what());
935  }
936 
937  return true;
938  }
939  return false;
940  }
941 
943  bool XMLReader::branchpoint() {
944  string b_name;
945  xmlChar *b_id = NULL;
946 
947  if (begin(TAG_BRANCHPOINT, false)) {
948  try {
949  string b_path = path.get(TAG_BRANCHPOINT);
950 
951 
952  /* Extract ID attribute.
953  */
954  b_id = xmlTextReaderGetAttribute(reader, (const xmlChar*) "id");
955 
956  read();
957 
958  /* We assign an internal name based on the ID of the
959  * branchpoint.
960  */
961  b_name = string("_") + (char*) b_id;
962 
963  /* Remember the mapping from id to name
964  */
965  names[b_id] = b_name;
966 
967 
968  //FIXME: probably not necessary
969  /* Any error messages generated by any of the
970  * procStateXXX calls must be attributed to the state
971  * element. To do this, we add a dummy position of
972  * length 1.
973  */
974  PositionTracker::setPath(parser, b_path);
975  PositionTracker::increment(parser, 1);
976 
977  /* Push branchpoint to parser builder.
978  */
979  parser->procBranchpoint(b_name.c_str());
980  } catch (TypeException &e) {
981  parser->handleError(e.what());
982  }
983  return true;
984  }
985  return false;
986  }
987 
991  bool XMLReader::init() {
992  if (begin(TAG_INIT, false)) {
993  /* Get reference attribute.
994  */
995  xmlChar *ref = xmlTextReaderGetAttribute(reader, (const xmlChar*) "ref");
996 
997  /* Find location name for the reference.
998  */
999  if (ref) {
1000  string name = getName(ref);
1001  try {
1002  parser->procStateInit(name.c_str());
1003  } catch (TypeException& te) {
1004  parser->handleError(te.what());
1005  }
1006  } else {
1007  parser->handleError("$Missing_initial_location");
1008  }
1009  xmlFree(ref);
1010  read();
1011  return true;
1012  } else {
1013  parser->handleError("$Missing_initial_location");
1014  }
1015  return false;
1016  }
1017 
1018  string XMLReader::reference(string attributeName) {
1019  string name;
1020  xmlChar *id = xmlTextReaderGetAttribute(reader, (const xmlChar*) attributeName.c_str());
1021  name = getName(id);
1022  xmlFree(id);
1023  read();
1024  return name;
1025  }
1026 
1028  string XMLReader::source() {
1029  if (begin(TAG_SOURCE, false))
1030  return reference("ref");
1031  throw std::runtime_error("Missing source element");
1032  }
1033 
1035  string XMLReader::target() {
1036  if (begin(TAG_TARGET, false))
1037  return reference("ref");
1038  throw std::runtime_error("Missing target element");
1039  }
1040 
1042  string XMLReader::anchor() {
1043  if (begin(TAG_ANCHOR, false))
1044  return reference("instanceid");
1045  throw std::runtime_error("Missing anchor element");
1046  }
1047 
1049  vector<char*> XMLReader::anchors() {
1050  vector<char*> names;
1051  while (begin(TAG_ANCHOR, false)) {
1052  string name = reference("instanceid");
1053  names.push_back(const_cast<char*> (name.c_str()));
1054  }
1055 
1056  if (names.size() == 0)
1057  throw std::runtime_error("Missing anchor element");
1058  return names;
1059  }
1060 
1062  bool XMLReader::transition() {
1063  if (begin(TAG_TRANSITION)) {
1064  string from;
1065  string to;
1066  bool control = true;
1067  string actname;
1068 
1069  /* Add dummy position mapping to the transition element.
1070  */
1071  try {
1072  xmlChar *type =
1073  xmlTextReaderGetAttribute(reader, (const xmlChar*) "controllable");
1074  control = (type == NULL || !(strcmp((char*) type, "true")));
1075  xmlFree(type);
1076 
1077  xmlChar *id = xmlTextReaderGetAttribute(reader, (const xmlChar*) "action");
1078  if (id) {
1079  actname = (char *) id;
1080  } else {
1081  actname = "SKIP";
1082  }
1083  xmlFree(id);
1084 
1085  read();
1086  from = source();
1087  to = target();
1088 
1089  parser->procEdgeBegin(from.c_str(), to.c_str(), control, actname.c_str());
1090  while (label());
1091  while (begin(TAG_NAIL)) {
1092  read();
1093  }
1094  parser->procEdgeEnd(from.c_str(), to.c_str());
1095  } catch (TypeException &e) {
1096  parser->handleError(e.what());
1097  }
1098 
1099  return true;
1100  }
1101  return false;
1102  }
1103 
1108  int XMLReader::parameter() {
1109  int count = 0;
1110  if (begin(TAG_PARAMETER)) {
1111  read();
1112  if (getNodeType() == XML_READER_TYPE_TEXT) {
1113  count = parse(xmlTextReaderConstValue(reader), S_PARAMETERS);
1114  }
1115  }
1116  return count;
1117  }
1118 
1120  bool XMLReader::templ() {
1121  string t_name;
1122 
1123  if (begin(TAG_TEMPLATE)) {
1124  string t_path = path.get(TAG_TEMPLATE);
1125  read();
1126  try {
1127  /* Get the name and the parameters of the template.
1128  */
1129  t_name = name();
1130  parameter();
1131 
1132  /* Push template start to parser builder. This might
1133  * throw a TypeException.
1134  */
1135  PositionTracker::setPath(parser, t_path);
1136  PositionTracker::increment(parser, 1);
1137  parser->procBegin(t_name.c_str());
1138 
1139  /* Parse declarations, locations, branchpoints,
1140  * the init tag and the transitions of the template.
1141  */
1142  declaration();
1143  while (location());
1144  while (branchpoint());
1145  PositionTracker::setPath(parser, t_path);
1146  PositionTracker::increment(parser, 1);
1147  init();
1148  while (transition());
1149 
1150  /* Push template end to parser builder.
1151  */
1152  PositionTracker::setPath(parser, t_path);
1153  PositionTracker::increment(parser, 1);
1154  parser->procEnd();
1155  } catch (TypeException &e) {
1156  parser->handleError(e.what());
1157  }
1158 
1159  return true;
1160  }
1161  return false;
1162  }
1163 
1165  bool XMLReader::lscTempl() {
1166  string t_name;
1167 
1168  if (begin(TAG_LSC)) {
1169  string t_path = path.get(TAG_LSC);
1170  read();
1171  try {
1172  /* Get the name and the parameters of the template.
1173  */
1174  t_name = name();
1175  parser->lscTemplateNames.push_back(t_name);
1176  parameter();
1177 
1178  currentType = type();
1179 
1180  currentMode = mode();
1181 
1182  /* Push template start to parser builder. This might
1183  * throw a TypeException.
1184  */
1185  PositionTracker::setPath(parser, t_path);
1186  PositionTracker::increment(parser, 1);
1187  parser->procBegin(t_name.c_str(), false, currentType, currentMode);
1188 
1189  /* Parse declarations, locations, instances, prechart
1190  * messages, conditions and updates
1191  */
1192  declaration();
1193 
1194  while (yloccoord());
1195 
1196  while (instance());
1197 
1198  prechart();
1199 
1200  while (message());
1201 
1202  while (condition());
1203 
1204  while (update());
1205 
1206  /* Push template end to parser builder.
1207  */
1208  PositionTracker::setPath(parser, t_path);
1209  PositionTracker::increment(parser, 1);
1210  parser->procEnd();
1211  } catch (TypeException &e) {
1212  parser->handleError(e.what());
1213  }
1214  return true;
1215  }
1216  return false;
1217  }
1218 
1220  bool XMLReader::instantiation() {
1221  if (begin(TAG_INSTANTIATION, false)) {
1222  const xmlChar *text = (const xmlChar*) "";
1223  read();
1224  if (getNodeType() == XML_READER_TYPE_TEXT) {
1225  text = xmlTextReaderConstValue(reader);
1226  }
1227  parse(text, S_INST);
1228  return true;
1229  }
1230  return false;
1231  }
1232 
1234  void XMLReader::system() {
1235  if (begin(TAG_SYSTEM, false)) {
1236  const xmlChar *text = (const xmlChar*) "";
1237  read();
1238  if (getNodeType() == XML_READER_TYPE_TEXT) {
1239  text = xmlTextReaderConstValue(reader);
1240  }
1241  parse(text, S_SYSTEM);
1242  while (!end(TAG_SYSTEM)) read();
1243  } else {
1244  string s = (nta) ? path.get(TAG_NTA) : path.get(TAG_PROJECT);
1245  PositionTracker::setPath(parser, s);
1246  PositionTracker::increment(parser, 1);
1247  parser->handleError("$Missing_system_tag");
1248  }
1249  }
1250 
1252  bool XMLReader::queries() {
1253  if (begin(TAG_QUERIES, false)) {
1254  read();
1255  while (!end(TAG_QUERIES) && query()) read();
1256  return true;
1257  } else {
1258  return false;
1259  }
1260  }
1261  bool XMLReader::query() {
1262  if (begin(TAG_QUERY, false)) {
1263  read();
1264  parser->queryBegin();
1265  formula();
1266  comment();
1267  parser->queryEnd();
1268  while (!end(TAG_QUERY)) read();
1269  return true;
1270  }
1271  return false;
1272  }
1273  bool XMLReader::formula(){
1274  if (begin(TAG_FORMULA, false)){
1275  read();
1276  string xpath = path.get(TAG_FORMULA);
1277  parser->queryFormula((const char*)xmlTextReaderConstValue(reader),
1278  xpath.c_str());
1279  return true;
1280  }
1281  return false;
1282  }
1283  bool XMLReader::comment(){
1284  if (begin(TAG_COMMENT, false)){
1285  read();
1286  parser->queryComment((const char*)xmlTextReaderConstValue(reader));
1287  return true;
1288  }
1289  return false;
1290  }
1291 
1293  void XMLReader::project() {
1294  if (!begin(TAG_NTA) && !begin(TAG_PROJECT)) {
1295 #ifdef ENABLE_SBML
1296  if (begin(TAG_SBML)) {
1297  // launch SBML converter
1298  UTAP::SBMLConverter * sbmlc = new SBMLConverter(reader);
1299  sbmlc->convertIntoXML();
1300  } else {
1301 #endif
1302  throw std::runtime_error("Missing nta or project element");
1303 #ifdef ENABLE_SBML
1304  }
1305 #endif
1306  } else {
1307  nta = (begin(TAG_NTA)) ? true : false;
1308  read();
1309  declaration();
1310  while (templ());
1311  while (lscTempl());
1312  instantiation();
1313  system();
1314  read(); // look ahead one tag
1315  if ((nta && !end(TAG_NTA)) || (!nta && !end(TAG_PROJECT)))
1316  queries();
1317  parser->done();
1318  }
1319  }
1320 
1321 }
1322 
1323 using namespace UTAP;
1324 
1325 int32_t parseXMLFile(const char *filename, ParserBuilder *pb, bool newxta)
1326 {
1327  xmlTextReaderPtr reader = xmlReaderForFile(filename, "",
1328  XML_PARSE_NOCDATA | XML_PARSE_NOBLANKS | XML_PARSE_HUGE | XML_PARSE_RECOVER);
1329  if (reader == NULL) {
1330  return -1;
1331  }
1332  XMLReader(reader, pb, newxta).project();
1333  return 0;
1334 }
1335 
1336 int32_t parseXMLBuffer(const char *buffer, ParserBuilder *pb, bool newxta) {
1337  size_t length = strlen(buffer);
1338  xmlTextReaderPtr reader = xmlReaderForMemory(buffer, length, "", "",
1339  XML_PARSE_NOCDATA | XML_PARSE_HUGE | XML_PARSE_RECOVER);
1340  if (reader == NULL) {
1341  return -1;
1342  }
1343  XMLReader(reader, pb, newxta).project();
1344  return 0;
1345 }
1346 
1353 string getXMLElement(xmlDocPtr docPtr, const string &path) {
1354 
1355  string res;
1356 
1357  // Get the context
1358  xmlXPathContextPtr context = xmlXPathNewContext(docPtr);
1359  if(context == NULL) {
1360  xmlFreeDoc(docPtr);
1361  return res;
1362  }
1363 
1364  xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*)path.c_str(), context);
1365  if(result!=NULL) {
1366  xmlNodeSetPtr nodeset = result->nodesetval;
1367  if(!xmlXPathNodeSetIsEmpty(nodeset) && nodeset->nodeNr>0) {
1368  //The first point of the xml node
1369  xmlNodePtr node = nodeset->nodeTab[0];
1370  xmlChar *s = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
1371  if(s) {
1372  res = (char*)s;
1373  }
1374  xmlFree(s);
1375  }
1376  xmlXPathFreeObject(result);
1377  }
1378 
1379  xmlXPathFreeContext(context);
1380 
1381  return res;
1382 }
1383 
1390 string getXMLElement(const char *xmlBuffer, const string &path) {
1391  xmlDocPtr docPtr = xmlParseMemory(xmlBuffer, strlen(xmlBuffer));
1392  if(docPtr) {
1393  string res = getXMLElement(docPtr,path);
1394  xmlFreeDoc(docPtr);
1395  return res;
1396  }
1397  else {
1398  return "";
1399  }
1400 }
static void setPath(ParserBuilder *builder, std::string s)
Sets the current path to s, offset to 0 and line to 1.
Definition: lexer.cc:819
virtual void procMessage(const char *from, const char *to, const int loc, const bool pch)=0
virtual void procStateUrgent(const char *name)=0
string getXMLElement(xmlDocPtr docPtr, const string &path)
Get the contents of the XML element with the specified path.
Definition: xmlreader.cpp:1353
virtual void procLscUpdate(const char *anchor, const int loc, const bool pch)=0
virtual void procBranchpoint(const char *name)=0
virtual void procCondition(const std::vector< char *> anchors, const int loc, const bool pch, const bool hot)=0
virtual void procStateInit(const char *name)=0
virtual void procStateCommit(const char *name)=0
The ParserBuilder interface is used by the parser to output the parsed system.
Definition: builder.h:80
xta_part_t
Type for specifying which XTA part to parse (syntax switch)
Definition: common.h:273
static syntax_t syntax
Definition: parser.cc:106
int32_t parseXMLFile(const char *filename, ParserBuilder *pb, bool newxta)
Parse the file with the given name assuming it is in the XML format, reporting the system to the give...
Definition: xmlreader.cpp:1325
virtual void queryBegin()=0
Verification queries.
virtual void procBegin(const char *name, const bool isTA=true, const std::string type="", const std::string mode="")=0
#define comment
Definition: lexer.cc:856
static bool isempty(string str)
Returns TRUE if string is zero length or contains only white spaces otherwise FALSE.
Definition: xmlreader.cpp:80
virtual void queryFormula(const char *formula, const char *location)=0
virtual void queryEnd()=0
static bool isAlpha(unsigned char c)
Definition: xmlreader.cpp:91
int32_t parseXMLBuffer(const char *buffer, ParserBuilder *pb, bool newxta)
Parse a buffer in the XML format, reporting the system to the given implementation of the the ParserB...
Definition: xmlreader.cpp:1336
static string symbol(const char *str)
Extracts the alpha-numerical symbol used for variable/type identifiers.
Definition: xmlreader.cpp:107
static bool isIdChr(unsigned char c)
Definition: xmlreader.cpp:95
virtual void procEnd()=0
tag_t
Enumeration type for tags.
Definition: xmlreader.cpp:57
virtual void handleError(const std::string &)=0
Exception indicating a type error.
Definition: builder.h:39
virtual void queryComment(const char *comment)=0
bool read(istream &file, string &str)
Definition: tracer.cpp:165
virtual void procEdgeEnd(const char *from, const char *to)=0
static int32_t parseXTA(ParserBuilder *aParserBuilder, bool newxta, xta_part_t part, std::string xpath)
Definition: parser.cc:8906
std::vector< std::string > lscTemplateNames
Definition: builder.h:94
virtual void done()=0
virtual void procInstanceLine()=0
virtual void hasPrechart(const bool pch)=0
Definition: lexer.cc:817
bool isKeyword(const char *id, uint32_t syntax)
Definition: keywords.cc:453
static int increment(ParserBuilder *builder, int n)
Sets the position of builder to [position, position + n) and increments position and offset by n...
Definition: lexer.cc:834
virtual void procEdgeBegin(const char *from, const char *to, const bool control, const char *actname="")=0
virtual void procState(const char *name, bool hasInvariant, bool hasER)=0