1
/* VerifyPN - TAPAAL Petri Net Engine
2
* Copyright (C) 2014 Jiri Srba <srba.jiri@gmail.com>
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation, either version 3 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18
#include "QueryXMLParser.h"
27
using namespace XMLSP;
30
QueryXMLParser::QueryXMLParser(const PNMLParser::TransitionEnablednessMap &transitionEnabledness) {
31
_transitionEnabledness = transitionEnabledness;
34
// QueryXMLParser::~QueryXMLParser() { };
37
bool QueryXMLParser::parse(const std::string& xml){
39
DOMElement* root = DOMElement::loadXML(xml);
42
parsingOK = parsePropertySet(root);
53
bool QueryXMLParser::parsePropertySet(DOMElement* element){
54
if (element->getElementName()!="property-set") {
55
fprintf(stderr,"ERROR missing property-set\n");
56
return false; // missing property-set element
58
DOMElements elements = element->getChilds();
59
DOMElements::iterator it;
60
for(it = elements.begin(); it != elements.end(); it++){
61
if (!parseProperty(*it)) {
68
bool QueryXMLParser::parseProperty(DOMElement* element){
69
if (element->getElementName()!="property") {
70
fprintf(stderr,"ERROR missing property\n");
71
return false; // unexpected element (only property is allowed)
75
bool negateResult=false;
76
bool isPlaceBound=false;
77
string placeNameForBound;
80
DOMElements elements = element->getChilds();
81
DOMElements::iterator it;
82
DOMElements::iterator formulaPtr;
83
for(it = elements.begin(); it != elements.end(); it++){
84
if ((*it)->getElementName()=="id") {
85
id = (*it)->getCData();
86
} else if ((*it)->getElementName()=="formula") {
88
} else if ((*it)->getElementName()=="tags") {
89
tagsOK=parseTags(*it);
94
fprintf(stderr,"ERROR a query with empty id\n");
100
if (tagsOK && parseFormula(*formulaPtr, queryText, negateResult, isPlaceBound, placeNameForBound)) {
101
queryItem.queryText=queryText;
102
queryItem.negateResult=negateResult;
103
queryItem.isPlaceBound=isPlaceBound;
104
queryItem.placeNameForBound=placeNameForBound;
105
queryItem.parsingResult=QueryItem::PARSING_OK;
107
queryItem.queryText="";
108
queryItem.negateResult=false;
109
queryItem.isPlaceBound=false;
110
queryItem.placeNameForBound="";
111
queryItem.parsingResult=QueryItem::UNSUPPORTED_QUERY;
113
queries.push_back(queryItem);
117
bool QueryXMLParser::parseTags(DOMElement* element){
118
// we can accept only reachability query
119
DOMElements elements = element->getChilds();
120
DOMElements::iterator it;
121
for(it = elements.begin(); it != elements.end(); it++){
122
if ((*it)->getElementName()=="is-reachability" && (*it)->getCData()!="true") {
129
bool QueryXMLParser::parseFormula(DOMElement* element, string &queryText, bool &negateResult, bool &isPlaceBound, string &placeNameForBound){
131
Describe here how to parse
132
* INV phi = AG phi = not EF not phi
133
* IMPOS phi = AG not phi = not EF phi
135
* NEG INV phi = not AG phi = EF not phi
136
* NEG IMPOS phi = not AG not phi = EF phi
137
* NEG POS phi = not EF phi
139
DOMElements elements = element->getChilds();
140
if (elements.size() != 1) {
143
DOMElements::iterator booleanFormula = elements.begin();
144
string elementName = (*booleanFormula)->getElementName();
145
if (elementName=="invariant") {
148
} else if (elementName=="impossibility") {
151
} else if (elementName=="possibility") {
154
} else if (elementName=="negation") {
155
DOMElements children = (*elements.begin())->getChilds();
156
if (children.size() !=1) {
159
booleanFormula = children.begin();
160
string negElementName = (*booleanFormula)->getElementName();
161
if (negElementName=="invariant") {
162
queryText="EF not( ";
164
} else if (negElementName=="impossibility") {
167
} else if (negElementName=="possibility") {
173
} else if (elementName == "place-bound") {
175
DOMElements children = (*booleanFormula)->getChilds();
176
if (children.size() != 1) {
177
return false; // we support only place-bound for one place
179
if (children[0]->getElementName() != "place") {
182
placeNameForBound = parsePlace(children[0]);
183
if (placeNameForBound=="") {
184
return false; // invalid place name
186
queryText += "\""+placeNameForBound+"\""+" < 0";
187
negateResult = false;
193
DOMElements nextElements = (*booleanFormula)->getChilds();
194
if (nextElements.size() !=1 || !parseBooleanFormula(nextElements[0] , queryText)) {
199
placeNameForBound = "";
203
bool QueryXMLParser::parseBooleanFormula(DOMElement* element, string &queryText){
204
string elementName = element->getElementName();
205
if (elementName == "deadlock") {
206
queryText+="deadlock";
208
} else if (elementName == "true") {
211
} else if (elementName == "false") {
214
} else if (elementName == "negation") {
215
DOMElements children = element->getChilds();
217
if (children.size()==1 && parseBooleanFormula(children[0], queryText)) {
223
} else if (elementName == "conjunction") {
224
DOMElements children = element->getChilds();
225
if (children.size()<2) {
228
if (!(parseBooleanFormula((children[0]), queryText))) {
231
DOMElements::iterator it;
232
for(it = (children.begin())+1; it != children.end(); it++) {
234
if (!(parseBooleanFormula(*it, queryText))) {
239
} else if (elementName == "disjunction") {
240
DOMElements children = element->getChilds();
241
if (children.size()<2) {
244
if (!(parseBooleanFormula(*children.begin(), queryText))) {
247
DOMElements::iterator it;
248
for(it = children.begin()+1; it != children.end(); it++) {
250
if (!(parseBooleanFormula(*it, queryText))) {
255
} else if (elementName == "exclusive-disjunction") {
256
DOMElements children = element->getChilds();
257
if (children.size()!=2) { // we support only two subformulae here
262
if (!(parseBooleanFormula(*(children.begin()), subformula1))) {
265
if (!(parseBooleanFormula(*(children.begin()+1), subformula2))) {
268
queryText+= "(("+subformula1+" and not("+subformula2+")) or (not("+subformula1+") and "+subformula2+"))";
270
} else if (elementName == "implication") {
271
DOMElements children = element->getChilds();
272
if (children.size()!=2) { // implication has only two subformulae
277
if (!(parseBooleanFormula(*(children.begin()), subformula1))) {
280
if (!(parseBooleanFormula(*(children.begin()+1), subformula2))) {
283
queryText+= "not("+subformula1+") or ( "+subformula2+" )";
285
} else if (elementName == "equivalence") {
286
DOMElements children = element->getChilds();
287
if (children.size()!=2) { // we support only two subformulae here
292
if (!(parseBooleanFormula(*(children.begin()), subformula1))) {
295
if (!(parseBooleanFormula(*(children.begin()+1), subformula2))) {
298
queryText+= "(("+subformula1+" and "+subformula2+") or (not("+subformula1+") and not("+subformula2+")))";
300
} else if ( elementName == "integer-eq" ||
301
elementName == "integer-ne" ||
302
elementName == "integer-lt" ||
303
elementName == "integer-le" ||
304
elementName == "integer-gt" ||
305
elementName == "integer-ge") {
306
DOMElements children = element->getChilds();
307
if (children.size()!=2) { // exactly two integer subformulae are required
312
if (!(parseIntegerExpression(children[0], subformula1))) {
315
if (!(parseIntegerExpression(children[1], subformula2))) {
319
if ( elementName == "integer-eq") mathoperator=" == ";
320
else if ( elementName == "integer-ne") mathoperator=" != ";
321
else if ( elementName == "integer-lt") mathoperator=" < ";
322
else if ( elementName == "integer-le") mathoperator=" <= ";
323
else if ( elementName == "integer-gt") mathoperator=" > ";
324
else if ( elementName == "integer-ge") mathoperator=" >= ";
326
queryText+="("+subformula1+mathoperator+subformula2+")";
328
} else if (elementName == "is-fireable") {
329
DOMElements children = element->getChilds();
330
if (children.size() == 0) {
333
if (children.size() > 1) {
336
for (int i = 0; i < children.size(); i++) {
337
if (children[i]->getElementName() != "transition") {
343
string transitionName = children[i]->getCData();
344
if(_transitionEnabledness.find(transitionName) == _transitionEnabledness.end()){
346
"XML Query Parsing error: Transition id=\"%s\" was not found!\n",
347
transitionName.c_str());
350
queryText += _transitionEnabledness[transitionName];
352
if (children.size() > 1) {
360
bool QueryXMLParser::parseIntegerExpression(DOMElement* element, string &queryText){
361
string elementName = element->getElementName();
362
if (elementName == "integer-constant") {
364
if(sscanf((element->getCData()).c_str(), "%d", &i) == EOF ) {
365
return false; // expected integer at this place
367
stringstream ss;//create a stringstream
368
ss << i;//add number to the stream
371
} else if (elementName == "tokens-count") {
372
DOMElements children = element->getChilds();
373
if (children.size()==0) {
376
if (children.size()>1) {
379
for (int i = 0; i < children.size(); i++) {
380
if (children[i]->getElementName() != "place") {
386
string placeName = parsePlace(children[i]);
387
if (placeName == "") {
388
return false; // invalid place name
390
queryText+="\""+placeName+"\"";
392
if (children.size()>1) {
396
} else if ( elementName == "integer-sum" ||
397
elementName == "integer-product" ) {
398
DOMElements children = element->getChilds();
399
if (children.size() < 2) { // at least two integer subexpression are required
403
if ( elementName == "integer-sum") mathoperator = " + ";
404
else if (elementName == "integer-product") mathoperator = " * ";
406
for (int i = 0; i < children.size(); i++) {
408
queryText+= mathoperator;
410
if (!parseIntegerExpression(children[i], queryText)) {
416
} else if (elementName == "integer-difference" ) {
417
DOMElements children = element->getChilds();
418
if (children.size() != 2) { // at least two integer subexpression are required
422
if (!parseIntegerExpression(children[0], queryText)) {
426
if (!parseIntegerExpression(children[1], queryText)) {
435
string QueryXMLParser::parsePlace(XMLSP::DOMElement* element) {
436
if (element->getElementName() != "place") {
437
return ""; // missing place tag
439
string placeName = element->getCData();
440
placeName.erase(std::remove_if(placeName.begin(), placeName.end(), ::isspace), placeName.end());
445
void QueryXMLParser::printQueries() {
446
QueryXMLParser::QueriesIterator it;
447
for(it = queries.begin(); it != queries.end(); it++){
448
cout << it->id << ": " << (it->isPlaceBound ? "\tplace-bound " : "");
449
if (it->parsingResult == QueryItem::UNSUPPORTED_QUERY) {
450
cout << "\t---------- unsupported query ----------" << endl;
452
cout << "\t" << (it->negateResult ? "not " : "") << it->queryText << endl;