The models, scripts, and results of the benchmarks performed for a Half Reification Journal paper
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
3/*
4 * Main authors:
5 * Guido Tack <guido.tack@monash.edu>
6 */
7
8/* This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11
12%define api.pure
13
14%parse-param {void *parm}
15
16%define api.header.include {<minizinc/parser.tab.hh>}
17
18%lex-param {void* SCANNER}
19%{
20#define SCANNER static_cast<ParserState*>(parm)->yyscanner
21#include <iostream>
22#include <fstream>
23#include <map>
24#include <cerrno>
25
26namespace MiniZinc{ class ParserLocation; }
27#define YYLTYPE MiniZinc::ParserLocation
28#define YYLTYPE_IS_DECLARED 1
29#define YYLTYPE_IS_TRIVIAL 0
30
31#define YYMAXDEPTH 10000
32#define YYINITDEPTH 10000
33
34#include <minizinc/parser.hh>
35#include <minizinc/file_utils.hh>
36
37using namespace std;
38using namespace MiniZinc;
39
40#define YYLLOC_DEFAULT(Current, Rhs, N) \
41 do { \
42 if (N > 0) { \
43 (Current).filename(YYRHSLOC(Rhs, 1).filename()); \
44 (Current).firstLine(YYRHSLOC(Rhs, 1).firstLine()); \
45 (Current).firstColumn(YYRHSLOC(Rhs, 1).firstColumn()); \
46 (Current).lastLine(YYRHSLOC(Rhs, N).lastLine()); \
47 (Current).lastColumn(YYRHSLOC(Rhs, N).lastColumn()); \
48 } else { \
49 (Current).filename(YYRHSLOC(Rhs, 0).filename()); \
50 (Current).firstLine(YYRHSLOC(Rhs, 0).lastLine()); \
51 (Current).firstColumn(YYRHSLOC(Rhs, 0).lastColumn()); \
52 (Current).lastLine(YYRHSLOC(Rhs, 0).lastLine()); \
53 (Current).lastColumn(YYRHSLOC(Rhs, 0).lastColumn()); \
54 } \
55 } while (false)
56
57int mzn_yyparse(void*);
58int mzn_yylex(YYSTYPE*, YYLTYPE*, void* scanner);
59int mzn_yylex_init (void** scanner);
60int mzn_yylex_destroy (void* scanner);
61int mzn_yyget_lineno (void* scanner);
62void mzn_yyset_extra (void* user_defined ,void* yyscanner );
63
64extern int yydebug;
65
66namespace MiniZinc {
67
68void yyerror(YYLTYPE* location, void* parm, const string& str) {
69 ParserState* pp = static_cast<ParserState*>(parm);
70 Model* m = pp->model;
71 while (m->parent() != nullptr) {
72 m = m->parent();
73 pp->err << "(included from file '" << m->filename() << "')" << endl;
74 }
75 pp->err << location->toString() << ":" << endl;
76 pp->printCurrentLine(location->firstColumn(),location->lastColumn());
77 pp->err << "Error: " << str << std::endl;
78 pp->hadError = true;
79 pp->syntaxErrors.push_back(SyntaxError(Location(*location), str));
80}
81
82bool notInDatafile(YYLTYPE* location, void* parm, const string& item) {
83 ParserState* pp = static_cast<ParserState*>(parm);
84 if (pp->isDatafile) {
85 yyerror(location,parm,item+" item not allowed in data file");
86 return false;
87 }
88 return true;
89}
90
91Expression* createDocComment(const ParserLocation& loc, const std::string& s) {
92 std::vector<Expression*> args(1);
93 args[0] = new StringLit(loc, s);
94 Call* c = new Call(Location(loc), constants().ann.doc_comment, args);
95 c->type(Type::ann());
96 return c;
97}
98
99Expression* createArrayAccess(const ParserLocation& loc, Expression* e, std::vector<std::vector<Expression*> >& idx) {
100 Expression* ret = e;
101 for (unsigned int i=0; i<idx.size(); i++) {
102 ret = new ArrayAccess(Location(loc), ret, idx[i]);
103 }
104 return ret;
105}
106
107}
108
109%}
110
111%union { long long int iValue; char* sValue; bool bValue; double dValue;
112 MiniZinc::Item* item;
113 MiniZinc::VarDecl* vardeclexpr;
114 std::vector<MiniZinc::VarDecl*>* vardeclexprs;
115 MiniZinc::TypeInst* tiexpr;
116 std::vector<MiniZinc::TypeInst*>* tiexprs;
117 MiniZinc::Expression* expression;
118 std::vector<MiniZinc::Expression*>* expressions1d;
119 std::vector<std::vector<MiniZinc::Expression*> >* expressions2d;
120 std::vector<std::vector<std::vector<MiniZinc::Expression*> > >* expressions3d;
121 MiniZinc::Generator* generator;
122 std::vector<MiniZinc::Generator>* generators;
123 std::vector<std::string>* strings;
124 std::vector<std::pair<MiniZinc::Expression*,MiniZinc::Expression*> >* expressionPairs;
125 MiniZinc::Generators* generatorsPointer;
126 }
127
128%locations
129%define parse.error verbose
130
131%initial-action
132{
133 GCLock lock;
134 @$.filename(ASTString(static_cast<ParserState*>(parm)->filename));
135}
136
137%token <iValue> MZN_INTEGER_LITERAL "integer literal" MZN_BOOL_LITERAL "bool literal"
138%token <dValue> MZN_FLOAT_LITERAL "float literal"
139%token <sValue> MZN_IDENTIFIER "identifier" MZN_QUOTED_IDENTIFIER "quoted identifier" MZN_STRING_LITERAL "string literal"
140%token <sValue> MZN_STRING_QUOTE_START "interpolated string start" MZN_STRING_QUOTE_MID "interpolated string middle" MZN_STRING_QUOTE_END "interpolated string end"
141%token <sValue> MZN_TI_IDENTIFIER "type-inst identifier" MZN_TI_ENUM_IDENTIFIER "type-inst enum identifier" MZN_DOC_COMMENT "documentation comment" MZN_DOC_FILE_COMMENT "file-level documentation comment"
142
143%token MZN_VAR "var" MZN_PAR "par"
144
145%token MZN_ABSENT "<>"
146%token MZN_ANN "ann"
147%token MZN_ANNOTATION "annotation"
148%token MZN_ANY "any"
149%token MZN_ARRAY "array"
150%token MZN_BOOL "bool"
151%token MZN_CASE "case"
152%token MZN_CONSTRAINT "constraint"
153%token MZN_DEFAULT "default"
154%token MZN_ELSE "else"
155%token MZN_ELSEIF "elseif"
156%token MZN_ENDIF "endif"
157%token MZN_ENUM "enum"
158%token MZN_FLOAT "float"
159%token MZN_FUNCTION "function"
160%token MZN_IF "if"
161%token MZN_INCLUDE "include"
162%token MZN_INFINITY "infinity"
163%token MZN_INT "int"
164%token MZN_LET "let"
165%token MZN_LIST "list"
166%token <bValue> MZN_MAXIMIZE "maximize"
167%token <bValue> MZN_MINIMIZE "minimize"
168%token MZN_OF "of"
169%token MZN_OPT "opt"
170%token MZN_SATISFY "satisfy"
171%token MZN_OUTPUT "output"
172%token MZN_PREDICATE "predicate"
173%token MZN_RECORD "record"
174%token MZN_SET "set"
175%token MZN_SOLVE "solve"
176%token MZN_STRING "string"
177%token MZN_TEST "test"
178%token MZN_THEN "then"
179%token MZN_TUPLE "tuple"
180%token MZN_TYPE "type"
181%token MZN_UNDERSCORE "_"
182%token MZN_VARIANT_RECORD "variant_record"
183%token MZN_WHERE "where"
184
185%token MZN_LEFT_BRACKET "["
186%token MZN_LEFT_2D_BRACKET "[|"
187%token MZN_RIGHT_BRACKET "]"
188%token MZN_RIGHT_2D_BRACKET "|]"
189
190// Used to signal an error when parsing a MiniZinc file
191// that contains identifiers starting with _
192%token FLATZINC_IDENTIFIER
193
194%token MZN_INVALID_INTEGER_LITERAL "invalid integer literal"
195%token MZN_INVALID_FLOAT_LITERAL "invalid float literal"
196%token MZN_UNTERMINATED_STRING "unterminated string"
197%token MZN_END_OF_LINE_IN_STRING "end of line inside string literal"
198%token MZN_INVALID_NULL "null character"
199
200%token END 0 "end of file"
201
202%token MZN_EQUIV "<->"
203%token MZN_IMPL "->" MZN_RIMPL "<-"
204%token MZN_OR "\\/" MZN_XOR "xor"
205%token MZN_AND "/\\"
206%token MZN_LE "<" MZN_GR ">" MZN_LQ "<=" MZN_GQ ">=" MZN_EQ "=" MZN_NQ "!=" MZN_WEAK_EQ "~="
207%token MZN_IN "in" MZN_SUBSET "subset" MZN_SUPERSET "superset"
208%token MZN_UNION "union" MZN_DIFF "diff" MZN_SYMDIFF "symdiff"
209%token MZN_DOTDOT ".."
210%token MZN_PLUS "+" MZN_MINUS "-" MZN_WEAK_PLUS "~+" MZN_WEAK_MINUS "~-"
211%token MZN_MULT "*" MZN_DIV "/" MZN_IDIV "div" MZN_MOD "mod" MZN_INTERSECT "intersect" MZN_WEAK_MULT "~*"
212%token MZN_POW "^"
213%token MZN_POW_MINUS1 "^-1"
214%token MZN_NOT "not"
215%token MZN_PLUSPLUS "++"
216%token MZN_COLONCOLON "::"
217
218%right PREC_ANNO
219%left MZN_EQUIV
220%left MZN_IMPL MZN_RIMPL
221%left MZN_OR MZN_XOR
222%left MZN_AND
223%nonassoc MZN_LE MZN_GR MZN_LQ MZN_GQ MZN_EQ MZN_NQ MZN_WEAK_EQ
224%nonassoc MZN_IN MZN_SUBSET MZN_SUPERSET
225%left MZN_UNION MZN_DIFF MZN_SYMDIFF MZN_INTERSECT
226%nonassoc MZN_DOTDOT
227%left MZN_PLUS MZN_MINUS MZN_WEAK_PLUS MZN_WEAK_MINUS
228%left MZN_MULT MZN_DIV MZN_IDIV MZN_MOD MZN_WEAK_MULT
229%left MZN_POW MZN_POW_MINUS1
230%nonassoc MZN_NOT
231%left MZN_PLUSPLUS
232%left MZN_QUOTED_IDENTIFIER
233%left MZN_COLONCOLON
234
235%token MZN_EQUIV_QUOTED "'<->'"
236%token MZN_IMPL_QUOTED "'->'" MZN_RIMPL_QUOTED "'<-'"
237%token MZN_OR_QUOTED "'\\/'" MZN_XOR_QUOTED "'xor'"
238%token MZN_AND_QUOTED "'/\\'"
239%token MZN_LE_QUOTED "'<'" MZN_GR_QUOTED "'>'" MZN_LQ_QUOTED "'<='" MZN_GQ_QUOTED "'>='" MZN_EQ_QUOTED "'='" MZN_NQ_QUOTED "'!='"
240%token MZN_IN_QUOTED "'in'" MZN_SUBSET_QUOTED "'subset'" MZN_SUPERSET_QUOTED "'superset'"
241%token MZN_UNION_QUOTED "'union'" MZN_DIFF_QUOTED "'diff'" MZN_SYMDIFF_QUOTED "'symdiff'"
242%token MZN_DOTDOT_QUOTED "'..'"
243%token MZN_PLUS_QUOTED "'+'" MZN_MINUS_QUOTED "'-'"
244%token MZN_MULT_QUOTED "'*'" MZN_DIV_QUOTED "'/'" MZN_IDIV_QUOTED "'div'" MZN_MOD_QUOTED "'mod'" MZN_INTERSECT_QUOTED "'intersect'"
245%token MZN_POW_QUOTED "'^'"
246%token MZN_NOT_QUOTED "'not'"
247%token MZN_COLONCOLON_QUOTED "'::'"
248%token MZN_PLUSPLUS_QUOTED "'++'"
249
250%type <item> item item_tail include_item vardecl_item assign_item constraint_item solve_item output_item predicate_item annotation_item function_item
251
252%type <vardeclexpr> ti_expr_and_id ti_expr_and_id_or_anon let_vardecl_item ann_param
253%type <vardeclexprs> params params_list params_list_head
254%type <tiexpr> ti_expr base_ti_expr base_ti_expr_tail
255%type <tiexprs> ti_expr_list ti_expr_list_head
256
257%type <expression> expr expr_atom_head expr_atom_head_nonstring array_access_expr
258%type <expression> set_expr string_expr string_quote_rest annotation_expr enum_construct
259%type <expression> simple_array_literal simple_array_literal_2d simple_array_comp if_then_else_expr call_expr quoted_op_call let_expr operation_item_tail set_literal set_comp
260
261%type <expressions1d> expr_list expr_list_head array_access_expr_list array_access_expr_list_head elseif_list let_vardecl_item_list enum_init enum_id_list string_lit_list
262%type <expressions2d> simple_array_literal_2d_list array_access_tail
263%type <expressions3d> simple_array_literal_3d_list
264
265%type <generatorsPointer> comp_tail
266%type <generator> generator generator_eq
267%type <generators> generator_list generator_list_head
268%type <strings> id_list id_list_head
269
270%type <expressionPairs> comp_or_expr comp_or_expr_head
271
272%type <expressions1d> annotations ne_annotations
273
274%type <iValue> quoted_op
275
276%type <sValue> id_or_quoted_op
277
278%type <bValue> opt_opt
279
280%%
281
282/********************************/
283/* main goal and item lists */
284/********************************/
285
286model : item_list
287
288item_list :
289 /* empty */
290 | item_list_head semi_or_none
291
292item_list_head:
293 item
294 {
295 ParserState* pp = static_cast<ParserState*>(parm);
296 if ($1) {
297 pp->model->addItem($1);
298 GC::unlock();
299 GC::lock();
300 }
301 }
302 | doc_file_comments item
303 {
304 ParserState* pp = static_cast<ParserState*>(parm);
305 if ($2) {
306 pp->model->addItem($2);
307 GC::unlock();
308 GC::lock();
309 }
310 }
311 | item_list_head ';' item
312 {
313 ParserState* pp = static_cast<ParserState*>(parm);
314 if ($3) {
315 pp->model->addItem($3);
316 GC::unlock();
317 GC::lock();
318 }
319 }
320 | item_list_head ';' doc_file_comments item
321 {
322 ParserState* pp = static_cast<ParserState*>(parm);
323 if ($4) {
324 pp->model->addItem($4);
325 GC::unlock();
326 GC::lock();
327 }
328 }
329 | item error_item_start
330{ yyerror(&@2, parm, "unexpected item, expecting ';' or end of file"); YYERROR; }
331 | error ';' item
332
333doc_file_comments:
334 MZN_DOC_FILE_COMMENT
335 {
336 ParserState* pp = static_cast<ParserState*>(parm);
337 if (pp->parseDocComments && $1) {
338 pp->model->addDocComment($1);
339 }
340 free($1);
341 }
342 | doc_file_comments MZN_DOC_FILE_COMMENT
343 {
344 ParserState* pp = static_cast<ParserState*>(parm);
345 if (pp->parseDocComments && $2) {
346 pp->model->addDocComment($2);
347 }
348 free($2);
349 }
350
351semi_or_none : | ';'
352
353item : MZN_DOC_COMMENT item_tail
354 { $$ = $2;
355 ParserState* pp = static_cast<ParserState*>(parm);
356 if (FunctionI* fi = Item::dynamicCast<FunctionI>($$)) {
357 if (pp->parseDocComments) {
358 fi->ann().add(createDocComment(@1,$1));
359 }
360 } else if (VarDeclI* vdi = Item::dynamicCast<VarDeclI>($$)) {
361 if (pp->parseDocComments) {
362 vdi->e()->addAnnotation(createDocComment(@1,$1));
363 }
364 } else {
365 yyerror(&@2, parm, "documentation comments are only supported for function, predicate and variable declarations");
366 }
367 free($1);
368 }
369 | item_tail
370 { $$ = $1; }
371
372item_tail :
373 include_item
374 { $$=notInDatafile(&@$,parm,"include") ? $1 : nullptr; }
375 | vardecl_item
376 { $$=notInDatafile(&@$,parm,"variable declaration") ? $1 : nullptr; }
377 | assign_item
378 | constraint_item
379 { $$=notInDatafile(&@$,parm,"constraint") ? $1 : nullptr; }
380 | solve_item
381 { $$=notInDatafile(&@$,parm,"solve") ? $1 : nullptr; }
382 | output_item
383 { $$=notInDatafile(&@$,parm,"output") ? $1 : nullptr; }
384 | predicate_item
385 { $$=notInDatafile(&@$,parm,"predicate") ? $1 : nullptr; }
386 | function_item
387 { $$=notInDatafile(&@$,parm,"predicate") ? $1 : nullptr; }
388 | annotation_item
389 { $$=notInDatafile(&@$,parm,"annotation") ? $1 : nullptr; }
390
391error_item_start : MZN_INCLUDE | MZN_ENUM | MZN_OUTPUT
392 | MZN_CONSTRAINT | MZN_SOLVE | MZN_PREDICATE | MZN_FUNCTION | MZN_TEST
393 | MZN_ANNOTATION
394
395include_item :
396 MZN_INCLUDE MZN_STRING_LITERAL
397 { ParserState* pp = static_cast<ParserState*>(parm);
398 string canonicalName=pp->canonicalFilename($2);
399 map<string,Model*>::iterator ret = pp->seenModels.find(canonicalName);
400 IncludeI* ii = new IncludeI(@$,ASTString($2));
401 $$ = ii;
402 if (ret == pp->seenModels.end()) {
403 Model* im = new Model;
404 im->setParent(pp->model);
405 im->setFilename(canonicalName);
406 string fpath = FileUtils::dir_name(pp->filename);
407 if (fpath=="")
408 fpath="./";
409 pp->files.emplace_back(im, ii, fpath, canonicalName, pp->isSTDLib);
410 ii->m(im);
411 pp->seenModels.insert(pair<string,Model*>(canonicalName,im));
412 } else {
413 ii->m(ret->second, false);
414 }
415 free($2);
416 }
417
418vardecl_item :
419 ti_expr_and_id
420 { if ($1)
421 $$ = new VarDeclI(@$,$1);
422 }
423 | ti_expr_and_id MZN_EQ expr
424 { if ($1) $1->e($3);
425 if ($1)
426 $$ = new VarDeclI(@$,$1);
427 }
428 | MZN_ENUM MZN_IDENTIFIER annotations
429 {
430 TypeInst* ti = new TypeInst(@$,Type::parsetint());
431 ti->setIsEnum(true);
432 VarDecl* vd = new VarDecl(@$,ti,$2);
433 if ($2 && $3)
434 vd->addAnnotations(*$3);
435 free($2);
436 $$ = new VarDeclI(@$,vd);
437 }
438 | MZN_ENUM MZN_IDENTIFIER annotations MZN_EQ enum_init
439 {
440 if ($5) {
441 TypeInst* ti = new TypeInst(@$,Type::parsetint());
442 ti->setIsEnum(true);
443 Expression* e;
444 if ($5->size()==1) {
445 e = (*$5)[0];
446 } else {
447 ArrayLit* al = new ArrayLit(@$,*$5);
448 e = new Call(@$, ASTString("enumFromConstructors"), {al});
449 }
450 VarDecl* vd = new VarDecl(@$,ti,$2,e);
451 $$ = new VarDeclI(@$,vd);
452 }
453 free($2);
454 delete $5;
455 }
456 | MZN_ENUM MZN_IDENTIFIER annotations MZN_EQ MZN_LEFT_BRACKET string_lit_list MZN_RIGHT_BRACKET
457 {
458 TypeInst* ti = new TypeInst(@$,Type::parsetint());
459 ti->setIsEnum(true);
460 vector<Expression*> args;
461 args.push_back(new ArrayLit(@$,*$6));
462 Call* sl = new Call(@$, constants().ids.anonEnumFromStrings, args);
463 VarDecl* vd = new VarDecl(@$,ti,$2,sl);
464 if ($2 && $3)
465 vd->addAnnotations(*$3);
466 free($2);
467 delete $6;
468 $$ = new VarDeclI(@$,vd);
469 }
470
471enum_init :
472 enum_construct
473 {
474 $$ = new std::vector<Expression*>({$1});
475 }
476 | enum_init MZN_PLUSPLUS enum_construct
477 {
478 $$ = $1;
479 if ($$) {
480 $$->push_back($3);
481 }
482 }
483
484enum_construct :
485 '{' enum_id_list '}'
486 {
487 $$ = new SetLit(@$, *$2);
488 delete $2;
489 }
490 | MZN_IDENTIFIER '(' expr ')'
491 {
492 vector<Expression*> args({$3});
493 $$ = new Call(@$, ASTString($1), args);
494 free($1);
495 }
496
497string_lit_list :
498 // empty
499 { $$ = new std::vector<Expression*>(); }
500 | MZN_STRING_LITERAL
501 { $$ = new std::vector<Expression*>();
502 $$->push_back(new StringLit(@$, $1)); free($1);
503 }
504 | string_lit_list ',' MZN_STRING_LITERAL
505 { $$ = $1;
506 if ($$) $$->push_back(new StringLit(@$, $3));
507 free($3);
508 }
509
510enum_id_list :
511 // empty
512 { $$ = new std::vector<Expression*>(); }
513 | MZN_IDENTIFIER
514 { $$ = new std::vector<Expression*>();
515 $$->push_back(new Id(@$,$1,nullptr)); free($1);
516 }
517 | enum_id_list ',' MZN_IDENTIFIER
518 { $$ = $1; if ($$) $$->push_back(new Id(@$,$3,nullptr)); free($3); }
519
520assign_item :
521 MZN_IDENTIFIER MZN_EQ expr
522 { $$ = new AssignI(@$,$1,$3);
523 free($1);
524 }
525
526constraint_item :
527 MZN_CONSTRAINT expr
528 { $$ = new ConstraintI(@$,$2);}
529 | MZN_CONSTRAINT MZN_COLONCOLON string_expr expr
530 { $$ = new ConstraintI(@$,$4);
531 if ($4 && $3)
532 $$->cast<ConstraintI>()->e()->ann().add(new Call(@2, ASTString("mzn_constraint_name"), {$3}));
533 }
534
535solve_item :
536 MZN_SOLVE annotations MZN_SATISFY
537 { $$ = SolveI::sat(@$);
538 if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
539 delete $2;
540 }
541 | MZN_SOLVE annotations MZN_MINIMIZE expr
542 { $$ = SolveI::min(@$,$4);
543 if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
544 delete $2;
545 }
546 | MZN_SOLVE annotations MZN_MAXIMIZE expr
547 { $$ = SolveI::max(@$,$4);
548 if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
549 delete $2;
550 }
551
552output_item :
553 MZN_OUTPUT expr
554 { $$ = new OutputI(@$,$2); }
555 | MZN_OUTPUT MZN_COLONCOLON string_expr expr
556 { $$ = new OutputI(@$,$4);
557 if ($$ && $3) {
558 $$->cast<OutputI>()->ann().add(new Call(@$, ASTString("mzn_output_section"), {$3}));
559 }
560 }
561
562
563predicate_item :
564 MZN_PREDICATE MZN_IDENTIFIER params ann_param annotations operation_item_tail
565 {
566 ParserState* pp = static_cast<ParserState*>(parm);
567 if ($3 && $4) $3->push_back($4);
568 if ($3) $$ = new FunctionI(@$,ASTString($2),new TypeInst(@$,
569 Type::varbool()),*$3,$6,pp->isSTDLib,$4 != nullptr);
570 if ($$ && $5) $$->cast<FunctionI>()->ann().add(*$5);
571 free($2);
572 delete $3;
573 delete $5;
574 }
575 | MZN_TEST MZN_IDENTIFIER params ann_param annotations operation_item_tail
576 {
577 ParserState* pp = static_cast<ParserState*>(parm);
578 if ($3 && $4) $3->push_back($4);
579 if ($3) $$ = new FunctionI(@$,ASTString($2),new TypeInst(@$,
580 Type::parbool()),*$3,$6,pp->isSTDLib,$4 != nullptr);
581 if ($$ && $5) $$->cast<FunctionI>()->ann().add(*$5);
582 free($2);
583 delete $3;
584 delete $5;
585 }
586 | MZN_PREDICATE MZN_IDENTIFIER MZN_POW_MINUS1 params ann_param annotations operation_item_tail
587 {
588 ParserState* pp = static_cast<ParserState*>(parm);
589 if ($4 && $5) $4->push_back($5);
590 if ($4) $$ = new FunctionI(@$,ASTString(std::string($2)+"⁻¹"),new TypeInst(@$,
591 Type::varbool()),*$4,$7,pp->isSTDLib,$5 != nullptr);
592 if ($$ && $6) $$->cast<FunctionI>()->ann().add(*$6);
593 free($2);
594 delete $4;
595 delete $6;
596 }
597 | MZN_TEST MZN_IDENTIFIER MZN_POW_MINUS1 params ann_param annotations operation_item_tail
598 {
599 ParserState* pp = static_cast<ParserState*>(parm);
600 if ($4 && $5) $4->push_back($5);
601 if ($4) $$ = new FunctionI(@$,ASTString(std::string($2)+"⁻¹"),new TypeInst(@$,
602 Type::parbool()),*$4,$7,pp->isSTDLib,$5 != nullptr);
603 if ($$ && $6) $$->cast<FunctionI>()->ann().add(*$6);
604 free($2);
605 delete $4;
606 delete $6;
607 }
608
609function_item :
610 MZN_FUNCTION ti_expr ':' id_or_quoted_op params ann_param annotations operation_item_tail
611 {
612 ParserState* pp = static_cast<ParserState*>(parm);
613 if ($5 && $6) $5->push_back($6);
614 if ($5) $$ = new FunctionI(@$,ASTString($4),$2,*$5,$8,pp->isSTDLib,$6 != nullptr);
615 if ($$ && $7) $$->cast<FunctionI>()->ann().add(*$7);
616 free($4);
617 delete $5;
618 delete $7;
619 }
620 | ti_expr ':' MZN_IDENTIFIER '(' params_list ')' ann_param annotations operation_item_tail
621 {
622 ParserState* pp = static_cast<ParserState*>(parm);
623 if ($5 && $7) $5->push_back($7);
624 if ($5) $$ = new FunctionI(@$,ASTString($3),$1,*$5,$9,pp->isSTDLib,$7 != nullptr);
625 if ($$ && $8) $$->cast<FunctionI>()->ann().add(*$8);
626 free($3);
627 delete $5;
628 delete $8;
629 }
630
631annotation_item :
632 MZN_ANNOTATION MZN_IDENTIFIER params
633 {
634 ParserState* pp = static_cast<ParserState*>(parm);
635 TypeInst* ti=new TypeInst(@1,Type::ann());
636 if ($3==nullptr || $3->empty()) {
637 VarDecl* vd = new VarDecl(@$,ti,$2);
638 $$ = new VarDeclI(@$,vd);
639 } else {
640 $$ = new FunctionI(@$,ASTString($2),ti,*$3,nullptr,pp->isSTDLib);
641 }
642 free($2);
643 delete $3;
644 }
645 | MZN_ANNOTATION MZN_IDENTIFIER params MZN_EQ expr
646 {
647 ParserState* pp = static_cast<ParserState*>(parm);
648 TypeInst* ti=new TypeInst(@1,Type::ann());
649 if ($3) $$ = new FunctionI(@$,ASTString($2),ti,*$3,$5,pp->isSTDLib);
650 delete $3;
651 }
652
653ann_param :
654 /*empty*/
655 { $$=nullptr; }
656 | MZN_ANN ':' MZN_IDENTIFIER
657 { if ($3) {
658 auto* ident = new Id(@3, $3, nullptr);
659 auto* ti = new TypeInst(@$,Type::ann(1));
660 $$ = new VarDecl(@$, ti, ident);
661 $$->toplevel(false);
662 } }
663
664operation_item_tail :
665 /*empty*/
666 { $$=nullptr; }
667 | MZN_EQ expr
668 { $$=$2; }
669
670params :
671 /* empty */
672 { $$=new vector<VarDecl*>(); }
673 | '(' params_list ')'
674 { $$=$2; }
675 | '(' error ')'
676 { $$=new vector<VarDecl*>(); }
677
678params_list :
679 /* empty */
680 { $$=new vector<VarDecl*>(); }
681 | params_list_head comma_or_none
682 { $$=$1; }
683
684params_list_head :
685 ti_expr_and_id_or_anon
686 { $$=new vector<VarDecl*>();
687 if ($1) $1->toplevel(false);
688 if ($1) $$->push_back($1); }
689 | params_list_head ',' ti_expr_and_id_or_anon
690 { $$=$1;
691 if ($3) $3->toplevel(false);
692 if ($1 && $3) $1->push_back($3); }
693
694comma_or_none : | ','
695
696ti_expr_and_id_or_anon :
697 ti_expr_and_id
698 { $$=$1; }
699 | ti_expr
700 { if ($1) $$=new VarDecl(@$, $1, ""); }
701
702ti_expr_and_id :
703 ti_expr ':' MZN_IDENTIFIER annotations
704 { if ($1 && $3) {
705 Id* ident = new Id(@3, $3, nullptr);
706 $$ = new VarDecl(@$, $1, ident);
707 if ($4) $$->ann().add(*$4);
708 }
709 free($3);
710 delete $4;
711 }
712
713ti_expr_list : ti_expr_list_head comma_or_none
714 { $$=$1; }
715
716ti_expr_list_head :
717 ti_expr
718 { $$=new vector<TypeInst*>(); $$->push_back($1); }
719 | ti_expr_list_head ',' ti_expr
720 { $$=$1; if ($1 && $3) $1->push_back($3); }
721
722ti_expr :
723 base_ti_expr
724 | MZN_ARRAY MZN_LEFT_BRACKET ti_expr_list MZN_RIGHT_BRACKET MZN_OF base_ti_expr
725 {
726 $$ = $6;
727 if ($$ && $3) $$->setRanges(*$3);
728 delete $3;
729 }
730 | MZN_LIST MZN_OF base_ti_expr
731 {
732 $$ = $3;
733 std::vector<TypeInst*> ti(1);
734 ti[0] = new TypeInst(@$,Type::parint());
735 if ($$) $$->setRanges(ti);
736 }
737
738base_ti_expr :
739 base_ti_expr_tail
740 { $$ = $1;
741 }
742 | MZN_OPT base_ti_expr_tail
743 { $$ = $2;
744 if ($$) {
745 Type tt = $$->type();
746 tt.ot(Type::OT_OPTIONAL);
747 $$->type(tt);
748 }
749 }
750 | MZN_PAR opt_opt base_ti_expr_tail
751 { $$ = $3;
752 if ($$ && $2) {
753 Type tt = $$->type();
754 tt.ot(Type::OT_OPTIONAL);
755 $$->type(tt);
756 }
757 }
758 | MZN_VAR opt_opt base_ti_expr_tail
759 { $$ = $3;
760 if ($$) {
761 Type tt = $$->type();
762 tt.ti(Type::TI_VAR);
763 if ($2) tt.ot(Type::OT_OPTIONAL);
764 $$->type(tt);
765 }
766 }
767 | MZN_SET MZN_OF base_ti_expr_tail
768 { $$ = $3;
769 if ($$) {
770 Type tt = $$->type();
771 tt.st(Type::ST_SET);
772 $$->type(tt);
773 }
774 }
775 | MZN_OPT MZN_SET MZN_OF base_ti_expr_tail
776 { $$ = $4;
777 if ($$) {
778 Type tt = $$->type();
779 tt.st(Type::ST_SET);
780 tt.ot(Type::OT_OPTIONAL);
781 $$->type(tt);
782 }
783 }
784 | MZN_PAR opt_opt MZN_SET MZN_OF base_ti_expr_tail
785 { $$ = $5;
786 if ($$) {
787 Type tt = $$->type();
788 tt.st(Type::ST_SET);
789 if ($2) tt.ot(Type::OT_OPTIONAL);
790 $$->type(tt);
791 }
792 }
793 | MZN_VAR opt_opt MZN_SET MZN_OF base_ti_expr_tail
794 { $$ = $5;
795 if ($$) {
796 Type tt = $$->type();
797 tt.ti(Type::TI_VAR);
798 tt.st(Type::ST_SET);
799 if ($2) tt.ot(Type::OT_OPTIONAL);
800 $$->type(tt);
801 }
802 }
803
804opt_opt:
805 /* nothing */
806 { $$ = false; }
807 | MZN_OPT
808 { $$ = true; }
809
810base_ti_expr_tail :
811 MZN_INT
812 { $$ = new TypeInst(@$,Type::parint()); }
813 | MZN_BOOL
814 { $$ = new TypeInst(@$,Type::parbool()); }
815 | MZN_FLOAT
816 { $$ = new TypeInst(@$,Type::parfloat()); }
817 | MZN_STRING
818 { $$ = new TypeInst(@$,Type::parstring()); }
819 | MZN_ANN
820 { $$ = new TypeInst(@$,Type::ann()); }
821 | set_expr
822 { if ($1) $$ = new TypeInst(@$,Type(),$1); }
823 | MZN_TI_IDENTIFIER
824 { $$ = new TypeInst(@$,Type::top(),
825 new TIId(@$, $1));
826 free($1);
827 }
828 | MZN_TI_ENUM_IDENTIFIER
829 { $$ = new TypeInst(@$,Type::parint(),
830 new TIId(@$, $1));
831 free($1);
832 }
833
834array_access_expr_list : array_access_expr_list_head comma_or_none
835
836array_access_expr_list_head :
837 array_access_expr
838 { $$=new std::vector<MiniZinc::Expression*>; $$->push_back($1); }
839 | array_access_expr_list_head ',' array_access_expr
840 { $$=$1; if ($$ && $3) $$->push_back($3); }
841
842array_access_expr :
843 expr
844 { $$ = $1; }
845 | MZN_DOTDOT
846 { $$=new SetLit(@$, IntSetVal::a(-IntVal::infinity(),IntVal::infinity())); }
847 | MZN_DOTDOT expr
848 { if ($2==nullptr) {
849 $$ = nullptr;
850 } else if ($2->isa<IntLit>()) {
851 $$=new SetLit(@$, IntSetVal::a(-IntVal::infinity(),$2->cast<IntLit>()->v()));
852 } else {
853 $$=new BinOp(@$, IntLit::a(-IntVal::infinity()), BOT_DOTDOT, $2);
854 }
855 }
856 | expr MZN_DOTDOT
857 { if ($1==nullptr) {
858 $$ = nullptr;
859 } else if ($1->isa<IntLit>()) {
860 $$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),IntVal::infinity()));
861 } else {
862 $$=new BinOp(@$, $1, BOT_DOTDOT, IntLit::a(IntVal::infinity()));
863 }
864 }
865
866
867expr_list : expr_list_head comma_or_none
868
869expr_list_head :
870 expr
871 { $$=new std::vector<MiniZinc::Expression*>; $$->push_back($1); }
872 | expr_list_head ',' expr
873 { $$=$1; if ($$ && $3) $$->push_back($3); }
874
875///
876
877set_expr :
878 expr_atom_head
879 | set_expr MZN_COLONCOLON annotation_expr
880 { if ($1 && $3) $1->addAnnotation($3); $$=$1; }
881 | set_expr MZN_UNION set_expr
882 { $$=new BinOp(@$, $1, BOT_UNION, $3); }
883 | set_expr MZN_DIFF set_expr
884 { $$=new BinOp(@$, $1, BOT_DIFF, $3); }
885 | set_expr MZN_SYMDIFF set_expr
886 { $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); }
887 | set_expr MZN_DOTDOT set_expr
888 { if ($1==nullptr || $3==nullptr) {
889 $$ = nullptr;
890 } else if ($1->isa<IntLit>() && $3->isa<IntLit>()) {
891 $$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),$3->cast<IntLit>()->v()));
892 } else {
893 $$=new BinOp(@$, $1, BOT_DOTDOT, $3);
894 }
895 }
896 | MZN_DOTDOT_QUOTED '(' expr ',' expr ')'
897 { if ($3==nullptr || $5==nullptr) {
898 $$ = nullptr;
899 } else if ($3->isa<IntLit>() && $5->isa<IntLit>()) {
900 $$=new SetLit(@$, IntSetVal::a($3->cast<IntLit>()->v(),$5->cast<IntLit>()->v()));
901 } else {
902 $$=new BinOp(@$, $3, BOT_DOTDOT, $5);
903 }
904 }
905 | set_expr MZN_INTERSECT set_expr
906 { $$=new BinOp(@$, $1, BOT_INTERSECT, $3); }
907 | set_expr MZN_PLUSPLUS set_expr
908 { $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); }
909 | set_expr MZN_PLUS set_expr
910 { $$=new BinOp(@$, $1, BOT_PLUS, $3); }
911 | set_expr MZN_MINUS set_expr
912 { $$=new BinOp(@$, $1, BOT_MINUS, $3); }
913 | set_expr MZN_MULT set_expr
914 { $$=new BinOp(@$, $1, BOT_MULT, $3); }
915 | set_expr MZN_DIV set_expr
916 { $$=new BinOp(@$, $1, BOT_DIV, $3); }
917 | set_expr MZN_IDIV set_expr
918 { $$=new BinOp(@$, $1, BOT_IDIV, $3); }
919 | set_expr MZN_MOD set_expr
920 { $$=new BinOp(@$, $1, BOT_MOD, $3); }
921 | set_expr MZN_POW set_expr
922 { $$=new BinOp(@$, $1, BOT_POW, $3); }
923 | set_expr MZN_WEAK_PLUS set_expr
924 { vector<Expression*> args;
925 args.push_back($1); args.push_back($3);
926 $$=new Call(@$, ASTString("~+"), args);
927 }
928 | set_expr MZN_WEAK_MINUS set_expr
929 { vector<Expression*> args;
930 args.push_back($1); args.push_back($3);
931 $$=new Call(@$, ASTString("~-"), args);
932 }
933 | set_expr MZN_WEAK_MULT set_expr
934 { vector<Expression*> args;
935 args.push_back($1); args.push_back($3);
936 $$=new Call(@$, ASTString("~*"), args);
937 }
938 | set_expr MZN_WEAK_EQ set_expr
939 { vector<Expression*> args;
940 args.push_back($1); args.push_back($3);
941 $$=new Call(@$, ASTString("~="), args);
942 }
943 | set_expr MZN_QUOTED_IDENTIFIER set_expr
944 { vector<Expression*> args;
945 args.push_back($1); args.push_back($3);
946 $$=new Call(@$, $2, args);
947 free($2);
948 }
949 | MZN_PLUS set_expr %prec MZN_NOT
950 { $$=new UnOp(@$, UOT_PLUS, $2); }
951 | MZN_MINUS set_expr %prec MZN_NOT
952 { if ($2 && $2->isa<IntLit>()) {
953 $$ = IntLit::a(-$2->cast<IntLit>()->v());
954 } else if ($2 && $2->isa<FloatLit>()) {
955 $$ = FloatLit::a(-$2->cast<FloatLit>()->v());
956 } else {
957 $$=new UnOp(@$, UOT_MINUS, $2);
958 }
959 }
960
961///
962
963expr :
964 expr_atom_head
965 | expr MZN_COLONCOLON annotation_expr
966 { if ($1 && $3) $1->addAnnotation($3); $$=$1; }
967 | expr MZN_EQUIV expr
968 { $$=new BinOp(@$, $1, BOT_EQUIV, $3); }
969 | expr MZN_IMPL expr
970 { $$=new BinOp(@$, $1, BOT_IMPL, $3); }
971 | expr MZN_RIMPL expr
972 { $$=new BinOp(@$, $1, BOT_RIMPL, $3); }
973 | expr MZN_OR expr
974 { $$=new BinOp(@$, $1, BOT_OR, $3); }
975 | expr MZN_XOR expr
976 { $$=new BinOp(@$, $1, BOT_XOR, $3); }
977 | expr MZN_AND expr
978 { $$=new BinOp(@$, $1, BOT_AND, $3); }
979 | expr MZN_LE expr
980 { $$=new BinOp(@$, $1, BOT_LE, $3); }
981 | expr MZN_GR expr
982 { $$=new BinOp(@$, $1, BOT_GR, $3); }
983 | expr MZN_LQ expr
984 { $$=new BinOp(@$, $1, BOT_LQ, $3); }
985 | expr MZN_GQ expr
986 { $$=new BinOp(@$, $1, BOT_GQ, $3); }
987 | expr MZN_EQ expr
988 { $$=new BinOp(@$, $1, BOT_EQ, $3); }
989 | expr MZN_NQ expr
990 { $$=new BinOp(@$, $1, BOT_NQ, $3); }
991 | expr MZN_IN expr
992 { $$=new BinOp(@$, $1, BOT_IN, $3); }
993 | expr MZN_SUBSET expr
994 { $$=new BinOp(@$, $1, BOT_SUBSET, $3); }
995 | expr MZN_SUPERSET expr
996 { $$=new BinOp(@$, $1, BOT_SUPERSET, $3); }
997 | expr MZN_UNION expr
998 { $$=new BinOp(@$, $1, BOT_UNION, $3); }
999 | expr MZN_DIFF expr
1000 { $$=new BinOp(@$, $1, BOT_DIFF, $3); }
1001 | expr MZN_SYMDIFF expr
1002 { $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); }
1003 | expr MZN_DOTDOT expr
1004 { if ($1==nullptr || $3==nullptr) {
1005 $$ = nullptr;
1006 } else if ($1->isa<IntLit>() && $3->isa<IntLit>()) {
1007 $$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),$3->cast<IntLit>()->v()));
1008 } else {
1009 $$=new BinOp(@$, $1, BOT_DOTDOT, $3);
1010 }
1011 }
1012 | MZN_DOTDOT_QUOTED '(' expr ',' expr ')'
1013 { if ($3==nullptr || $5==nullptr) {
1014 $$ = nullptr;
1015 } else if ($3->isa<IntLit>() && $5->isa<IntLit>()) {
1016 $$=new SetLit(@$, IntSetVal::a($3->cast<IntLit>()->v(),$5->cast<IntLit>()->v()));
1017 } else {
1018 $$=new BinOp(@$, $3, BOT_DOTDOT, $5);
1019 }
1020 }
1021 | expr MZN_INTERSECT expr
1022 { $$=new BinOp(@$, $1, BOT_INTERSECT, $3); }
1023 | expr MZN_PLUSPLUS expr
1024 { $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); }
1025 | expr MZN_PLUS expr
1026 { $$=new BinOp(@$, $1, BOT_PLUS, $3); }
1027 | expr MZN_MINUS expr
1028 { $$=new BinOp(@$, $1, BOT_MINUS, $3); }
1029 | expr MZN_MULT expr
1030 { $$=new BinOp(@$, $1, BOT_MULT, $3); }
1031 | expr MZN_DIV expr
1032 { $$=new BinOp(@$, $1, BOT_DIV, $3); }
1033 | expr MZN_IDIV expr
1034 { $$=new BinOp(@$, $1, BOT_IDIV, $3); }
1035 | expr MZN_MOD expr
1036 { $$=new BinOp(@$, $1, BOT_MOD, $3); }
1037 | expr MZN_POW expr
1038 { $$=new BinOp(@$, $1, BOT_POW, $3); }
1039 | expr MZN_WEAK_PLUS expr
1040 { vector<Expression*> args;
1041 args.push_back($1); args.push_back($3);
1042 $$=new Call(@$, ASTString("~+"), args);
1043 }
1044 | expr MZN_WEAK_MINUS expr
1045 { vector<Expression*> args;
1046 args.push_back($1); args.push_back($3);
1047 $$=new Call(@$, ASTString("~-"), args);
1048 }
1049 | expr MZN_WEAK_MULT expr
1050 { vector<Expression*> args;
1051 args.push_back($1); args.push_back($3);
1052 $$=new Call(@$, ASTString("~*"), args);
1053 }
1054 | expr MZN_WEAK_EQ expr
1055 { vector<Expression*> args;
1056 args.push_back($1); args.push_back($3);
1057 $$=new Call(@$, ASTString("~="), args);
1058 }
1059 | expr MZN_QUOTED_IDENTIFIER expr
1060 { vector<Expression*> args;
1061 args.push_back($1); args.push_back($3);
1062 $$=new Call(@$, $2, args);
1063 free($2);
1064 }
1065 | MZN_NOT expr %prec MZN_NOT
1066 { $$=new UnOp(@$, UOT_NOT, $2); }
1067 | MZN_PLUS expr %prec MZN_NOT
1068 { if (($2 && $2->isa<IntLit>()) || ($2 && $2->isa<FloatLit>())) {
1069 $$ = $2;
1070 } else {
1071 $$=new UnOp(@$, UOT_PLUS, $2);
1072 }
1073 }
1074 | MZN_MINUS expr %prec MZN_NOT
1075 { if ($2 && $2->isa<IntLit>()) {
1076 $$ = IntLit::a(-$2->cast<IntLit>()->v());
1077 } else if ($2 && $2->isa<FloatLit>()) {
1078 $$ = FloatLit::a(-$2->cast<FloatLit>()->v());
1079 } else {
1080 $$=new UnOp(@$, UOT_MINUS, $2);
1081 }
1082 }
1083
1084
1085expr_atom_head :
1086 expr_atom_head_nonstring
1087 { $$=$1; }
1088 | string_expr
1089 { $$=$1; }
1090
1091expr_atom_head_nonstring :
1092 '(' expr ')'
1093 { $$=$2; }
1094 | '(' expr ')' array_access_tail
1095 { if ($4) $$=createArrayAccess(@$, $2, *$4); delete $4; }
1096 | '(' expr ')' MZN_POW_MINUS1
1097 { $$=new BinOp(@$, $2, BOT_POW, IntLit::a(-1)); }
1098 | '(' expr ')' array_access_tail MZN_POW_MINUS1
1099 { if ($4) $$=new BinOp(@$,createArrayAccess(@$, $2, *$4), BOT_POW, IntLit::a(-1)); delete $4; }
1100 | MZN_IDENTIFIER
1101 { $$=new Id(@$, $1, nullptr); free($1); }
1102 | MZN_IDENTIFIER array_access_tail
1103 { if ($2) $$=createArrayAccess(@$, new Id(@1,$1,nullptr), *$2);
1104 free($1); delete $2; }
1105 | MZN_IDENTIFIER MZN_POW_MINUS1
1106 { $$=new BinOp(@$,new Id(@$, $1, nullptr), BOT_POW, IntLit::a(-1)); free($1); }
1107 | MZN_IDENTIFIER array_access_tail MZN_POW_MINUS1
1108 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, new Id(@1,$1,nullptr), *$2), BOT_POW, IntLit::a(-1));
1109 free($1); delete $2; }
1110 | MZN_UNDERSCORE
1111 { $$=new AnonVar(@$); }
1112 | MZN_UNDERSCORE array_access_tail
1113 { if ($2) $$=createArrayAccess(@$, new AnonVar(@$), *$2);
1114 delete $2; }
1115 | MZN_UNDERSCORE MZN_POW_MINUS1
1116 { $$=new BinOp(@$,new AnonVar(@$), BOT_POW, IntLit::a(-1)); }
1117 | MZN_UNDERSCORE array_access_tail MZN_POW_MINUS1
1118 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, new AnonVar(@$), *$2), BOT_POW, IntLit::a(-1));
1119 delete $2; }
1120 | MZN_BOOL_LITERAL
1121 { $$=constants().boollit(($1!=0)); }
1122 | MZN_BOOL_LITERAL MZN_POW_MINUS1
1123 { $$=new BinOp(@$,constants().boollit(($1!=0)), BOT_POW, IntLit::a(-1)); }
1124 | MZN_INTEGER_LITERAL
1125 { $$=IntLit::a($1); }
1126 | MZN_INTEGER_LITERAL MZN_POW_MINUS1
1127 { $$=new BinOp(@$,IntLit::a($1), BOT_POW, IntLit::a(-1)); }
1128 | MZN_INFINITY
1129 { $$=IntLit::a(IntVal::infinity()); }
1130 | MZN_INFINITY MZN_POW_MINUS1
1131 { $$=new BinOp(@$,IntLit::a(IntVal::infinity()), BOT_POW, IntLit::a(-1)); }
1132 | MZN_FLOAT_LITERAL
1133 { $$=FloatLit::a($1); }
1134 | MZN_FLOAT_LITERAL MZN_POW_MINUS1
1135 { $$=new BinOp(@$,FloatLit::a($1), BOT_POW, IntLit::a(-1)); }
1136 | MZN_ABSENT
1137 { $$=constants().absent; }
1138 | MZN_ABSENT MZN_POW_MINUS1
1139 { $$=constants().absent; }
1140 | set_literal
1141 | set_literal array_access_tail
1142 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1143 delete $2; }
1144 | set_literal MZN_POW_MINUS1
1145 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1146 | set_literal array_access_tail MZN_POW_MINUS1
1147 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1148 delete $2; }
1149 | set_comp
1150 | set_comp array_access_tail
1151 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1152 delete $2; }
1153 | set_comp MZN_POW_MINUS1
1154 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1155 | set_comp array_access_tail MZN_POW_MINUS1
1156 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1157 delete $2; }
1158 | simple_array_literal
1159 | simple_array_literal array_access_tail
1160 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1161 delete $2; }
1162 | simple_array_literal MZN_POW_MINUS1
1163 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1164 | simple_array_literal array_access_tail MZN_POW_MINUS1
1165 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1166 delete $2; }
1167 | simple_array_literal_2d
1168 | simple_array_literal_2d array_access_tail
1169 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1170 delete $2; }
1171 | simple_array_literal_2d MZN_POW_MINUS1
1172 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1173 | simple_array_literal_2d array_access_tail MZN_POW_MINUS1
1174 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1175 delete $2; }
1176 | simple_array_comp
1177 | simple_array_comp array_access_tail
1178 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1179 delete $2; }
1180 | simple_array_comp MZN_POW_MINUS1
1181 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1182 | simple_array_comp array_access_tail MZN_POW_MINUS1
1183 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1184 delete $2; }
1185 | if_then_else_expr
1186 | if_then_else_expr array_access_tail
1187 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1188 delete $2; }
1189 | if_then_else_expr MZN_POW_MINUS1
1190 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1191 | if_then_else_expr array_access_tail MZN_POW_MINUS1
1192 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1193 delete $2; }
1194 | let_expr
1195 | call_expr
1196 | call_expr array_access_tail
1197 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1198 delete $2; }
1199 | call_expr MZN_POW_MINUS1
1200 | call_expr array_access_tail MZN_POW_MINUS1
1201 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1202 delete $2; }
1203
1204string_expr:
1205 MZN_STRING_LITERAL
1206 { $$=new StringLit(@$, $1); free($1); }
1207 | MZN_STRING_QUOTE_START string_quote_rest
1208 { $$=new BinOp(@$, new StringLit(@$, $1), BOT_PLUSPLUS, $2);
1209 free($1);
1210 }
1211
1212string_quote_rest:
1213 expr_list_head MZN_STRING_QUOTE_END
1214 { if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS, new StringLit(@$,$2));
1215 free($2);
1216 delete $1;
1217 }
1218 | expr_list_head MZN_STRING_QUOTE_MID string_quote_rest
1219 { if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS,
1220 new BinOp(@$, new StringLit(@$,$2), BOT_PLUSPLUS, $3));
1221 free($2);
1222 delete $1;
1223 }
1224
1225array_access_tail :
1226 MZN_LEFT_BRACKET array_access_expr_list MZN_RIGHT_BRACKET
1227 { $$=new std::vector<std::vector<Expression*> >();
1228 if ($2) {
1229 $$->push_back(*$2);
1230 delete $2;
1231 }
1232 }
1233 | array_access_tail MZN_LEFT_BRACKET array_access_expr_list MZN_RIGHT_BRACKET
1234 { $$=$1;
1235 if ($$ && $3) {
1236 $$->push_back(*$3);
1237 delete $3;
1238 }
1239 }
1240
1241set_literal :
1242 '{' '}'
1243 { $$ = new SetLit(@$, std::vector<Expression*>()); }
1244 | '{' expr_list '}'
1245 { if ($2) $$ = new SetLit(@$, *$2);
1246 delete $2; }
1247
1248set_comp :
1249 '{' expr '|' comp_tail '}'
1250 { if ($4) $$ = new Comprehension(@$, $2, *$4, true);
1251 delete $4;
1252 }
1253
1254comp_tail :
1255 generator_list
1256 { if ($1) $$=new Generators; $$->g = *$1; delete $1; }
1257
1258generator_list : generator_list_head comma_or_none
1259
1260generator_list_head :
1261 generator
1262 { $$=new std::vector<Generator>; if ($1) $$->push_back(*$1); delete $1; }
1263 | generator_eq
1264 { $$=new std::vector<Generator>; if ($1) $$->push_back(*$1); delete $1; }
1265 | generator_eq MZN_WHERE expr
1266 { $$=new std::vector<Generator>;
1267 if ($1) $$->push_back(*$1);
1268 if ($1 && $3) $$->push_back(Generator($$->size(),$3));
1269 delete $1;
1270 }
1271 | generator_list_head ',' generator
1272 { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
1273 | generator_list_head ',' generator_eq
1274 { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
1275 | generator_list_head ',' generator_eq MZN_WHERE expr
1276 { $$=$1;
1277 if ($$ && $3) $$->push_back(*$3);
1278 if ($$ && $3 && $5) $$->push_back(Generator($$->size(),$5));
1279 delete $3;
1280 }
1281
1282generator :
1283 id_list MZN_IN expr
1284 { if ($1 && $3) $$=new Generator(*$1,$3,nullptr); else $$=nullptr; delete $1; }
1285 | id_list MZN_IN expr MZN_WHERE expr
1286 { if ($1 && $3) $$=new Generator(*$1,$3,$5); else $$=nullptr; delete $1; }
1287generator_eq :
1288 MZN_IDENTIFIER MZN_EQ expr
1289 { if ($3) $$=new Generator({$1},nullptr,$3); else $$=nullptr; free($1); }
1290
1291id_list : id_list_head comma_or_none
1292
1293id_list_head :
1294 MZN_IDENTIFIER
1295 { $$=new std::vector<std::string>; $$->push_back($1); free($1); }
1296 | id_list_head ',' MZN_IDENTIFIER
1297 { $$=$1; if ($$ && $3) $$->push_back($3); free($3); }
1298
1299simple_array_literal :
1300 MZN_LEFT_BRACKET MZN_RIGHT_BRACKET
1301 { $$=new ArrayLit(@$, std::vector<MiniZinc::Expression*>()); }
1302 | MZN_LEFT_BRACKET expr_list MZN_RIGHT_BRACKET
1303 { if ($2) $$=new ArrayLit(@$, *$2); delete $2; }
1304
1305simple_array_literal_2d :
1306 MZN_LEFT_2D_BRACKET MZN_RIGHT_2D_BRACKET
1307 { $$=new ArrayLit(@$, std::vector<std::vector<Expression*> >()); }
1308 | MZN_LEFT_2D_BRACKET simple_array_literal_2d_list MZN_RIGHT_2D_BRACKET
1309 { if ($2) {
1310 $$=new ArrayLit(@$, *$2);
1311 for (unsigned int i=1; i<$2->size(); i++)
1312 if ((*$2)[i].size() != (*$2)[i-1].size())
1313 yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length");
1314 delete $2;
1315 } else {
1316 $$ = nullptr;
1317 }
1318 }
1319 | MZN_LEFT_2D_BRACKET simple_array_literal_2d_list '|' MZN_RIGHT_2D_BRACKET
1320 { if ($2) {
1321 $$=new ArrayLit(@$, *$2);
1322 for (unsigned int i=1; i<$2->size(); i++)
1323 if ((*$2)[i].size() != (*$2)[i-1].size())
1324 yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length");
1325 delete $2;
1326 } else {
1327 $$ = nullptr;
1328 }
1329 }
1330 | MZN_LEFT_2D_BRACKET simple_array_literal_3d_list MZN_RIGHT_2D_BRACKET
1331 {
1332 if ($2) {
1333 std::vector<std::pair<int,int> > dims(3);
1334 dims[0] = std::pair<int,int>(1,static_cast<int>($2->size()));
1335 if ($2->size()==0) {
1336 dims[1] = std::pair<int,int>(1,0);
1337 dims[2] = std::pair<int,int>(1,0);
1338 } else {
1339 dims[1] = std::pair<int,int>(1,static_cast<int>((*$2)[0].size()));
1340 if ((*$2)[0].size()==0) {
1341 dims[2] = std::pair<int,int>(1,0);
1342 } else {
1343 dims[2] = std::pair<int,int>(1,static_cast<int>((*$2)[0][0].size()));
1344 }
1345 }
1346 std::vector<Expression*> a;
1347 for (int i=0; i<dims[0].second; i++) {
1348 if ((*$2)[i].size() != dims[1].second) {
1349 yyerror(&@2, parm, "syntax error, all sub-arrays of 3d array literal must have the same length");
1350 } else {
1351 for (int j=0; j<dims[1].second; j++) {
1352 if ((*$2)[i][j].size() != dims[2].second) {
1353 yyerror(&@2, parm, "syntax error, all sub-arrays of 3d array literal must have the same length");
1354 } else {
1355 for (int k=0; k<dims[2].second; k++) {
1356 a.push_back((*$2)[i][j][k]);
1357 }
1358 }
1359 }
1360 }
1361 }
1362 $$ = new ArrayLit(@$,a,dims);
1363 delete $2;
1364 } else {
1365 $$ = nullptr;
1366 }
1367 }
1368
1369simple_array_literal_3d_list :
1370 '|' '|'
1371 { $$=new std::vector<std::vector<std::vector<MiniZinc::Expression*> > >;
1372 }
1373 | '|' simple_array_literal_2d_list '|'
1374 { $$=new std::vector<std::vector<std::vector<MiniZinc::Expression*> > >;
1375 if ($2) $$->push_back(*$2);
1376 delete $2;
1377 }
1378 | simple_array_literal_3d_list ',' '|' simple_array_literal_2d_list '|'
1379 { $$=$1;
1380 if ($$ && $4) $$->push_back(*$4);
1381 delete $4;
1382 }
1383
1384simple_array_literal_2d_list :
1385 expr_list
1386 { $$=new std::vector<std::vector<MiniZinc::Expression*> >;
1387 if ($1) $$->push_back(*$1);
1388 delete $1;
1389 }
1390 | simple_array_literal_2d_list '|' expr_list
1391 { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
1392
1393simple_array_comp :
1394 MZN_LEFT_BRACKET expr '|' comp_tail MZN_RIGHT_BRACKET
1395 { if ($4) $$=new Comprehension(@$, $2, *$4, false);
1396 delete $4;
1397 }
1398
1399if_then_else_expr :
1400 MZN_IF expr MZN_THEN expr MZN_ENDIF
1401 {
1402 std::vector<Expression*> iexps;
1403 iexps.push_back($2);
1404 iexps.push_back($4);
1405 $$=new ITE(@$, iexps, nullptr);
1406 }
1407 | MZN_IF expr MZN_THEN expr elseif_list MZN_ELSE expr MZN_ENDIF
1408 {
1409 std::vector<Expression*> iexps;
1410 iexps.push_back($2);
1411 iexps.push_back($4);
1412 if ($5) {
1413 for (unsigned int i=0; i<$5->size(); i+=2) {
1414 iexps.push_back((*$5)[i]);
1415 iexps.push_back((*$5)[i+1]);
1416 }
1417 }
1418 $$=new ITE(@$, iexps,$7);
1419 delete $5;
1420 }
1421
1422elseif_list :
1423 { $$=new std::vector<MiniZinc::Expression*>; }
1424 | elseif_list MZN_ELSEIF expr MZN_THEN expr
1425 { $$=$1; if ($$ && $3 && $5) { $$->push_back($3); $$->push_back($5); } }
1426
1427quoted_op :
1428 MZN_EQUIV_QUOTED
1429 { $$=BOT_EQUIV; }
1430 | MZN_IMPL_QUOTED
1431 { $$=BOT_IMPL; }
1432 | MZN_RIMPL_QUOTED
1433 { $$=BOT_RIMPL; }
1434 | MZN_OR_QUOTED
1435 { $$=BOT_OR; }
1436 | MZN_XOR_QUOTED
1437 { $$=BOT_XOR; }
1438 | MZN_AND_QUOTED
1439 { $$=BOT_AND; }
1440 | MZN_LE_QUOTED
1441 { $$=BOT_LE; }
1442 | MZN_GR_QUOTED
1443 { $$=BOT_GR; }
1444 | MZN_LQ_QUOTED
1445 { $$=BOT_LQ; }
1446 | MZN_GQ_QUOTED
1447 { $$=BOT_GQ; }
1448 | MZN_EQ_QUOTED
1449 { $$=BOT_EQ; }
1450 | MZN_NQ_QUOTED
1451 { $$=BOT_NQ; }
1452 | MZN_IN_QUOTED
1453 { $$=BOT_IN; }
1454 | MZN_SUBSET_QUOTED
1455 { $$=BOT_SUBSET; }
1456 | MZN_SUPERSET_QUOTED
1457 { $$=BOT_SUPERSET; }
1458 | MZN_UNION_QUOTED
1459 { $$=BOT_UNION; }
1460 | MZN_DIFF_QUOTED
1461 { $$=BOT_DIFF; }
1462 | MZN_SYMDIFF_QUOTED
1463 { $$=BOT_SYMDIFF; }
1464 | MZN_PLUS_QUOTED
1465 { $$=BOT_PLUS; }
1466 | MZN_MINUS_QUOTED
1467 { $$=BOT_MINUS; }
1468 | MZN_MULT_QUOTED
1469 { $$=BOT_MULT; }
1470 | MZN_POW_QUOTED
1471 { $$=BOT_POW; }
1472 | MZN_DIV_QUOTED
1473 { $$=BOT_DIV; }
1474 | MZN_IDIV_QUOTED
1475 { $$=BOT_IDIV; }
1476 | MZN_MOD_QUOTED
1477 { $$=BOT_MOD; }
1478 | MZN_INTERSECT_QUOTED
1479 { $$=BOT_INTERSECT; }
1480 | MZN_PLUSPLUS_QUOTED
1481 { $$=BOT_PLUSPLUS; }
1482 | MZN_NOT_QUOTED
1483 { $$=-1; }
1484
1485quoted_op_call :
1486 quoted_op '(' expr ',' expr ')'
1487 { if ($1==-1) {
1488 $$=nullptr;
1489 yyerror(&@3, parm, "syntax error, unary operator with two arguments");
1490 } else {
1491 $$=new BinOp(@$, $3,static_cast<BinOpType>($1),$5);
1492 }
1493 }
1494 | quoted_op '(' expr ')'
1495 { int uot=-1;
1496 switch ($1) {
1497 case -1:
1498 uot = UOT_NOT;
1499 break;
1500 case BOT_MINUS:
1501 uot = UOT_MINUS;
1502 break;
1503 case BOT_PLUS:
1504 uot = UOT_PLUS;
1505 break;
1506 default:
1507 yyerror(&@3, parm, "syntax error, binary operator with unary argument list");
1508 break;
1509 }
1510 if (uot==-1)
1511 $$=nullptr;
1512 else {
1513 if (uot==UOT_PLUS && $3 && ($3->isa<IntLit>() || $3->isa<FloatLit>())) {
1514 $$ = $3;
1515 } else if (uot==UOT_MINUS && $3 && $3->isa<IntLit>()) {
1516 $$ = IntLit::a(-$3->cast<IntLit>()->v());
1517 } else if (uot==UOT_MINUS && $3 && $3->isa<FloatLit>()) {
1518 $$ = FloatLit::a(-$3->cast<FloatLit>()->v());
1519 } else {
1520 $$=new UnOp(@$, static_cast<UnOpType>(uot),$3);
1521 }
1522 }
1523 }
1524
1525call_expr :
1526 MZN_IDENTIFIER '(' ')'
1527 { $$=new Call(@$, $1, std::vector<Expression*>()); free($1); }
1528 | MZN_IDENTIFIER MZN_POW_MINUS1 '(' ')'
1529 { $$=new Call(@$, std::string($1)+"⁻¹", std::vector<Expression*>()); free($1); }
1530 | quoted_op_call
1531 | MZN_IDENTIFIER '(' comp_or_expr ')'
1532 {
1533 if ($3!=nullptr) {
1534 bool hadWhere = false;
1535 std::vector<Expression*> args;
1536 for (unsigned int i=0; i<$3->size(); i++) {
1537 if ((*$3)[i].second) {
1538 yyerror(&@3, parm, "syntax error, 'where' expression outside generator call");
1539 hadWhere = true;
1540 $$=nullptr;
1541 }
1542 args.push_back((*$3)[i].first);
1543 }
1544 if (!hadWhere) {
1545 $$=new Call(@$, $1, args);
1546 }
1547 }
1548 free($1);
1549 delete $3;
1550 }
1551 | MZN_IDENTIFIER '(' comp_or_expr ')' '(' expr ')'
1552 {
1553 vector<Generator> gens;
1554 vector<Id*> ids;
1555 if ($3) {
1556 for (unsigned int i=0; i<$3->size(); i++) {
1557 if (Id* id = Expression::dynamicCast<Id>((*$3)[i].first)) {
1558 if ((*$3)[i].second) {
1559 ParserLocation loc = (*$3)[i].second->loc().parserLocation();
1560 yyerror(&loc, parm, "illegal where expression in generator call");
1561 }
1562 ids.push_back(id);
1563 } else {
1564 if (BinOp* boe = Expression::dynamicCast<BinOp>((*$3)[i].first)) {
1565 if (boe->lhs() && boe->rhs()) {
1566 Id* id = Expression::dynamicCast<Id>(boe->lhs());
1567 if (id && boe->op() == BOT_IN) {
1568 ids.push_back(id);
1569 gens.push_back(Generator(ids,boe->rhs(),(*$3)[i].second));
1570 ids = vector<Id*>();
1571 } else if (id && boe->op() == BOT_EQ && ids.empty()) {
1572 ids.push_back(id);
1573 gens.push_back(Generator(ids,nullptr,boe->rhs()));
1574 if ((*$3)[i].second) {
1575 gens.push_back(Generator(gens.size(),(*$3)[i].second));
1576 }
1577 ids = vector<Id*>();
1578 } else {
1579 ParserLocation loc = (*$3)[i].first->loc().parserLocation();
1580 yyerror(&loc, parm, "illegal expression in generator call");
1581 }
1582 }
1583 } else {
1584 ParserLocation loc = (*$3)[i].first->loc().parserLocation();
1585 yyerror(&loc, parm, "illegal expression in generator call");
1586 }
1587 }
1588 }
1589 }
1590 if (ids.size() != 0) {
1591 yyerror(&@3, parm, "illegal expression in generator call");
1592 }
1593 ParserState* pp = static_cast<ParserState*>(parm);
1594 if (pp->hadError) {
1595 $$=nullptr;
1596 } else {
1597 Generators g; g.g = gens;
1598 Comprehension* ac = new Comprehension(@$, $6,g,false);
1599 vector<Expression*> args; args.push_back(ac);
1600 $$=new Call(@$, $1, args);
1601 }
1602 free($1);
1603 delete $3;
1604 }
1605 | MZN_IDENTIFIER MZN_POW_MINUS1 '(' comp_or_expr ')'
1606 {
1607 if ($4!=nullptr) {
1608 bool hadWhere = false;
1609 std::vector<Expression*> args;
1610 for (unsigned int i=0; i<$4->size(); i++) {
1611 if ((*$4)[i].second) {
1612 yyerror(&@4, parm, "syntax error, 'where' expression outside generator call");
1613 hadWhere = true;
1614 $$=nullptr;
1615 }
1616 args.push_back((*$4)[i].first);
1617 }
1618 if (!hadWhere) {
1619 $$=new Call(@$, std::string($1)+"⁻¹", args);
1620 }
1621 }
1622 free($1);
1623 delete $4;
1624 }
1625 | MZN_IDENTIFIER MZN_POW_MINUS1 '(' comp_or_expr ')' '(' expr ')'
1626 {
1627 vector<Generator> gens;
1628 vector<Id*> ids;
1629 if ($4) {
1630 for (unsigned int i=0; i<$4->size(); i++) {
1631 if (Id* id = Expression::dynamicCast<Id>((*$4)[i].first)) {
1632 if ((*$4)[i].second) {
1633 ParserLocation loc = (*$4)[i].second->loc().parserLocation();
1634 yyerror(&loc, parm, "illegal where expression in generator call");
1635 }
1636 ids.push_back(id);
1637 } else {
1638 if (BinOp* boe = Expression::dynamicCast<BinOp>((*$4)[i].first)) {
1639 if (boe->lhs() && boe->rhs()) {
1640 Id* id = Expression::dynamicCast<Id>(boe->lhs());
1641 if (id && boe->op() == BOT_IN) {
1642 ids.push_back(id);
1643 gens.push_back(Generator(ids,boe->rhs(),(*$4)[i].second));
1644 ids = vector<Id*>();
1645 } else if (id && boe->op() == BOT_EQ && ids.empty()) {
1646 ids.push_back(id);
1647 gens.push_back(Generator(ids,nullptr,boe->rhs()));
1648 if ((*$4)[i].second) {
1649 gens.push_back(Generator(gens.size(),(*$4)[i].second));
1650 }
1651 ids = vector<Id*>();
1652 } else {
1653 ParserLocation loc = (*$4)[i].first->loc().parserLocation();
1654 yyerror(&loc, parm, "illegal expression in generator call");
1655 }
1656 }
1657 } else {
1658 ParserLocation loc = (*$4)[i].first->loc().parserLocation();
1659 yyerror(&loc, parm, "illegal expression in generator call");
1660 }
1661 }
1662 }
1663 }
1664 if (ids.size() != 0) {
1665 yyerror(&@4, parm, "illegal expression in generator call");
1666 }
1667 ParserState* pp = static_cast<ParserState*>(parm);
1668 if (pp->hadError) {
1669 $$=nullptr;
1670 } else {
1671 Generators g; g.g = gens;
1672 Comprehension* ac = new Comprehension(@$, $7,g,false);
1673 vector<Expression*> args; args.push_back(ac);
1674 $$=new Call(@$, std::string($1)+"⁻¹", args);
1675 }
1676 free($1);
1677 delete $4;
1678 }
1679
1680comp_or_expr : comp_or_expr_head comma_or_none
1681
1682comp_or_expr_head :
1683 expr
1684 { $$=new vector<pair<Expression*,Expression*> >;
1685 if ($1) {
1686 $$->push_back(pair<Expression*,Expression*>($1,nullptr));
1687 }
1688 }
1689 | expr MZN_WHERE expr
1690 { $$=new vector<pair<Expression*,Expression*> >;
1691 if ($1 && $3) {
1692 $$->push_back(pair<Expression*,Expression*>($1,$3));
1693 }
1694 }
1695 | comp_or_expr_head ',' expr
1696 { $$=$1; if ($$ && $3) $$->push_back(pair<Expression*,Expression*>($3,nullptr)); }
1697 | comp_or_expr_head ',' expr MZN_WHERE expr
1698 { $$=$1; if ($$ && $3 && $5) $$->push_back(pair<Expression*,Expression*>($3,$5)); }
1699
1700let_expr :
1701 MZN_LET '{' let_vardecl_item_list '}' MZN_IN expr %prec PREC_ANNO
1702 { if ($3 && $6) {
1703 $$=new Let(@$, *$3, $6); delete $3;
1704 } else {
1705 $$=nullptr;
1706 }
1707 }
1708 | MZN_LET '{' let_vardecl_item_list comma_or_semi '}' MZN_IN expr %prec PREC_ANNO
1709 { if ($3 && $7) {
1710 $$=new Let(@$, *$3, $7); delete $3;
1711 } else {
1712 $$=nullptr;
1713 }
1714 }
1715
1716let_vardecl_item_list :
1717 let_vardecl_item
1718 { $$=new vector<Expression*>; $$->push_back($1); }
1719 | constraint_item
1720 { $$=new vector<Expression*>;
1721 if ($1) {
1722 ConstraintI* ce = $1->cast<ConstraintI>();
1723 $$->push_back(ce->e());
1724 ce->e(nullptr);
1725 }
1726 }
1727 | let_vardecl_item_list comma_or_semi let_vardecl_item
1728 { $$=$1; if ($$ && $3) $$->push_back($3); }
1729 | let_vardecl_item_list comma_or_semi constraint_item
1730 { $$=$1;
1731 if ($$ && $3) {
1732 ConstraintI* ce = $3->cast<ConstraintI>();
1733 $$->push_back(ce->e());
1734 ce->e(nullptr);
1735 }
1736 }
1737
1738comma_or_semi : ',' | ';'
1739
1740let_vardecl_item :
1741 ti_expr_and_id
1742 { $$ = $1;
1743 if ($$) $$->toplevel(false);
1744 }
1745 | ti_expr_and_id MZN_EQ expr
1746 { if ($1) $1->e($3);
1747 $$ = $1;
1748 if ($$) $$->loc(@$);
1749 if ($$) $$->toplevel(false);
1750 }
1751
1752annotations :
1753 /* empty */
1754 { $$=nullptr; }
1755 | ne_annotations
1756
1757annotation_expr :
1758 expr_atom_head_nonstring
1759 { $$ = $1; }
1760 | string_expr
1761 { $$ = new Call(@1, ASTString("mzn_expression_name"), {$1}); }
1762
1763ne_annotations :
1764 MZN_COLONCOLON annotation_expr
1765 { $$=new std::vector<Expression*>(1);
1766 (*$$)[0] = $2;
1767 }
1768 | ne_annotations MZN_COLONCOLON annotation_expr
1769 { $$=$1; if ($$) $$->push_back($3); }
1770
1771id_or_quoted_op :
1772 MZN_IDENTIFIER
1773 { $$=$1; }
1774 | MZN_IDENTIFIER MZN_POW_MINUS1
1775 { $$=strdup((std::string($1)+"⁻¹").c_str()); }
1776 | MZN_EQUIV_QUOTED
1777 { $$=strdup("'<->'"); }
1778 | MZN_IMPL_QUOTED
1779 { $$=strdup("'->'"); }
1780 | MZN_RIMPL_QUOTED
1781 { $$=strdup("'<-'"); }
1782 | MZN_OR_QUOTED
1783 { $$=strdup("'\\/'"); }
1784 | MZN_XOR_QUOTED
1785 { $$=strdup("'xor'"); }
1786 | MZN_AND_QUOTED
1787 { $$=strdup("'/\\'"); }
1788 | MZN_LE_QUOTED
1789 { $$=strdup("'<'"); }
1790 | MZN_GR_QUOTED
1791 { $$=strdup("'>'"); }
1792 | MZN_LQ_QUOTED
1793 { $$=strdup("'<='"); }
1794 | MZN_GQ_QUOTED
1795 { $$=strdup("'>='"); }
1796 | MZN_EQ_QUOTED
1797 { $$=strdup("'='"); }
1798 | MZN_NQ_QUOTED
1799 { $$=strdup("'!='"); }
1800 | MZN_IN_QUOTED
1801 { $$=strdup("'in'"); }
1802 | MZN_SUBSET_QUOTED
1803 { $$=strdup("'subset'"); }
1804 | MZN_SUPERSET_QUOTED
1805 { $$=strdup("'superset'"); }
1806 | MZN_UNION_QUOTED
1807 { $$=strdup("'union'"); }
1808 | MZN_DIFF_QUOTED
1809 { $$=strdup("'diff'"); }
1810 | MZN_SYMDIFF_QUOTED
1811 { $$=strdup("'symdiff'"); }
1812 | MZN_DOTDOT_QUOTED
1813 { $$=strdup("'..'"); }
1814 | MZN_PLUS_QUOTED
1815 { $$=strdup("'+'"); }
1816 | MZN_MINUS_QUOTED
1817 { $$=strdup("'-'"); }
1818 | MZN_MULT_QUOTED
1819 { $$=strdup("'*'"); }
1820 | MZN_POW_QUOTED
1821 { $$=strdup("'^'"); }
1822 | MZN_DIV_QUOTED
1823 { $$=strdup("'/'"); }
1824 | MZN_IDIV_QUOTED
1825 { $$=strdup("'div'"); }
1826 | MZN_MOD_QUOTED
1827 { $$=strdup("'mod'"); }
1828 | MZN_INTERSECT_QUOTED
1829 { $$=strdup("'intersect'"); }
1830 | MZN_NOT_QUOTED
1831 { $$=strdup("'not'"); }
1832 | MZN_PLUSPLUS_QUOTED
1833 { $$=strdup("'++'"); }