~tapaal-ltl/verifypn/scc-optimise

« back to all changes in this revision

Viewing changes to src/PetriParse/QueryXMLParser.cpp

  • Committer: srba.jiri at gmail
  • Date: 2020-09-11 14:23:39 UTC
  • mfrom: (213.1.151 interval_tar)
  • Revision ID: srba.jiri@gmail.com-20200911142339-bq9328s1gppw24uj
merged in lp:~verifypn-maintainers/verifypn/interval_tar doing 
- Implements TAR w/o z3, but using a simple integer inference engine for Hoare logic.
 - Replaces LP-Solve with GLPK, reduces computation-time and memory overhead
 - Implements new global properties, translated into CTL formulae.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* VerifyPN - TAPAAL Petri Net Engine
 
2
 * Copyright (C) 2014 Jiri Srba <srba.jiri@gmail.com>,
 
3
 *                    Peter Gjøl Jensen <root@petergjoel.dk>
 
4
 *
 
5
 * This program is free software: you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation, either version 3 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include "PetriParse/QueryXMLParser.h"
 
20
#include "PetriEngine/PQL/Expressions.h"
 
21
 
 
22
#include <string>
 
23
#include <cstdio>
 
24
#include <cstdlib>
 
25
#include <iostream>
 
26
#include <algorithm>
 
27
 
 
28
using namespace std;
 
29
 
 
30
int getChildCount(rapidxml::xml_node<> *n)
 
31
{
 
32
  int c = 0;
 
33
  for (rapidxml::xml_node<> *child = n->first_node(); child != nullptr; child = child->next_sibling())
 
34
  {
 
35
    c++;
 
36
  } 
 
37
  return c;
 
38
 
39
 
 
40
QueryXMLParser::QueryXMLParser() = default;
 
41
 
 
42
QueryXMLParser::~QueryXMLParser() = default;
 
43
 
 
44
bool QueryXMLParser::parse(std::ifstream& xml, const std::set<size_t>& parse_only) {
 
45
    //Parse the xml
 
46
    rapidxml::xml_document<> doc;
 
47
    vector<char> buffer((istreambuf_iterator<char>(xml)), istreambuf_iterator<char>());
 
48
    buffer.push_back('\0');
 
49
    doc.parse<0>(&buffer[0]);
 
50
    rapidxml::xml_node<>*  root = doc.first_node();
 
51
    bool parsingOK;
 
52
    if (root) {
 
53
        parsingOK = parsePropertySet(root, parse_only);
 
54
    } else {
 
55
        parsingOK = false;
 
56
    }
 
57
 
 
58
    //Release DOM tree
 
59
    return parsingOK;
 
60
}
 
61
 
 
62
bool QueryXMLParser::parsePropertySet(rapidxml::xml_node<>*  element, const std::set<size_t>& parse_only) {
 
63
    if (strcmp(element->name(), "property-set") != 0) {
 
64
        fprintf(stderr, "ERROR missing property-set\n");
 
65
        return false; // missing property-set element
 
66
    }
 
67
    
 
68
    size_t i = 0;
 
69
    for (auto it = element->first_node(); it; it = it->next_sibling()) {
 
70
        if(parse_only.empty() || parse_only.count(i) > 0)
 
71
        {
 
72
            if (!parseProperty(it)) {
 
73
                return false;
 
74
            }
 
75
        }
 
76
        else
 
77
        {
 
78
            QueryItem queryItem;
 
79
            queryItem.query = nullptr;
 
80
            queryItem.parsingResult = QueryItem::PARSING_OK;
 
81
            queries.push_back(queryItem);
 
82
        }
 
83
        ++i;
 
84
    }
 
85
    return true;
 
86
}
 
87
 
 
88
bool QueryXMLParser::parseProperty(rapidxml::xml_node<>*  element) {
 
89
    if (strcmp(element->name(), "property") != 0) {
 
90
        fprintf(stderr, "ERROR missing property\n");
 
91
        return false; // unexpected element (only property is allowed)
 
92
    }
 
93
    string id;
 
94
    bool tagsOK = true;
 
95
    rapidxml::xml_node<>* formulaPtr = nullptr;
 
96
    for (auto it = element->first_node(); it; it = it->next_sibling()) {
 
97
        if (strcmp(it->name(), "id") == 0) {
 
98
            id = it->value();
 
99
        } else if (strcmp(it->name(), "formula") == 0) {
 
100
            formulaPtr = it;
 
101
        } else if (strcmp(it->name(), "tags") == 0) {
 
102
            tagsOK = parseTags(it);
 
103
        }
 
104
    }
 
105
 
 
106
    if (id.empty()) {
 
107
        fprintf(stderr, "ERROR a query with empty id\n");
 
108
        return false;
 
109
    }
 
110
 
 
111
    QueryItem queryItem;
 
112
    queryItem.id = id;
 
113
    if(tagsOK)
 
114
    {
 
115
        queryItem.query = parseFormula(formulaPtr);
 
116
        assert(queryItem.query);
 
117
        queryItem.parsingResult = QueryItem::PARSING_OK;
 
118
    } else {
 
119
        queryItem.query = nullptr;
 
120
        queryItem.parsingResult = QueryItem::UNSUPPORTED_QUERY;
 
121
    }
 
122
    queries.push_back(queryItem);
 
123
    return true;
 
124
}
 
125
 
 
126
bool QueryXMLParser::parseTags(rapidxml::xml_node<>*  element) {
 
127
    // we can accept only reachability query
 
128
    for (auto it = element->first_node(); it; it = it->next_sibling()) {
 
129
        if (strcmp(it->name(), "is-reachability") == 0 && strcmp(it->value(), "true") == 0) {
 
130
            return false;
 
131
        }
 
132
    }
 
133
    return true;
 
134
}
 
135
 
 
136
void QueryXMLParser::fatal_error(const std::string &token) {
 
137
    std::cerr << "An error occurred while parsing the query." << std::endl;
 
138
    std::cerr << token << std::endl;
 
139
    assert(false);
 
140
    exit(ErrorCode);
 
141
}
 
142
 
 
143
Condition_ptr QueryXMLParser::parseFormula(rapidxml::xml_node<>*  element) {
 
144
    if (getChildCount(element) != 1) 
 
145
    {
 
146
        assert(false);
 
147
        return nullptr;    
 
148
    }
 
149
    auto child = element->first_node();
 
150
    string childName = child->name();
 
151
    Condition_ptr cond = nullptr;
 
152
    
 
153
    // Formula is either CTL/Reachability, UpperBounds or one of the global properties
 
154
    // - k-safe (contains integer bound) : for all p. it holds that AG p <= bound
 
155
    // - quasi-liveness : for all t. EF is-fireable(t)
 
156
    // - stable-marking : exists p. and x. s.t. AG p == x (i.e. the initial marking)
 
157
    // - liveness : for all t. AG EF is-fireable(t)
 
158
    // we unfold global properties here to avoid introducing special-cases in the AST.
 
159
    if (childName == "k-safe")
 
160
    {
 
161
        Expr_ptr bound = nullptr;
 
162
        for (auto it = child->first_node(); it ; it = it->next_sibling()) {
 
163
            if(bound != nullptr) fatal_error(childName);
 
164
            bound = parseIntegerExpression(child->first_node());
 
165
            if(bound == nullptr) fatal_error(childName);
 
166
        }
 
167
        if(bound == nullptr) fatal_error(childName);
 
168
        return std::make_shared<KSafeCondition>(bound);
 
169
    }
 
170
    else if(childName == "quasi-liveness")
 
171
    {
 
172
        return std::make_shared<QuasiLivenessCondition>();
 
173
    }
 
174
    else if(childName == "stable-marking")
 
175
    {
 
176
        return std::make_shared<StableMarkingCondition>();
 
177
    }
 
178
    else if(childName == "liveness")
 
179
    {
 
180
        return std::make_shared<LivenessCondition>();
 
181
    }
 
182
    else if (childName == "place-bound") {
 
183
        std::vector<std::string> places;
 
184
        for (auto it = child->first_node(); it ; it = it->next_sibling()) {
 
185
            if (strcmp(it->name(), "place") != 0) 
 
186
            {
 
187
                assert(false);
 
188
                return nullptr;
 
189
            }
 
190
            auto place = parsePlace(it);
 
191
            if (place.empty())
 
192
            {             
 
193
                assert(false);
 
194
                return nullptr; // invalid place name
 
195
            }
 
196
            places.push_back(place);
 
197
        }
 
198
        auto bnds = std::make_shared<UpperBoundsCondition>(places);
 
199
        return std::make_shared<EFCondition>(bnds);
 
200
    } else if ((cond = parseBooleanFormula(child)) != nullptr) {
 
201
        return cond;
 
202
    } else {
 
203
        assert(false);
 
204
        return nullptr;
 
205
    }
 
206
}
 
207
 
 
208
 
 
209
Condition_ptr QueryXMLParser::parseBooleanFormula(rapidxml::xml_node<>*  element) {
 
210
    /*
 
211
     Describe here how to parse
 
212
     * INV phi =  AG phi =  not EF not phi
 
213
     * IMPOS phi = AG not phi = not EF phi
 
214
     * POS phi = EF phi
 
215
     * NEG INV phi = not AG phi = EF not phi
 
216
     * NEG IMPOS phi = not AG not phi = EF phi
 
217
     * NEG POS phi = not EF phi
 
218
     */
 
219
    
 
220
    string elementName = element->name();
 
221
    Condition_ptr cond = nullptr, cond2 = nullptr;
 
222
    
 
223
    if (elementName == "invariant") {
 
224
        if ((cond = parseBooleanFormula(element->first_node())) != nullptr)
 
225
            return std::make_shared<NotCondition>(std::make_shared<EFCondition>(std::make_shared<NotCondition>(cond)));
 
226
    } else if (elementName == "impossibility") {
 
227
        if ((cond = parseBooleanFormula(element->first_node())) != nullptr)
 
228
            return std::make_shared<NotCondition>(std::make_shared<EFCondition>(cond));
 
229
    } else if (elementName == "possibility") {
 
230
        if ((cond = parseBooleanFormula(element->first_node())) != nullptr)
 
231
            return std::make_shared<EFCondition>(cond);
 
232
    } else if (elementName == "exists-path") {
 
233
        if (getChildCount(element) != 1) 
 
234
        {
 
235
            assert(false);
 
236
            return nullptr;
 
237
        }
 
238
        auto child = element->first_node();
 
239
        if (strcmp(child->name(), "next") == 0) {
 
240
            if (getChildCount(child) != 1) 
 
241
            {
 
242
                assert(false);
 
243
                return nullptr;
 
244
            }
 
245
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr)
 
246
                return std::make_shared<EXCondition>(cond);
 
247
        } else if (strcmp(child->name(), "globally") == 0) {
 
248
            if (getChildCount(child) != 1) 
 
249
            {
 
250
                assert(false);
 
251
                return nullptr;
 
252
            }
 
253
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr)
 
254
                return std::make_shared<EGCondition>(cond);
 
255
        } else if (strcmp(child->name(), "finally") == 0) {
 
256
            if (getChildCount(child) != 1) 
 
257
            {
 
258
                assert(false);
 
259
                return nullptr;
 
260
            }
 
261
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr)
 
262
                return std::make_shared<EFCondition>(cond);
 
263
        } else if (strcmp(child->name(), "until") == 0) {
 
264
            if (getChildCount(child) != 2) 
 
265
            {
 
266
                assert(false);
 
267
                return nullptr;
 
268
            }
 
269
            auto before = child->first_node();
 
270
            auto reach = before->next_sibling();
 
271
            if (getChildCount(before) != 1 || getChildCount(reach) != 1 ||
 
272
                    strcmp(before->name(), "before") != 0 || strcmp(reach->name(), "reach") != 0) 
 
273
                {
 
274
                    assert(false);
 
275
                    return nullptr;
 
276
                }
 
277
            if ((cond = parseBooleanFormula(before->first_node())) != nullptr) {
 
278
                if ((cond2 = parseBooleanFormula(reach->first_node())) != nullptr) {
 
279
                    return std::make_shared<EUCondition>(cond, cond2);
 
280
                }
 
281
            }
 
282
        }
 
283
    } else if (elementName == "all-paths") {
 
284
        if (getChildCount(element) != 1) 
 
285
        {
 
286
            assert(false);
 
287
            return nullptr;
 
288
        }
 
289
        auto child = element->first_node();
 
290
        if (strcmp(child->name(), "next") == 0) {
 
291
            if (getChildCount(child) != 1) 
 
292
            {
 
293
                assert(false);
 
294
                return nullptr;
 
295
            }
 
296
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr)
 
297
                return std::make_shared<AXCondition>(cond);
 
298
        } else if (strcmp(child->name(), "globally") == 0) {
 
299
            if (getChildCount(child) != 1) 
 
300
            {
 
301
                assert(false);
 
302
                return nullptr;
 
303
            }
 
304
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr)
 
305
                return std::make_shared<AGCondition>(cond);
 
306
        } else if (strcmp(child->name(), "finally") == 0) {
 
307
            if (getChildCount(child) != 1) 
 
308
            {
 
309
                assert(false);
 
310
                return nullptr;
 
311
            }
 
312
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr)
 
313
                return std::make_shared<AFCondition>(cond);
 
314
        } else if (strcmp(child->name(), "until") == 0) {
 
315
            if (getChildCount(child) != 2) 
 
316
            {
 
317
                assert(false);
 
318
                return nullptr;
 
319
            }
 
320
            auto before = child->first_node();
 
321
            auto reach = before->next_sibling();
 
322
            if (getChildCount(before) != 1 || getChildCount(reach) != 1 ||
 
323
                    strcmp(before->name(), "before") != 0 || strcmp(reach->name(), "reach") != 0)
 
324
            {
 
325
                assert(false);
 
326
                return nullptr;
 
327
            }
 
328
            if ((cond = parseBooleanFormula(before->first_node())) != nullptr){
 
329
                if ((cond2 = parseBooleanFormula(reach->first_node())) != nullptr) {
 
330
                    return std::make_shared<AUCondition>(cond, cond2);
 
331
                }
 
332
            }
 
333
        }
 
334
    } else if (elementName == "deadlock") {
 
335
        return std::make_shared<DeadlockCondition>();
 
336
    } else if (elementName == "true") {
 
337
        return BooleanCondition::TRUE_CONSTANT;
 
338
    } else if (elementName == "false") {
 
339
        return BooleanCondition::FALSE_CONSTANT;
 
340
    } else if (elementName == "negation") {
 
341
        if (getChildCount(element) != 1) 
 
342
        {
 
343
            assert(false);
 
344
            return nullptr;
 
345
        }
 
346
        auto child = element->first_node();
 
347
        if (strcmp(child->name(), "invariant") == 0) {
 
348
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr) {
 
349
                return std::make_shared<EFCondition>(std::make_shared<NotCondition>(cond));
 
350
            }
 
351
        } else if (strcmp(child->name(), "impossibility") == 0) {
 
352
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr) {
 
353
                return std::make_shared<EFCondition>(cond);
 
354
            }
 
355
        } else if (strcmp(child->name(), "possibility") == 0) {
 
356
            if ((cond = parseBooleanFormula(child->first_node())) != nullptr) {
 
357
                return std::make_shared<NotCondition>(std::make_shared<EFCondition>(cond));
 
358
            }
 
359
        } else {
 
360
            if ((cond = parseBooleanFormula(child)) != nullptr) {
 
361
                return std::make_shared<NotCondition>(cond);
 
362
            }
 
363
        }
 
364
    } else if (elementName == "conjunction") {
 
365
        auto children = element->first_node();
 
366
        if (getChildCount(element) < 2) 
 
367
        {
 
368
            assert(false);
 
369
            return nullptr;
 
370
        }
 
371
        auto it = children;
 
372
        cond = parseBooleanFormula(it);
 
373
        // skip a sibling
 
374
        for (it = it->next_sibling(); it; it = it->next_sibling()) {
 
375
            Condition_ptr child = parseBooleanFormula(it);
 
376
            if(child == nullptr || cond == nullptr) 
 
377
            {
 
378
                assert(false);
 
379
                return nullptr;
 
380
            }
 
381
            cond = std::make_shared<AndCondition>(cond, child);
 
382
        }
 
383
        return cond;
 
384
    } else if (elementName == "disjunction") {
 
385
        auto children = element->first_node();
 
386
        if (getChildCount(element) < 2) 
 
387
        {
 
388
            assert(false);
 
389
            return nullptr;
 
390
        }
 
391
        auto it = children;
 
392
        cond = parseBooleanFormula(it);
 
393
        // skip a sibling
 
394
        for (it = it->next_sibling(); it; it = it->next_sibling()) {
 
395
            Condition_ptr child = parseBooleanFormula(it);
 
396
            if(child == nullptr || cond == nullptr) 
 
397
            {
 
398
                assert(false);
 
399
                return nullptr;
 
400
            }
 
401
            cond = std::make_shared<OrCondition>(cond, child);
 
402
        }
 
403
        return cond;
 
404
    } else if (elementName == "exclusive-disjunction") {
 
405
        auto children = element->first_node();
 
406
        if (getChildCount(element) != 2) 
 
407
        {
 
408
            assert(false);
 
409
            return nullptr;
 
410
        }
 
411
        cond = parseBooleanFormula(children);
 
412
        cond2 = parseBooleanFormula(children->next_sibling());
 
413
        if (cond == nullptr || cond2 == nullptr)    
 
414
        {
 
415
            assert(false);
 
416
            return nullptr;
 
417
        }
 
418
        return std::make_shared<OrCondition>(
 
419
                std::make_shared<AndCondition>(cond, std::make_shared<NotCondition>(cond2)),
 
420
                std::make_shared<AndCondition>(std::make_shared<NotCondition>(cond), cond2));
 
421
    } else if (elementName == "implication") {
 
422
        auto children = element->first_node();
 
423
        if (getChildCount(element) != 2)             
 
424
        {
 
425
            assert(false);
 
426
            return nullptr;
 
427
        }
 
428
        cond = parseBooleanFormula(children);
 
429
        cond2 = parseBooleanFormula(children->next_sibling());
 
430
        if (cond == nullptr || cond2 == nullptr)
 
431
        {
 
432
            assert(false);
 
433
            return nullptr;       
 
434
        }
 
435
        return std::make_shared<OrCondition>(std::make_shared<NotCondition>(cond), cond2);
 
436
    } else if (elementName == "equivalence") {
 
437
        auto children = element->first_node();
 
438
        if (getChildCount(element) != 2) 
 
439
        {
 
440
            assert(false);
 
441
            return nullptr;       
 
442
        }
 
443
        cond = parseBooleanFormula(children);
 
444
        cond2 = parseBooleanFormula(children->next_sibling());
 
445
        if (cond == nullptr || cond2 == nullptr) return nullptr;
 
446
        return std::make_shared<OrCondition>(std::make_shared<AndCondition>(cond, cond2),
 
447
                std::make_shared<AndCondition>(std::make_shared<NotCondition>(cond), 
 
448
                std::make_shared<NotCondition>(cond2)));
 
449
    } else if (elementName == "integer-eq" || elementName == "integer-ne" ||
 
450
            elementName == "integer-lt" || elementName == "integer-le" ||
 
451
            elementName == "integer-gt" || elementName == "integer-ge") {
 
452
        auto children = element->first_node();
 
453
        if (getChildCount(element) != 2) 
 
454
        {
 
455
            assert(false);
 
456
            return nullptr;       
 
457
        }
 
458
        Expr_ptr expr1 = parseIntegerExpression(children);
 
459
        Expr_ptr expr2 = parseIntegerExpression(children->next_sibling());
 
460
        if(expr1 == nullptr || expr2 == nullptr) 
 
461
        {
 
462
            assert(false);
 
463
            return nullptr;       
 
464
        }
 
465
        if (elementName == "integer-eq") return std::make_shared<EqualCondition>(expr1, expr2);
 
466
        else if (elementName == "integer-ne") return std::make_shared<NotEqualCondition>(expr1, expr2);
 
467
        else if (elementName == "integer-lt") return std::make_shared<LessThanCondition>(expr1, expr2);
 
468
        else if (elementName == "integer-le") return std::make_shared<LessThanOrEqualCondition>(expr1, expr2);
 
469
        else if (elementName == "integer-gt") return std::make_shared<GreaterThanCondition>(expr1, expr2);
 
470
        else if (elementName == "integer-ge") return std::make_shared<GreaterThanOrEqualCondition>(expr1, expr2);        
 
471
    } else if (elementName == "is-fireable") {
 
472
        size_t nrOfChildren = getChildCount(element);
 
473
        if (nrOfChildren == 0) 
 
474
        {
 
475
            assert(false);
 
476
            return nullptr;       
 
477
        }
 
478
        std::vector<Condition_ptr> conds;
 
479
        for (auto it = element->first_node(); it; it = it->next_sibling()) {
 
480
            if (strcmp(it->name(), "transition") != 0) 
 
481
            {
 
482
                assert(false);
 
483
                return nullptr;       
 
484
            }
 
485
            conds.emplace_back(std::make_shared<FireableCondition>(it->value()));
 
486
        }
 
487
        return std::make_shared<OrCondition>(conds);
 
488
    }
 
489
    fatal_error(elementName);
 
490
    return nullptr;
 
491
}
 
492
 
 
493
Expr_ptr QueryXMLParser::parseIntegerExpression(rapidxml::xml_node<>*  element) {
 
494
    string elementName = element->name();
 
495
    if (elementName == "integer-constant") {
 
496
        int i;
 
497
        if (sscanf(element->value(), "%d", &i) == EOF) 
 
498
        {
 
499
            assert(false);
 
500
            return nullptr;       
 
501
        }
 
502
        return std::make_shared<LiteralExpr>(i);
 
503
    } else if (elementName == "tokens-count") {
 
504
        auto children = element->first_node();
 
505
        std::vector<Expr_ptr> ids;        
 
506
        for (auto it = children; it; it = it->next_sibling()) {
 
507
            if (strcmp(it->name(), "place") != 0)
 
508
            {
 
509
                assert(false);
 
510
                return nullptr;
 
511
            }
 
512
            string placeName = parsePlace(it);
 
513
            if (placeName.empty())
 
514
            {
 
515
                assert(false);
 
516
                return nullptr; // invalid place name
 
517
            }
 
518
            auto id = std::make_shared<IdentifierExpr>(placeName);
 
519
            ids.emplace_back(id);
 
520
        }
 
521
        
 
522
        if (ids.empty())
 
523
        {
 
524
            assert(false);
 
525
            return nullptr;       
 
526
        }
 
527
        if (ids.size() == 1) return ids[0];
 
528
        
 
529
        return std::make_shared<PlusExpr>(std::move(ids), true);
 
530
    } else if (elementName == "integer-sum" || elementName == "integer-product") {
 
531
        auto children = element->first_node();
 
532
        bool isMult = false;
 
533
        if (elementName == "integer-sum") isMult = false;
 
534
        else if (elementName == "integer-product") isMult = true;
 
535
 
 
536
        std::vector<Expr_ptr> els;
 
537
        auto it = children;
 
538
       
 
539
        for (; it; it = it->next_sibling()) {
 
540
            els.emplace_back(parseIntegerExpression(it));
 
541
            if(!els.back())  
 
542
        {
 
543
            assert(false);
 
544
            return nullptr;       
 
545
        }
 
546
        }
 
547
 
 
548
        if (els.size() < 2) 
 
549
        {
 
550
            assert(false);
 
551
            return nullptr;       
 
552
        }
 
553
 
 
554
        return  isMult ? 
 
555
                std::dynamic_pointer_cast<Expr>(std::make_shared<MultiplyExpr>(std::move(els))) :
 
556
                std::dynamic_pointer_cast<Expr>(std::make_shared<PlusExpr>(std::move(els)));
 
557
 
 
558
    } else if (elementName == "integer-difference") {
 
559
        auto children = element->first_node();
 
560
        std::vector<Expr_ptr> els;
 
561
        for (auto it = children; it; it = it->next_sibling()) {
 
562
            els.emplace_back(parseIntegerExpression(it));
 
563
        }
 
564
        if(els.size() == 1) 
 
565
            els.emplace(els.begin(), std::make_shared<LiteralExpr>(0));
 
566
        return std::make_shared<SubtractExpr>(std::move(els));
 
567
    }
 
568
    assert(false);
 
569
    return nullptr;
 
570
}
 
571
 
 
572
string QueryXMLParser::parsePlace(rapidxml::xml_node<>*  element) {
 
573
    if (strcmp(element->name(), "place") != 0)  return ""; // missing place tag
 
574
    string placeName = element->value();
 
575
    placeName.erase(std::remove_if(placeName.begin(), placeName.end(), ::isspace), placeName.end());
 
576
    return placeName;
 
577
}
 
578
 
 
579
void QueryXMLParser::printQueries(size_t i) {
 
580
    //  QueryXMLParser::QueriesIterator it;
 
581
    if (i <= 0 || i > queries.size()) {
 
582
        cout << "In printQueries the query index is out of scope\n\n";
 
583
        return;
 
584
    }
 
585
    QueryItem it = queries[i - 1];
 
586
    cout << it.id << ": " ;
 
587
    if (it.parsingResult == QueryItem::UNSUPPORTED_QUERY) {
 
588
        cout << "\t---------- unsupported query ----------" << endl;
 
589
    } else {
 
590
        cout << "\t";
 
591
        it.query->toString(cout);
 
592
        cout << std::endl;
 
593
    }
 
594
}
 
595
 
 
596
void QueryXMLParser::printQueries() {
 
597
    for (size_t i = 1; i <= queries.size(); i++) {
 
598
        printQueries(i);
 
599
    }
 
600
}