git-subtree-dir: software/chuffed git-subtree-split: 2ed0c01558d2a5c49c1ce57e048d32c17adf92d3
1842 lines
60 KiB
Plaintext
1842 lines
60 KiB
Plaintext
/*
|
|
* 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 {<chuffed/flatzinc/parser.tab.h>}
|
|
|
|
%lex-param {YYLEX_PARAM}
|
|
%parse-param {void *parm}
|
|
%{
|
|
#define YYPARSE_PARAM parm
|
|
#define YYLEX_PARAM static_cast<ParserState*>(parm)->yyscanner
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
#include <chuffed/flatzinc/flatzinc.h>
|
|
#include <chuffed/flatzinc/parser.tab.h>
|
|
|
|
#ifdef HAVE_MMAP
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#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<ParserState*>(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<int> 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<AST::SetLit> 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<AST::SetLit* >& 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<int>(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<BoolVarSpec *>(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<IntVarSpec*>(pp->intvars[i].second));
|
|
IntVar* newiv = pp->fg->iv[pp->fg->intVarCount-1];
|
|
intVarString.insert(std::pair<IntVar*, std::string>(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<BoolVarSpec*>(pp->boolvars[i].second));
|
|
BoolView newiv = pp->fg->bv[pp->fg->boolVarCount-1];
|
|
if (pp->boolvars[i].second->assigned)
|
|
boolVarString.insert(std::pair<BoolView, std::string>(newiv, "ASSIGNED_AT_ROOT"));
|
|
else
|
|
boolVarString.insert(std::pair<BoolView, std::string>(newiv, pp->boolvars[i].first));
|
|
string label;
|
|
label = pp->boolvars[i].first;
|
|
label.append("=true");
|
|
litString.insert(std::pair<int,std::string>(toInt(newiv.getLit(true)), label));
|
|
label = pp->boolvars[i].first;
|
|
label.append("=false");
|
|
litString.insert(std::pair<int,std::string>(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<SetVarSpec*>(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<int>(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<char>(file),
|
|
istreambuf_iterator<char>());
|
|
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<char>(is),
|
|
istreambuf_iterator<char>());
|
|
|
|
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<int>* setValue;
|
|
FlatZinc::AST::SetLit* setLit;
|
|
std::vector<double>* floatSetValue;
|
|
std::vector<FlatZinc::AST::SetLit>* setValueList;
|
|
FlatZinc::Option<FlatZinc::AST::SetLit* > oSet;
|
|
FlatZinc::VarSpec* varSpec;
|
|
FlatZinc::Option<FlatZinc::AST::Node*> oArg;
|
|
std::vector<FlatZinc::VarSpec*>* varSpecVec;
|
|
FlatZinc::Option<std::vector<FlatZinc::VarSpec*>* > oVarSpecVec;
|
|
FlatZinc::AST::Node* arg;
|
|
FlatZinc::AST::Array* argVec;
|
|
}
|
|
|
|
%define parse.error verbose
|
|
|
|
%token <iValue> INT_LIT BOOL_LIT
|
|
%token <dValue> FLOAT_LIT
|
|
%token <sValue> ID STRING_LIT
|
|
|
|
%token <bValue> 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 <bValue> MAXIMIZE
|
|
%token <bValue> 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 <setLit> set_literal
|
|
|
|
%type <varSpec> int_init bool_init set_init float_init
|
|
%type <oSet> int_ti_expr_tail bool_ti_expr_tail
|
|
|
|
%type <oVarSpecVec> vardecl_int_var_array_init
|
|
%type <oVarSpecVec> vardecl_bool_var_array_init
|
|
%type <oVarSpecVec> vardecl_float_var_array_init
|
|
%type <oVarSpecVec> vardecl_set_var_array_init
|
|
%type <varSpecVec> int_var_array_literal
|
|
%type <varSpecVec> bool_var_array_literal
|
|
%type <varSpecVec> float_var_array_literal
|
|
%type <varSpecVec> set_var_array_literal
|
|
%type <varSpecVec> int_init_list int_init_list_head
|
|
%type <varSpecVec> bool_init_list bool_init_list_head
|
|
%type <varSpecVec> float_init_list float_init_list_head
|
|
%type <varSpecVec> set_init_list set_init_list_head
|
|
|
|
%type <setValue> int_list int_list_head
|
|
%type <setValue> bool_list bool_list_head
|
|
%type <setValueList> set_literal_list set_literal_list_head
|
|
%type <floatSetValue> float_list float_list_head
|
|
|
|
%type <arg> flat_expr non_array_expr annotation_expr ann_non_array_expr
|
|
%type <oArg> non_array_expr_opt
|
|
%type <argVec> flat_expr_list non_array_expr_list non_array_expr_list_head
|
|
|
|
%type <iValue> solve_expr
|
|
%type <bValue> minmax
|
|
|
|
%type <argVec> annotations annotations_head
|
|
%type <arg> 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<ParserState*>(parm));
|
|
#endif
|
|
}
|
|
| vardecl_items_head
|
|
{
|
|
#if !EXPOSE_INT_LITS
|
|
initfg(static_cast<ParserState*>(parm));
|
|
#endif
|
|
}
|
|
|
|
vardecl_items_head :
|
|
vardecl_item ';'
|
|
| vardecl_items_head vardecl_item ';'
|
|
|
|
constraint_items :
|
|
/* empty */
|
|
{
|
|
#if EXPOSE_INT_LITS
|
|
initfg(static_cast<ParserState*>(parm));
|
|
#endif
|
|
}
|
|
| constraint_items_head
|
|
{
|
|
#if EXPOSE_INT_LITS
|
|
initfg(static_cast<ParserState*>(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<ParserState*>(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<ParserState*>(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<ParserState*>(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<ParserState*>(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<ParserState*>(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<ParserState*>(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<ParserState*>(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<ParserState*>(parm);
|
|
yyassert(pp, $3 == 1, "Arrays must start at 1");
|
|
if (!pp->hadError) {
|
|
bool print = $12 && $12->hasCall("output_array");
|
|
vector<int> vars($5);
|
|
yyassert(pp, !$9() || !$9.some()->empty(), "Empty var int domain.");
|
|
if (!pp->hadError) {
|
|
if ($13()) {
|
|
vector<VarSpec*>* vsv = $13.some();
|
|
yyassert(pp, vsv->size() == static_cast<unsigned int>($5),
|
|
"Initializer size does not match array dimension");
|
|
if (!pp->hadError) {
|
|
for (int i = 0; i < $5; i++) {
|
|
IntVarSpec* ivsv = static_cast<IntVarSpec*>((*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<AST::SetLit*> opt =
|
|
Option<AST::SetLit*>::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<ParserState*>(parm);
|
|
bool print = $12 && $12->hasCall("output_array");
|
|
yyassert(pp, $3 == 1, "Arrays must start at 1");
|
|
if (!pp->hadError) {
|
|
vector<int> vars($5);
|
|
if ($13()) {
|
|
vector<VarSpec*>* vsv = $13.some();
|
|
yyassert(pp, vsv->size() == static_cast<unsigned int>($5),
|
|
"Initializer size does not match array dimension");
|
|
if (!pp->hadError) {
|
|
for (int i = 0; i < $5; i++) {
|
|
BoolVarSpec* bvsv = static_cast<BoolVarSpec*>((*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<AST::SetLit*> opt =
|
|
Option<AST::SetLit*>::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<ParserState*>(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<ParserState*>(parm);
|
|
bool print = $14 && $14->hasCall("output_array");
|
|
yyassert(pp, $3 == 1, "Arrays must start at 1");
|
|
if (!pp->hadError) {
|
|
vector<int> vars($5);
|
|
if ($15()) {
|
|
vector<VarSpec*>* vsv = $15.some();
|
|
yyassert(pp, vsv->size() == static_cast<unsigned int>($5),
|
|
"Initializer size does not match array dimension");
|
|
if (!pp->hadError) {
|
|
for (int i = 0; i < $5; i++) {
|
|
SetVarSpec* svsv = static_cast<SetVarSpec*>((*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<AST::SetLit*> opt =
|
|
Option<AST::SetLit*>::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<ParserState*>(parm);
|
|
yyassert(pp, $3 == 1, "Arrays must start at 1");
|
|
yyassert(pp, $14->size() == static_cast<unsigned int>($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<ParserState*>(parm);
|
|
yyassert(pp, $3 == 1, "Arrays must start at 1");
|
|
yyassert(pp, $14->size() == static_cast<unsigned int>($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<ParserState*>(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<ParserState*>(parm);
|
|
yyassert(pp, $3 == 1, "Arrays must start at 1");
|
|
yyassert(pp, $16->size() == static_cast<unsigned int>($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<ParserState*>(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<int> v;
|
|
ParserState* pp = static_cast<ParserState*>(parm);
|
|
if (pp->intvararrays.get($1, v)) {
|
|
yyassert(pp,static_cast<unsigned int>($3) > 0 &&
|
|
static_cast<unsigned int>($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<VarSpec*>(0);
|
|
}
|
|
| int_init_list_head list_tail
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
int_init_list_head :
|
|
int_init
|
|
{
|
|
$$ = new vector<VarSpec*>(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<ParserState*>(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<int> v;
|
|
ParserState* pp = static_cast<ParserState*>(parm);
|
|
if (pp->floatvararrays.get($1, v)) {
|
|
yyassert(pp,static_cast<unsigned int>($3) > 0 &&
|
|
static_cast<unsigned int>($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<VarSpec*>(0);
|
|
}
|
|
| float_init_list_head list_tail
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
float_init_list_head :
|
|
float_init
|
|
{
|
|
$$ = new vector<VarSpec*>(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<ParserState*>(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<int> v;
|
|
ParserState* pp = static_cast<ParserState*>(parm);
|
|
if (pp->boolvararrays.get($1, v)) {
|
|
yyassert(pp,static_cast<unsigned int>($3) > 0 &&
|
|
static_cast<unsigned int>($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<VarSpec*>(0);
|
|
}
|
|
| bool_init_list_head list_tail
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
bool_init_list_head :
|
|
bool_init
|
|
{
|
|
$$ = new vector<VarSpec*>(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<AST::SetLit*>::some($1),false,true,false);
|
|
}
|
|
| ID
|
|
{
|
|
ParserState* pp = static_cast<ParserState*>(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<int> v;
|
|
ParserState* pp = static_cast<ParserState*>(parm);
|
|
if (pp->setvararrays.get($1, v)) {
|
|
yyassert(pp,static_cast<unsigned int>($3) > 0 &&
|
|
static_cast<unsigned int>($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<VarSpec*>(0);
|
|
}
|
|
| set_init_list_head list_tail
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
set_init_list_head :
|
|
set_init
|
|
{
|
|
$$ = new vector<VarSpec*>(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<vector<VarSpec*>* >::none();
|
|
}
|
|
| '=' int_var_array_literal
|
|
{
|
|
$$ = Option<vector<VarSpec*>* >::some($2);
|
|
}
|
|
|
|
vardecl_bool_var_array_init :
|
|
/* empty */
|
|
{
|
|
$$ = Option<vector<VarSpec*>* >::none();
|
|
}
|
|
| '=' bool_var_array_literal
|
|
{
|
|
$$ = Option<vector<VarSpec*>* >::some($2);
|
|
}
|
|
|
|
vardecl_float_var_array_init :
|
|
/* empty */
|
|
{
|
|
$$ = Option<vector<VarSpec*>* >::none();
|
|
}
|
|
| '=' float_var_array_literal
|
|
{
|
|
$$ = Option<vector<VarSpec*>* >::some($2);
|
|
}
|
|
|
|
vardecl_set_var_array_init :
|
|
/* empty */
|
|
{
|
|
$$ = Option<vector<VarSpec*>* >::none();
|
|
}
|
|
| '=' set_var_array_literal
|
|
{
|
|
$$ = Option<vector<VarSpec*>* >::some($2);
|
|
}
|
|
|
|
constraint_item :
|
|
CONSTRAINT ID '(' flat_expr_list ')' annotations
|
|
{
|
|
ParserState *pp = static_cast<ParserState*>(parm);
|
|
#if EXPOSE_INT_LITS
|
|
pp->domainConstraints2.push_back(std::pair<ConExpr*, AST::Node*>(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<ParserState*>(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<ConExpr*, AST::Node*>(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<ParserState*>(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<ConExpr*, AST::Node*>(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<ParserState*>(parm);
|
|
if (!pp->hadError) {
|
|
pp->fg->solve($2);
|
|
}
|
|
delete $2;
|
|
}
|
|
| SOLVE annotations minmax solve_expr
|
|
{
|
|
ParserState *pp = static_cast<ParserState*>(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<AST::SetLit* >::none();
|
|
}
|
|
| '{' int_list '}'
|
|
{
|
|
$$ = Option<AST::SetLit* >::some(new AST::SetLit(*$2));
|
|
}
|
|
| INT_LIT DOTDOT INT_LIT
|
|
{
|
|
$$ = Option<AST::SetLit* >::some(new AST::SetLit($1, $3));
|
|
}
|
|
|
|
bool_ti_expr_tail :
|
|
BOOLTOK
|
|
{
|
|
$$ = Option<AST::SetLit* >::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<AST::SetLit* >::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<int>(0);
|
|
}
|
|
| int_list_head list_tail
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
int_list_head :
|
|
INT_LIT
|
|
{
|
|
$$ = new vector<int>(1);
|
|
(*$$)[0] = $1;
|
|
}
|
|
| int_list_head ',' INT_LIT
|
|
{
|
|
$$ = $1;
|
|
$$->push_back($3);
|
|
}
|
|
|
|
bool_list :
|
|
/* empty */
|
|
{
|
|
$$ = new vector<int>(0);
|
|
}
|
|
| bool_list_head list_tail
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
bool_list_head :
|
|
BOOL_LIT
|
|
{
|
|
$$ = new vector<int>(1);
|
|
(*$$)[0] = $1;
|
|
}
|
|
| bool_list_head ',' BOOL_LIT
|
|
{
|
|
$$ = $1;
|
|
$$->push_back($3);
|
|
}
|
|
|
|
float_list :
|
|
/* empty */
|
|
{
|
|
$$ = new vector<double>(0);
|
|
}
|
|
| float_list_head list_tail
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
float_list_head :
|
|
FLOAT_LIT
|
|
{
|
|
$$ = new vector<double>(1);
|
|
(*$$)[0] = $1;
|
|
}
|
|
| float_list_head ',' FLOAT_LIT
|
|
{
|
|
$$ = $1;
|
|
$$->push_back($3);
|
|
}
|
|
|
|
set_literal_list :
|
|
/* empty */
|
|
{
|
|
$$ = new vector<AST::SetLit>(0);
|
|
}
|
|
| set_literal_list_head list_tail
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
set_literal_list_head :
|
|
set_literal
|
|
{
|
|
$$ = new vector<AST::SetLit>(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<AST::Node*>::none();
|
|
}
|
|
| '=' non_array_expr
|
|
{
|
|
$$ = Option<AST::Node*>::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<int> as;
|
|
ParserState* pp = static_cast<ParserState*>(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<int> is;
|
|
std::vector<AST::SetLit> 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<ParserState*>(parm);
|
|
int i = -1;
|
|
yyassert(pp, $3->isInt(i), "Non-integer array index.");
|
|
if (!pp->hadError)
|
|
$$ = getArrayElement(static_cast<ParserState*>(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<ParserState*>(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<IntVarSpec*>(pp->intvars[i].second));
|
|
IntVar* newiv = pp->fg->iv[pp->fg->intVarCount-1];
|
|
intVarString.insert(std::pair<IntVar*, std::string>(newiv, pp->intvars[i].first));
|
|
} catch (FlatZinc::Error& e) {
|
|
yyerror(pp, e.toString().c_str());
|
|
}
|
|
}
|
|
$$ = i;
|
|
}
|
|
| ID
|
|
{
|
|
ParserState *pp = static_cast<ParserState*>(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<IntVarSpec*>(pp->intvars[i].second));
|
|
IntVar* newiv = pp->fg->iv[pp->fg->intVarCount-1];
|
|
intVarString.insert(std::pair<IntVar*, std::string>(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<int> tmp;
|
|
ParserState *pp = static_cast<ParserState*>(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<unsigned int>($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<int> as;
|
|
ParserState* pp = static_cast<ParserState*>(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<int> 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<ParserState*>(parm);
|
|
int i = -1;
|
|
yyassert(pp, $3->isInt(i), "Non-integer array index.");
|
|
if (!pp->hadError)
|
|
$$ = getArrayElement(static_cast<ParserState*>(parm),$1,i);
|
|
else
|
|
$$ = new AST::IntLit(0); // keep things consistent
|
|
free($1);
|
|
}
|
|
| STRING_LIT
|
|
{
|
|
$$ = new AST::String($1);
|
|
free($1);
|
|
}
|