1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

1600 lines
48 KiB
Plaintext

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Guido Tack <guido.tack@monash.edu>
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%define api.pure
%parse-param {void *parm}
%define api.header.include {<minizinc/parser.tab.hh>}
%lex-param {void* SCANNER}
%{
#define SCANNER static_cast<ParserState*>(parm)->yyscanner
#include <iostream>
#include <fstream>
#include <map>
#include <cerrno>
namespace MiniZinc{ class ParserLocation; }
#define YYLTYPE MiniZinc::ParserLocation
#define YYLTYPE_IS_DECLARED 1
#define YYLTYPE_IS_TRIVIAL 0
#define YYMAXDEPTH 10000
#define YYINITDEPTH 10000
#include <minizinc/parser.hh>
#include <minizinc/file_utils.hh>
using namespace std;
using namespace MiniZinc;
#define YYLLOC_DEFAULT(Current, Rhs, N) \
(Current).filename(Rhs[1].filename()); \
(Current).first_line(Rhs[1].first_line()); \
(Current).first_column(Rhs[1].first_column()); \
(Current).last_line(Rhs[N].last_line()); \
(Current).last_column(Rhs[N].last_column());
int mzn_yyparse(void*);
int mzn_yylex(YYSTYPE*, YYLTYPE*, void* scanner);
int mzn_yylex_init (void** scanner);
int mzn_yylex_destroy (void* scanner);
int mzn_yyget_lineno (void* scanner);
void mzn_yyset_extra (void* user_defined ,void* yyscanner );
extern int yydebug;
void yyerror(YYLTYPE* location, void* parm, const string& str) {
ParserState* pp = static_cast<ParserState*>(parm);
Model* m = pp->model;
while (m->parent() != NULL) {
m = m->parent();
pp->err << "(included from file '" << m->filename() << "')" << endl;
}
pp->err << location->toString() << ":" << endl;
pp->printCurrentLine(location->first_column(),location->last_column());
pp->err << "Error: " << str << std::endl;
pp->hadError = true;
pp->syntaxErrors.push_back(SyntaxError(Location(*location), str));
}
bool notInDatafile(YYLTYPE* location, void* parm, const string& item) {
ParserState* pp = static_cast<ParserState*>(parm);
if (pp->isDatafile) {
yyerror(location,parm,item+" item not allowed in data file");
return false;
}
return true;
}
Expression* createDocComment(const ParserLocation& loc, const std::string& s) {
std::vector<Expression*> args(1);
args[0] = new StringLit(loc, s);
Call* c = new Call(Location(loc), constants().ann.doc_comment, args);
c->type(Type::ann());
return c;
}
Expression* createArrayAccess(const ParserLocation& loc, Expression* e, std::vector<std::vector<Expression*> >& idx) {
Expression* ret = e;
for (unsigned int i=0; i<idx.size(); i++) {
ret = new ArrayAccess(Location(loc), ret, idx[i]);
}
return ret;
}
%}
%union { long long int iValue; char* sValue; bool bValue; double dValue;
MiniZinc::Item* item;
MiniZinc::VarDecl* vardeclexpr;
std::vector<MiniZinc::VarDecl*>* vardeclexpr_v;
MiniZinc::TypeInst* tiexpr;
std::vector<MiniZinc::TypeInst*>* tiexpr_v;
MiniZinc::Expression* expression;
std::vector<MiniZinc::Expression*>* expression_v;
std::vector<std::vector<MiniZinc::Expression*> >* expression_vv;
std::vector<std::vector<std::vector<MiniZinc::Expression*> > >* expression_vvv;
MiniZinc::Generator* generator;
std::vector<MiniZinc::Generator>* generator_v;
std::vector<std::string>* string_v;
std::vector<std::pair<MiniZinc::Expression*,MiniZinc::Expression*> >* expression_p;
MiniZinc::Generators* generators;
}
%locations
%define parse.error verbose
%initial-action
{
GCLock lock;
@$.filename(ASTString(static_cast<ParserState*>(parm)->filename));
}
%token <iValue> MZN_INTEGER_LITERAL "integer literal" MZN_BOOL_LITERAL "bool literal"
%token <dValue> MZN_FLOAT_LITERAL "float literal"
%token <sValue> MZN_IDENTIFIER "identifier" MZN_QUOTED_IDENTIFIER "quoted identifier" MZN_STRING_LITERAL "string literal"
%token <sValue> MZN_STRING_QUOTE_START "interpolated string start" MZN_STRING_QUOTE_MID "interpolated string middle" MZN_STRING_QUOTE_END "interpolated string end"
%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"
%token MZN_VAR "var" MZN_PAR "par"
%token MZN_ABSENT "<>"
%token MZN_ANN "ann"
%token MZN_ANNOTATION "annotation"
%token MZN_ANY "any"
%token MZN_ARRAY "array"
%token MZN_BOOL "bool"
%token MZN_CASE "case"
%token MZN_CONSTRAINT "constraint"
%token MZN_DEFAULT "default"
%token MZN_ELSE "else"
%token MZN_ELSEIF "elseif"
%token MZN_ENDIF "endif"
%token MZN_ENUM "enum"
%token MZN_FLOAT "float"
%token MZN_FUNCTION "function"
%token MZN_IF "if"
%token MZN_INCLUDE "include"
%token MZN_INFINITY "infinity"
%token MZN_INT "int"
%token MZN_LET "let"
%token MZN_LIST "list"
%token <bValue> MZN_MAXIMIZE "maximize"
%token <bValue> MZN_MINIMIZE "minimize"
%token MZN_OF "of"
%token MZN_OPT "opt"
%token MZN_SATISFY "satisfy"
%token MZN_OUTPUT "output"
%token MZN_PREDICATE "predicate"
%token MZN_RECORD "record"
%token MZN_SET "set"
%token MZN_SOLVE "solve"
%token MZN_STRING "string"
%token MZN_TEST "test"
%token MZN_THEN "then"
%token MZN_TUPLE "tuple"
%token MZN_TYPE "type"
%token MZN_UNDERSCORE "_"
%token MZN_VARIANT_RECORD "variant_record"
%token MZN_WHERE "where"
%token MZN_LEFT_BRACKET "["
%token MZN_LEFT_2D_BRACKET "[|"
%token MZN_RIGHT_BRACKET "]"
%token MZN_RIGHT_2D_BRACKET "|]"
// Used to signal an error when parsing a MiniZinc file
// that contains identifiers starting with _
%token FLATZINC_IDENTIFIER
%token MZN_INVALID_INTEGER_LITERAL "invalid integer literal"
%token MZN_INVALID_FLOAT_LITERAL "invalid float literal"
%token MZN_UNTERMINATED_STRING "unterminated string"
%token MZN_END_OF_LINE_IN_STRING "end of line inside string literal"
%token MZN_INVALID_NULL "null character"
%token END 0 "end of file"
%token MZN_EQUIV "<->"
%token MZN_IMPL "->" MZN_RIMPL "<-"
%token MZN_OR "\\/" MZN_XOR "xor"
%token MZN_AND "/\\"
%token MZN_LE "<" MZN_GR ">" MZN_LQ "<=" MZN_GQ ">=" MZN_EQ "=" MZN_NQ "!=" MZN_WEAK_EQ "~="
%token MZN_IN "in" MZN_SUBSET "subset" MZN_SUPERSET "superset"
%token MZN_UNION "union" MZN_DIFF "diff" MZN_SYMDIFF "symdiff"
%token MZN_DOTDOT ".."
%token MZN_PLUS "+" MZN_MINUS "-" MZN_WEAK_PLUS "~+" MZN_WEAK_MINUS "~-"
%token MZN_MULT "*" MZN_DIV "/" MZN_IDIV "div" MZN_MOD "mod" MZN_INTERSECT "intersect" MZN_WEAK_MULT "~*"
%token MZN_POW "^"
%token MZN_NOT "not"
%token MZN_PLUSPLUS "++"
%token MZN_COLONCOLON "::"
%right PREC_ANNO
%left MZN_EQUIV
%left MZN_IMPL MZN_RIMPL
%left MZN_OR MZN_XOR
%left MZN_AND
%nonassoc MZN_LE MZN_GR MZN_LQ MZN_GQ MZN_EQ MZN_NQ MZN_WEAK_EQ
%nonassoc MZN_IN MZN_SUBSET MZN_SUPERSET
%left MZN_UNION MZN_DIFF MZN_SYMDIFF MZN_INTERSECT
%nonassoc MZN_DOTDOT
%left MZN_PLUS MZN_MINUS MZN_WEAK_PLUS MZN_WEAK_MINUS
%left MZN_MULT MZN_DIV MZN_IDIV MZN_MOD MZN_WEAK_MULT
%left MZN_POW
%nonassoc MZN_NOT
%left MZN_PLUSPLUS
%left MZN_QUOTED_IDENTIFIER
%left MZN_COLONCOLON
%token MZN_EQUIV_QUOTED "'<->'"
%token MZN_IMPL_QUOTED "'->'" MZN_RIMPL_QUOTED "'<-'"
%token MZN_OR_QUOTED "'\\/'" MZN_XOR_QUOTED "'xor'"
%token MZN_AND_QUOTED "'/\\'"
%token MZN_LE_QUOTED "'<'" MZN_GR_QUOTED "'>'" MZN_LQ_QUOTED "'<='" MZN_GQ_QUOTED "'>='" MZN_EQ_QUOTED "'='" MZN_NQ_QUOTED "'!='"
%token MZN_IN_QUOTED "'in'" MZN_SUBSET_QUOTED "'subset'" MZN_SUPERSET_QUOTED "'superset'"
%token MZN_UNION_QUOTED "'union'" MZN_DIFF_QUOTED "'diff'" MZN_SYMDIFF_QUOTED "'symdiff'"
%token MZN_DOTDOT_QUOTED "'..'"
%token MZN_PLUS_QUOTED "'+'" MZN_MINUS_QUOTED "'-'"
%token MZN_MULT_QUOTED "'*'" MZN_DIV_QUOTED "'/'" MZN_IDIV_QUOTED "'div'" MZN_MOD_QUOTED "'mod'" MZN_INTERSECT_QUOTED "'intersect'"
%token MZN_POW_QUOTED "'^'"
%token MZN_NOT_QUOTED "'not'"
%token MZN_COLONCOLON_QUOTED "'::'"
%token MZN_PLUSPLUS_QUOTED "'++'"
%type <item> item item_tail include_item vardecl_item assign_item constraint_item solve_item output_item predicate_item annotation_item function_item
%type <vardeclexpr> ti_expr_and_id ti_expr_and_id_or_anon let_vardecl_item
%type <vardeclexpr_v> params params_list params_list_head
%type <tiexpr> ti_expr base_ti_expr base_ti_expr_tail
%type <tiexpr_v> ti_expr_list ti_expr_list_head
%type <expression> expr expr_atom_head expr_atom_head_nonstring array_access_expr
%type <expression> set_expr string_expr string_quote_rest annotation_expr
%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
%type <expression_v> expr_list expr_list_head array_access_expr_list array_access_expr_list_head elseif_list let_vardecl_item_list enum_id_list string_lit_list
%type <expression_vv> simple_array_literal_2d_list array_access_tail
%type <expression_vvv> simple_array_literal_3d_list
%type <generators> comp_tail
%type <generator> generator generator_eq
%type <generator_v> generator_list generator_list_head
%type <string_v> id_list id_list_head
%type <expression_p> comp_or_expr comp_or_expr_head
%type <expression_v> annotations ne_annotations
%type <iValue> quoted_op
%type <sValue> id_or_quoted_op
%type <bValue> opt_opt
%%
/********************************/
/* main goal and item lists */
/********************************/
model : item_list
item_list :
/* empty */
| item_list_head semi_or_none
item_list_head:
item
{
ParserState* pp = static_cast<ParserState*>(parm);
if ($1) {
pp->model->addItem($1);
GC::unlock();
GC::lock();
}
}
| doc_file_comments item
{
ParserState* pp = static_cast<ParserState*>(parm);
if ($2) {
pp->model->addItem($2);
GC::unlock();
GC::lock();
}
}
| item_list_head ';' item
{
ParserState* pp = static_cast<ParserState*>(parm);
if ($3) {
pp->model->addItem($3);
GC::unlock();
GC::lock();
}
}
| item_list_head ';' doc_file_comments item
{
ParserState* pp = static_cast<ParserState*>(parm);
if ($4) {
pp->model->addItem($4);
GC::unlock();
GC::lock();
}
}
| item error_item_start
{ yyerror(&@2, parm, "unexpected item, expecting ';' or end of file"); YYERROR; }
| error ';' item
doc_file_comments:
MZN_DOC_FILE_COMMENT
{
ParserState* pp = static_cast<ParserState*>(parm);
if (pp->parseDocComments && $1) {
pp->model->addDocComment($1);
}
free($1);
}
| doc_file_comments MZN_DOC_FILE_COMMENT
{
ParserState* pp = static_cast<ParserState*>(parm);
if (pp->parseDocComments && $2) {
pp->model->addDocComment($2);
}
free($2);
}
semi_or_none : | ';'
item : MZN_DOC_COMMENT item_tail
{ $$ = $2;
ParserState* pp = static_cast<ParserState*>(parm);
if (FunctionI* fi = Item::dyn_cast<FunctionI>($$)) {
if (pp->parseDocComments) {
fi->ann().add(createDocComment(@1,$1));
}
} else if (VarDeclI* vdi = Item::dyn_cast<VarDeclI>($$)) {
if (pp->parseDocComments) {
vdi->e()->addAnnotation(createDocComment(@1,$1));
}
} else {
yyerror(&@2, parm, "documentation comments are only supported for function, predicate and variable declarations");
}
free($1);
}
| item_tail
{ $$ = $1; }
item_tail :
include_item
{ $$=notInDatafile(&@$,parm,"include") ? $1 : NULL; }
| vardecl_item
{ $$=notInDatafile(&@$,parm,"variable declaration") ? $1 : NULL; }
| assign_item
| constraint_item
{ $$=notInDatafile(&@$,parm,"constraint") ? $1 : NULL; }
| solve_item
{ $$=notInDatafile(&@$,parm,"solve") ? $1 : NULL; }
| output_item
{ $$=notInDatafile(&@$,parm,"output") ? $1 : NULL; }
| predicate_item
{ $$=notInDatafile(&@$,parm,"predicate") ? $1 : NULL; }
| function_item
{ $$=notInDatafile(&@$,parm,"predicate") ? $1 : NULL; }
| annotation_item
{ $$=notInDatafile(&@$,parm,"annotation") ? $1 : NULL; }
error_item_start : MZN_INCLUDE | MZN_ENUM | MZN_OUTPUT
| MZN_CONSTRAINT | MZN_SOLVE | MZN_PREDICATE | MZN_FUNCTION | MZN_TEST
| MZN_ANNOTATION
include_item :
MZN_INCLUDE MZN_STRING_LITERAL
{ ParserState* pp = static_cast<ParserState*>(parm);
map<string,Model*>::iterator ret = pp->seenModels.find($2);
IncludeI* ii = new IncludeI(@$,ASTString($2));
$$ = ii;
if (ret == pp->seenModels.end()) {
Model* im = new Model;
im->setParent(pp->model);
im->setFilename($2);
string fpath = FileUtils::dir_name(pp->filename);
string fbase = FileUtils::base_name(pp->filename);
if (fpath=="")
fpath="./";
ParseWorkItem pm(im, ii, fpath, $2);
pp->files.push_back(pm);
ii->m(im);
pp->seenModels.insert(pair<string,Model*>($2,im));
} else {
ii->m(ret->second, false);
}
free($2);
}
vardecl_item :
ti_expr_and_id annotations
{ if ($1 && $2) $1->addAnnotations(*$2);
if ($1)
$$ = new VarDeclI(@$,$1);
delete $2;
}
| ti_expr_and_id annotations MZN_EQ expr
{ if ($1) $1->e($4);
if ($1 && $2) $1->addAnnotations(*$2);
if ($1)
$$ = new VarDeclI(@$,$1);
delete $2;
}
| MZN_ENUM MZN_IDENTIFIER
{
TypeInst* ti = new TypeInst(@$,Type::parsetint());
ti->setIsEnum(true);
VarDecl* vd = new VarDecl(@$,ti,$2);
free($2);
$$ = new VarDeclI(@$,vd);
}
| MZN_ENUM MZN_IDENTIFIER MZN_EQ '{' enum_id_list '}'
{
TypeInst* ti = new TypeInst(@$,Type::parsetint());
ti->setIsEnum(true);
SetLit* sl = new SetLit(@$, *$5);
VarDecl* vd = new VarDecl(@$,ti,$2,sl);
free($2);
delete $5;
$$ = new VarDeclI(@$,vd);
}
| MZN_ENUM MZN_IDENTIFIER MZN_EQ MZN_LEFT_BRACKET string_lit_list MZN_RIGHT_BRACKET
{
TypeInst* ti = new TypeInst(@$,Type::parsetint());
ti->setIsEnum(true);
vector<Expression*> args;
args.push_back(new ArrayLit(@$,*$5));
Call* sl = new Call(@$, constants().ids.anonEnumFromStrings, args);
VarDecl* vd = new VarDecl(@$,ti,$2,sl);
free($2);
delete $5;
$$ = new VarDeclI(@$,vd);
}
| MZN_ENUM MZN_IDENTIFIER MZN_EQ MZN_IDENTIFIER '(' expr ')'
{
TypeInst* ti = new TypeInst(@$,Type::parsetint());
ti->setIsEnum(true);
vector<Expression*> args;
args.push_back($6);
Call* sl = new Call(@$, ASTString($4), args);
VarDecl* vd = new VarDecl(@$,ti,$2,sl);
free($2);
free($4);
$$ = new VarDeclI(@$,vd);
}
string_lit_list :
// empty
{ $$ = new std::vector<Expression*>(); }
| MZN_STRING_LITERAL
{ $$ = new std::vector<Expression*>();
$$->push_back(new StringLit(@$, $1)); free($1);
}
| string_lit_list ',' MZN_STRING_LITERAL
{ $$ = $1;
if ($$) $$->push_back(new StringLit(@$, $3));
free($3);
}
enum_id_list :
// empty
{ $$ = new std::vector<Expression*>(); }
| MZN_IDENTIFIER
{ $$ = new std::vector<Expression*>();
$$->push_back(new Id(@$,$1,NULL)); free($1);
}
| enum_id_list ',' MZN_IDENTIFIER
{ $$ = $1; if ($$) $$->push_back(new Id(@$,$3,NULL)); free($3); }
assign_item :
MZN_IDENTIFIER MZN_EQ expr
{ $$ = new AssignI(@$,$1,$3);
free($1);
}
constraint_item :
MZN_CONSTRAINT expr
{ $$ = new ConstraintI(@$,$2);}
| MZN_CONSTRAINT MZN_COLONCOLON string_expr expr
{ $$ = new ConstraintI(@$,$4);
if ($4 && $3)
$$->cast<ConstraintI>()->e()->ann().add(new Call(@2, ASTString("mzn_constraint_name"), {$3}));
}
solve_item :
MZN_SOLVE annotations MZN_SATISFY
{ $$ = SolveI::sat(@$);
if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
delete $2;
}
| MZN_SOLVE annotations MZN_MINIMIZE expr
{ $$ = SolveI::min(@$,$4);
if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
delete $2;
}
| MZN_SOLVE annotations MZN_MAXIMIZE expr
{ $$ = SolveI::max(@$,$4);
if ($$ && $2) $$->cast<SolveI>()->ann().add(*$2);
delete $2;
}
output_item :
MZN_OUTPUT expr
{ $$ = new OutputI(@$,$2);}
predicate_item :
MZN_PREDICATE MZN_IDENTIFIER params annotations operation_item_tail
{ if ($3) $$ = new FunctionI(@$,$2,new TypeInst(@$,
Type::varbool()),*$3,$5);
if ($$ && $4) $$->cast<FunctionI>()->ann().add(*$4);
free($2);
delete $3;
delete $4;
}
| MZN_TEST MZN_IDENTIFIER params annotations operation_item_tail
{ if ($3) $$ = new FunctionI(@$,$2,new TypeInst(@$,
Type::parbool()),*$3,$5);
if ($$ && $4) $$->cast<FunctionI>()->ann().add(*$4);
free($2);
delete $3;
delete $4;
}
function_item :
MZN_FUNCTION ti_expr ':' id_or_quoted_op params annotations operation_item_tail
{ if ($5) $$ = new FunctionI(@$,$4,$2,*$5,$7);
if ($$ && $6) $$->cast<FunctionI>()->ann().add(*$6);
free($4);
delete $5;
delete $6;
}
| ti_expr ':' MZN_IDENTIFIER '(' params_list ')' annotations operation_item_tail
{ if ($5) $$ = new FunctionI(@$,$3,$1,*$5,$8);
if ($$ && $7) $$->cast<FunctionI>()->ann().add(*$7);
free($3);
delete $5;
delete $7;
}
annotation_item :
MZN_ANNOTATION MZN_IDENTIFIER params
{
TypeInst* ti=new TypeInst(@1,Type::ann());
if ($3==NULL || $3->empty()) {
VarDecl* vd = new VarDecl(@$,ti,$2);
$$ = new VarDeclI(@$,vd);
} else {
$$ = new FunctionI(@$,$2,ti,*$3,NULL);
}
free($2);
delete $3;
}
| MZN_ANNOTATION MZN_IDENTIFIER params MZN_EQ expr
{ TypeInst* ti=new TypeInst(@1,Type::ann());
if ($3) $$ = new FunctionI(@$,$2,ti,*$3,$5);
delete $3;
}
operation_item_tail :
/*empty*/
{ $$=NULL; }
| MZN_EQ expr
{ $$=$2; }
params :
/* empty */
{ $$=new vector<VarDecl*>(); }
| '(' params_list ')'
{ $$=$2; }
| '(' error ')'
{ $$=new vector<VarDecl*>(); }
params_list :
/* empty */
{ $$=new vector<VarDecl*>(); }
| params_list_head comma_or_none
{ $$=$1; }
params_list_head :
ti_expr_and_id_or_anon
{ $$=new vector<VarDecl*>();
if ($1) $1->toplevel(false);
if ($1) $$->push_back($1); }
| params_list_head ',' ti_expr_and_id_or_anon
{ $$=$1;
if ($3) $3->toplevel(false);
if ($1 && $3) $1->push_back($3); }
comma_or_none : | ','
ti_expr_and_id_or_anon :
ti_expr_and_id
{ $$=$1; }
| ti_expr
{ if ($1) $$=new VarDecl(@$, $1, ""); }
ti_expr_and_id :
ti_expr ':' MZN_IDENTIFIER
{ if ($1 && $3) $$ = new VarDecl(@$, $1, $3);
free($3);
}
ti_expr_list : ti_expr_list_head comma_or_none
{ $$=$1; }
ti_expr_list_head :
ti_expr
{ $$=new vector<TypeInst*>(); $$->push_back($1); }
| ti_expr_list_head ',' ti_expr
{ $$=$1; if ($1 && $3) $1->push_back($3); }
ti_expr :
base_ti_expr
| MZN_ARRAY MZN_LEFT_BRACKET ti_expr_list MZN_RIGHT_BRACKET MZN_OF base_ti_expr
{
$$ = $6;
if ($$ && $3) $$->setRanges(*$3);
delete $3;
}
| MZN_LIST MZN_OF base_ti_expr
{
$$ = $3;
std::vector<TypeInst*> ti(1);
ti[0] = new TypeInst(@$,Type::parint());
if ($$) $$->setRanges(ti);
}
base_ti_expr :
base_ti_expr_tail
{ $$ = $1;
}
| MZN_OPT base_ti_expr_tail
{ $$ = $2;
if ($$) {
Type tt = $$->type();
tt.ot(Type::OT_OPTIONAL);
$$->type(tt);
}
}
| MZN_PAR opt_opt base_ti_expr_tail
{ $$ = $3;
if ($$ && $2) {
Type tt = $$->type();
tt.ot(Type::OT_OPTIONAL);
$$->type(tt);
}
}
| MZN_VAR opt_opt base_ti_expr_tail
{ $$ = $3;
if ($$) {
Type tt = $$->type();
tt.ti(Type::TI_VAR);
if ($2) tt.ot(Type::OT_OPTIONAL);
$$->type(tt);
}
}
| opt_opt MZN_SET MZN_OF base_ti_expr_tail
{ $$ = $4;
if ($$) {
Type tt = $$->type();
tt.st(Type::ST_SET);
if ($1) tt.ot(Type::OT_OPTIONAL);
$$->type(tt);
}
}
| MZN_PAR opt_opt MZN_SET MZN_OF base_ti_expr_tail
{ $$ = $5;
if ($$) {
Type tt = $$->type();
tt.st(Type::ST_SET);
if ($2) tt.ot(Type::OT_OPTIONAL);
$$->type(tt);
}
}
| MZN_VAR opt_opt MZN_SET MZN_OF base_ti_expr_tail
{ $$ = $5;
if ($$) {
Type tt = $$->type();
tt.ti(Type::TI_VAR);
tt.st(Type::ST_SET);
if ($2) tt.ot(Type::OT_OPTIONAL);
$$->type(tt);
}
}
opt_opt:
/* nothing */
{ $$ = false; }
| MZN_OPT
{ $$ = true; }
base_ti_expr_tail :
MZN_INT
{ $$ = new TypeInst(@$,Type::parint()); }
| MZN_BOOL
{ $$ = new TypeInst(@$,Type::parbool()); }
| MZN_FLOAT
{ $$ = new TypeInst(@$,Type::parfloat()); }
| MZN_STRING
{ $$ = new TypeInst(@$,Type::parstring()); }
| MZN_ANN
{ $$ = new TypeInst(@$,Type::ann()); }
| set_expr
{ if ($1) $$ = new TypeInst(@$,Type(),$1); }
| MZN_TI_IDENTIFIER
{ $$ = new TypeInst(@$,Type::top(),
new TIId(@$, $1));
free($1);
}
| MZN_TI_ENUM_IDENTIFIER
{ $$ = new TypeInst(@$,Type::parint(),
new TIId(@$, $1));
free($1);
}
array_access_expr_list : array_access_expr_list_head comma_or_none
array_access_expr_list_head :
array_access_expr
{ $$=new std::vector<MiniZinc::Expression*>; $$->push_back($1); }
| array_access_expr_list_head ',' array_access_expr
{ $$=$1; if ($$ && $3) $$->push_back($3); }
array_access_expr :
expr
{ $$ = $1; }
| MZN_DOTDOT
{ $$=new SetLit(@$, IntSetVal::a(-IntVal::infinity(),IntVal::infinity())); }
| MZN_DOTDOT expr
{ if ($2==NULL) {
$$ = NULL;
} else if ($2->isa<IntLit>()) {
$$=new SetLit(@$, IntSetVal::a(-IntVal::infinity(),$2->cast<IntLit>()->v()));
} else {
$$=new BinOp(@$, IntLit::a(-IntVal::infinity()), BOT_DOTDOT, $2);
}
}
| expr MZN_DOTDOT
{ if ($1==NULL) {
$$ = NULL;
} else if ($1->isa<IntLit>()) {
$$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),IntVal::infinity()));
} else {
$$=new BinOp(@$, $1, BOT_DOTDOT, IntLit::a(IntVal::infinity()));
}
}
expr_list : expr_list_head comma_or_none
expr_list_head :
expr
{ $$=new std::vector<MiniZinc::Expression*>; $$->push_back($1); }
| expr_list_head ',' expr
{ $$=$1; if ($$ && $3) $$->push_back($3); }
///
set_expr :
expr_atom_head
| set_expr MZN_COLONCOLON annotation_expr
{ if ($1 && $3) $1->addAnnotation($3); $$=$1; }
| set_expr MZN_UNION set_expr
{ $$=new BinOp(@$, $1, BOT_UNION, $3); }
| set_expr MZN_DIFF set_expr
{ $$=new BinOp(@$, $1, BOT_DIFF, $3); }
| set_expr MZN_SYMDIFF set_expr
{ $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); }
| set_expr MZN_DOTDOT set_expr
{ if ($1==NULL || $3==NULL) {
$$ = NULL;
} else if ($1->isa<IntLit>() && $3->isa<IntLit>()) {
$$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),$3->cast<IntLit>()->v()));
} else {
$$=new BinOp(@$, $1, BOT_DOTDOT, $3);
}
}
| MZN_DOTDOT_QUOTED '(' expr ',' expr ')'
{ if ($3==NULL || $5==NULL) {
$$ = NULL;
} else if ($3->isa<IntLit>() && $5->isa<IntLit>()) {
$$=new SetLit(@$, IntSetVal::a($3->cast<IntLit>()->v(),$5->cast<IntLit>()->v()));
} else {
$$=new BinOp(@$, $3, BOT_DOTDOT, $5);
}
}
| set_expr MZN_INTERSECT set_expr
{ $$=new BinOp(@$, $1, BOT_INTERSECT, $3); }
| set_expr MZN_PLUSPLUS set_expr
{ $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); }
| set_expr MZN_PLUS set_expr
{ $$=new BinOp(@$, $1, BOT_PLUS, $3); }
| set_expr MZN_MINUS set_expr
{ $$=new BinOp(@$, $1, BOT_MINUS, $3); }
| set_expr MZN_MULT set_expr
{ $$=new BinOp(@$, $1, BOT_MULT, $3); }
| set_expr MZN_DIV set_expr
{ $$=new BinOp(@$, $1, BOT_DIV, $3); }
| set_expr MZN_IDIV set_expr
{ $$=new BinOp(@$, $1, BOT_IDIV, $3); }
| set_expr MZN_MOD set_expr
{ $$=new BinOp(@$, $1, BOT_MOD, $3); }
| set_expr MZN_POW set_expr
{ $$=new BinOp(@$, $1, BOT_POW, $3); }
| set_expr MZN_WEAK_PLUS set_expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, ASTString("~+"), args);
}
| set_expr MZN_WEAK_MINUS set_expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, ASTString("~-"), args);
}
| set_expr MZN_WEAK_MULT set_expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, ASTString("~*"), args);
}
| set_expr MZN_WEAK_EQ set_expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, ASTString("~="), args);
}
| set_expr MZN_QUOTED_IDENTIFIER set_expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, $2, args);
free($2);
}
| MZN_PLUS set_expr %prec MZN_NOT
{ $$=new UnOp(@$, UOT_PLUS, $2); }
| MZN_MINUS set_expr %prec MZN_NOT
{ if ($2 && $2->isa<IntLit>()) {
$$ = IntLit::a(-$2->cast<IntLit>()->v());
} else if ($2 && $2->isa<FloatLit>()) {
$$ = FloatLit::a(-$2->cast<FloatLit>()->v());
} else {
$$=new UnOp(@$, UOT_MINUS, $2);
}
}
///
expr :
expr_atom_head
| expr MZN_COLONCOLON annotation_expr
{ if ($1 && $3) $1->addAnnotation($3); $$=$1; }
| expr MZN_EQUIV expr
{ $$=new BinOp(@$, $1, BOT_EQUIV, $3); }
| expr MZN_IMPL expr
{ $$=new BinOp(@$, $1, BOT_IMPL, $3); }
| expr MZN_RIMPL expr
{ $$=new BinOp(@$, $1, BOT_RIMPL, $3); }
| expr MZN_OR expr
{ $$=new BinOp(@$, $1, BOT_OR, $3); }
| expr MZN_XOR expr
{ $$=new BinOp(@$, $1, BOT_XOR, $3); }
| expr MZN_AND expr
{ $$=new BinOp(@$, $1, BOT_AND, $3); }
| expr MZN_LE expr
{ $$=new BinOp(@$, $1, BOT_LE, $3); }
| expr MZN_GR expr
{ $$=new BinOp(@$, $1, BOT_GR, $3); }
| expr MZN_LQ expr
{ $$=new BinOp(@$, $1, BOT_LQ, $3); }
| expr MZN_GQ expr
{ $$=new BinOp(@$, $1, BOT_GQ, $3); }
| expr MZN_EQ expr
{ $$=new BinOp(@$, $1, BOT_EQ, $3); }
| expr MZN_NQ expr
{ $$=new BinOp(@$, $1, BOT_NQ, $3); }
| expr MZN_IN expr
{ $$=new BinOp(@$, $1, BOT_IN, $3); }
| expr MZN_SUBSET expr
{ $$=new BinOp(@$, $1, BOT_SUBSET, $3); }
| expr MZN_SUPERSET expr
{ $$=new BinOp(@$, $1, BOT_SUPERSET, $3); }
| expr MZN_UNION expr
{ $$=new BinOp(@$, $1, BOT_UNION, $3); }
| expr MZN_DIFF expr
{ $$=new BinOp(@$, $1, BOT_DIFF, $3); }
| expr MZN_SYMDIFF expr
{ $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); }
| expr MZN_DOTDOT expr
{ if ($1==NULL || $3==NULL) {
$$ = NULL;
} else if ($1->isa<IntLit>() && $3->isa<IntLit>()) {
$$=new SetLit(@$, IntSetVal::a($1->cast<IntLit>()->v(),$3->cast<IntLit>()->v()));
} else {
$$=new BinOp(@$, $1, BOT_DOTDOT, $3);
}
}
| MZN_DOTDOT_QUOTED '(' expr ',' expr ')'
{ if ($3==NULL || $5==NULL) {
$$ = NULL;
} else if ($3->isa<IntLit>() && $5->isa<IntLit>()) {
$$=new SetLit(@$, IntSetVal::a($3->cast<IntLit>()->v(),$5->cast<IntLit>()->v()));
} else {
$$=new BinOp(@$, $3, BOT_DOTDOT, $5);
}
}
| expr MZN_INTERSECT expr
{ $$=new BinOp(@$, $1, BOT_INTERSECT, $3); }
| expr MZN_PLUSPLUS expr
{ $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); }
| expr MZN_PLUS expr
{ $$=new BinOp(@$, $1, BOT_PLUS, $3); }
| expr MZN_MINUS expr
{ $$=new BinOp(@$, $1, BOT_MINUS, $3); }
| expr MZN_MULT expr
{ $$=new BinOp(@$, $1, BOT_MULT, $3); }
| expr MZN_DIV expr
{ $$=new BinOp(@$, $1, BOT_DIV, $3); }
| expr MZN_IDIV expr
{ $$=new BinOp(@$, $1, BOT_IDIV, $3); }
| expr MZN_MOD expr
{ $$=new BinOp(@$, $1, BOT_MOD, $3); }
| expr MZN_POW expr
{ $$=new BinOp(@$, $1, BOT_POW, $3); }
| expr MZN_WEAK_PLUS expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, ASTString("~+"), args);
}
| expr MZN_WEAK_MINUS expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, ASTString("~-"), args);
}
| expr MZN_WEAK_MULT expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, ASTString("~*"), args);
}
| expr MZN_WEAK_EQ expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, ASTString("~="), args);
}
| expr MZN_QUOTED_IDENTIFIER expr
{ vector<Expression*> args;
args.push_back($1); args.push_back($3);
$$=new Call(@$, $2, args);
free($2);
}
| MZN_NOT expr %prec MZN_NOT
{ $$=new UnOp(@$, UOT_NOT, $2); }
| MZN_PLUS expr %prec MZN_NOT
{ if (($2 && $2->isa<IntLit>()) || ($2 && $2->isa<FloatLit>())) {
$$ = $2;
} else {
$$=new UnOp(@$, UOT_PLUS, $2);
}
}
| MZN_MINUS expr %prec MZN_NOT
{ if ($2 && $2->isa<IntLit>()) {
$$ = IntLit::a(-$2->cast<IntLit>()->v());
} else if ($2 && $2->isa<FloatLit>()) {
$$ = FloatLit::a(-$2->cast<FloatLit>()->v());
} else {
$$=new UnOp(@$, UOT_MINUS, $2);
}
}
expr_atom_head :
expr_atom_head_nonstring
{ $$=$1; }
| string_expr
{ $$=$1; }
expr_atom_head_nonstring :
'(' expr ')'
{ $$=$2; }
| '(' expr ')' array_access_tail
{ if ($4) $$=createArrayAccess(@$, $2, *$4); delete $4; }
| MZN_IDENTIFIER
{ $$=new Id(@$, $1, NULL); free($1); }
| MZN_IDENTIFIER array_access_tail
{ if ($2) $$=createArrayAccess(@$, new Id(@1,$1,NULL), *$2);
free($1); delete $2; }
| MZN_UNDERSCORE
{ $$=new AnonVar(@$); }
| MZN_UNDERSCORE array_access_tail
{ if ($2) $$=createArrayAccess(@$, new AnonVar(@$), *$2);
delete $2; }
| MZN_BOOL_LITERAL
{ $$=constants().boollit(($1!=0)); }
| MZN_INTEGER_LITERAL
{ $$=IntLit::a($1); }
| MZN_INFINITY
{ $$=IntLit::a(IntVal::infinity()); }
| MZN_FLOAT_LITERAL
{ $$=FloatLit::a($1); }
| MZN_ABSENT
{ $$=constants().absent; }
| set_literal
| set_literal array_access_tail
{ if ($2) $$=createArrayAccess(@$, $1, *$2);
delete $2; }
| set_comp
| set_comp array_access_tail
{ if ($2) $$=createArrayAccess(@$, $1, *$2);
delete $2; }
| simple_array_literal
| simple_array_literal array_access_tail
{ if ($2) $$=createArrayAccess(@$, $1, *$2);
delete $2; }
| simple_array_literal_2d
| simple_array_literal_2d array_access_tail
{ if ($2) $$=createArrayAccess(@$, $1, *$2);
delete $2; }
| simple_array_comp
| simple_array_comp array_access_tail
{ if ($2) $$=createArrayAccess(@$, $1, *$2);
delete $2; }
| if_then_else_expr
| if_then_else_expr array_access_tail
{ if ($2) $$=createArrayAccess(@$, $1, *$2);
delete $2; }
| let_expr
| call_expr
| call_expr array_access_tail
{ if ($2) $$=createArrayAccess(@$, $1, *$2);
delete $2; }
string_expr:
MZN_STRING_LITERAL
{ $$=new StringLit(@$, $1); free($1); }
| MZN_STRING_QUOTE_START string_quote_rest
{ $$=new BinOp(@$, new StringLit(@$, $1), BOT_PLUSPLUS, $2);
free($1);
}
string_quote_rest:
expr_list_head MZN_STRING_QUOTE_END
{ if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS, new StringLit(@$,$2));
free($2);
delete $1;
}
| expr_list_head MZN_STRING_QUOTE_MID string_quote_rest
{ if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS,
new BinOp(@$, new StringLit(@$,$2), BOT_PLUSPLUS, $3));
free($2);
delete $1;
}
array_access_tail :
MZN_LEFT_BRACKET array_access_expr_list MZN_RIGHT_BRACKET
{ $$=new std::vector<std::vector<Expression*> >();
if ($2) {
$$->push_back(*$2);
delete $2;
}
}
| array_access_tail MZN_LEFT_BRACKET array_access_expr_list MZN_RIGHT_BRACKET
{ $$=$1;
if ($$ && $3) {
$$->push_back(*$3);
delete $3;
}
}
set_literal :
'{' '}'
{ $$ = new SetLit(@$, std::vector<Expression*>()); }
| '{' expr_list '}'
{ if ($2) $$ = new SetLit(@$, *$2);
delete $2; }
set_comp :
'{' expr '|' comp_tail '}'
{ if ($4) $$ = new Comprehension(@$, $2, *$4, true);
delete $4;
}
comp_tail :
generator_list
{ if ($1) $$=new Generators; $$->_g = *$1; delete $1; }
generator_list : generator_list_head comma_or_none
generator_list_head :
generator
{ $$=new std::vector<Generator>; if ($1) $$->push_back(*$1); delete $1; }
| generator_eq
{ $$=new std::vector<Generator>; if ($1) $$->push_back(*$1); delete $1; }
| generator_eq MZN_WHERE expr
{ $$=new std::vector<Generator>;
if ($1) $$->push_back(*$1);
if ($1 && $3) $$->push_back(Generator($$->size(),$3));
delete $1;
}
| generator_list_head ',' generator
{ $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
| generator_list_head ',' generator_eq
{ $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
| generator_list_head ',' generator_eq MZN_WHERE expr
{ $$=$1;
if ($$ && $3) $$->push_back(*$3);
if ($$ && $3 && $5) $$->push_back(Generator($$->size(),$5));
delete $3;
}
generator :
id_list MZN_IN expr
{ if ($1 && $3) $$=new Generator(*$1,$3,NULL); else $$=NULL; delete $1; }
| id_list MZN_IN expr MZN_WHERE expr
{ if ($1 && $3) $$=new Generator(*$1,$3,$5); else $$=NULL; delete $1; }
generator_eq :
MZN_IDENTIFIER MZN_EQ expr
{ if ($3) $$=new Generator({$1},NULL,$3); else $$=NULL; free($1); }
id_list : id_list_head comma_or_none
id_list_head :
MZN_IDENTIFIER
{ $$=new std::vector<std::string>; $$->push_back($1); free($1); }
| id_list_head ',' MZN_IDENTIFIER
{ $$=$1; if ($$ && $3) $$->push_back($3); free($3); }
simple_array_literal :
MZN_LEFT_BRACKET MZN_RIGHT_BRACKET
{ $$=new ArrayLit(@$, std::vector<MiniZinc::Expression*>()); }
| MZN_LEFT_BRACKET expr_list MZN_RIGHT_BRACKET
{ if ($2) $$=new ArrayLit(@$, *$2); delete $2; }
simple_array_literal_2d :
MZN_LEFT_2D_BRACKET MZN_RIGHT_2D_BRACKET
{ $$=new ArrayLit(@$, std::vector<std::vector<Expression*> >()); }
| MZN_LEFT_2D_BRACKET simple_array_literal_2d_list MZN_RIGHT_2D_BRACKET
{ if ($2) {
$$=new ArrayLit(@$, *$2);
for (unsigned int i=1; i<$2->size(); i++)
if ((*$2)[i].size() != (*$2)[i-1].size())
yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length");
delete $2;
} else {
$$ = NULL;
}
}
| MZN_LEFT_2D_BRACKET simple_array_literal_2d_list '|' MZN_RIGHT_2D_BRACKET
{ if ($2) {
$$=new ArrayLit(@$, *$2);
for (unsigned int i=1; i<$2->size(); i++)
if ((*$2)[i].size() != (*$2)[i-1].size())
yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length");
delete $2;
} else {
$$ = NULL;
}
}
| MZN_LEFT_2D_BRACKET simple_array_literal_3d_list MZN_RIGHT_2D_BRACKET
{
if ($2) {
std::vector<std::pair<int,int> > dims(3);
dims[0] = std::pair<int,int>(1,static_cast<int>($2->size()));
if ($2->size()==0) {
dims[1] = std::pair<int,int>(1,0);
dims[2] = std::pair<int,int>(1,0);
} else {
dims[1] = std::pair<int,int>(1,static_cast<int>((*$2)[0].size()));
if ((*$2)[0].size()==0) {
dims[2] = std::pair<int,int>(1,0);
} else {
dims[2] = std::pair<int,int>(1,static_cast<int>((*$2)[0][0].size()));
}
}
std::vector<Expression*> a;
for (int i=0; i<dims[0].second; i++) {
if ((*$2)[i].size() != dims[1].second) {
yyerror(&@2, parm, "syntax error, all sub-arrays of 3d array literal must have the same length");
} else {
for (int j=0; j<dims[1].second; j++) {
if ((*$2)[i][j].size() != dims[2].second) {
yyerror(&@2, parm, "syntax error, all sub-arrays of 3d array literal must have the same length");
} else {
for (int k=0; k<dims[2].second; k++) {
a.push_back((*$2)[i][j][k]);
}
}
}
}
}
$$ = new ArrayLit(@$,a,dims);
delete $2;
} else {
$$ = NULL;
}
}
simple_array_literal_3d_list :
'|' '|'
{ $$=new std::vector<std::vector<std::vector<MiniZinc::Expression*> > >;
}
| '|' simple_array_literal_2d_list '|'
{ $$=new std::vector<std::vector<std::vector<MiniZinc::Expression*> > >;
if ($2) $$->push_back(*$2);
delete $2;
}
| simple_array_literal_3d_list ',' '|' simple_array_literal_2d_list '|'
{ $$=$1;
if ($$ && $4) $$->push_back(*$4);
delete $4;
}
simple_array_literal_2d_list :
expr_list
{ $$=new std::vector<std::vector<MiniZinc::Expression*> >;
if ($1) $$->push_back(*$1);
delete $1;
}
| simple_array_literal_2d_list '|' expr_list
{ $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; }
simple_array_comp :
MZN_LEFT_BRACKET expr '|' comp_tail MZN_RIGHT_BRACKET
{ if ($4) $$=new Comprehension(@$, $2, *$4, false);
delete $4;
}
if_then_else_expr :
MZN_IF expr MZN_THEN expr MZN_ENDIF
{
std::vector<Expression*> iexps;
iexps.push_back($2);
iexps.push_back($4);
$$=new ITE(@$, iexps, NULL);
}
| MZN_IF expr MZN_THEN expr elseif_list MZN_ELSE expr MZN_ENDIF
{
std::vector<Expression*> iexps;
iexps.push_back($2);
iexps.push_back($4);
if ($5) {
for (unsigned int i=0; i<$5->size(); i+=2) {
iexps.push_back((*$5)[i]);
iexps.push_back((*$5)[i+1]);
}
}
$$=new ITE(@$, iexps,$7);
delete $5;
}
elseif_list :
{ $$=new std::vector<MiniZinc::Expression*>; }
| elseif_list MZN_ELSEIF expr MZN_THEN expr
{ $$=$1; if ($$ && $3 && $5) { $$->push_back($3); $$->push_back($5); } }
quoted_op :
MZN_EQUIV_QUOTED
{ $$=BOT_EQUIV; }
| MZN_IMPL_QUOTED
{ $$=BOT_IMPL; }
| MZN_RIMPL_QUOTED
{ $$=BOT_RIMPL; }
| MZN_OR_QUOTED
{ $$=BOT_OR; }
| MZN_XOR_QUOTED
{ $$=BOT_XOR; }
| MZN_AND_QUOTED
{ $$=BOT_AND; }
| MZN_LE_QUOTED
{ $$=BOT_LE; }
| MZN_GR_QUOTED
{ $$=BOT_GR; }
| MZN_LQ_QUOTED
{ $$=BOT_LQ; }
| MZN_GQ_QUOTED
{ $$=BOT_GQ; }
| MZN_EQ_QUOTED
{ $$=BOT_EQ; }
| MZN_NQ_QUOTED
{ $$=BOT_NQ; }
| MZN_IN_QUOTED
{ $$=BOT_IN; }
| MZN_SUBSET_QUOTED
{ $$=BOT_SUBSET; }
| MZN_SUPERSET_QUOTED
{ $$=BOT_SUPERSET; }
| MZN_UNION_QUOTED
{ $$=BOT_UNION; }
| MZN_DIFF_QUOTED
{ $$=BOT_DIFF; }
| MZN_SYMDIFF_QUOTED
{ $$=BOT_SYMDIFF; }
| MZN_PLUS_QUOTED
{ $$=BOT_PLUS; }
| MZN_MINUS_QUOTED
{ $$=BOT_MINUS; }
| MZN_MULT_QUOTED
{ $$=BOT_MULT; }
| MZN_POW_QUOTED
{ $$=BOT_POW; }
| MZN_DIV_QUOTED
{ $$=BOT_DIV; }
| MZN_IDIV_QUOTED
{ $$=BOT_IDIV; }
| MZN_MOD_QUOTED
{ $$=BOT_MOD; }
| MZN_INTERSECT_QUOTED
{ $$=BOT_INTERSECT; }
| MZN_PLUSPLUS_QUOTED
{ $$=BOT_PLUSPLUS; }
| MZN_NOT_QUOTED
{ $$=-1; }
quoted_op_call :
quoted_op '(' expr ',' expr ')'
{ if ($1==-1) {
$$=NULL;
yyerror(&@3, parm, "syntax error, unary operator with two arguments");
} else {
$$=new BinOp(@$, $3,static_cast<BinOpType>($1),$5);
}
}
| quoted_op '(' expr ')'
{ int uot=-1;
switch ($1) {
case -1:
uot = UOT_NOT;
break;
case BOT_MINUS:
uot = UOT_MINUS;
break;
case BOT_PLUS:
uot = UOT_PLUS;
break;
default:
yyerror(&@3, parm, "syntax error, binary operator with unary argument list");
break;
}
if (uot==-1)
$$=NULL;
else {
if (uot==UOT_PLUS && $3 && ($3->isa<IntLit>() || $3->isa<FloatLit>())) {
$$ = $3;
} else if (uot==UOT_MINUS && $3 && $3->isa<IntLit>()) {
$$ = IntLit::a(-$3->cast<IntLit>()->v());
} else if (uot==UOT_MINUS && $3 && $3->isa<FloatLit>()) {
$$ = FloatLit::a(-$3->cast<FloatLit>()->v());
} else {
$$=new UnOp(@$, static_cast<UnOpType>(uot),$3);
}
}
}
call_expr :
MZN_IDENTIFIER '(' ')'
{ $$=new Call(@$, $1, std::vector<Expression*>()); free($1); }
| quoted_op_call
| MZN_IDENTIFIER '(' comp_or_expr ')'
{
if ($3!=NULL) {
bool hadWhere = false;
std::vector<Expression*> args;
for (unsigned int i=0; i<$3->size(); i++) {
if ((*$3)[i].second) {
yyerror(&@3, parm, "syntax error, 'where' expression outside generator call");
hadWhere = true;
$$=NULL;
}
args.push_back((*$3)[i].first);
}
if (!hadWhere) {
$$=new Call(@$, $1, args);
}
}
free($1);
delete $3;
}
| MZN_IDENTIFIER '(' comp_or_expr ')' '(' expr ')'
{
vector<Generator> gens;
vector<Id*> ids;
if ($3) {
for (unsigned int i=0; i<$3->size(); i++) {
if (Id* id = Expression::dyn_cast<Id>((*$3)[i].first)) {
if ((*$3)[i].second) {
ParserLocation loc = (*$3)[i].second->loc().parserLocation();
yyerror(&loc, parm, "illegal where expression in generator call");
}
ids.push_back(id);
} else {
if (BinOp* boe = Expression::dyn_cast<BinOp>((*$3)[i].first)) {
if (boe->lhs() && boe->rhs()) {
Id* id = Expression::dyn_cast<Id>(boe->lhs());
if (id && boe->op() == BOT_IN) {
ids.push_back(id);
gens.push_back(Generator(ids,boe->rhs(),(*$3)[i].second));
ids = vector<Id*>();
} else if (id && boe->op() == BOT_EQ && ids.empty()) {
ids.push_back(id);
gens.push_back(Generator(ids,NULL,boe->rhs()));
if ((*$3)[i].second) {
gens.push_back(Generator(gens.size(),(*$3)[i].second));
}
ids = vector<Id*>();
} else {
ParserLocation loc = (*$3)[i].first->loc().parserLocation();
yyerror(&loc, parm, "illegal expression in generator call");
}
}
} else {
ParserLocation loc = (*$3)[i].first->loc().parserLocation();
yyerror(&loc, parm, "illegal expression in generator call");
}
}
}
}
if (ids.size() != 0) {
yyerror(&@3, parm, "illegal expression in generator call");
}
ParserState* pp = static_cast<ParserState*>(parm);
if (pp->hadError) {
$$=NULL;
} else {
Generators g; g._g = gens;
Comprehension* ac = new Comprehension(@$, $6,g,false);
vector<Expression*> args; args.push_back(ac);
$$=new Call(@$, $1, args);
}
free($1);
delete $3;
}
comp_or_expr : comp_or_expr_head comma_or_none
comp_or_expr_head :
expr
{ $$=new vector<pair<Expression*,Expression*> >;
if ($1) {
$$->push_back(pair<Expression*,Expression*>($1,NULL));
}
}
| expr MZN_WHERE expr
{ $$=new vector<pair<Expression*,Expression*> >;
if ($1 && $3) {
$$->push_back(pair<Expression*,Expression*>($1,$3));
}
}
| comp_or_expr_head ',' expr
{ $$=$1; if ($$ && $3) $$->push_back(pair<Expression*,Expression*>($3,NULL)); }
| comp_or_expr_head ',' expr MZN_WHERE expr
{ $$=$1; if ($$ && $3 && $5) $$->push_back(pair<Expression*,Expression*>($3,$5)); }
let_expr :
MZN_LET '{' let_vardecl_item_list '}' MZN_IN expr %prec PREC_ANNO
{ if ($3 && $6) {
$$=new Let(@$, *$3, $6); delete $3;
} else {
$$=NULL;
}
}
| MZN_LET '{' let_vardecl_item_list comma_or_semi '}' MZN_IN expr %prec PREC_ANNO
{ if ($3 && $7) {
$$=new Let(@$, *$3, $7); delete $3;
} else {
$$=NULL;
}
}
let_vardecl_item_list :
let_vardecl_item
{ $$=new vector<Expression*>; $$->push_back($1); }
| constraint_item
{ $$=new vector<Expression*>;
if ($1) {
ConstraintI* ce = $1->cast<ConstraintI>();
$$->push_back(ce->e());
ce->e(NULL);
}
}
| let_vardecl_item_list comma_or_semi let_vardecl_item
{ $$=$1; if ($$ && $3) $$->push_back($3); }
| let_vardecl_item_list comma_or_semi constraint_item
{ $$=$1;
if ($$ && $3) {
ConstraintI* ce = $3->cast<ConstraintI>();
$$->push_back(ce->e());
ce->e(NULL);
}
}
comma_or_semi : ',' | ';'
let_vardecl_item :
ti_expr_and_id annotations
{ $$ = $1;
if ($$) $$->toplevel(false);
if ($$ && $2) $$->addAnnotations(*$2);
delete $2;
}
| ti_expr_and_id annotations MZN_EQ expr
{ if ($1) $1->e($4);
$$ = $1;
if ($$) $$->loc(@$);
if ($$) $$->toplevel(false);
if ($$ && $2) $$->addAnnotations(*$2);
delete $2;
}
annotations :
/* empty */
{ $$=NULL; }
| ne_annotations
annotation_expr :
expr_atom_head_nonstring
{ $$ = $1; }
| string_expr
{ $$ = new Call(@1, ASTString("mzn_expression_name"), {$1}); }
ne_annotations :
MZN_COLONCOLON annotation_expr
{ $$=new std::vector<Expression*>(1);
(*$$)[0] = $2;
}
| ne_annotations MZN_COLONCOLON annotation_expr
{ $$=$1; if ($$) $$->push_back($3); }
id_or_quoted_op :
MZN_IDENTIFIER
{ $$=$1; }
| MZN_EQUIV_QUOTED
{ $$=strdup("'<->'"); }
| MZN_IMPL_QUOTED
{ $$=strdup("'->'"); }
| MZN_RIMPL_QUOTED
{ $$=strdup("'<-'"); }
| MZN_OR_QUOTED
{ $$=strdup("'\\/'"); }
| MZN_XOR_QUOTED
{ $$=strdup("'xor'"); }
| MZN_AND_QUOTED
{ $$=strdup("'/\\'"); }
| MZN_LE_QUOTED
{ $$=strdup("'<'"); }
| MZN_GR_QUOTED
{ $$=strdup("'>'"); }
| MZN_LQ_QUOTED
{ $$=strdup("'<='"); }
| MZN_GQ_QUOTED
{ $$=strdup("'>='"); }
| MZN_EQ_QUOTED
{ $$=strdup("'='"); }
| MZN_NQ_QUOTED
{ $$=strdup("'!='"); }
| MZN_IN_QUOTED
{ $$=strdup("'in'"); }
| MZN_SUBSET_QUOTED
{ $$=strdup("'subset'"); }
| MZN_SUPERSET_QUOTED
{ $$=strdup("'superset'"); }
| MZN_UNION_QUOTED
{ $$=strdup("'union'"); }
| MZN_DIFF_QUOTED
{ $$=strdup("'diff'"); }
| MZN_SYMDIFF_QUOTED
{ $$=strdup("'symdiff'"); }
| MZN_DOTDOT_QUOTED
{ $$=strdup("'..'"); }
| MZN_PLUS_QUOTED
{ $$=strdup("'+'"); }
| MZN_MINUS_QUOTED
{ $$=strdup("'-'"); }
| MZN_MULT_QUOTED
{ $$=strdup("'*'"); }
| MZN_POW_QUOTED
{ $$=strdup("'^'"); }
| MZN_DIV_QUOTED
{ $$=strdup("'/'"); }
| MZN_IDIV_QUOTED
{ $$=strdup("'div'"); }
| MZN_MOD_QUOTED
{ $$=strdup("'mod'"); }
| MZN_INTERSECT_QUOTED
{ $$=strdup("'intersect'"); }
| MZN_NOT_QUOTED
{ $$=strdup("'not'"); }
| MZN_PLUSPLUS_QUOTED
{ $$=strdup("'++'"); }