this repo has no description
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
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 map<string,Model*>::iterator ret = pp->seenModels.find($2);
399 IncludeI* ii = new IncludeI(@$,ASTString($2));
400 $$ = ii;
401 if (ret == pp->seenModels.end()) {
402 Model* im = new Model;
403 im->setParent(pp->model);
404 im->setFilename($2);
405 string fpath = FileUtils::dir_name(pp->filename);
406 string fbase = FileUtils::base_name(pp->filename);
407 if (fpath=="")
408 fpath="./";
409 pp->files.emplace_back(im, ii, fpath, $2, pp->isSTDLib);
410 ii->m(im);
411 pp->seenModels.insert(pair<string,Model*>($2,im));
412 } else {
413 ii->m(ret->second, false);
414 }
415 free($2);
416 }
417
418vardecl_item :
419 ti_expr_and_id annotations
420 { if ($1 && $2) $1->addAnnotations(*$2);
421 if ($1)
422 $$ = new VarDeclI(@$,$1);
423 delete $2;
424 }
425 | ti_expr_and_id annotations MZN_EQ expr
426 { if ($1) $1->e($4);
427 if ($1 && $2) $1->addAnnotations(*$2);
428 if ($1)
429 $$ = new VarDeclI(@$,$1);
430 delete $2;
431 }
432 | MZN_ENUM MZN_IDENTIFIER annotations
433 {
434 TypeInst* ti = new TypeInst(@$,Type::parsetint());
435 ti->setIsEnum(true);
436 VarDecl* vd = new VarDecl(@$,ti,$2);
437 if ($2 && $3)
438 vd->addAnnotations(*$3);
439 free($2);
440 $$ = new VarDeclI(@$,vd);
441 }
442 | MZN_ENUM MZN_IDENTIFIER annotations MZN_EQ enum_init
443 {
444 if ($5) {
445 TypeInst* ti = new TypeInst(@$,Type::parsetint());
446 ti->setIsEnum(true);
447 Expression* e;
448 if ($5->size()==1) {
449 e = (*$5)[0];
450 } else {
451 ArrayLit* al = new ArrayLit(@$,*$5);
452 e = new Call(@$, ASTString("enumFromConstructors"), {al});
453 }
454 VarDecl* vd = new VarDecl(@$,ti,$2,e);
455 $$ = new VarDeclI(@$,vd);
456 }
457 free($2);
458 delete $5;
459 }
460 | MZN_ENUM MZN_IDENTIFIER annotations MZN_EQ MZN_LEFT_BRACKET string_lit_list MZN_RIGHT_BRACKET
461 {
462 TypeInst* ti = new TypeInst(@$,Type::parsetint());
463 ti->setIsEnum(true);
464 vector<Expression*> args;
465 args.push_back(new ArrayLit(@$,*$6));
466 Call* sl = new Call(@$, constants().ids.anonEnumFromStrings, args);
467 VarDecl* vd = new VarDecl(@$,ti,$2,sl);
468 if ($2 && $3)
469 vd->addAnnotations(*$3);
470 free($2);
471 delete $6;
472 $$ = new VarDeclI(@$,vd);
473 }
474
475enum_init :
476 enum_construct
477 {
478 $$ = new std::vector<Expression*>({$1});
479 }
480 | enum_init MZN_PLUSPLUS enum_construct
481 {
482 $$ = $1;
483 if ($$) {
484 $$->push_back($3);
485 }
486 }
487
488enum_construct :
489 '{' enum_id_list '}'
490 {
491 $$ = new SetLit(@$, *$2);
492 delete $2;
493 }
494 | MZN_IDENTIFIER '(' expr ')'
495 {
496 vector<Expression*> args({$3});
497 $$ = new Call(@$, ASTString($1), args);
498 free($1);
499 }
500
501string_lit_list :
502 // empty
503 { $$ = new std::vector<Expression*>(); }
504 | MZN_STRING_LITERAL
505 { $$ = new std::vector<Expression*>();
506 $$->push_back(new StringLit(@$, $1)); free($1);
507 }
508 | string_lit_list ',' MZN_STRING_LITERAL
509 { $$ = $1;
510 if ($$) $$->push_back(new StringLit(@$, $3));
511 free($3);
512 }
513
514enum_id_list :
515 // empty
516 { $$ = new std::vector<Expression*>(); }
517 | MZN_IDENTIFIER
518 { $$ = new std::vector<Expression*>();
519 $$->push_back(new Id(@$,$1,nullptr)); free($1);
520 }
521 | enum_id_list ',' MZN_IDENTIFIER
522 { $$ = $1; if ($$) $$->push_back(new Id(@$,$3,nullptr)); free($3); }
523
524assign_item :
525 MZN_IDENTIFIER MZN_EQ expr
526 { $$ = new AssignI(@$,$1,$3);
527 free($1);
528 }
529
530constraint_item :
531 MZN_CONSTRAINT expr
532 { $$ = new ConstraintI(@$,$2);}
533 | MZN_CONSTRAINT MZN_COLONCOLON string_expr expr
534 { $$ = new ConstraintI(@$,$4);
535 if ($4 && $3)
536 $$->cast<ConstraintI>()->e()->ann().add(new Call(@2, ASTString("mzn_constraint_name"), {$3}));
537 }
538
539solve_item :
540 MZN_SOLVE annotations MZN_SATISFY
541 { $$ = SolveI::sat(@$);
542 if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
543 delete $2;
544 }
545 | MZN_SOLVE annotations MZN_MINIMIZE expr
546 { $$ = SolveI::min(@$,$4);
547 if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
548 delete $2;
549 }
550 | MZN_SOLVE annotations MZN_MAXIMIZE expr
551 { $$ = SolveI::max(@$,$4);
552 if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
553 delete $2;
554 }
555
556output_item :
557 MZN_OUTPUT expr
558 { $$ = new OutputI(@$,$2);}
559
560predicate_item :
561 MZN_PREDICATE MZN_IDENTIFIER params annotations operation_item_tail
562 {
563 ParserState* pp = static_cast<ParserState*>(parm);
564 if ($3) $$ = new FunctionI(@$,$2,new TypeInst(@$,
565 Type::varbool()),*$3,$5,pp->isSTDLib);
566 if ($$ && $4) $$->cast<FunctionI>()->ann().add(*$4);
567 free($2);
568 delete $3;
569 delete $4;
570 }
571 | MZN_TEST MZN_IDENTIFIER params annotations operation_item_tail
572 {
573 ParserState* pp = static_cast<ParserState*>(parm);
574 if ($3) $$ = new FunctionI(@$,$2,new TypeInst(@$,
575 Type::parbool()),*$3,$5,pp->isSTDLib);
576 if ($$ && $4) $$->cast<FunctionI>()->ann().add(*$4);
577 free($2);
578 delete $3;
579 delete $4;
580 }
581 | MZN_PREDICATE MZN_IDENTIFIER MZN_POW_MINUS1 params annotations operation_item_tail
582 { if ($4) $$ = new FunctionI(@$,std::string($2)+"⁻¹",new TypeInst(@$,
583 Type::varbool()),*$4,$6);
584 if ($$ && $5) $$->cast<FunctionI>()->ann().add(*$5);
585 free($2);
586 delete $4;
587 delete $5;
588 }
589 | MZN_TEST MZN_IDENTIFIER MZN_POW_MINUS1 params annotations operation_item_tail
590 { if ($4) $$ = new FunctionI(@$,std::string($2)+"⁻¹",new TypeInst(@$,
591 Type::parbool()),*$4,$6);
592 if ($$ && $5) $$->cast<FunctionI>()->ann().add(*$5);
593 free($2);
594 delete $4;
595 delete $5;
596 }
597
598function_item :
599 MZN_FUNCTION ti_expr ':' id_or_quoted_op params annotations operation_item_tail
600 {
601 ParserState* pp = static_cast<ParserState*>(parm);
602 if ($5) $$ = new FunctionI(@$,$4,$2,*$5,$7,pp->isSTDLib);
603 if ($$ && $6) $$->cast<FunctionI>()->ann().add(*$6);
604 free($4);
605 delete $5;
606 delete $6;
607 }
608 | ti_expr ':' MZN_IDENTIFIER '(' params_list ')' annotations operation_item_tail
609 {
610 ParserState* pp = static_cast<ParserState*>(parm);
611 if ($5) $$ = new FunctionI(@$,$3,$1,*$5,$8,pp->isSTDLib);
612 if ($$ && $7) $$->cast<FunctionI>()->ann().add(*$7);
613 free($3);
614 delete $5;
615 delete $7;
616 }
617
618annotation_item :
619 MZN_ANNOTATION MZN_IDENTIFIER params
620 {
621 ParserState* pp = static_cast<ParserState*>(parm);
622 TypeInst* ti=new TypeInst(@1,Type::ann());
623 if ($3==nullptr || $3->empty()) {
624 VarDecl* vd = new VarDecl(@$,ti,$2);
625 $$ = new VarDeclI(@$,vd);
626 } else {
627 $$ = new FunctionI(@$,$2,ti,*$3,nullptr,pp->isSTDLib);
628 }
629 free($2);
630 delete $3;
631 }
632 | MZN_ANNOTATION MZN_IDENTIFIER params MZN_EQ expr
633 {
634 ParserState* pp = static_cast<ParserState*>(parm);
635 TypeInst* ti=new TypeInst(@1,Type::ann());
636 if ($3) $$ = new FunctionI(@$,$2,ti,*$3,$5,pp->isSTDLib);
637 delete $3;
638 }
639
640operation_item_tail :
641 /*empty*/
642 { $$=nullptr; }
643 | MZN_EQ expr
644 { $$=$2; }
645
646params :
647 /* empty */
648 { $$=new vector<VarDecl*>(); }
649 | '(' params_list ')'
650 { $$=$2; }
651 | '(' error ')'
652 { $$=new vector<VarDecl*>(); }
653
654params_list :
655 /* empty */
656 { $$=new vector<VarDecl*>(); }
657 | params_list_head comma_or_none
658 { $$=$1; }
659
660params_list_head :
661 ti_expr_and_id_or_anon
662 { $$=new vector<VarDecl*>();
663 if ($1) $1->toplevel(false);
664 if ($1) $$->push_back($1); }
665 | params_list_head ',' ti_expr_and_id_or_anon
666 { $$=$1;
667 if ($3) $3->toplevel(false);
668 if ($1 && $3) $1->push_back($3); }
669
670comma_or_none : | ','
671
672ti_expr_and_id_or_anon :
673 ti_expr_and_id
674 { $$=$1; }
675 | ti_expr
676 { if ($1) $$=new VarDecl(@$, $1, ""); }
677
678ti_expr_and_id :
679 ti_expr ':' MZN_IDENTIFIER
680 { if ($1 && $3) {
681 Id* ident = new Id(@3, $3, nullptr);
682 $$ = new VarDecl(@$, $1, ident);
683 }
684 free($3);
685 }
686
687ti_expr_list : ti_expr_list_head comma_or_none
688 { $$=$1; }
689
690ti_expr_list_head :
691 ti_expr
692 { $$=new vector<TypeInst*>(); $$->push_back($1); }
693 | ti_expr_list_head ',' ti_expr
694 { $$=$1; if ($1 && $3) $1->push_back($3); }
695
696ti_expr :
697 base_ti_expr
698 | MZN_ARRAY MZN_LEFT_BRACKET ti_expr_list MZN_RIGHT_BRACKET MZN_OF base_ti_expr
699 {
700 $$ = $6;
701 if ($$ && $3) $$->setRanges(*$3);
702 delete $3;
703 }
704 | MZN_LIST MZN_OF base_ti_expr
705 {
706 $$ = $3;
707 std::vector<TypeInst*> ti(1);
708 ti[0] = new TypeInst(@$,Type::parint());
709 if ($$) $$->setRanges(ti);
710 }
711
712base_ti_expr :
713 base_ti_expr_tail
714 { $$ = $1;
715 }
716 | MZN_OPT base_ti_expr_tail
717 { $$ = $2;
718 if ($$) {
719 Type tt = $$->type();
720 tt.ot(Type::OT_OPTIONAL);
721 $$->type(tt);
722 }
723 }
724 | MZN_PAR opt_opt base_ti_expr_tail
725 { $$ = $3;
726 if ($$ && $2) {
727 Type tt = $$->type();
728 tt.ot(Type::OT_OPTIONAL);
729 $$->type(tt);
730 }
731 }
732 | MZN_VAR opt_opt base_ti_expr_tail
733 { $$ = $3;
734 if ($$) {
735 Type tt = $$->type();
736 tt.ti(Type::TI_VAR);
737 if ($2) tt.ot(Type::OT_OPTIONAL);
738 $$->type(tt);
739 }
740 }
741 | MZN_SET MZN_OF base_ti_expr_tail
742 { $$ = $3;
743 if ($$) {
744 Type tt = $$->type();
745 tt.st(Type::ST_SET);
746 $$->type(tt);
747 }
748 }
749 | MZN_OPT MZN_SET MZN_OF base_ti_expr_tail
750 { $$ = $4;
751 if ($$) {
752 Type tt = $$->type();
753 tt.st(Type::ST_SET);
754 tt.ot(Type::OT_OPTIONAL);
755 $$->type(tt);
756 }
757 }
758 | MZN_PAR opt_opt MZN_SET MZN_OF base_ti_expr_tail
759 { $$ = $5;
760 if ($$) {
761 Type tt = $$->type();
762 tt.st(Type::ST_SET);
763 if ($2) tt.ot(Type::OT_OPTIONAL);
764 $$->type(tt);
765 }
766 }
767 | MZN_VAR opt_opt MZN_SET MZN_OF base_ti_expr_tail
768 { $$ = $5;
769 if ($$) {
770 Type tt = $$->type();
771 tt.ti(Type::TI_VAR);
772 tt.st(Type::ST_SET);
773 if ($2) tt.ot(Type::OT_OPTIONAL);
774 $$->type(tt);
775 }
776 }
777
778opt_opt:
779 /* nothing */
780 { $$ = false; }
781 | MZN_OPT
782 { $$ = true; }
783
784base_ti_expr_tail :
785 MZN_INT
786 { $$ = new TypeInst(@$,Type::parint()); }
787 | MZN_BOOL
788 { $$ = new TypeInst(@$,Type::parbool()); }
789 | MZN_FLOAT
790 { $$ = new TypeInst(@$,Type::parfloat()); }
791 | MZN_STRING
792 { $$ = new TypeInst(@$,Type::parstring()); }
793 | MZN_ANN
794 { $$ = new TypeInst(@$,Type::ann()); }
795 | set_expr
796 { if ($1) $$ = new TypeInst(@$,Type(),$1); }
797 | MZN_TI_IDENTIFIER
798 { $$ = new TypeInst(@$,Type::top(),
799 new TIId(@$, $1));
800 free($1);
801 }
802 | MZN_TI_ENUM_IDENTIFIER
803 { $$ = new TypeInst(@$,Type::parint(),
804 new TIId(@$, $1));
805 free($1);
806 }
807
808array_access_expr_list : array_access_expr_list_head comma_or_none
809
810array_access_expr_list_head :
811 array_access_expr
812 { $$=new std::vector<MiniZinc::Expression*>; $$->push_back($1); }
813 | array_access_expr_list_head ',' array_access_expr
814 { $$=$1; if ($$ && $3) $$->push_back($3); }
815
816array_access_expr :
817 expr
818 { $$ = $1; }
819 | MZN_DOTDOT
820 { $$=new SetLit(@$, IntSetVal::a(-IntVal::infinity(),IntVal::infinity())); }
821 | MZN_DOTDOT expr
822 { if ($2==nullptr) {
823 $$ = nullptr;
824 } else if ($2->isa<IntLit>()) {
825 $$=new SetLit(@$, IntSetVal::a(-IntVal::infinity(),$2->cast<IntLit>()->v()));
826 } else {
827 $$=new BinOp(@$, IntLit::a(-IntVal::infinity()), BOT_DOTDOT, $2);
828 }
829 }
830 | expr MZN_DOTDOT
831 { if ($1==nullptr) {
832 $$ = nullptr;
833 } else if ($1->isa<IntLit>()) {
834 $$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),IntVal::infinity()));
835 } else {
836 $$=new BinOp(@$, $1, BOT_DOTDOT, IntLit::a(IntVal::infinity()));
837 }
838 }
839
840
841expr_list : expr_list_head comma_or_none
842
843expr_list_head :
844 expr
845 { $$=new std::vector<MiniZinc::Expression*>; $$->push_back($1); }
846 | expr_list_head ',' expr
847 { $$=$1; if ($$ && $3) $$->push_back($3); }
848
849///
850
851set_expr :
852 expr_atom_head
853 | set_expr MZN_COLONCOLON annotation_expr
854 { if ($1 && $3) $1->addAnnotation($3); $$=$1; }
855 | set_expr MZN_UNION set_expr
856 { $$=new BinOp(@$, $1, BOT_UNION, $3); }
857 | set_expr MZN_DIFF set_expr
858 { $$=new BinOp(@$, $1, BOT_DIFF, $3); }
859 | set_expr MZN_SYMDIFF set_expr
860 { $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); }
861 | set_expr MZN_DOTDOT set_expr
862 { if ($1==nullptr || $3==nullptr) {
863 $$ = nullptr;
864 } else if ($1->isa<IntLit>() && $3->isa<IntLit>()) {
865 $$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),$3->cast<IntLit>()->v()));
866 } else {
867 $$=new BinOp(@$, $1, BOT_DOTDOT, $3);
868 }
869 }
870 | MZN_DOTDOT_QUOTED '(' expr ',' expr ')'
871 { if ($3==nullptr || $5==nullptr) {
872 $$ = nullptr;
873 } else if ($3->isa<IntLit>() && $5->isa<IntLit>()) {
874 $$=new SetLit(@$, IntSetVal::a($3->cast<IntLit>()->v(),$5->cast<IntLit>()->v()));
875 } else {
876 $$=new BinOp(@$, $3, BOT_DOTDOT, $5);
877 }
878 }
879 | set_expr MZN_INTERSECT set_expr
880 { $$=new BinOp(@$, $1, BOT_INTERSECT, $3); }
881 | set_expr MZN_PLUSPLUS set_expr
882 { $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); }
883 | set_expr MZN_PLUS set_expr
884 { $$=new BinOp(@$, $1, BOT_PLUS, $3); }
885 | set_expr MZN_MINUS set_expr
886 { $$=new BinOp(@$, $1, BOT_MINUS, $3); }
887 | set_expr MZN_MULT set_expr
888 { $$=new BinOp(@$, $1, BOT_MULT, $3); }
889 | set_expr MZN_DIV set_expr
890 { $$=new BinOp(@$, $1, BOT_DIV, $3); }
891 | set_expr MZN_IDIV set_expr
892 { $$=new BinOp(@$, $1, BOT_IDIV, $3); }
893 | set_expr MZN_MOD set_expr
894 { $$=new BinOp(@$, $1, BOT_MOD, $3); }
895 | set_expr MZN_POW set_expr
896 { $$=new BinOp(@$, $1, BOT_POW, $3); }
897 | set_expr MZN_WEAK_PLUS set_expr
898 { vector<Expression*> args;
899 args.push_back($1); args.push_back($3);
900 $$=new Call(@$, ASTString("~+"), args);
901 }
902 | set_expr MZN_WEAK_MINUS set_expr
903 { vector<Expression*> args;
904 args.push_back($1); args.push_back($3);
905 $$=new Call(@$, ASTString("~-"), args);
906 }
907 | set_expr MZN_WEAK_MULT set_expr
908 { vector<Expression*> args;
909 args.push_back($1); args.push_back($3);
910 $$=new Call(@$, ASTString("~*"), args);
911 }
912 | set_expr MZN_WEAK_EQ set_expr
913 { vector<Expression*> args;
914 args.push_back($1); args.push_back($3);
915 $$=new Call(@$, ASTString("~="), args);
916 }
917 | set_expr MZN_QUOTED_IDENTIFIER set_expr
918 { vector<Expression*> args;
919 args.push_back($1); args.push_back($3);
920 $$=new Call(@$, $2, args);
921 free($2);
922 }
923 | MZN_PLUS set_expr %prec MZN_NOT
924 { $$=new UnOp(@$, UOT_PLUS, $2); }
925 | MZN_MINUS set_expr %prec MZN_NOT
926 { if ($2 && $2->isa<IntLit>()) {
927 $$ = IntLit::a(-$2->cast<IntLit>()->v());
928 } else if ($2 && $2->isa<FloatLit>()) {
929 $$ = FloatLit::a(-$2->cast<FloatLit>()->v());
930 } else {
931 $$=new UnOp(@$, UOT_MINUS, $2);
932 }
933 }
934
935///
936
937expr :
938 expr_atom_head
939 | expr MZN_COLONCOLON annotation_expr
940 { if ($1 && $3) $1->addAnnotation($3); $$=$1; }
941 | expr MZN_EQUIV expr
942 { $$=new BinOp(@$, $1, BOT_EQUIV, $3); }
943 | expr MZN_IMPL expr
944 { $$=new BinOp(@$, $1, BOT_IMPL, $3); }
945 | expr MZN_RIMPL expr
946 { $$=new BinOp(@$, $1, BOT_RIMPL, $3); }
947 | expr MZN_OR expr
948 { $$=new BinOp(@$, $1, BOT_OR, $3); }
949 | expr MZN_XOR expr
950 { $$=new BinOp(@$, $1, BOT_XOR, $3); }
951 | expr MZN_AND expr
952 { $$=new BinOp(@$, $1, BOT_AND, $3); }
953 | expr MZN_LE expr
954 { $$=new BinOp(@$, $1, BOT_LE, $3); }
955 | expr MZN_GR expr
956 { $$=new BinOp(@$, $1, BOT_GR, $3); }
957 | expr MZN_LQ expr
958 { $$=new BinOp(@$, $1, BOT_LQ, $3); }
959 | expr MZN_GQ expr
960 { $$=new BinOp(@$, $1, BOT_GQ, $3); }
961 | expr MZN_EQ expr
962 { $$=new BinOp(@$, $1, BOT_EQ, $3); }
963 | expr MZN_NQ expr
964 { $$=new BinOp(@$, $1, BOT_NQ, $3); }
965 | expr MZN_IN expr
966 { $$=new BinOp(@$, $1, BOT_IN, $3); }
967 | expr MZN_SUBSET expr
968 { $$=new BinOp(@$, $1, BOT_SUBSET, $3); }
969 | expr MZN_SUPERSET expr
970 { $$=new BinOp(@$, $1, BOT_SUPERSET, $3); }
971 | expr MZN_UNION expr
972 { $$=new BinOp(@$, $1, BOT_UNION, $3); }
973 | expr MZN_DIFF expr
974 { $$=new BinOp(@$, $1, BOT_DIFF, $3); }
975 | expr MZN_SYMDIFF expr
976 { $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); }
977 | expr MZN_DOTDOT expr
978 { if ($1==nullptr || $3==nullptr) {
979 $$ = nullptr;
980 } else if ($1->isa<IntLit>() && $3->isa<IntLit>()) {
981 $$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),$3->cast<IntLit>()->v()));
982 } else {
983 $$=new BinOp(@$, $1, BOT_DOTDOT, $3);
984 }
985 }
986 | MZN_DOTDOT_QUOTED '(' expr ',' expr ')'
987 { if ($3==nullptr || $5==nullptr) {
988 $$ = nullptr;
989 } else if ($3->isa<IntLit>() && $5->isa<IntLit>()) {
990 $$=new SetLit(@$, IntSetVal::a($3->cast<IntLit>()->v(),$5->cast<IntLit>()->v()));
991 } else {
992 $$=new BinOp(@$, $3, BOT_DOTDOT, $5);
993 }
994 }
995 | expr MZN_INTERSECT expr
996 { $$=new BinOp(@$, $1, BOT_INTERSECT, $3); }
997 | expr MZN_PLUSPLUS expr
998 { $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); }
999 | expr MZN_PLUS expr
1000 { $$=new BinOp(@$, $1, BOT_PLUS, $3); }
1001 | expr MZN_MINUS expr
1002 { $$=new BinOp(@$, $1, BOT_MINUS, $3); }
1003 | expr MZN_MULT expr
1004 { $$=new BinOp(@$, $1, BOT_MULT, $3); }
1005 | expr MZN_DIV expr
1006 { $$=new BinOp(@$, $1, BOT_DIV, $3); }
1007 | expr MZN_IDIV expr
1008 { $$=new BinOp(@$, $1, BOT_IDIV, $3); }
1009 | expr MZN_MOD expr
1010 { $$=new BinOp(@$, $1, BOT_MOD, $3); }
1011 | expr MZN_POW expr
1012 { $$=new BinOp(@$, $1, BOT_POW, $3); }
1013 | expr MZN_WEAK_PLUS expr
1014 { vector<Expression*> args;
1015 args.push_back($1); args.push_back($3);
1016 $$=new Call(@$, ASTString("~+"), args);
1017 }
1018 | expr MZN_WEAK_MINUS expr
1019 { vector<Expression*> args;
1020 args.push_back($1); args.push_back($3);
1021 $$=new Call(@$, ASTString("~-"), args);
1022 }
1023 | expr MZN_WEAK_MULT expr
1024 { vector<Expression*> args;
1025 args.push_back($1); args.push_back($3);
1026 $$=new Call(@$, ASTString("~*"), args);
1027 }
1028 | expr MZN_WEAK_EQ expr
1029 { vector<Expression*> args;
1030 args.push_back($1); args.push_back($3);
1031 $$=new Call(@$, ASTString("~="), args);
1032 }
1033 | expr MZN_QUOTED_IDENTIFIER expr
1034 { vector<Expression*> args;
1035 args.push_back($1); args.push_back($3);
1036 $$=new Call(@$, $2, args);
1037 free($2);
1038 }
1039 | MZN_NOT expr %prec MZN_NOT
1040 { $$=new UnOp(@$, UOT_NOT, $2); }
1041 | MZN_PLUS expr %prec MZN_NOT
1042 { if (($2 && $2->isa<IntLit>()) || ($2 && $2->isa<FloatLit>())) {
1043 $$ = $2;
1044 } else {
1045 $$=new UnOp(@$, UOT_PLUS, $2);
1046 }
1047 }
1048 | MZN_MINUS expr %prec MZN_NOT
1049 { if ($2 && $2->isa<IntLit>()) {
1050 $$ = IntLit::a(-$2->cast<IntLit>()->v());
1051 } else if ($2 && $2->isa<FloatLit>()) {
1052 $$ = FloatLit::a(-$2->cast<FloatLit>()->v());
1053 } else {
1054 $$=new UnOp(@$, UOT_MINUS, $2);
1055 }
1056 }
1057
1058
1059expr_atom_head :
1060 expr_atom_head_nonstring
1061 { $$=$1; }
1062 | string_expr
1063 { $$=$1; }
1064
1065expr_atom_head_nonstring :
1066 '(' expr ')'
1067 { $$=$2; }
1068 | '(' expr ')' array_access_tail
1069 { if ($4) $$=createArrayAccess(@$, $2, *$4); delete $4; }
1070 | '(' expr ')' MZN_POW_MINUS1
1071 { $$=new BinOp(@$, $2, BOT_POW, IntLit::a(-1)); }
1072 | '(' expr ')' array_access_tail MZN_POW_MINUS1
1073 { if ($4) $$=new BinOp(@$,createArrayAccess(@$, $2, *$4), BOT_POW, IntLit::a(-1)); delete $4; }
1074 | MZN_IDENTIFIER
1075 { $$=new Id(@$, $1, nullptr); free($1); }
1076 | MZN_IDENTIFIER array_access_tail
1077 { if ($2) $$=createArrayAccess(@$, new Id(@1,$1,nullptr), *$2);
1078 free($1); delete $2; }
1079 | MZN_IDENTIFIER MZN_POW_MINUS1
1080 { $$=new BinOp(@$,new Id(@$, $1, nullptr), BOT_POW, IntLit::a(-1)); free($1); }
1081 | MZN_IDENTIFIER array_access_tail MZN_POW_MINUS1
1082 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, new Id(@1,$1,nullptr), *$2), BOT_POW, IntLit::a(-1));
1083 free($1); delete $2; }
1084 | MZN_UNDERSCORE
1085 { $$=new AnonVar(@$); }
1086 | MZN_UNDERSCORE array_access_tail
1087 { if ($2) $$=createArrayAccess(@$, new AnonVar(@$), *$2);
1088 delete $2; }
1089 | MZN_UNDERSCORE MZN_POW_MINUS1
1090 { $$=new BinOp(@$,new AnonVar(@$), BOT_POW, IntLit::a(-1)); }
1091 | MZN_UNDERSCORE array_access_tail MZN_POW_MINUS1
1092 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, new AnonVar(@$), *$2), BOT_POW, IntLit::a(-1));
1093 delete $2; }
1094 | MZN_BOOL_LITERAL
1095 { $$=constants().boollit(($1!=0)); }
1096 | MZN_BOOL_LITERAL MZN_POW_MINUS1
1097 { $$=new BinOp(@$,constants().boollit(($1!=0)), BOT_POW, IntLit::a(-1)); }
1098 | MZN_INTEGER_LITERAL
1099 { $$=IntLit::a($1); }
1100 | MZN_INTEGER_LITERAL MZN_POW_MINUS1
1101 { $$=new BinOp(@$,IntLit::a($1), BOT_POW, IntLit::a(-1)); }
1102 | MZN_INFINITY
1103 { $$=IntLit::a(IntVal::infinity()); }
1104 | MZN_INFINITY MZN_POW_MINUS1
1105 { $$=new BinOp(@$,IntLit::a(IntVal::infinity()), BOT_POW, IntLit::a(-1)); }
1106 | MZN_FLOAT_LITERAL
1107 { $$=FloatLit::a($1); }
1108 | MZN_FLOAT_LITERAL MZN_POW_MINUS1
1109 { $$=new BinOp(@$,FloatLit::a($1), BOT_POW, IntLit::a(-1)); }
1110 | MZN_ABSENT
1111 { $$=constants().absent; }
1112 | MZN_ABSENT MZN_POW_MINUS1
1113 { $$=constants().absent; }
1114 | set_literal
1115 | set_literal array_access_tail
1116 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1117 delete $2; }
1118 | set_literal MZN_POW_MINUS1
1119 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1120 | set_literal array_access_tail MZN_POW_MINUS1
1121 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1122 delete $2; }
1123 | set_comp
1124 | set_comp array_access_tail
1125 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1126 delete $2; }
1127 | set_comp MZN_POW_MINUS1
1128 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1129 | set_comp array_access_tail MZN_POW_MINUS1
1130 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1131 delete $2; }
1132 | simple_array_literal
1133 | simple_array_literal array_access_tail
1134 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1135 delete $2; }
1136 | simple_array_literal MZN_POW_MINUS1
1137 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1138 | simple_array_literal array_access_tail MZN_POW_MINUS1
1139 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1140 delete $2; }
1141 | simple_array_literal_2d
1142 | simple_array_literal_2d array_access_tail
1143 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1144 delete $2; }
1145 | simple_array_literal_2d MZN_POW_MINUS1
1146 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1147 | simple_array_literal_2d array_access_tail MZN_POW_MINUS1
1148 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1149 delete $2; }
1150 | simple_array_comp
1151 | simple_array_comp array_access_tail
1152 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1153 delete $2; }
1154 | simple_array_comp MZN_POW_MINUS1
1155 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1156 | simple_array_comp array_access_tail MZN_POW_MINUS1
1157 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1158 delete $2; }
1159 | if_then_else_expr
1160 | if_then_else_expr array_access_tail
1161 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1162 delete $2; }
1163 | if_then_else_expr MZN_POW_MINUS1
1164 { $$ = new BinOp(@$,$1, BOT_POW, IntLit::a(-1)); }
1165 | if_then_else_expr array_access_tail MZN_POW_MINUS1
1166 { if ($2) $$=new BinOp(@$,createArrayAccess(@$, $1, *$2), BOT_POW, IntLit::a(-1));
1167 delete $2; }
1168 | let_expr
1169 | call_expr
1170 | call_expr array_access_tail
1171 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1172 delete $2; }
1173 | call_expr MZN_POW_MINUS1
1174 | call_expr array_access_tail MZN_POW_MINUS1
1175 { if ($2) $$=createArrayAccess(@$, $1, *$2);
1176 delete $2; }
1177
1178string_expr:
1179 MZN_STRING_LITERAL
1180 { $$=new StringLit(@$, $1); free($1); }
1181 | MZN_STRING_QUOTE_START string_quote_rest
1182 { $$=new BinOp(@$, new StringLit(@$, $1), BOT_PLUSPLUS, $2);
1183 free($1);
1184 }
1185
1186string_quote_rest:
1187 expr_list_head MZN_STRING_QUOTE_END
1188 { if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS, new StringLit(@$,$2));
1189 free($2);
1190 delete $1;
1191 }
1192 | expr_list_head MZN_STRING_QUOTE_MID string_quote_rest
1193 { if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS,
1194 new BinOp(@$, new StringLit(@$,$2), BOT_PLUSPLUS, $3));
1195 free($2);
1196 delete $1;
1197 }
1198
1199array_access_tail :
1200 MZN_LEFT_BRACKET array_access_expr_list MZN_RIGHT_BRACKET
1201 { $$=new std::vector<std::vector<Expression*> >();
1202 if ($2) {
1203 $$->push_back(*$2);
1204 delete $2;
1205 }
1206 }
1207 | array_access_tail MZN_LEFT_BRACKET array_access_expr_list MZN_RIGHT_BRACKET
1208 { $$=$1;
1209 if ($$ && $3) {
1210 $$->push_back(*$3);
1211 delete $3;
1212 }
1213 }
1214
1215set_literal :
1216 '{' '}'
1217 { $$ = new SetLit(@$, std::vector<Expression*>()); }
1218 | '{' expr_list '}'
1219 { if ($2) $$ = new SetLit(@$, *$2);
1220 delete $2; }
1221
1222set_comp :
1223 '{' expr '|' comp_tail '}'
1224 { if ($4) $$ = new Comprehension(@$, $2, *$4, true);
1225 delete $4;
1226 }
1227
1228comp_tail :
1229 generator_list
1230 { if ($1) $$=new Generators; $$->g = *$1; delete $1; }
1231
1232generator_list : generator_list_head comma_or_none
1233
1234generator_list_head :
1235 generator
1236 { $$=new std::vector<Generator>; if ($1) $$->push_back(*$1); delete $1; }
1237 | generator_eq
1238 { $$=new std::vector<Generator>; if ($1) $$->push_back(*$1); delete $1; }
1239 | generator_eq MZN_WHERE expr
1240 { $$=new std::vector<Generator>;
1241 if ($1) $$->push_back(*$1);
1242 if ($1 && $3) $$->push_back(Generator($$->size(),$3));
1243 delete $1;
1244 }
1245 | generator_list_head ',' generator
1246 { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
1247 | generator_list_head ',' generator_eq
1248 { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
1249 | generator_list_head ',' generator_eq MZN_WHERE expr
1250 { $$=$1;
1251 if ($$ && $3) $$->push_back(*$3);
1252 if ($$ && $3 && $5) $$->push_back(Generator($$->size(),$5));
1253 delete $3;
1254 }
1255
1256generator :
1257 id_list MZN_IN expr
1258 { if ($1 && $3) $$=new Generator(*$1,$3,nullptr); else $$=nullptr; delete $1; }
1259 | id_list MZN_IN expr MZN_WHERE expr
1260 { if ($1 && $3) $$=new Generator(*$1,$3,$5); else $$=nullptr; delete $1; }
1261generator_eq :
1262 MZN_IDENTIFIER MZN_EQ expr
1263 { if ($3) $$=new Generator({$1},nullptr,$3); else $$=nullptr; free($1); }
1264
1265id_list : id_list_head comma_or_none
1266
1267id_list_head :
1268 MZN_IDENTIFIER
1269 { $$=new std::vector<std::string>; $$->push_back($1); free($1); }
1270 | id_list_head ',' MZN_IDENTIFIER
1271 { $$=$1; if ($$ && $3) $$->push_back($3); free($3); }
1272
1273simple_array_literal :
1274 MZN_LEFT_BRACKET MZN_RIGHT_BRACKET
1275 { $$=new ArrayLit(@$, std::vector<MiniZinc::Expression*>()); }
1276 | MZN_LEFT_BRACKET expr_list MZN_RIGHT_BRACKET
1277 { if ($2) $$=new ArrayLit(@$, *$2); delete $2; }
1278
1279simple_array_literal_2d :
1280 MZN_LEFT_2D_BRACKET MZN_RIGHT_2D_BRACKET
1281 { $$=new ArrayLit(@$, std::vector<std::vector<Expression*> >()); }
1282 | MZN_LEFT_2D_BRACKET simple_array_literal_2d_list MZN_RIGHT_2D_BRACKET
1283 { if ($2) {
1284 $$=new ArrayLit(@$, *$2);
1285 for (unsigned int i=1; i<$2->size(); i++)
1286 if ((*$2)[i].size() != (*$2)[i-1].size())
1287 yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length");
1288 delete $2;
1289 } else {
1290 $$ = nullptr;
1291 }
1292 }
1293 | MZN_LEFT_2D_BRACKET simple_array_literal_2d_list '|' MZN_RIGHT_2D_BRACKET
1294 { if ($2) {
1295 $$=new ArrayLit(@$, *$2);
1296 for (unsigned int i=1; i<$2->size(); i++)
1297 if ((*$2)[i].size() != (*$2)[i-1].size())
1298 yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length");
1299 delete $2;
1300 } else {
1301 $$ = nullptr;
1302 }
1303 }
1304 | MZN_LEFT_2D_BRACKET simple_array_literal_3d_list MZN_RIGHT_2D_BRACKET
1305 {
1306 if ($2) {
1307 std::vector<std::pair<int,int> > dims(3);
1308 dims[0] = std::pair<int,int>(1,static_cast<int>($2->size()));
1309 if ($2->size()==0) {
1310 dims[1] = std::pair<int,int>(1,0);
1311 dims[2] = std::pair<int,int>(1,0);
1312 } else {
1313 dims[1] = std::pair<int,int>(1,static_cast<int>((*$2)[0].size()));
1314 if ((*$2)[0].size()==0) {
1315 dims[2] = std::pair<int,int>(1,0);
1316 } else {
1317 dims[2] = std::pair<int,int>(1,static_cast<int>((*$2)[0][0].size()));
1318 }
1319 }
1320 std::vector<Expression*> a;
1321 for (int i=0; i<dims[0].second; i++) {
1322 if ((*$2)[i].size() != dims[1].second) {
1323 yyerror(&@2, parm, "syntax error, all sub-arrays of 3d array literal must have the same length");
1324 } else {
1325 for (int j=0; j<dims[1].second; j++) {
1326 if ((*$2)[i][j].size() != dims[2].second) {
1327 yyerror(&@2, parm, "syntax error, all sub-arrays of 3d array literal must have the same length");
1328 } else {
1329 for (int k=0; k<dims[2].second; k++) {
1330 a.push_back((*$2)[i][j][k]);
1331 }
1332 }
1333 }
1334 }
1335 }
1336 $$ = new ArrayLit(@$,a,dims);
1337 delete $2;
1338 } else {
1339 $$ = nullptr;
1340 }
1341 }
1342
1343simple_array_literal_3d_list :
1344 '|' '|'
1345 { $$=new std::vector<std::vector<std::vector<MiniZinc::Expression*> > >;
1346 }
1347 | '|' simple_array_literal_2d_list '|'
1348 { $$=new std::vector<std::vector<std::vector<MiniZinc::Expression*> > >;
1349 if ($2) $$->push_back(*$2);
1350 delete $2;
1351 }
1352 | simple_array_literal_3d_list ',' '|' simple_array_literal_2d_list '|'
1353 { $$=$1;
1354 if ($$ && $4) $$->push_back(*$4);
1355 delete $4;
1356 }
1357
1358simple_array_literal_2d_list :
1359 expr_list
1360 { $$=new std::vector<std::vector<MiniZinc::Expression*> >;
1361 if ($1) $$->push_back(*$1);
1362 delete $1;
1363 }
1364 | simple_array_literal_2d_list '|' expr_list
1365 { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
1366
1367simple_array_comp :
1368 MZN_LEFT_BRACKET expr '|' comp_tail MZN_RIGHT_BRACKET
1369 { if ($4) $$=new Comprehension(@$, $2, *$4, false);
1370 delete $4;
1371 }
1372
1373if_then_else_expr :
1374 MZN_IF expr MZN_THEN expr MZN_ENDIF
1375 {
1376 std::vector<Expression*> iexps;
1377 iexps.push_back($2);
1378 iexps.push_back($4);
1379 $$=new ITE(@$, iexps, nullptr);
1380 }
1381 | MZN_IF expr MZN_THEN expr elseif_list MZN_ELSE expr MZN_ENDIF
1382 {
1383 std::vector<Expression*> iexps;
1384 iexps.push_back($2);
1385 iexps.push_back($4);
1386 if ($5) {
1387 for (unsigned int i=0; i<$5->size(); i+=2) {
1388 iexps.push_back((*$5)[i]);
1389 iexps.push_back((*$5)[i+1]);
1390 }
1391 }
1392 $$=new ITE(@$, iexps,$7);
1393 delete $5;
1394 }
1395
1396elseif_list :
1397 { $$=new std::vector<MiniZinc::Expression*>; }
1398 | elseif_list MZN_ELSEIF expr MZN_THEN expr
1399 { $$=$1; if ($$ && $3 && $5) { $$->push_back($3); $$->push_back($5); } }
1400
1401quoted_op :
1402 MZN_EQUIV_QUOTED
1403 { $$=BOT_EQUIV; }
1404 | MZN_IMPL_QUOTED
1405 { $$=BOT_IMPL; }
1406 | MZN_RIMPL_QUOTED
1407 { $$=BOT_RIMPL; }
1408 | MZN_OR_QUOTED
1409 { $$=BOT_OR; }
1410 | MZN_XOR_QUOTED
1411 { $$=BOT_XOR; }
1412 | MZN_AND_QUOTED
1413 { $$=BOT_AND; }
1414 | MZN_LE_QUOTED
1415 { $$=BOT_LE; }
1416 | MZN_GR_QUOTED
1417 { $$=BOT_GR; }
1418 | MZN_LQ_QUOTED
1419 { $$=BOT_LQ; }
1420 | MZN_GQ_QUOTED
1421 { $$=BOT_GQ; }
1422 | MZN_EQ_QUOTED
1423 { $$=BOT_EQ; }
1424 | MZN_NQ_QUOTED
1425 { $$=BOT_NQ; }
1426 | MZN_IN_QUOTED
1427 { $$=BOT_IN; }
1428 | MZN_SUBSET_QUOTED
1429 { $$=BOT_SUBSET; }
1430 | MZN_SUPERSET_QUOTED
1431 { $$=BOT_SUPERSET; }
1432 | MZN_UNION_QUOTED
1433 { $$=BOT_UNION; }
1434 | MZN_DIFF_QUOTED
1435 { $$=BOT_DIFF; }
1436 | MZN_SYMDIFF_QUOTED
1437 { $$=BOT_SYMDIFF; }
1438 | MZN_PLUS_QUOTED
1439 { $$=BOT_PLUS; }
1440 | MZN_MINUS_QUOTED
1441 { $$=BOT_MINUS; }
1442 | MZN_MULT_QUOTED
1443 { $$=BOT_MULT; }
1444 | MZN_POW_QUOTED
1445 { $$=BOT_POW; }
1446 | MZN_DIV_QUOTED
1447 { $$=BOT_DIV; }
1448 | MZN_IDIV_QUOTED
1449 { $$=BOT_IDIV; }
1450 | MZN_MOD_QUOTED
1451 { $$=BOT_MOD; }
1452 | MZN_INTERSECT_QUOTED
1453 { $$=BOT_INTERSECT; }
1454 | MZN_PLUSPLUS_QUOTED
1455 { $$=BOT_PLUSPLUS; }
1456 | MZN_NOT_QUOTED
1457 { $$=-1; }
1458
1459quoted_op_call :
1460 quoted_op '(' expr ',' expr ')'
1461 { if ($1==-1) {
1462 $$=nullptr;
1463 yyerror(&@3, parm, "syntax error, unary operator with two arguments");
1464 } else {
1465 $$=new BinOp(@$, $3,static_cast<BinOpType>($1),$5);
1466 }
1467 }
1468 | quoted_op '(' expr ')'
1469 { int uot=-1;
1470 switch ($1) {
1471 case -1:
1472 uot = UOT_NOT;
1473 break;
1474 case BOT_MINUS:
1475 uot = UOT_MINUS;
1476 break;
1477 case BOT_PLUS:
1478 uot = UOT_PLUS;
1479 break;
1480 default:
1481 yyerror(&@3, parm, "syntax error, binary operator with unary argument list");
1482 break;
1483 }
1484 if (uot==-1)
1485 $$=nullptr;
1486 else {
1487 if (uot==UOT_PLUS && $3 && ($3->isa<IntLit>() || $3->isa<FloatLit>())) {
1488 $$ = $3;
1489 } else if (uot==UOT_MINUS && $3 && $3->isa<IntLit>()) {
1490 $$ = IntLit::a(-$3->cast<IntLit>()->v());
1491 } else if (uot==UOT_MINUS && $3 && $3->isa<FloatLit>()) {
1492 $$ = FloatLit::a(-$3->cast<FloatLit>()->v());
1493 } else {
1494 $$=new UnOp(@$, static_cast<UnOpType>(uot),$3);
1495 }
1496 }
1497 }
1498
1499call_expr :
1500 MZN_IDENTIFIER '(' ')'
1501 { $$=new Call(@$, $1, std::vector<Expression*>()); free($1); }
1502 | MZN_IDENTIFIER MZN_POW_MINUS1 '(' ')'
1503 { $$=new Call(@$, std::string($1)+"⁻¹", std::vector<Expression*>()); free($1); }
1504 | quoted_op_call
1505 | MZN_IDENTIFIER '(' comp_or_expr ')'
1506 {
1507 if ($3!=nullptr) {
1508 bool hadWhere = false;
1509 std::vector<Expression*> args;
1510 for (unsigned int i=0; i<$3->size(); i++) {
1511 if ((*$3)[i].second) {
1512 yyerror(&@3, parm, "syntax error, 'where' expression outside generator call");
1513 hadWhere = true;
1514 $$=nullptr;
1515 }
1516 args.push_back((*$3)[i].first);
1517 }
1518 if (!hadWhere) {
1519 $$=new Call(@$, $1, args);
1520 }
1521 }
1522 free($1);
1523 delete $3;
1524 }
1525 | MZN_IDENTIFIER '(' comp_or_expr ')' '(' expr ')'
1526 {
1527 vector<Generator> gens;
1528 vector<Id*> ids;
1529 if ($3) {
1530 for (unsigned int i=0; i<$3->size(); i++) {
1531 if (Id* id = Expression::dynamicCast<Id>((*$3)[i].first)) {
1532 if ((*$3)[i].second) {
1533 ParserLocation loc = (*$3)[i].second->loc().parserLocation();
1534 yyerror(&loc, parm, "illegal where expression in generator call");
1535 }
1536 ids.push_back(id);
1537 } else {
1538 if (BinOp* boe = Expression::dynamicCast<BinOp>((*$3)[i].first)) {
1539 if (boe->lhs() && boe->rhs()) {
1540 Id* id = Expression::dynamicCast<Id>(boe->lhs());
1541 if (id && boe->op() == BOT_IN) {
1542 ids.push_back(id);
1543 gens.push_back(Generator(ids,boe->rhs(),(*$3)[i].second));
1544 ids = vector<Id*>();
1545 } else if (id && boe->op() == BOT_EQ && ids.empty()) {
1546 ids.push_back(id);
1547 gens.push_back(Generator(ids,nullptr,boe->rhs()));
1548 if ((*$3)[i].second) {
1549 gens.push_back(Generator(gens.size(),(*$3)[i].second));
1550 }
1551 ids = vector<Id*>();
1552 } else {
1553 ParserLocation loc = (*$3)[i].first->loc().parserLocation();
1554 yyerror(&loc, parm, "illegal expression in generator call");
1555 }
1556 }
1557 } else {
1558 ParserLocation loc = (*$3)[i].first->loc().parserLocation();
1559 yyerror(&loc, parm, "illegal expression in generator call");
1560 }
1561 }
1562 }
1563 }
1564 if (ids.size() != 0) {
1565 yyerror(&@3, parm, "illegal expression in generator call");
1566 }
1567 ParserState* pp = static_cast<ParserState*>(parm);
1568 if (pp->hadError) {
1569 $$=nullptr;
1570 } else {
1571 Generators g; g.g = gens;
1572 Comprehension* ac = new Comprehension(@$, $6,g,false);
1573 vector<Expression*> args; args.push_back(ac);
1574 $$=new Call(@$, $1, args);
1575 }
1576 free($1);
1577 delete $3;
1578 }
1579 | MZN_IDENTIFIER MZN_POW_MINUS1 '(' comp_or_expr ')'
1580 {
1581 if ($4!=nullptr) {
1582 bool hadWhere = false;
1583 std::vector<Expression*> args;
1584 for (unsigned int i=0; i<$4->size(); i++) {
1585 if ((*$4)[i].second) {
1586 yyerror(&@4, parm, "syntax error, 'where' expression outside generator call");
1587 hadWhere = true;
1588 $$=nullptr;
1589 }
1590 args.push_back((*$4)[i].first);
1591 }
1592 if (!hadWhere) {
1593 $$=new Call(@$, std::string($1)+"⁻¹", args);
1594 }
1595 }
1596 free($1);
1597 delete $4;
1598 }
1599 | MZN_IDENTIFIER MZN_POW_MINUS1 '(' comp_or_expr ')' '(' expr ')'
1600 {
1601 vector<Generator> gens;
1602 vector<Id*> ids;
1603 if ($4) {
1604 for (unsigned int i=0; i<$4->size(); i++) {
1605 if (Id* id = Expression::dynamicCast<Id>((*$4)[i].first)) {
1606 if ((*$4)[i].second) {
1607 ParserLocation loc = (*$4)[i].second->loc().parserLocation();
1608 yyerror(&loc, parm, "illegal where expression in generator call");
1609 }
1610 ids.push_back(id);
1611 } else {
1612 if (BinOp* boe = Expression::dynamicCast<BinOp>((*$4)[i].first)) {
1613 if (boe->lhs() && boe->rhs()) {
1614 Id* id = Expression::dynamicCast<Id>(boe->lhs());
1615 if (id && boe->op() == BOT_IN) {
1616 ids.push_back(id);
1617 gens.push_back(Generator(ids,boe->rhs(),(*$4)[i].second));
1618 ids = vector<Id*>();
1619 } else if (id && boe->op() == BOT_EQ && ids.empty()) {
1620 ids.push_back(id);
1621 gens.push_back(Generator(ids,nullptr,boe->rhs()));
1622 if ((*$4)[i].second) {
1623 gens.push_back(Generator(gens.size(),(*$4)[i].second));
1624 }
1625 ids = vector<Id*>();
1626 } else {
1627 ParserLocation loc = (*$4)[i].first->loc().parserLocation();
1628 yyerror(&loc, parm, "illegal expression in generator call");
1629 }
1630 }
1631 } else {
1632 ParserLocation loc = (*$4)[i].first->loc().parserLocation();
1633 yyerror(&loc, parm, "illegal expression in generator call");
1634 }
1635 }
1636 }
1637 }
1638 if (ids.size() != 0) {
1639 yyerror(&@4, parm, "illegal expression in generator call");
1640 }
1641 ParserState* pp = static_cast<ParserState*>(parm);
1642 if (pp->hadError) {
1643 $$=nullptr;
1644 } else {
1645 Generators g; g.g = gens;
1646 Comprehension* ac = new Comprehension(@$, $7,g,false);
1647 vector<Expression*> args; args.push_back(ac);
1648 $$=new Call(@$, std::string($1)+"⁻¹", args);
1649 }
1650 free($1);
1651 delete $4;
1652 }
1653
1654comp_or_expr : comp_or_expr_head comma_or_none
1655
1656comp_or_expr_head :
1657 expr
1658 { $$=new vector<pair<Expression*,Expression*> >;
1659 if ($1) {
1660 $$->push_back(pair<Expression*,Expression*>($1,nullptr));
1661 }
1662 }
1663 | expr MZN_WHERE expr
1664 { $$=new vector<pair<Expression*,Expression*> >;
1665 if ($1 && $3) {
1666 $$->push_back(pair<Expression*,Expression*>($1,$3));
1667 }
1668 }
1669 | comp_or_expr_head ',' expr
1670 { $$=$1; if ($$ && $3) $$->push_back(pair<Expression*,Expression*>($3,nullptr)); }
1671 | comp_or_expr_head ',' expr MZN_WHERE expr
1672 { $$=$1; if ($$ && $3 && $5) $$->push_back(pair<Expression*,Expression*>($3,$5)); }
1673
1674let_expr :
1675 MZN_LET '{' let_vardecl_item_list '}' MZN_IN expr %prec PREC_ANNO
1676 { if ($3 && $6) {
1677 $$=new Let(@$, *$3, $6); delete $3;
1678 } else {
1679 $$=nullptr;
1680 }
1681 }
1682 | MZN_LET '{' let_vardecl_item_list comma_or_semi '}' MZN_IN expr %prec PREC_ANNO
1683 { if ($3 && $7) {
1684 $$=new Let(@$, *$3, $7); delete $3;
1685 } else {
1686 $$=nullptr;
1687 }
1688 }
1689
1690let_vardecl_item_list :
1691 let_vardecl_item
1692 { $$=new vector<Expression*>; $$->push_back($1); }
1693 | constraint_item
1694 { $$=new vector<Expression*>;
1695 if ($1) {
1696 ConstraintI* ce = $1->cast<ConstraintI>();
1697 $$->push_back(ce->e());
1698 ce->e(nullptr);
1699 }
1700 }
1701 | let_vardecl_item_list comma_or_semi let_vardecl_item
1702 { $$=$1; if ($$ && $3) $$->push_back($3); }
1703 | let_vardecl_item_list comma_or_semi constraint_item
1704 { $$=$1;
1705 if ($$ && $3) {
1706 ConstraintI* ce = $3->cast<ConstraintI>();
1707 $$->push_back(ce->e());
1708 ce->e(nullptr);
1709 }
1710 }
1711
1712comma_or_semi : ',' | ';'
1713
1714let_vardecl_item :
1715 ti_expr_and_id annotations
1716 { $$ = $1;
1717 if ($$) $$->toplevel(false);
1718 if ($$ && $2) $$->addAnnotations(*$2);
1719 delete $2;
1720 }
1721 | ti_expr_and_id annotations MZN_EQ expr
1722 { if ($1) $1->e($4);
1723 $$ = $1;
1724 if ($$) $$->loc(@$);
1725 if ($$) $$->toplevel(false);
1726 if ($$ && $2) $$->addAnnotations(*$2);
1727 delete $2;
1728 }
1729
1730annotations :
1731 /* empty */
1732 { $$=nullptr; }
1733 | ne_annotations
1734
1735annotation_expr :
1736 expr_atom_head_nonstring
1737 { $$ = $1; }
1738 | string_expr
1739 { $$ = new Call(@1, ASTString("mzn_expression_name"), {$1}); }
1740
1741ne_annotations :
1742 MZN_COLONCOLON annotation_expr
1743 { $$=new std::vector<Expression*>(1);
1744 (*$$)[0] = $2;
1745 }
1746 | ne_annotations MZN_COLONCOLON annotation_expr
1747 { $$=$1; if ($$) $$->push_back($3); }
1748
1749id_or_quoted_op :
1750 MZN_IDENTIFIER
1751 { $$=$1; }
1752 | MZN_IDENTIFIER MZN_POW_MINUS1
1753 { $$=strdup((std::string($1)+"⁻¹").c_str()); }
1754 | MZN_EQUIV_QUOTED
1755 { $$=strdup("'<->'"); }
1756 | MZN_IMPL_QUOTED
1757 { $$=strdup("'->'"); }
1758 | MZN_RIMPL_QUOTED
1759 { $$=strdup("'<-'"); }
1760 | MZN_OR_QUOTED
1761 { $$=strdup("'\\/'"); }
1762 | MZN_XOR_QUOTED
1763 { $$=strdup("'xor'"); }
1764 | MZN_AND_QUOTED
1765 { $$=strdup("'/\\'"); }
1766 | MZN_LE_QUOTED
1767 { $$=strdup("'<'"); }
1768 | MZN_GR_QUOTED
1769 { $$=strdup("'>'"); }
1770 | MZN_LQ_QUOTED
1771 { $$=strdup("'<='"); }
1772 | MZN_GQ_QUOTED
1773 { $$=strdup("'>='"); }
1774 | MZN_EQ_QUOTED
1775 { $$=strdup("'='"); }
1776 | MZN_NQ_QUOTED
1777 { $$=strdup("'!='"); }
1778 | MZN_IN_QUOTED
1779 { $$=strdup("'in'"); }
1780 | MZN_SUBSET_QUOTED
1781 { $$=strdup("'subset'"); }
1782 | MZN_SUPERSET_QUOTED
1783 { $$=strdup("'superset'"); }
1784 | MZN_UNION_QUOTED
1785 { $$=strdup("'union'"); }
1786 | MZN_DIFF_QUOTED
1787 { $$=strdup("'diff'"); }
1788 | MZN_SYMDIFF_QUOTED
1789 { $$=strdup("'symdiff'"); }
1790 | MZN_DOTDOT_QUOTED
1791 { $$=strdup("'..'"); }
1792 | MZN_PLUS_QUOTED
1793 { $$=strdup("'+'"); }
1794 | MZN_MINUS_QUOTED
1795 { $$=strdup("'-'"); }
1796 | MZN_MULT_QUOTED
1797 { $$=strdup("'*'"); }
1798 | MZN_POW_QUOTED
1799 { $$=strdup("'^'"); }
1800 | MZN_DIV_QUOTED
1801 { $$=strdup("'/'"); }
1802 | MZN_IDIV_QUOTED
1803 { $$=strdup("'div'"); }
1804 | MZN_MOD_QUOTED
1805 { $$=strdup("'mod'"); }
1806 | MZN_INTERSECT_QUOTED
1807 { $$=strdup("'intersect'"); }
1808 | MZN_NOT_QUOTED
1809 { $$=strdup("'not'"); }
1810 | MZN_PLUSPLUS_QUOTED
1811 { $$=strdup("'++'"); }