/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack * * Copyright: * Guido Tack, 2007 * * This file is part of Gecode, the generic constraint * development environment: * http://www.gecode.org * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ %pure-parser %parse-param {void *parm} %lex-param {void *YYLEX_PARAM} %{ #define YYPARSE_PARAM parm #define YYLEX_PARAM static_cast(parm)->yyscanner #include #include #include #include #include #ifdef HAVE_MMAP #include #include #include #include #include #include #include #endif using namespace std; int yyparse(void*); int yylex(YYSTYPE*, void* scanner); int yylex_init (void** scanner); int yylex_destroy (void* scanner); int yyget_lineno (void* scanner); void yyset_extra (void* user_defined ,void* yyscanner ); extern int yydebug; using namespace Gecode; using namespace Gecode::FlatZinc; void yyerror(void* parm, const char *str) { ParserState* pp = static_cast(parm); pp->err << "Error: " << str << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; } void yyassert(ParserState* pp, bool cond, const char* str) { if (!cond) { pp->err << "Error: " << str << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; } } /* * The symbol tables * */ AST::Node* getArrayElement(ParserState* pp, string id, int offset, bool annotation) { if (offset > 0) { SymbolEntry e; if (pp->symbols.get(id,e)) { switch (e.t) { case ST_INTVARARRAY: if (offset > pp->arrays[e.i]) goto error; { std::string n; if (annotation) { std::ostringstream oss; oss << id << "[" << offset << "]"; n = oss.str(); } return new AST::IntVar(pp->arrays[e.i+offset],n); } case ST_BOOLVARARRAY: if (offset > pp->arrays[e.i]) goto error; { std::string n; if (annotation) { std::ostringstream oss; oss << id << "[" << offset << "]"; n = oss.str(); } return new AST::BoolVar(pp->arrays[e.i+offset],n); } case ST_SETVARARRAY: if (offset > pp->arrays[e.i]) goto error; { std::string n; if (annotation) { std::ostringstream oss; oss << id << "[" << offset << "]"; n = oss.str(); } return new AST::SetVar(pp->arrays[e.i+offset],n); } case ST_FLOATVARARRAY: if (offset > pp->arrays[e.i]) goto error; { std::string n; if (annotation) { std::ostringstream oss; oss << id << "[" << offset << "]"; n = oss.str(); } return new AST::FloatVar(pp->arrays[e.i+offset],n); } case ST_INTVALARRAY: if (offset > pp->arrays[e.i]) goto error; return new AST::IntLit(pp->arrays[e.i+offset]); case ST_SETVALARRAY: if (offset > pp->arrays[e.i]) goto error; return new AST::SetLit(pp->setvals[pp->arrays[e.i+1]+offset-1]); case ST_FLOATVALARRAY: if (offset > pp->arrays[e.i]) goto error; return new AST::FloatLit(pp->floatvals[pp->arrays[e.i+1]+offset-1]); default: break; } } } error: pp->err << "Error: array access to " << id << " invalid" << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; return new AST::IntVar(0); // keep things consistent } AST::Node* getVarRefArg(ParserState* pp, string id, bool annotation = false) { SymbolEntry e; string n; if (annotation) n = id; if (pp->symbols.get(id, e)) { switch (e.t) { case ST_INTVAR: return new AST::IntVar(e.i,n); case ST_BOOLVAR: return new AST::BoolVar(e.i,n); case ST_SETVAR: return new AST::SetVar(e.i,n); case ST_FLOATVAR: return new AST::FloatVar(e.i,n); default: break; } } if (annotation) return new AST::Atom(id); pp->err << "Error: undefined variable " << id << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; return new AST::IntVar(0); // keep things consistent } void addDomainConstraint(ParserState* pp, std::string id, AST::Node* var, Option& dom) { if (!dom()) return; AST::Array* args = new AST::Array(2); args->a[0] = var; args->a[1] = dom.some(); pp->domainConstraints.push_back(new ConExpr(id, args, NULL)); } void addDomainConstraint(ParserState* pp, AST::Node* var, Option* > dom) { if (!dom()) return; { AST::Array* args = new AST::Array(2); args->a[0] = new AST::FloatLit(dom.some()->first); args->a[1] = var; pp->domainConstraints.push_back(new ConExpr("float_le", args, NULL)); } { AST::Array* args = new AST::Array(2); AST::FloatVar* fv = static_cast(var); args->a[0] = new AST::FloatVar(fv->i,fv->n); args->a[1] = new AST::FloatLit(dom.some()->second); pp->domainConstraints.push_back(new ConExpr("float_le", args, NULL)); } delete dom.some(); } int getBaseIntVar(ParserState* pp, int i) { int base = i; IntVarSpec* ivs = static_cast(pp->intvars[base].second); while (ivs->alias) { base = ivs->i; ivs = static_cast(pp->intvars[base].second); } return base; } int getBaseBoolVar(ParserState* pp, int i) { int base = i; BoolVarSpec* ivs = static_cast(pp->boolvars[base].second); while (ivs->alias) { base = ivs->i; ivs = static_cast(pp->boolvars[base].second); } return base; } int getBaseFloatVar(ParserState* pp, int i) { int base = i; FloatVarSpec* ivs = static_cast(pp->floatvars[base].second); while (ivs->alias) { base = ivs->i; ivs = static_cast(pp->floatvars[base].second); } return base; } int getBaseSetVar(ParserState* pp, int i) { int base = i; SetVarSpec* ivs = static_cast(pp->setvars[base].second); while (ivs->alias) { base = ivs->i; ivs = static_cast(pp->setvars[base].second); } return base; } /* * Initialize the root gecode space * */ void initfg(ParserState* pp) { if (!pp->hadError) pp->fg->init(pp->intvars.size(), pp->boolvars.size(), pp->setvars.size(), pp->floatvars.size()); for (unsigned int i=0; iintvars.size(); i++) { if (!pp->hadError) { try { pp->fg->newIntVar(static_cast(pp->intvars[i].second)); } catch (Gecode::FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } delete pp->intvars[i].second; pp->intvars[i].second = NULL; } for (unsigned int i=0; iboolvars.size(); i++) { if (!pp->hadError) { try { pp->fg->newBoolVar( static_cast(pp->boolvars[i].second)); } catch (Gecode::FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } delete pp->boolvars[i].second; pp->boolvars[i].second = NULL; } for (unsigned int i=0; isetvars.size(); i++) { if (!pp->hadError) { try { pp->fg->newSetVar(static_cast(pp->setvars[i].second)); } catch (Gecode::FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } delete pp->setvars[i].second; pp->setvars[i].second = NULL; } for (unsigned int i=0; ifloatvars.size(); i++) { if (!pp->hadError) { try { pp->fg->newFloatVar( static_cast(pp->floatvars[i].second)); } catch (Gecode::FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } delete pp->floatvars[i].second; pp->floatvars[i].second = NULL; } if (pp->status_idx >= 0) { pp->fg->restart_status = IntVarArray(*(pp->fg), 1); pp->fg->restart_status[0] = pp->fg->iv[pp->status_idx]; } if (!(pp->int_uniform.empty())) { pp->fg->int_uniform_var = IntVarArray(*(pp->fg), pp->int_uniform.size()); pp->fg->int_uniform_lb = new int[pp->int_uniform.size()]; pp->fg->int_uniform_ub = new int[pp->int_uniform.size()]; for (int i = 0; i < pp->int_uniform.size(); ++i) { pp->fg->int_uniform_lb[i] = pp->int_uniform[i][0]; pp->fg->int_uniform_ub[i] = pp->int_uniform[i][1]; pp->fg->int_uniform_var[i] = pp->fg->iv[pp->int_uniform[i][2]]; } } if (!(pp->int_sol.empty())) { pp->fg->int_sol_orig = IntVarArray(*(pp->fg), pp->int_sol.size()); pp->fg->int_sol_var = IntVarArray(*(pp->fg), pp->int_sol.size()); for (int i = 0; i < pp->int_sol.size(); ++i) { pp->fg->int_sol_orig[i] = pp->fg->iv[(pp->int_sol[i][0])]; pp->fg->int_sol_var[i] = pp->fg->iv[(pp->int_sol[i][1])]; } } if (!(pp->int_lastval.empty())) { pp->fg->int_lastval_var = IntVarArray(*(pp->fg), pp->int_lastval.size()); pp->fg->int_lastval_val = new std::shared_ptr[pp->int_lastval.size()]; for (int i = 0; i < pp->int_lastval.size(); ++i) { pp->fg->int_lastval_var[i] = pp->fg->iv[(pp->int_lastval[i][1])]; pp->fg->int_lastval_val[i] = std::make_shared(); LastVal::post(*(pp->fg), pp->fg->iv[(pp->int_lastval[i][0])], pp->fg->int_lastval_val[i]); } } if (!pp->hadError) { pp->fg->postConstraints(pp->domainConstraints); pp->fg->postConstraints(pp->constraints); } } void fillPrinter(ParserState& pp, Gecode::FlatZinc::Printer& p) { p.init(pp.getOutput()); for (unsigned int i=0; iargs->isArray()) { a = ann->args->getArray(); } else { a = new AST::Array(ann->args); } std::ostringstream oss; oss << "array" << a->a.size() << "d("; for (unsigned int i=0; ia.size(); i++) { AST::SetLit* s = a->a[i]->getSet(); if (s->empty()) oss << "{}, "; else if (s->interval) oss << s->min << ".." << s->max << ", "; else { oss << "{"; for (unsigned int j=0; js.size(); j++) { oss << s->s[j]; if (js.size()-1) oss << ","; } oss << "}, "; } } if (!ann->args->isArray()) { a->a[0] = NULL; delete a; } return new AST::String(oss.str()); } /* * The main program * */ namespace Gecode { namespace FlatZinc { FlatZincSpace* parse(const std::string& filename, Printer& p, std::ostream& err, FlatZincSpace* fzs, Rnd& rnd) { #ifdef HAVE_MMAP int fd; char* data; struct stat sbuf; fd = open(filename.c_str(), O_RDONLY); if (fd == -1) { err << "Cannot open file " << filename << endl; return NULL; } if (stat(filename.c_str(), &sbuf) == -1) { err << "Cannot stat file " << filename << endl; return NULL; } data = (char*)mmap((caddr_t)0, sbuf.st_size, PROT_READ, MAP_SHARED, fd,0); if (data == (caddr_t)(-1)) { err << "Cannot mmap file " << filename << endl; return NULL; } if (fzs == NULL) { fzs = new FlatZincSpace(rnd); } ParserState pp(data, sbuf.st_size, err, fzs); #else std::ifstream file; file.open(filename.c_str()); if (!file.is_open()) { err << "Cannot open file " << filename << endl; return NULL; } std::string s = string(istreambuf_iterator(file), istreambuf_iterator()); if (fzs == NULL) { fzs = new FlatZincSpace(rnd); } ParserState pp(s, err, fzs); #endif yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); // yydebug = 1; yyparse(&pp); fillPrinter(pp, p); if (pp.yyscanner) yylex_destroy(pp.yyscanner); return pp.hadError ? NULL : pp.fg; } FlatZincSpace* parse(std::istream& is, Printer& p, std::ostream& err, FlatZincSpace* fzs, Rnd& rnd) { std::string s = string(istreambuf_iterator(is), istreambuf_iterator()); if (fzs == NULL) { fzs = new FlatZincSpace(rnd); } ParserState pp(s, err, fzs); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); // yydebug = 1; yyparse(&pp); fillPrinter(pp, p); if (pp.yyscanner) yylex_destroy(pp.yyscanner); return pp.hadError ? NULL : pp.fg; } }} %} %union { int iValue; char* sValue; bool bValue; double dValue; std::vector* setValue; Gecode::FlatZinc::AST::SetLit* setLit; std::vector* floatSetValue; std::vector* setValueList; Gecode::FlatZinc::Option oSet; Gecode::FlatZinc::Option* > oPFloat; Gecode::FlatZinc::VarSpec* varSpec; Gecode::FlatZinc::Option oArg; std::vector* varSpecVec; Gecode::FlatZinc::Option* > oVarSpecVec; Gecode::FlatZinc::AST::Node* arg; Gecode::FlatZinc::AST::Array* argVec; } %error-verbose %token FZ_INT_LIT FZ_BOOL_LIT %token FZ_FLOAT_LIT %token FZ_ID FZ_U_ID FZ_STRING_LIT %token FZ_VAR FZ_PAR %token FZ_ANNOTATION %token FZ_ANY %token FZ_ARRAY %token FZ_BOOL %token FZ_CASE %token FZ_COLONCOLON %token FZ_CONSTRAINT %token FZ_DEFAULT %token FZ_DOTDOT %token FZ_ELSE %token FZ_ELSEIF %token FZ_ENDIF %token FZ_ENUM %token FZ_FLOAT %token FZ_FUNCTION %token FZ_IF %token FZ_INCLUDE %token FZ_INT %token FZ_LET %token FZ_MAXIMIZE %token FZ_MINIMIZE %token FZ_OF %token FZ_SATISFY %token FZ_OUTPUT %token FZ_PREDICATE %token FZ_RECORD %token FZ_SET %token FZ_SHOW %token FZ_SHOWCOND %token FZ_SOLVE %token FZ_STRING %token FZ_TEST %token FZ_THEN %token FZ_TUPLE %token FZ_TYPE %token FZ_VARIANT_RECORD %token FZ_WHERE %type var_par_id %type set_literal %type int_init bool_init set_init float_init %type int_ti_expr_tail bool_ti_expr_tail %type float_ti_expr_tail %type vardecl_int_var_array_init %type vardecl_bool_var_array_init %type vardecl_float_var_array_init %type vardecl_set_var_array_init %type int_var_array_literal %type bool_var_array_literal %type float_var_array_literal %type set_var_array_literal %type int_init_list int_init_list_head %type bool_init_list bool_init_list_head %type float_init_list float_init_list_head %type set_init_list set_init_list_head %type int_list int_list_head %type bool_list bool_list_head %type set_literal_list set_literal_list_head %type float_list float_list_head %type flat_expr non_array_expr annotation_expr ann_non_array_expr %type non_array_expr_opt %type flat_expr_list non_array_expr_list non_array_expr_list_head %type solve_expr %type minmax %type annotations annotations_head %type annotation annotation_list %% /********************************/ /* main goal and item lists */ /********************************/ model : preddecl_items vardecl_items constraint_items solve_item ';' preddecl_items: /* empty */ | preddecl_items_head preddecl_items_head: preddecl_item ';' | preddecl_items_head preddecl_item ';' vardecl_items: /* emtpy */ | vardecl_items_head vardecl_items_head: vardecl_item ';' | vardecl_items_head vardecl_item ';' constraint_items: /* emtpy */ | constraint_items_head constraint_items_head: constraint_item ';' | constraint_items_head constraint_item ';' /********************************/ /* predicate declarations */ /********************************/ preddecl_item: FZ_PREDICATE FZ_ID '(' pred_arg_list ')' { free($2); } pred_arg_list: /* empty */ | pred_arg_list_head list_tail pred_arg_list_head: pred_arg | pred_arg_list_head ',' pred_arg pred_arg: pred_arg_type ':' FZ_ID { free($3); } pred_arg_type: FZ_ARRAY '[' pred_array_init ']' FZ_OF pred_arg_simple_type | FZ_ARRAY '[' pred_array_init ']' FZ_OF FZ_VAR pred_arg_simple_type | FZ_VAR pred_arg_simple_type | pred_arg_simple_type pred_arg_simple_type: int_ti_expr_tail { if ($1()) delete $1.some(); } | FZ_SET FZ_OF int_ti_expr_tail { if ($3()) delete $3.some(); } | FZ_BOOL | FZ_FLOAT pred_array_init: pred_array_init_arg | pred_array_init ',' pred_array_init_arg pred_array_init_arg: FZ_INT | FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT /********************************/ /* variable declarations */ /********************************/ var_par_id : FZ_ID | FZ_U_ID vardecl_item: FZ_VAR int_ti_expr_tail ':' var_par_id annotations non_array_expr_opt { ParserState* pp = static_cast(parm); bool print = $5 != NULL && $5->hasAtom("output_var"); bool funcDep = $5 != NULL && $5->hasAtom("is_defined_var"); yyassert(pp, pp->symbols.put($4, se_iv(pp->intvars.size())), "Duplicate symbol"); if (print) { pp->output(std::string($4), new AST::IntVar(pp->intvars.size())); } if ($6()) { AST::Node* arg = $6.some(); if (arg->isInt()) { pp->intvars.push_back(varspec($4, new IntVarSpec(arg->getInt(),!print,funcDep))); } else if (arg->isIntVar()) { pp->intvars.push_back(varspec($4, new IntVarSpec(Alias(arg->getIntVar()),!print,funcDep))); } else { yyassert(pp, false, "Invalid var int initializer"); } if (!pp->hadError) addDomainConstraint(pp, "int_in", new AST::IntVar(pp->intvars.size()-1), $2); delete arg; } else { pp->intvars.push_back(varspec($4, new IntVarSpec($2,!print,funcDep))); } delete $5; free($4); } | FZ_VAR bool_ti_expr_tail ':' var_par_id annotations non_array_expr_opt { ParserState* pp = static_cast(parm); bool print = $5 != NULL && $5->hasAtom("output_var"); bool funcDep = $5 != NULL && $5->hasAtom("is_defined_var"); yyassert(pp, pp->symbols.put($4, se_bv(pp->boolvars.size())), "Duplicate symbol"); if (print) { pp->output(std::string($4), new AST::BoolVar(pp->boolvars.size())); } if ($6()) { AST::Node* arg = $6.some(); if (arg->isBool()) { pp->boolvars.push_back(varspec($4, new BoolVarSpec(arg->getBool(),!print,funcDep))); } else if (arg->isBoolVar()) { pp->boolvars.push_back(varspec($4, new BoolVarSpec(Alias(arg->getBoolVar()),!print,funcDep))); } else { yyassert(pp, false, "Invalid var bool initializer"); } if (!pp->hadError) addDomainConstraint(pp, "int_in", new AST::BoolVar(pp->boolvars.size()-1), $2); delete arg; } else { pp->boolvars.push_back(varspec($4, new BoolVarSpec($2,!print,funcDep))); } delete $5; free($4); } | FZ_VAR float_ti_expr_tail ':' var_par_id annotations non_array_expr_opt { ParserState* pp = static_cast(parm); bool print = $5 != NULL && $5->hasAtom("output_var"); bool funcDep = $5 != NULL && $5->hasAtom("is_defined_var"); yyassert(pp, pp->symbols.put($4, se_fv(pp->floatvars.size())), "Duplicate symbol"); if (print) { pp->output(std::string($4), new AST::FloatVar(pp->floatvars.size())); } if ($6()) { AST::Node* arg = $6.some(); if (arg->isFloat()) { pp->floatvars.push_back(varspec($4, new FloatVarSpec(arg->getFloat(),!print,funcDep))); } else if (arg->isFloatVar()) { pp->floatvars.push_back(varspec($4, new FloatVarSpec( Alias(arg->getFloatVar()),!print,funcDep))); } else { yyassert(pp, false, "Invalid var float initializer"); } if (!pp->hadError && $2()) { AST::FloatVar* fv = new AST::FloatVar(pp->floatvars.size()-1); addDomainConstraint(pp, fv, $2); } delete arg; } else { Option > dom = $2() ? Option >::some(*$2.some()) : Option >::none(); if ($2()) delete $2.some(); pp->floatvars.push_back(varspec($4, new FloatVarSpec(dom,!print,funcDep))); } delete $5; free($4); } | FZ_VAR FZ_SET FZ_OF int_ti_expr_tail ':' var_par_id annotations non_array_expr_opt { ParserState* pp = static_cast(parm); bool print = $7 != NULL && $7->hasAtom("output_var"); bool funcDep = $7 != NULL && $7->hasAtom("is_defined_var"); yyassert(pp, pp->symbols.put($6, se_sv(pp->setvars.size())), "Duplicate symbol"); if (print) { pp->output(std::string($6), new AST::SetVar(pp->setvars.size())); } if ($8()) { AST::Node* arg = $8.some(); if (arg->isSet()) { pp->setvars.push_back(varspec($6, new SetVarSpec(arg->getSet(),!print,funcDep))); } else if (arg->isSetVar()) { pp->setvars.push_back(varspec($6, new SetVarSpec(Alias(arg->getSetVar()),!print,funcDep))); delete arg; } else { yyassert(pp, false, "Invalid var set initializer"); delete arg; } if (!pp->hadError) addDomainConstraint(pp, "set_subset", new AST::SetVar(pp->setvars.size()-1), $4); } else { pp->setvars.push_back(varspec($6, new SetVarSpec($4,!print,funcDep))); } delete $7; free($6); } | FZ_INT ':' var_par_id annotations '=' non_array_expr { ParserState* pp = static_cast(parm); yyassert(pp, $6->isInt(), "Invalid int initializer"); yyassert(pp, pp->symbols.put($3, se_i($6->getInt())), "Duplicate symbol"); delete $4; free($3); } | FZ_FLOAT ':' var_par_id annotations '=' non_array_expr { ParserState* pp = static_cast(parm); yyassert(pp, $6->isFloat(), "Invalid float initializer"); pp->floatvals.push_back($6->getFloat()); yyassert(pp, pp->symbols.put($3, se_f(pp->floatvals.size()-1)), "Duplicate symbol"); delete $4; free($3); } | FZ_BOOL ':' var_par_id annotations '=' non_array_expr { ParserState* pp = static_cast(parm); yyassert(pp, $6->isBool(), "Invalid bool initializer"); yyassert(pp, pp->symbols.put($3, se_b($6->getBool())), "Duplicate symbol"); delete $4; free($3); } | FZ_SET FZ_OF FZ_INT ':' var_par_id annotations '=' non_array_expr { ParserState* pp = static_cast(parm); yyassert(pp, $8->isSet(), "Invalid set initializer"); AST::SetLit* set = $8->getSet(); pp->setvals.push_back(*set); yyassert(pp, pp->symbols.put($5, se_s(pp->setvals.size()-1)), "Duplicate symbol"); delete set; delete $6; free($5); } | FZ_ARRAY '[' FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT ']' FZ_OF FZ_VAR int_ti_expr_tail ':' var_par_id annotations vardecl_int_var_array_init { ParserState* pp = static_cast(parm); yyassert(pp, $3==1, "Arrays must start at 1"); if (!pp->hadError) { bool print = $12 != NULL && $12->hasCall("output_array"); vector vars($5); if (!pp->hadError) { if ($13()) { vector* vsv = $13.some(); yyassert(pp, vsv->size() == static_cast($5), "Initializer size does not match array dimension"); if (!pp->hadError) { for (int i=0; i<$5; i++) { IntVarSpec* ivsv = static_cast((*vsv)[i]); if (ivsv->alias) { if (print) static_cast(pp->intvars[ivsv->i].second)->introduced = false; vars[i] = ivsv->i; } else { if (print) ivsv->introduced = false; vars[i] = pp->intvars.size(); pp->intvars.push_back(varspec($11, ivsv)); } if (!pp->hadError && $9()) { Option opt = Option::some(new AST::SetLit(*$9.some())); addDomainConstraint(pp, "int_in", new AST::IntVar(vars[i]), opt); } } } delete vsv; } else { if ($5>0) { for (int i=0; i<$5; i++) { Option dom = $9() ? Option::some(new AST::SetLit($9.some())) : Option::none(); IntVarSpec* ispec = new IntVarSpec(dom,!print,false); vars[i] = pp->intvars.size(); pp->intvars.push_back(varspec($11, ispec)); } } if ($9()) delete $9.some(); } } if (print) { AST::Array* a = new AST::Array(); a->a.push_back(arrayOutput($12->getCall("output_array"))); AST::Array* output = new AST::Array(); for (int i=0; i<$5; i++) output->a.push_back(new AST::IntVar(vars[i])); a->a.push_back(output); a->a.push_back(new AST::String(")")); pp->output(std::string($11), a); } int iva = pp->arrays.size(); pp->arrays.push_back(vars.size()); for (unsigned int i=0; iarrays.push_back(vars[i]); yyassert(pp, pp->symbols.put($11, se_iva(iva)), "Duplicate symbol"); } delete $12; free($11); } | FZ_ARRAY '[' FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT ']' FZ_OF FZ_VAR bool_ti_expr_tail ':' var_par_id annotations vardecl_bool_var_array_init { ParserState* pp = static_cast(parm); bool print = $12 != NULL && $12->hasCall("output_array"); yyassert(pp, $3==1, "Arrays must start at 1"); if (!pp->hadError) { vector vars($5); if ($13()) { vector* vsv = $13.some(); yyassert(pp, vsv->size() == static_cast($5), "Initializer size does not match array dimension"); if (!pp->hadError) { for (int i=0; i<$5; i++) { BoolVarSpec* bvsv = static_cast((*vsv)[i]); if (bvsv->alias) { if (print) static_cast(pp->boolvars[bvsv->i].second)->introduced = false; vars[i] = bvsv->i; } else { if (print) bvsv->introduced = false; vars[i] = pp->boolvars.size(); pp->boolvars.push_back(varspec($11, (*vsv)[i])); } if (!pp->hadError && $9()) { Option opt = Option::some(new AST::SetLit(*$9.some())); addDomainConstraint(pp, "int_in", new AST::BoolVar(vars[i]), opt); } } } delete vsv; } else { for (int i=0; i<$5; i++) { Option dom = $9() ? Option::some(new AST::SetLit($9.some())) : Option::none(); vars[i] = pp->boolvars.size(); pp->boolvars.push_back(varspec($11, new BoolVarSpec(dom,!print,false))); } if ($9()) delete $9.some(); } if (print) { AST::Array* a = new AST::Array(); a->a.push_back(arrayOutput($12->getCall("output_array"))); AST::Array* output = new AST::Array(); for (int i=0; i<$5; i++) output->a.push_back(new AST::BoolVar(vars[i])); a->a.push_back(output); a->a.push_back(new AST::String(")")); pp->output(std::string($11), a); } int bva = pp->arrays.size(); pp->arrays.push_back(vars.size()); for (unsigned int i=0; iarrays.push_back(vars[i]); yyassert(pp, pp->symbols.put($11, se_bva(bva)), "Duplicate symbol"); } delete $12; free($11); } | FZ_ARRAY '[' FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT ']' FZ_OF FZ_VAR float_ti_expr_tail ':' var_par_id annotations vardecl_float_var_array_init { ParserState* pp = static_cast(parm); yyassert(pp, $3==1, "Arrays must start at 1"); if (!pp->hadError) { bool print = $12 != NULL && $12->hasCall("output_array"); vector vars($5); if (!pp->hadError) { if ($13()) { vector* vsv = $13.some(); yyassert(pp, vsv->size() == static_cast($5), "Initializer size does not match array dimension"); if (!pp->hadError) { for (int i=0; i<$5; i++) { FloatVarSpec* ivsv = static_cast((*vsv)[i]); if (ivsv->alias) { if (print) static_cast(pp->floatvars[ivsv->i].second)->introduced = false; vars[i] = ivsv->i; } else { if (print) ivsv->introduced = false; vars[i] = pp->floatvars.size(); pp->floatvars.push_back(varspec($11, ivsv)); } if (!pp->hadError && $9()) { Option*> opt = Option*>::some( new std::pair(*$9.some())); addDomainConstraint(pp, new AST::FloatVar(vars[i]), opt); } } } delete vsv; } else { if ($5>0) { Option > dom = $9() ? Option >::some(*$9.some()) : Option >::none(); for (int i=0; i<$5; i++) { FloatVarSpec* ispec = new FloatVarSpec(dom,!print,false); vars[i] = pp->floatvars.size(); pp->floatvars.push_back(varspec($11, ispec)); } } } } if (print) { AST::Array* a = new AST::Array(); a->a.push_back(arrayOutput($12->getCall("output_array"))); AST::Array* output = new AST::Array(); for (int i=0; i<$5; i++) output->a.push_back(new AST::FloatVar(vars[i])); a->a.push_back(output); a->a.push_back(new AST::String(")")); pp->output(std::string($11), a); } int fva = pp->arrays.size(); pp->arrays.push_back(vars.size()); for (unsigned int i=0; iarrays.push_back(vars[i]); yyassert(pp, pp->symbols.put($11, se_fva(fva)), "Duplicate symbol"); } if ($9()) delete $9.some(); delete $12; free($11); } | FZ_ARRAY '[' FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT ']' FZ_OF FZ_VAR FZ_SET FZ_OF int_ti_expr_tail ':' var_par_id annotations vardecl_set_var_array_init { ParserState* pp = static_cast(parm); bool print = $14 != NULL && $14->hasCall("output_array"); yyassert(pp, $3==1, "Arrays must start at 1"); if (!pp->hadError) { vector vars($5); if ($15()) { vector* vsv = $15.some(); yyassert(pp, vsv->size() == static_cast($5), "Initializer size does not match array dimension"); if (!pp->hadError) { for (int i=0; i<$5; i++) { SetVarSpec* svsv = static_cast((*vsv)[i]); if (svsv->alias) { if (print) static_cast(pp->setvars[svsv->i].second)->introduced = false; vars[i] = svsv->i; } else { if (print) svsv->introduced = false; vars[i] = pp->setvars.size(); pp->setvars.push_back(varspec($13, (*vsv)[i])); } if (!pp->hadError && $11()) { Option opt = Option::some(new AST::SetLit(*$11.some())); addDomainConstraint(pp, "set_subset", new AST::SetVar(vars[i]), opt); } } } delete vsv; } else { if ($5>0) { for (int i=0; i<$5; i++) { Option dom = $11() ? Option::some(new AST::SetLit($11.some())) : Option::none(); SetVarSpec* ispec = new SetVarSpec(dom,!print,false); vars[i] = pp->setvars.size(); pp->setvars.push_back(varspec($13, ispec)); } if ($11()) delete $11.some(); } } if (print) { AST::Array* a = new AST::Array(); a->a.push_back(arrayOutput($14->getCall("output_array"))); AST::Array* output = new AST::Array(); for (int i=0; i<$5; i++) output->a.push_back(new AST::SetVar(vars[i])); a->a.push_back(output); a->a.push_back(new AST::String(")")); pp->output(std::string($13), a); } int sva = pp->arrays.size(); pp->arrays.push_back(vars.size()); for (unsigned int i=0; iarrays.push_back(vars[i]); yyassert(pp, pp->symbols.put($13, se_sva(sva)), "Duplicate symbol"); } delete $14; free($13); } | FZ_ARRAY '[' FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT ']' FZ_OF FZ_INT ':' var_par_id annotations '=' '[' int_list ']' { ParserState* pp = static_cast(parm); yyassert(pp, $3==1, "Arrays must start at 1"); yyassert(pp, $14->size() == static_cast($5), "Initializer size does not match array dimension"); if (!pp->hadError) { int ia = pp->arrays.size(); pp->arrays.push_back($14->size()); for (unsigned int i=0; i<$14->size(); i++) pp->arrays.push_back((*$14)[i]); yyassert(pp, pp->symbols.put($10, se_ia(ia)), "Duplicate symbol"); } delete $14; free($10); delete $11; } | FZ_ARRAY '[' FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT ']' FZ_OF FZ_BOOL ':' var_par_id annotations '=' '[' bool_list ']' { ParserState* pp = static_cast(parm); yyassert(pp, $3==1, "Arrays must start at 1"); yyassert(pp, $14->size() == static_cast($5), "Initializer size does not match array dimension"); if (!pp->hadError) { int ia = pp->arrays.size(); pp->arrays.push_back($14->size()); for (unsigned int i=0; i<$14->size(); i++) pp->arrays.push_back((*$14)[i]); yyassert(pp, pp->symbols.put($10, se_ba(ia)), "Duplicate symbol"); } delete $14; free($10); delete $11; } | FZ_ARRAY '[' FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT ']' FZ_OF FZ_FLOAT ':' var_par_id annotations '=' '[' float_list ']' { ParserState* pp = static_cast(parm); yyassert(pp, $3==1, "Arrays must start at 1"); yyassert(pp, $14->size() == static_cast($5), "Initializer size does not match array dimension"); if (!pp->hadError) { int fa = pp->arrays.size(); pp->arrays.push_back($14->size()); pp->arrays.push_back(pp->floatvals.size()); for (unsigned int i=0; i<$14->size(); i++) pp->floatvals.push_back((*$14)[i]); yyassert(pp, pp->symbols.put($10, se_fa(fa)), "Duplicate symbol"); } delete $14; delete $11; free($10); } | FZ_ARRAY '[' FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT ']' FZ_OF FZ_SET FZ_OF FZ_INT ':' var_par_id annotations '=' '[' set_literal_list ']' { ParserState* pp = static_cast(parm); yyassert(pp, $3==1, "Arrays must start at 1"); yyassert(pp, $16->size() == static_cast($5), "Initializer size does not match array dimension"); if (!pp->hadError) { int sa = pp->arrays.size(); pp->arrays.push_back($16->size()); pp->arrays.push_back(pp->setvals.size()); for (unsigned int i=0; i<$16->size(); i++) pp->setvals.push_back((*$16)[i]); yyassert(pp, pp->symbols.put($12, se_sa(sa)), "Duplicate symbol"); } delete $16; delete $13; free($12); } int_init : FZ_INT_LIT { $$ = new IntVarSpec($1,false,false); } | var_par_id { SymbolEntry e; ParserState* pp = static_cast(parm); if (pp->symbols.get($1, e) && e.t == ST_INTVAR) $$ = new IntVarSpec(Alias(e.i),false,false); else { pp->err << "Error: undefined identifier for type int " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new IntVarSpec(0,false,false); // keep things consistent } free($1); } | var_par_id '[' FZ_INT_LIT ']' { vector v; SymbolEntry e; ParserState* pp = static_cast(parm); if (pp->symbols.get($1, e) && e.t == ST_INTVARARRAY) { yyassert(pp,$3 > 0 && $3 <= pp->arrays[e.i], "array access out of bounds"); if (!pp->hadError) $$ = new IntVarSpec(Alias(pp->arrays[e.i+$3]),false,false); else $$ = new IntVarSpec(0,false,false); // keep things consistent } else { pp->err << "Error: undefined array identifier for type int " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new IntVarSpec(0,false,false); // keep things consistent } free($1); } int_init_list : /* empty */ { $$ = new vector(0); } | int_init_list_head list_tail { $$ = $1; } int_init_list_head : int_init { $$ = new vector(1); (*$$)[0] = $1; } | int_init_list_head ',' int_init { $$ = $1; $$->push_back($3); } list_tail : | ',' int_var_array_literal : '[' int_init_list ']' { $$ = $2; } float_init : FZ_FLOAT_LIT { $$ = new FloatVarSpec($1,false,false); } | var_par_id { SymbolEntry e; ParserState* pp = static_cast(parm); if (pp->symbols.get($1, e) && e.t == ST_FLOATVAR) $$ = new FloatVarSpec(Alias(e.i),false,false); else { pp->err << "Error: undefined identifier for type float " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new FloatVarSpec(0.0,false,false); } free($1); } | var_par_id '[' FZ_INT_LIT ']' { SymbolEntry e; ParserState* pp = static_cast(parm); if (pp->symbols.get($1, e) && e.t == ST_FLOATVARARRAY) { yyassert(pp,$3 > 0 && $3 <= pp->arrays[e.i], "array access out of bounds"); if (!pp->hadError) $$ = new FloatVarSpec(Alias(pp->arrays[e.i+$3]),false,false); else $$ = new FloatVarSpec(0.0,false,false); } else { pp->err << "Error: undefined array identifier for type float " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new FloatVarSpec(0.0,false,false); } free($1); } float_init_list : /* empty */ { $$ = new vector(0); } | float_init_list_head list_tail { $$ = $1; } float_init_list_head : float_init { $$ = new vector(1); (*$$)[0] = $1; } | float_init_list_head ',' float_init { $$ = $1; $$->push_back($3); } float_var_array_literal : '[' float_init_list ']' { $$ = $2; } bool_init : FZ_BOOL_LIT { $$ = new BoolVarSpec($1,false,false); } | var_par_id { SymbolEntry e; ParserState* pp = static_cast(parm); if (pp->symbols.get($1, e) && e.t == ST_BOOLVAR) $$ = new BoolVarSpec(Alias(e.i),false,false); else { pp->err << "Error: undefined identifier for type bool " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new BoolVarSpec(false,false,false); } free($1); } | var_par_id '[' FZ_INT_LIT ']' { SymbolEntry e; ParserState* pp = static_cast(parm); if (pp->symbols.get($1, e) && e.t == ST_BOOLVARARRAY) { yyassert(pp,$3 > 0 && $3 <= pp->arrays[e.i], "array access out of bounds"); if (!pp->hadError) $$ = new BoolVarSpec(Alias(pp->arrays[e.i+$3]),false,false); else $$ = new BoolVarSpec(false,false,false); } else { pp->err << "Error: undefined array identifier for type bool " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new BoolVarSpec(false,false,false); } free($1); } bool_init_list : /* empty */ { $$ = new vector(0); } | bool_init_list_head list_tail { $$ = $1; } bool_init_list_head : bool_init { $$ = new vector(1); (*$$)[0] = $1; } | bool_init_list_head ',' bool_init { $$ = $1; $$->push_back($3); } bool_var_array_literal : '[' bool_init_list ']' { $$ = $2; } set_init : set_literal { $$ = new SetVarSpec($1,false,false); } | var_par_id { ParserState* pp = static_cast(parm); SymbolEntry e; if (pp->symbols.get($1, e) && e.t == ST_SETVAR) $$ = new SetVarSpec(Alias(e.i),false,false); else { pp->err << "Error: undefined identifier for type set " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new SetVarSpec(Alias(0),false,false); } free($1); } | var_par_id '[' FZ_INT_LIT ']' { SymbolEntry e; ParserState* pp = static_cast(parm); if (pp->symbols.get($1, e) && e.t == ST_SETVARARRAY) { yyassert(pp,$3 > 0 && $3 <= pp->arrays[e.i], "array access out of bounds"); if (!pp->hadError) $$ = new SetVarSpec(Alias(pp->arrays[e.i+$3]),false,false); else $$ = new SetVarSpec(Alias(0),false,false); } else { pp->err << "Error: undefined array identifier for type set " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new SetVarSpec(Alias(0),false,false); } free($1); } set_init_list : /* empty */ { $$ = new vector(0); } | set_init_list_head list_tail { $$ = $1; } set_init_list_head : set_init { $$ = new vector(1); (*$$)[0] = $1; } | set_init_list_head ',' set_init { $$ = $1; $$->push_back($3); } set_var_array_literal : '[' set_init_list ']' { $$ = $2; } vardecl_int_var_array_init : /* empty */ { $$ = Option* >::none(); } | '=' int_var_array_literal { $$ = Option* >::some($2); } vardecl_bool_var_array_init : /* empty */ { $$ = Option* >::none(); } | '=' bool_var_array_literal { $$ = Option* >::some($2); } vardecl_float_var_array_init : /* empty */ { $$ = Option* >::none(); } | '=' float_var_array_literal { $$ = Option* >::some($2); } vardecl_set_var_array_init : /* empty */ { $$ = Option* >::none(); } | '=' set_var_array_literal { $$ = Option* >::some($2); } constraint_item : FZ_CONSTRAINT FZ_ID '(' flat_expr_list ')' annotations { ParserState *pp = static_cast(parm); if (!pp->hadError) { std::string cid($2); if (cid=="status" && $4->a[0]->isIntVar()) { pp->status_idx = $4->a[0]->getIntVar(); } else if (cid=="int_lastval" && $4->a[0]->isIntVar() && $4->a[1]->isIntVar()) { int base0 = getBaseIntVar(pp,$4->a[0]->getIntVar()); int base1 = getBaseIntVar(pp,$4->a[1]->getIntVar()); pp->int_lastval.emplace_back(std::array{ base0, base1 }); } else if (cid=="int_uniform" && $4->a[0]->isInt() && $4->a[1]->isInt() && $4->a[2]->isIntVar()) { int base = getBaseIntVar(pp,$4->a[2]->getIntVar()); pp->int_uniform.emplace_back(std::array{ $4->a[0]->getInt(), $4->a[1]->getInt(), base }); } else if (cid=="int_sol" && $4->a[0]->isIntVar() && $4->a[1]->isIntVar()) { int base0 = getBaseIntVar(pp,$4->a[0]->getIntVar()); int base1 = getBaseIntVar(pp,$4->a[1]->getIntVar()); pp->int_sol.emplace_back(std::array{ base0, base1 }); } else if (cid=="int_eq" && $4->a[0]->isIntVar() && $4->a[1]->isIntVar()) { int base0 = getBaseIntVar(pp,$4->a[0]->getIntVar()); int base1 = getBaseIntVar(pp,$4->a[1]->getIntVar()); if (base0 > base1) { std::swap(base0, base1); } if (base0==base1) { // do nothing, already aliased } else { IntVarSpec* ivs1 = static_cast(pp->intvars[base1].second); AST::SetLit* sl = NULL; if (ivs1->assigned) { sl = new AST::SetLit(ivs1->i,ivs1->i); } else if (ivs1->domain()) { sl = new AST::SetLit(ivs1->domain.some()->getSet()); } if (sl) { Option newdom = Option::some(sl); addDomainConstraint(pp, "int_in", new AST::IntVar(base0), newdom); ivs1->domain = Option::none(); } ivs1->alias = true; ivs1->i = base0; } } else if (cid=="bool_eq" && $4->a[0]->isBoolVar() && $4->a[1]->isBoolVar()) { int base0 = getBaseBoolVar(pp,$4->a[0]->getBoolVar()); int base1 = getBaseBoolVar(pp,$4->a[1]->getBoolVar()); if (base0 > base1) { std::swap(base0, base1); } if (base0==base1) { // do nothing, already aliased } else { BoolVarSpec* ivs1 = static_cast(pp->boolvars[base1].second); AST::SetLit* sl = NULL; if (ivs1->assigned) { sl = new AST::SetLit(ivs1->i,ivs1->i); } else if (ivs1->domain()) { sl = new AST::SetLit(ivs1->domain.some()->getSet()); } if (sl) { Option newdom = Option::some(sl); addDomainConstraint(pp, "int_in", new AST::BoolVar(base0), newdom); ivs1->domain = Option::none(); } ivs1->alias = true; ivs1->i = base0; } } else if (cid=="float_eq" && $4->a[0]->isFloatVar() && $4->a[1]->isFloatVar()) { int base0 = getBaseFloatVar(pp,$4->a[0]->getFloatVar()); int base1 = getBaseFloatVar(pp,$4->a[1]->getFloatVar()); if (base0 > base1) { std::swap(base0, base1); } if (base0==base1) { // do nothing, already aliased } else { FloatVarSpec* ivs1 = static_cast(pp->floatvars[base1].second); ivs1->alias = true; ivs1->i = base0; if (ivs1->domain()) { std::pair* dom = new std::pair(ivs1->domain.some()); addDomainConstraint(pp, new AST::FloatVar(base0), Option* >::some(dom)); ivs1->domain = Option >::none(); } } } else if (cid=="set_eq" && $4->a[0]->isSetVar() && $4->a[1]->isSetVar()) { int base0 = getBaseSetVar(pp,$4->a[0]->getSetVar()); int base1 = getBaseSetVar(pp,$4->a[1]->getSetVar()); if (base0 > base1) { std::swap(base0, base1); } if (base0==base1) { // do nothing, already aliased } else { SetVarSpec* ivs1 = static_cast(pp->setvars[base1].second); ivs1->alias = true; ivs1->i = base0; if (ivs1->upperBound()) { AST::SetLit* sl = new AST::SetLit(ivs1->upperBound.some()->getSet()); Option newdom = Option::some(sl); if (ivs1->assigned) { addDomainConstraint(pp, "set_eq", new AST::SetVar(base0), newdom); } else { addDomainConstraint(pp, "set_subset", new AST::SetVar(base0), newdom); } ivs1->upperBound = Option::none(); } } } else if ( (cid=="int_le" || cid=="int_lt" || cid=="int_ge" || cid=="int_gt" || cid=="int_eq" || cid=="int_ne") && ($4->a[0]->isInt() || $4->a[1]->isInt()) ) { pp->domainConstraints.push_back(new ConExpr($2, $4, $6)); } else if ( cid=="set_in" && ($4->a[0]->isSet() || $4->a[1]->isSet()) ) { pp->domainConstraints.push_back(new ConExpr($2, $4, $6)); } else { pp->constraints.push_back(new ConExpr($2, $4, $6)); } } free($2); } solve_item : FZ_SOLVE annotations FZ_SATISFY { ParserState *pp = static_cast(parm); initfg(pp); if (!pp->hadError) { try { pp->fg->solve($2); } catch (Gecode::FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } else { delete $2; } } | FZ_SOLVE annotations minmax solve_expr { ParserState *pp = static_cast(parm); initfg(pp); if (!pp->hadError) { try { int v = $4 < 0 ? (-$4-1) : $4; bool vi = $4 >= 0; if ($3) pp->fg->minimize(v,vi,$2); else pp->fg->maximize(v,vi,$2); } catch (Gecode::FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } else { delete $2; } } /********************************/ /* type-insts */ /********************************/ int_ti_expr_tail : FZ_INT { $$ = Option::none(); } | '{' int_list '}' { $$ = Option::some(new AST::SetLit(*$2)); } | FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT { $$ = Option::some(new AST::SetLit($1, $3)); } bool_ti_expr_tail : FZ_BOOL { $$ = Option::none(); } | '{' bool_list_head list_tail '}' { bool haveTrue = false; bool haveFalse = false; for (int i=$2->size(); i--;) { haveTrue |= ((*$2)[i] == 1); haveFalse |= ((*$2)[i] == 0); } delete $2; $$ = Option::some( new AST::SetLit(!haveFalse,haveTrue)); } float_ti_expr_tail : FZ_FLOAT { $$ = Option* >::none(); } | FZ_FLOAT_LIT FZ_DOTDOT FZ_FLOAT_LIT { std::pair* dom = new std::pair($1,$3); $$ = Option* >::some(dom); } /********************************/ /* literals */ /********************************/ set_literal : '{' int_list '}' { $$ = new AST::SetLit(*$2); } | FZ_INT_LIT FZ_DOTDOT FZ_INT_LIT { $$ = new AST::SetLit($1, $3); } /* list containing only primitive literals */ int_list : /* empty */ { $$ = new vector(0); } | int_list_head list_tail { $$ = $1; } int_list_head : FZ_INT_LIT { $$ = new vector(1); (*$$)[0] = $1; } | int_list_head ',' FZ_INT_LIT { $$ = $1; $$->push_back($3); } bool_list : /* empty */ { $$ = new vector(0); } | bool_list_head list_tail { $$ = $1; } bool_list_head : FZ_BOOL_LIT { $$ = new vector(1); (*$$)[0] = $1; } | bool_list_head ',' FZ_BOOL_LIT { $$ = $1; $$->push_back($3); } float_list : /* empty */ { $$ = new vector(0); } | float_list_head list_tail { $$ = $1; } float_list_head: FZ_FLOAT_LIT { $$ = new vector(1); (*$$)[0] = $1; } | float_list_head ',' FZ_FLOAT_LIT { $$ = $1; $$->push_back($3); } set_literal_list : /* empty */ { $$ = new vector(0); } | set_literal_list_head list_tail { $$ = $1; } set_literal_list_head : set_literal { $$ = new vector(1); (*$$)[0] = *$1; delete $1; } | set_literal_list_head ',' set_literal { $$ = $1; $$->push_back(*$3); delete $3; } /********************************/ /* constraint expressions */ /********************************/ flat_expr_list : flat_expr { $$ = new AST::Array($1); } | flat_expr_list ',' flat_expr { $$ = $1; $$->append($3); } flat_expr : non_array_expr { $$ = $1; } | '[' non_array_expr_list ']' { $$ = $2; } non_array_expr_opt : /* empty */ { $$ = Option::none(); } | '=' non_array_expr { $$ = Option::some($2); } non_array_expr : FZ_BOOL_LIT { $$ = new AST::BoolLit($1); } | FZ_INT_LIT { $$ = new AST::IntLit($1); } | FZ_FLOAT_LIT { $$ = new AST::FloatLit($1); } | set_literal { $$ = $1; } | var_par_id /* variable, possibly array */ { ParserState* pp = static_cast(parm); SymbolEntry e; if (pp->symbols.get($1, e)) { switch (e.t) { case ST_INTVARARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::IntVar(pp->arrays[e.i+i+1]); $$ = v; } break; case ST_BOOLVARARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::BoolVar(pp->arrays[e.i+i+1]); $$ = v; } break; case ST_FLOATVARARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::FloatVar(pp->arrays[e.i+i+1]); $$ = v; } break; case ST_SETVARARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::SetVar(pp->arrays[e.i+i+1]); $$ = v; } break; case ST_INTVALARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::IntLit(pp->arrays[e.i+i+1]); $$ = v; } break; case ST_BOOLVALARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::BoolLit(pp->arrays[e.i+i+1]); $$ = v; } break; case ST_SETVALARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); int idx = pp->arrays[e.i+1]; for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::SetLit(pp->setvals[idx+i]); $$ = v; } break; case ST_FLOATVALARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); int idx = pp->arrays[e.i+1]; for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::FloatLit(pp->floatvals[idx+i]); $$ = v; } break; case ST_INT: $$ = new AST::IntLit(e.i); break; case ST_BOOL: $$ = new AST::BoolLit(e.i); break; case ST_FLOAT: $$ = new AST::FloatLit(pp->floatvals[e.i]); break; case ST_SET: $$ = new AST::SetLit(pp->setvals[e.i]); break; default: $$ = getVarRefArg(pp,$1); } } else { pp->err << "Error: undefined identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = NULL; } free($1); } | var_par_id '[' non_array_expr ']' /* array access */ { ParserState* pp = static_cast(parm); int i = -1; yyassert(pp, $3->isInt(i), "Non-integer array index"); if (!pp->hadError) $$ = getArrayElement(static_cast(parm),$1,i,false); else $$ = new AST::IntLit(0); // keep things consistent delete $3; free($1); } non_array_expr_list : /* empty */ { $$ = new AST::Array(0); } | non_array_expr_list_head list_tail { $$ = $1; } non_array_expr_list_head : non_array_expr { $$ = new AST::Array($1); } | non_array_expr_list_head ',' non_array_expr { $$ = $1; $$->append($3); } /********************************/ /* solve expressions */ /********************************/ solve_expr: var_par_id { ParserState *pp = static_cast(parm); SymbolEntry e; bool haveSym = pp->symbols.get($1,e); if (haveSym) { switch (e.t) { case ST_INTVAR: $$ = e.i; break; case ST_FLOATVAR: $$ = -e.i-1; break; case ST_INT: case ST_FLOAT: pp->intvars.push_back(varspec("OBJ_CONST_INTRODUCED", new IntVarSpec(0,true,false))); $$ = pp->intvars.size()-1; break; default: pp->err << "Error: unknown int or float variable " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; break; } } else { pp->err << "Error: unknown int or float variable " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; } free($1); } | FZ_INT_LIT { ParserState *pp = static_cast(parm); pp->intvars.push_back(varspec("OBJ_CONST_INTRODUCED", new IntVarSpec(0,true,false))); $$ = pp->intvars.size()-1; } | FZ_FLOAT_LIT { ParserState *pp = static_cast(parm); pp->intvars.push_back(varspec("OBJ_CONST_INTRODUCED", new IntVarSpec(0,true,false))); $$ = pp->intvars.size()-1; } | var_par_id '[' FZ_INT_LIT ']' { SymbolEntry e; ParserState *pp = static_cast(parm); if ( (!pp->symbols.get($1, e)) || (e.t != ST_INTVARARRAY && e.t != ST_FLOATVARARRAY)) { pp->err << "Error: unknown int or float variable array " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; } if ($3 == 0 || $3 > pp->arrays[e.i]) { pp->err << "Error: array index out of bounds for array " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; } else { if (e.t == ST_INTVARARRAY) $$ = pp->arrays[e.i+$3]; else $$ = -pp->arrays[e.i+$3]-1; } free($1); } minmax: FZ_MINIMIZE | FZ_MAXIMIZE /********************************/ /* annotation expresions */ /********************************/ annotations : /* empty */ { $$ = NULL; } | annotations_head { $$ = $1; } annotations_head : FZ_COLONCOLON annotation { $$ = new AST::Array($2); } | annotations_head FZ_COLONCOLON annotation { $$ = $1; $$->append($3); } annotation : FZ_ID '(' annotation_list ')' { $$ = new AST::Call($1, AST::extractSingleton($3)); free($1); } | annotation_expr { $$ = $1; } annotation_list: annotation { $$ = new AST::Array($1); } | annotation_list ',' annotation { $$ = $1; $$->append($3); } annotation_expr : ann_non_array_expr { $$ = $1; } | '[' ']' { $$ = new AST::Array(); } | '[' annotation_list annotation_list_tail ']' { $$ = $2; } annotation_list_tail : | ',' ann_non_array_expr : FZ_BOOL_LIT { $$ = new AST::BoolLit($1); } | FZ_INT_LIT { $$ = new AST::IntLit($1); } | FZ_FLOAT_LIT { $$ = new AST::FloatLit($1); } | set_literal { $$ = $1; } | var_par_id /* variable, possibly array */ { ParserState* pp = static_cast(parm); SymbolEntry e; bool gotSymbol = false; if (pp->symbols.get($1, e)) { gotSymbol = true; switch (e.t) { case ST_INTVARARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) { std::ostringstream oss; oss << $1 << "["<<(i+1)<<"]"; v->a[i] = new AST::IntVar(pp->arrays[e.i+i+1], oss.str()); } $$ = v; } break; case ST_BOOLVARARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) { std::ostringstream oss; oss << $1 << "["<<(i+1)<<"]"; v->a[i] = new AST::BoolVar(pp->arrays[e.i+i+1], oss.str()); } $$ = v; } break; case ST_FLOATVARARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) { std::ostringstream oss; oss << $1 << "["<<(i+1)<<"]"; v->a[i] = new AST::FloatVar(pp->arrays[e.i+i+1], oss.str()); } $$ = v; } break; case ST_SETVARARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) { std::ostringstream oss; oss << $1 << "["<<(i+1)<<"]"; v->a[i] = new AST::SetVar(pp->arrays[e.i+i+1], oss.str()); } $$ = v; } break; case ST_INTVALARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::IntLit(pp->arrays[e.i+i+1]); $$ = v; } break; case ST_BOOLVALARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::BoolLit(pp->arrays[e.i+i+1]); $$ = v; } break; case ST_SETVALARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); int idx = pp->arrays[e.i+1]; for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::SetLit(pp->setvals[idx+i]); $$ = v; } break; case ST_FLOATVALARRAY: { AST::Array *v = new AST::Array(pp->arrays[e.i]); int idx = pp->arrays[e.i+1]; for (int i=pp->arrays[e.i]; i--;) v->a[i] = new AST::FloatLit(pp->floatvals[idx+i]); $$ = v; } break; case ST_INT: $$ = new AST::IntLit(e.i); break; case ST_BOOL: $$ = new AST::BoolLit(e.i); break; case ST_FLOAT: $$ = new AST::FloatLit(pp->floatvals[e.i]); break; case ST_SET: $$ = new AST::SetLit(pp->setvals[e.i]); break; default: gotSymbol = false; } } if (!gotSymbol) $$ = getVarRefArg(pp,$1,true); free($1); } | var_par_id '[' ann_non_array_expr ']' /* array access */ { ParserState* pp = static_cast(parm); int i = -1; yyassert(pp, $3->isInt(i), "Non-integer array index"); if (!pp->hadError) $$ = getArrayElement(static_cast(parm),$1,i,true); else $$ = new AST::IntLit(0); // keep things consistent free($1); } | FZ_STRING_LIT { $$ = new AST::String($1); free($1); }