/* * 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. * */ %define api.pure %define api.header.include {} %lex-param {YYLEX_PARAM} %parse-param {void *parm} %{ #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 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, unsigned int offset) { if (offset > 0) { vector tmp; if (pp->intvararrays.get(id, tmp) && offset<= tmp.size()) return new AST::IntVar(tmp[offset-1]); if (pp->boolvararrays.get(id, tmp) && offset<= tmp.size()) return new AST::BoolVar(tmp[offset-1]); if (pp->setvararrays.get(id, tmp) && offset<= tmp.size()) return new AST::SetVar(tmp[offset-1]); if (pp->intvalarrays.get(id, tmp) && offset<= tmp.size()) return new AST::IntLit(tmp[offset-1]); if (pp->boolvalarrays.get(id, tmp) && offset<= tmp.size()) return new AST::BoolLit(tmp[offset-1]); vector tmpS; if (pp->setvalarrays.get(id, tmpS) && offset<= tmpS.size()) return new AST::SetLit(tmpS[offset-1]); } 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) { int tmp; if (pp->intvarTable.get(id, tmp)) return new AST::IntVar(tmp); if (pp->boolvarTable.get(id, tmp)) return new AST::BoolVar(tmp); if (pp->setvarTable.get(id, tmp)) return new AST::SetVar(tmp); 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)); } /* * Initialize the root gecode space * */ void initfg(ParserState* pp) { #if EXPOSE_INT_LITS static struct { const char *int_CMP_reif; IntRelType irt; } int_CMP_table[] = { { "int_eq_reif", IRT_EQ }, { "int_ne_reif", IRT_NE }, { "int_ge_reif", IRT_GE }, { "int_gt_reif", IRT_GT }, { "int_le_reif", IRT_LE }, { "int_lt_reif", IRT_LT } }; for (int i = 0; i < static_cast(pp->domainConstraints2.size()); ) { ConExpr& c = *pp->domainConstraints2[i].first; for (int j = 0; j < 6; ++j) if (c.id.compare(int_CMP_table[j].int_CMP_reif) == 0) { if (!c[2]->isBoolVar()) goto not_found; int k; for (k = c[2]->getBoolVar(); pp->boolvars[k].second->alias; k = pp->boolvars[k].second->i) ; BoolVarSpec& boolvar = *static_cast(pp->boolvars[k].second); if (boolvar.alias_var >= 0) goto not_found; if (c[0]->isIntVar() && c[1]->isInt(boolvar.alias_val)) { boolvar.alias_var = c[0]->getIntVar(); boolvar.alias_irt = int_CMP_table[j].irt; goto found; } if (c[1]->isIntVar() && c[0]->isInt(boolvar.alias_val)) { boolvar.alias_var = c[1]->getIntVar(); boolvar.alias_irt = -int_CMP_table[j].irt; goto found; } } not_found: ++i; continue; found: delete pp->domainConstraints2[i].first; delete pp->domainConstraints2[i].second; pp->domainConstraints2.erase(pp->domainConstraints2.begin() + i); } #endif if (!pp->hadError) pp->fg = new FlatZincSpace(pp->intvars.size(), pp->boolvars.size(), pp->setvars.size()); for (unsigned int i = 0; i < pp->intvars.size(); i++) { if (!pp->hadError) { try { pp->fg->newIntVar(static_cast(pp->intvars[i].second)); IntVar* newiv = pp->fg->iv[pp->fg->intVarCount-1]; intVarString.insert(std::pair(newiv, pp->intvars[i].first)); } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } if (pp->intvars[i].first[0] != '[') { delete pp->intvars[i].second; pp->intvars[i].second = NULL; } } for (unsigned int i = 0; i < pp->boolvars.size(); i++) { if (!pp->hadError) { try { pp->fg->newBoolVar(static_cast(pp->boolvars[i].second)); BoolView newiv = pp->fg->bv[pp->fg->boolVarCount-1]; if (pp->boolvars[i].second->assigned) boolVarString.insert(std::pair(newiv, "ASSIGNED_AT_ROOT")); else boolVarString.insert(std::pair(newiv, pp->boolvars[i].first)); string label; label = pp->boolvars[i].first; label.append("=true"); litString.insert(std::pair(toInt(newiv.getLit(true)), label)); label = pp->boolvars[i].first; label.append("=false"); litString.insert(std::pair(toInt(newiv.getLit(false)), label)); } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } if (pp->boolvars[i].first[0] != '[') { delete pp->boolvars[i].second; pp->boolvars[i].second = NULL; } } for (unsigned int i = 0; i < pp->setvars.size(); i++) { if (!pp->hadError) { try { pp->fg->newSetVar(static_cast(pp->setvars[i].second)); } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } if (pp->setvars[i].first[0] != '[') { delete pp->setvars[i].second; pp->setvars[i].second = NULL; } } for (unsigned int i = pp->domainConstraints.size(); i--;) { if (!pp->hadError) { try { assert(pp->domainConstraints[i]->args->a.size() == 2); pp->fg->postConstraint(*pp->domainConstraints[i], NULL); delete pp->domainConstraints[i]; } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } } #if EXPOSE_INT_LITS for (int i = 0; i < static_cast(pp->domainConstraints2.size()); ++i) { if (!pp->hadError) { try { pp->fg->postConstraint(*pp->domainConstraints2[i].first, pp->domainConstraints2[i].second); delete pp->domainConstraints2[i].first; delete pp->domainConstraints2[i].second; } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } } #endif } AST::Node* arrayOutput(AST::Call* ann) { AST::Array* a = NULL; if (ann->args->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; i < a->a.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; j < s->s.size(); j++) { oss << s->s[j]; if (j < s->s.size()-1) oss << ","; } oss << "}, "; } } if (!ann->args->isArray()) { a->a[0] = NULL; delete a; } return new AST::String(oss.str()); } /* * The main program * */ namespace FlatZinc { void solve(const std::string& filename, std::ostream& err) { #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; exit(0); } if (stat(filename.c_str(), &sbuf) == -1) { err << "Cannot stat file " << filename << endl; return; } 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; } ParserState pp(data, sbuf.st_size, err); #else std::ifstream file; file.open(filename.c_str()); if (!file.is_open()) { err << "Cannot open file " << filename << endl; exit(0); } std::string s = string(istreambuf_iterator(file), istreambuf_iterator()); ParserState pp(s, err); #endif yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); // yydebug = 1; yyparse(&pp); FlatZinc::s->output = pp.getOutput(); FlatZinc::s->setOutput(); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) abort(); } void solve(std::istream& is, std::ostream& err) { std::string s = string(istreambuf_iterator(is), istreambuf_iterator()); ParserState pp(s, err); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); // yydebug = 1; yyparse(&pp); FlatZinc::s->output = pp.getOutput(); FlatZinc::s->setOutput(); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) abort(); } } %} %union { int iValue; char* sValue; bool bValue; double dValue; std::vector* setValue; FlatZinc::AST::SetLit* setLit; std::vector* floatSetValue; std::vector* setValueList; FlatZinc::Option oSet; FlatZinc::VarSpec* varSpec; FlatZinc::Option oArg; std::vector* varSpecVec; FlatZinc::Option* > oVarSpecVec; FlatZinc::AST::Node* arg; FlatZinc::AST::Array* argVec; } %define parse.error verbose %token INT_LIT BOOL_LIT %token FLOAT_LIT %token ID STRING_LIT %token VAR PAR %token ANNOTATION %token ANY %token ARRAY %token BOOLTOK %token CASE %token COLONCOLON %token CONSTRAINT %token DEFAULT %token DOTDOT %token ELSE %token ELSEIF %token ENDIF %token ENUM %token FLOATTOK %token FUNCTION %token IF %token INCLUDE %token INTTOK %token LET %token MAXIMIZE %token MINIMIZE %token OF %token SATISFY %token OUTPUT %token PREDICATE %token RECORD %token SET %token SHOW %token SHOWCOND %token SOLVE %token STRING %token TEST %token THEN %token TUPLE %token TYPE %token VARIANT_RECORD %token WHERE %type set_literal %type int_init bool_init set_init float_init %type int_ti_expr_tail bool_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 : /* empty */ { #if !EXPOSE_INT_LITS initfg(static_cast(parm)); #endif } | vardecl_items_head { #if !EXPOSE_INT_LITS initfg(static_cast(parm)); #endif } vardecl_items_head : vardecl_item ';' | vardecl_items_head vardecl_item ';' constraint_items : /* empty */ { #if EXPOSE_INT_LITS initfg(static_cast(parm)); #endif } | constraint_items_head { #if EXPOSE_INT_LITS initfg(static_cast(parm)); #endif } constraint_items_head : constraint_item ';' | constraint_items_head constraint_item ';' /********************************/ /* predicate declarations */ /********************************/ preddecl_item : PREDICATE ID '(' pred_arg_list ')' 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 ':' ID pred_arg_type : ARRAY '[' pred_array_init ']' OF pred_arg_simple_type | ARRAY '[' pred_array_init ']' OF VAR pred_arg_simple_type | VAR pred_arg_simple_type | pred_arg_simple_type pred_arg_simple_type : int_ti_expr_tail | SET OF int_ti_expr_tail | BOOLTOK | FLOATTOK pred_array_init : pred_array_init_arg | pred_array_init ',' pred_array_init_arg pred_array_init_arg : INTTOK | INT_LIT DOTDOT INT_LIT /********************************/ /* variable declarations */ /********************************/ vardecl_item : VAR int_ti_expr_tail ':' ID annotations non_array_expr_opt { ParserState* pp = static_cast(parm); yyassert(pp, !$2() || !$2.some()->empty(), "Empty var int domain."); bool print = $5 && $5->hasAtom("output_var"); pp->intvarTable.put($4, pp->intvars.size()); if (print) { pp->output(std::string($4), new AST::IntVar(pp->intvars.size())); } bool introduced = $5 && $5->hasAtom("var_is_introduced"); bool looks_introduced = (strncmp($4, "X_INTRODUCED_", 13) == 0); if ($6()) { AST::Node* arg = $6.some(); if (arg->isInt()) { pp->intvars.push_back(varspec($4, new IntVarSpec(arg->getInt(),print,introduced,looks_introduced))); } else if (arg->isIntVar()) { pp->intvars.push_back(varspec($4, new IntVarSpec(Alias(arg->getIntVar()),print,introduced,looks_introduced))); } else { yyassert(pp, false, "Invalid var int initializer."); } if (!pp->hadError) addDomainConstraint(pp, "set_in", new AST::IntVar(pp->intvars.size()-1), $2); delete arg; } else { pp->intvars.push_back(varspec($4, new IntVarSpec($2,print,introduced,looks_introduced))); } delete $5; free($4); } | VAR bool_ti_expr_tail ':' ID annotations non_array_expr_opt { ParserState* pp = static_cast(parm); bool print = $5 && $5->hasAtom("output_var"); pp->boolvarTable.put($4, pp->boolvars.size()); if (print) { pp->output(std::string($4), new AST::BoolVar(pp->boolvars.size())); } bool introduced = $5 && $5->hasAtom("var_is_introduced"); bool looks_introduced = (strncmp($4, "X_INTRODUCED_", 13) == 0); if ($6()) { AST::Node* arg = $6.some(); if (arg->isBool()) { pp->boolvars.push_back(varspec($4, new BoolVarSpec(arg->getBool(),print,introduced,looks_introduced))); } else if (arg->isBoolVar()) { pp->boolvars.push_back(varspec($4, new BoolVarSpec(Alias(arg->getBoolVar()),print,introduced,looks_introduced))); } else { yyassert(pp, false, "Invalid var bool initializer."); } if (!pp->hadError) addDomainConstraint(pp, "set_in", new AST::BoolVar(pp->boolvars.size()-1), $2); delete arg; } else { pp->boolvars.push_back(varspec($4, new BoolVarSpec($2,print,introduced,looks_introduced))); } delete $5; free($4); } | VAR float_ti_expr_tail ':' ID annotations non_array_expr_opt { ParserState* pp = static_cast(parm); yyassert(pp, false, "Floats not supported."); delete $5; free($4); } | VAR SET OF int_ti_expr_tail ':' ID annotations non_array_expr_opt { ParserState* pp = static_cast(parm); bool print = $7 && $7->hasAtom("output_var"); pp->setvarTable.put($6, pp->setvars.size()); if (print) { pp->output(std::string($6), new AST::SetVar(pp->setvars.size())); } bool introduced = $7 && $7->hasAtom("var_is_introduced"); bool looks_introduced = (strncmp($6, "X_INTRODUCED_", 13) == 0); if ($8()) { AST::Node* arg = $8.some(); if (arg->isSet()) { pp->setvars.push_back(varspec($6, new SetVarSpec(arg->getSet(),print,introduced,looks_introduced))); } else if (arg->isSetVar()) { pp->setvars.push_back(varspec($6, new SetVarSpec(Alias(arg->getSetVar()),print,introduced,looks_introduced))); 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,introduced,looks_introduced))); } delete $7; free($6); } | int_ti_expr_tail ':' ID annotations '=' non_array_expr { ParserState* pp = static_cast(parm); yyassert(pp, !$1() || !$1.some()->empty(), "Empty int domain."); yyassert(pp, $6->isInt(), "Invalid int initializer."); int i = -1; bool isInt = $6->isInt(i); if ($1() && isInt) { AST::SetLit* sl = $1.some(); if (sl->interval) { yyassert(pp, i >= sl->min && i <= sl->max, "Empty int domain."); } else { bool found = false; for (unsigned int j = 0; j < sl->s.size(); j++) { if (sl->s[j] == i) { found = true; break; } } yyassert(pp, found, "Empty int domain."); } } pp->intvals.put($3, i); delete $4; free($3); } | BOOLTOK ':' ID annotations '=' non_array_expr { ParserState* pp = static_cast(parm); yyassert(pp, $6->isBool(), "Invalid bool initializer."); if ($6->isBool()) { pp->boolvals.put($3, $6->getBool()); } delete $4; free($3); } | SET OF int_ti_expr_tail ':' ID annotations '=' non_array_expr { ParserState* pp = static_cast(parm); yyassert(pp, !$3() || !$3.some()->empty(), "Empty set domain."); yyassert(pp, $8->isSet(), "Invalid set initializer."); AST::SetLit* set = NULL; if ($8->isSet()) set = $8->getSet(); pp->setvals.put($5, *set); delete set; delete $6; free($5); } | ARRAY '[' INT_LIT DOTDOT INT_LIT ']' OF VAR int_ti_expr_tail ':' 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 && $12->hasCall("output_array"); vector vars($5); yyassert(pp, !$9() || !$9.some()->empty(), "Empty var int domain."); 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) { vars[i] = ivsv->i; } else { 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, "set_in", new AST::IntVar(vars[i]), opt); } } } delete vsv; } else { IntVarSpec* ispec = new IntVarSpec($9,print,!print,false); string arrayname = "["; arrayname += $11; for (int i = 0; i < $5-1; i++) { vars[i] = pp->intvars.size(); pp->intvars.push_back(varspec(arrayname, ispec)); } vars[$5-1] = pp->intvars.size(); pp->intvars.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::IntVar(vars[i])); a->a.push_back(output); a->a.push_back(new AST::String(")")); pp->output(std::string($11), a); } pp->intvararrays.put($11, vars); } delete $12; free($11); } | ARRAY '[' INT_LIT DOTDOT INT_LIT ']' OF VAR bool_ti_expr_tail ':' ID annotations vardecl_bool_var_array_init { ParserState* pp = static_cast(parm); bool print = $12 && $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) vars[i] = bvsv->i; else { 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, "set_in", new AST::BoolVar(vars[i]), opt); } } } delete vsv; } else { for (int i = 0; i < $5; i++) { vars[i] = pp->boolvars.size(); pp->boolvars.push_back(varspec($11, new BoolVarSpec($9,print,!print,false))); } } 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); } pp->boolvararrays.put($11, vars); } delete $12; free($11); } | ARRAY '[' INT_LIT DOTDOT INT_LIT ']' OF VAR float_ti_expr_tail ':' ID annotations vardecl_float_var_array_init { ParserState* pp = static_cast(parm); yyassert(pp, false, "Floats not supported."); delete $12; free($11); } | ARRAY '[' INT_LIT DOTDOT INT_LIT ']' OF VAR SET OF int_ti_expr_tail ':' ID annotations vardecl_set_var_array_init { ParserState* pp = static_cast(parm); bool print = $14 && $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) vars[i] = svsv->i; else { 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 { SetVarSpec* ispec = new SetVarSpec($11,print,!print, false); string arrayname = "["; arrayname += $13; for (int i = 0; i < $5-1; i++) { vars[i] = pp->setvars.size(); pp->setvars.push_back(varspec(arrayname, ispec)); } vars[$5-1] = pp->setvars.size(); pp->setvars.push_back(varspec($13, ispec)); } 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); } pp->setvararrays.put($13, vars); } delete $14; free($13); } | ARRAY '[' INT_LIT DOTDOT INT_LIT ']' OF int_ti_expr_tail ':' 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) pp->intvalarrays.put($10, *$14); delete $14; free($10); delete $11; } | ARRAY '[' INT_LIT DOTDOT INT_LIT ']' OF BOOLTOK ':' 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) pp->boolvalarrays.put($10, *$14); delete $14; free($10); delete $11; } | ARRAY '[' INT_LIT DOTDOT INT_LIT ']' OF FLOATTOK ':' ID annotations '=' '[' float_list ']' { ParserState* pp = static_cast(parm); yyassert(pp, false, "Floats not supported."); delete $11; free($10); } | ARRAY '[' INT_LIT DOTDOT INT_LIT ']' OF SET OF int_ti_expr_tail ':' 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) pp->setvalarrays.put($12, *$16); delete $16; delete $13; free($12); } int_init : INT_LIT { $$ = new IntVarSpec($1, false, true, false); } | ID { int v = 0; ParserState* pp = static_cast(parm); if (pp->intvarTable.get($1, v)) $$ = new IntVarSpec(Alias(v), false, true, false); else { pp->err << "Error: undefined identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new IntVarSpec(0,false,true,false); // keep things consistent } free($1); } | ID '[' INT_LIT ']' { vector v; ParserState* pp = static_cast(parm); if (pp->intvararrays.get($1, v)) { yyassert(pp,static_cast($3) > 0 && static_cast($3) <= v.size(), "array access out of bounds"); if (!pp->hadError) $$ = new IntVarSpec(Alias(v[$3-1]),false,true,false); else $$ = new IntVarSpec(0,false,true,false); // keep things consistent } else { pp->err << "Error: undefined array identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new IntVarSpec(0,false,true,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 : /* empty */ | ',' int_var_array_literal : '[' int_init_list ']' { $$ = $2; } float_init : FLOAT_LIT { $$ = new FloatVarSpec($1,false,true,false); } | ID { int v = 0; ParserState* pp = static_cast(parm); if (pp->floatvarTable.get($1, v)) $$ = new FloatVarSpec(Alias(v),false,true,false); else { pp->err << "Error: undefined identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new FloatVarSpec(0.0,false,true,false); } free($1); } | ID '[' INT_LIT ']' { vector v; ParserState* pp = static_cast(parm); if (pp->floatvararrays.get($1, v)) { yyassert(pp,static_cast($3) > 0 && static_cast($3) <= v.size(), "array access out of bounds"); if (!pp->hadError) $$ = new FloatVarSpec(Alias(v[$3-1]),false,true,false); else $$ = new FloatVarSpec(0.0,false,true,false); } else { pp->err << "Error: undefined array identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new FloatVarSpec(0.0,false,true,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 : BOOL_LIT { $$ = new BoolVarSpec($1,false,true,false); } | ID { int v = 0; ParserState* pp = static_cast(parm); if (pp->boolvarTable.get($1, v)) $$ = new BoolVarSpec(Alias(v),false,true,false); else { pp->err << "Error: undefined identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new BoolVarSpec(false,false,true,false); } free($1); } | ID '[' INT_LIT ']' { vector v; ParserState* pp = static_cast(parm); if (pp->boolvararrays.get($1, v)) { yyassert(pp,static_cast($3) > 0 && static_cast($3) <= v.size(), "array access out of bounds"); if (!pp->hadError) $$ = new BoolVarSpec(Alias(v[$3-1]),false,true,false); else $$ = new BoolVarSpec(false,false,true,false); } else { pp->err << "Error: undefined array identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new BoolVarSpec(false,false,true,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(Option::some($1),false,true,false); } | ID { ParserState* pp = static_cast(parm); int v = 0; if (pp->setvarTable.get($1, v)) $$ = new SetVarSpec(Alias(v),false,true,false); else { pp->err << "Error: undefined identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new SetVarSpec(Alias(0),false,true,false); } free($1); } | ID '[' INT_LIT ']' { vector v; ParserState* pp = static_cast(parm); if (pp->setvararrays.get($1, v)) { yyassert(pp,static_cast($3) > 0 && static_cast($3) <= v.size(), "array access out of bounds"); if (!pp->hadError) $$ = new SetVarSpec(Alias(v[$3-1]),false,true,false); else $$ = new SetVarSpec(Alias(0),false,true,false); } else { pp->err << "Error: undefined array identifier " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; $$ = new SetVarSpec(Alias(0),false,true,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 : CONSTRAINT ID '(' flat_expr_list ')' annotations { ParserState *pp = static_cast(parm); #if EXPOSE_INT_LITS pp->domainConstraints2.push_back(std::pair(new ConExpr($2, $4), $6)); #else ConExpr c($2, $4); if (!pp->hadError) { try { pp->fg->postConstraint(c, $6); } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } delete $6; #endif free($2); } | CONSTRAINT ID annotations { ParserState *pp = static_cast(parm); AST::Array* args = new AST::Array(2); args->a[0] = getVarRefArg(pp,$2); args->a[1] = new AST::BoolLit(true); #if EXPOSE_INT_LITS pp->domainConstraints2.push_back(std::pair(new ConExpr("bool_eq", args), $3)); #else ConExpr c("bool_eq", args); if (!pp->hadError) { try { pp->fg->postConstraint(c, $3); } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } delete $3; #endif free($2); } | CONSTRAINT ID '[' INT_LIT ']' annotations { ParserState *pp = static_cast(parm); AST::Array* args = new AST::Array(2); args->a[0] = getArrayElement(pp,$2,$4); args->a[1] = new AST::BoolLit(true); #if EXPOSE_INT_LITS pp->domainConstraints2.push_back(std::pair(new ConExpr("bool_eq", args), $6)); #else ConExpr c("bool_eq", args); if (!pp->hadError) { try { pp->fg->postConstraint(c, $6); } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } delete $6; #endif free($2); } solve_item : SOLVE annotations SATISFY { ParserState *pp = static_cast(parm); if (!pp->hadError) { pp->fg->solve($2); } delete $2; } | SOLVE annotations minmax solve_expr { ParserState *pp = static_cast(parm); if (!pp->hadError) { if ($3) pp->fg->minimize($4,$2); else pp->fg->maximize($4,$2); } delete $2; } /********************************/ /* type-insts */ /********************************/ int_ti_expr_tail : INTTOK { $$ = Option::none(); } | '{' int_list '}' { $$ = Option::some(new AST::SetLit(*$2)); } | INT_LIT DOTDOT INT_LIT { $$ = Option::some(new AST::SetLit($1, $3)); } bool_ti_expr_tail : BOOLTOK { $$ = 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 : FLOATTOK | '{' float_list_head list_tail '}' /********************************/ /* literals */ /********************************/ set_literal : '{' int_list '}' { $$ = new AST::SetLit(*$2); } | INT_LIT DOTDOT 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 : INT_LIT { $$ = new vector(1); (*$$)[0] = $1; } | int_list_head ',' INT_LIT { $$ = $1; $$->push_back($3); } bool_list : /* empty */ { $$ = new vector(0); } | bool_list_head list_tail { $$ = $1; } bool_list_head : BOOL_LIT { $$ = new vector(1); (*$$)[0] = $1; } | bool_list_head ',' BOOL_LIT { $$ = $1; $$->push_back($3); } float_list : /* empty */ { $$ = new vector(0); } | float_list_head list_tail { $$ = $1; } float_list_head : FLOAT_LIT { $$ = new vector(1); (*$$)[0] = $1; } | float_list_head ',' 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 : BOOL_LIT { $$ = new AST::BoolLit($1); } | INT_LIT { $$ = new AST::IntLit($1); } | FLOAT_LIT { $$ = new AST::FloatLit($1); } | set_literal { $$ = $1; } | ID /* variable, possibly array */ { vector as; ParserState* pp = static_cast(parm); if (pp->intvararrays.get($1, as)) { AST::Array *ia = new AST::Array(as.size()); for (int i = as.size(); i--;) ia->a[i] = new AST::IntVar(as[i]); $$ = ia; } else if (pp->boolvararrays.get($1, as)) { AST::Array *ia = new AST::Array(as.size()); for (int i = as.size(); i--;) ia->a[i] = new AST::BoolVar(as[i]); $$ = ia; } else if (pp->setvararrays.get($1, as)) { AST::Array *ia = new AST::Array(as.size()); for (int i = as.size(); i--;) ia->a[i] = new AST::SetVar(as[i]); $$ = ia; } else { std::vector is; std::vector isS; int ival = 0; bool bval = false; if (pp->intvalarrays.get($1, is)) { AST::Array *v = new AST::Array(is.size()); for (int i = is.size(); i--;) v->a[i] = new AST::IntLit(is[i]); $$ = v; } else if (pp->boolvalarrays.get($1, is)) { AST::Array *v = new AST::Array(is.size()); for (int i = is.size(); i--;) v->a[i] = new AST::BoolLit(is[i]); $$ = v; } else if (pp->setvalarrays.get($1, isS)) { AST::Array *v = new AST::Array(isS.size()); for (int i = isS.size(); i--;) v->a[i] = new AST::SetLit(isS[i]); $$ = v; } else if (pp->intvals.get($1, ival)) { $$ = new AST::IntLit(ival); } else if (pp->boolvals.get($1, bval)) { $$ = new AST::BoolLit(bval); } else { $$ = getVarRefArg(pp,$1); } } free($1); } | 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); else $$ = new AST::IntLit(0); // keep things consistent 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: INT_LIT { ParserState *pp = static_cast(parm); // Create a new variable in the parser and append at the end const int i = pp->intvars.size(); const std::string objname = "X_INTRODUCED_CHUFFEDOBJ"; pp->intvarTable.put(objname, i); pp->intvars.push_back(varspec(objname, new IntVarSpec($1,false,true,false))); if (pp->fg != NULL) { // Add a new IntVar to the FlatZincSpace if it was already created try { pp->fg->newIntVar(static_cast(pp->intvars[i].second)); IntVar* newiv = pp->fg->iv[pp->fg->intVarCount-1]; intVarString.insert(std::pair(newiv, pp->intvars[i].first)); } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } $$ = i; } | ID { ParserState *pp = static_cast(parm); int tmp = -1; // Check whether the Objective variable is an integer constant if (pp->intvals.get($1, tmp) && !pp->intvarTable.get($1, $$)) { // Create a new variable in the parser and append at the end const int i = pp->intvars.size(); pp->intvarTable.put($1, i); pp->intvars.push_back(varspec($1, new IntVarSpec(tmp,false,true,false))); if (pp->fg != NULL) { // Add a new IntVar to the FlatZincSpace if it was already created try { pp->fg->newIntVar(static_cast(pp->intvars[i].second)); IntVar* newiv = pp->fg->iv[pp->fg->intVarCount-1]; intVarString.insert(std::pair(newiv, pp->intvars[i].first)); } catch (FlatZinc::Error& e) { yyerror(pp, e.toString().c_str()); } } } if (!pp->intvarTable.get($1, $$)) { pp->err << "Error: unknown integer variable " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; } free($1); } | ID '[' INT_LIT ']' { vector tmp; ParserState *pp = static_cast(parm); if (!pp->intvararrays.get($1, tmp)) { pp->err << "Error: unknown integer variable array " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; } if ($3 == 0 || static_cast($3) > tmp.size()) { pp->err << "Error: array index out of bounds for array " << $1 << " in line no. " << yyget_lineno(pp->yyscanner) << std::endl; pp->hadError = true; } else { $$ = tmp[$3-1]; } free($1); } minmax: MINIMIZE | MAXIMIZE /********************************/ /* annotation expresions */ /********************************/ annotations : /* empty */ { $$ = NULL; } | annotations_head { $$ = $1; } annotations_head : COLONCOLON annotation { $$ = new AST::Array($2); } | annotations_head COLONCOLON annotation { $$ = $1; $$->append($3); } annotation : 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; } | '[' annotation_list ']' { $$ = $2; } ann_non_array_expr : BOOL_LIT { $$ = new AST::BoolLit($1); } | INT_LIT { $$ = new AST::IntLit($1); } | FLOAT_LIT { $$ = new AST::FloatLit($1); } | set_literal { $$ = $1; } | ID /* variable, possibly array */ { vector as; ParserState* pp = static_cast(parm); if (pp->intvararrays.get($1, as)) { AST::Array *ia = new AST::Array(as.size()); for (int i = as.size(); i--;) ia->a[i] = new AST::IntVar(as[i]); $$ = ia; } else if (pp->boolvararrays.get($1, as)) { AST::Array *ia = new AST::Array(as.size()); for (int i = as.size(); i--;) ia->a[i] = new AST::BoolVar(as[i]); $$ = ia; } else if (pp->setvararrays.get($1, as)) { AST::Array *ia = new AST::Array(as.size()); for (int i = as.size(); i--;) ia->a[i] = new AST::SetVar(as[i]); $$ = ia; } else { std::vector is; int ival = 0; bool bval = false; if (pp->intvalarrays.get($1, is)) { AST::Array *v = new AST::Array(is.size()); for (int i = is.size(); i--;) v->a[i] = new AST::IntLit(is[i]); $$ = v; } else if (pp->boolvalarrays.get($1, is)) { AST::Array *v = new AST::Array(is.size()); for (int i = is.size(); i--;) v->a[i] = new AST::BoolLit(is[i]); $$ = v; } else if (pp->intvals.get($1, ival)) { $$ = new AST::IntLit(ival); } else if (pp->boolvals.get($1, bval)) { $$ = new AST::BoolLit(bval); } else { $$ = getVarRefArg(pp,$1,true); } } free($1); } | 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); else $$ = new AST::IntLit(0); // keep things consistent free($1); } | STRING_LIT { $$ = new AST::String($1); free($1); }