Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
11 kB · 295 lines
C++
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* * Main authors: * Guido Tack <guido.tack@monash.edu> */
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This (main) file coordinates flattening and solving. * The corresponding modules are flexibly plugged in * as derived classes, prospectively from DLLs. * A flattening module should provide MinZinc::GetFlattener() * A solving module should provide an object of a class derived from SolverFactory. * Need to get more flexible for multi-pass & multi-solving stuff TODO */
#include <minizinc/file_utils.hh>#include <minizinc/json_parser.hh>#include <minizinc/parser.hh>#include <minizinc/prettyprinter.hh>
#include <fstream>
using namespace std;
int mzn_yylex_init(void** scanner);void mzn_yyset_extra(void* user_defined, void* yyscanner);int mzn_yyparse(void*);int mzn_yylex_destroy(void* scanner);
namespace {// fastest way to read a file into a string (especially big files)// see: http://insanecoding.blogspot.be/2011/11/how-to-read-in-file-in-c.htmlstd::string get_file_contents(std::ifstream& in) { if (in) { std::string contents; in.seekg(0, std::ios::end); contents.resize(static_cast<unsigned int>(in.tellg())); in.seekg(0, std::ios::beg); in.read(&contents[0], contents.size()); in.close(); if (contents.size() > 0 && contents[0] == '@') { contents = MiniZinc::FileUtils::decodeBase64(contents); MiniZinc::FileUtils::inflateString(contents); } return (contents); } throw(errno);}} // namespace
namespace MiniZinc {
void parse(Env& env, Model*& model, const vector<string>& filenames, const vector<string>& datafiles, const std::string& modelString, const std::string& modelStringName, const vector<string>& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err, std::vector<SyntaxError>& syntaxErrors) { vector<string> includePaths; for (unsigned int i = 0; i < ip.size(); i++) includePaths.push_back(ip[i]);
vector<ParseWorkItem> files; map<string, Model*> seenModels;
string workingDir = FileUtils::working_directory();
if (filenames.size() > 0) { GCLock lock; model->setFilename(FileUtils::base_name(filenames[0])); if (FileUtils::is_absolute(filenames[0])) { files.push_back(ParseWorkItem(model, NULL, "", filenames[0])); } else { files.push_back(ParseWorkItem(model, NULL, "", workingDir + "/" + filenames[0])); }
for (unsigned int i = 1; i < filenames.size(); i++) { GCLock lock; string fullName = filenames[i]; string baseName = FileUtils::base_name(filenames[i]); if (!FileUtils::is_absolute(fullName)) fullName = workingDir + "/" + fullName; bool isFzn = (baseName.compare(baseName.length() - 4, 4, ".fzn") == 0); if (isFzn) { files.push_back(ParseWorkItem(model, NULL, "", fullName)); } else { Model* includedModel = new Model; includedModel->setFilename(baseName); files.push_back(ParseWorkItem(includedModel, NULL, "", fullName)); seenModels.insert(pair<string, Model*>(baseName, includedModel)); Location loc(ASTString(filenames[i]), 0, 0, 0, 0); IncludeI* inc = new IncludeI(loc, includedModel->filename()); inc->m(includedModel, true); model->addItem(inc); } } if (!modelString.empty()) { Model* includedModel = new Model; includedModel->setFilename(modelStringName); files.push_back(ParseWorkItem(includedModel, NULL, modelString, modelStringName, true)); seenModels.insert(pair<string, Model*>(modelStringName, includedModel)); Location loc(ASTString(modelStringName), 0, 0, 0, 0); IncludeI* inc = new IncludeI(loc, includedModel->filename()); inc->m(includedModel, true); model->addItem(inc); } } else if (!modelString.empty()) { GCLock lock; model->setFilename(modelStringName); files.push_back(ParseWorkItem(model, NULL, modelString, modelStringName, true)); }
if (!ignoreStdlib) { GCLock lock; Model* stdlib = new Model; stdlib->setFilename("stdlib.mzn"); files.push_back(ParseWorkItem(stdlib, NULL, "./", "stdlib.mzn")); seenModels.insert(pair<string, Model*>("stdlib.mzn", stdlib)); Location stdlibloc(ASTString(model->filename()), 0, 0, 0, 0); IncludeI* stdlibinc = new IncludeI(stdlibloc, stdlib->filename()); stdlibinc->m(stdlib, true); model->addItem(stdlibinc); }
while (!files.empty()) { GCLock lock; ParseWorkItem& np = files.back(); string parentPath = np.dirName; Model* m = np.m; bool isModelString = np.isModelString; IncludeI* np_ii = np.ii; string f(np.fileName); files.pop_back();
std::string s; std::string fullname; bool isFzn; if (!isModelString) { for (Model* p = m->parent(); p; p = p->parent()) { if (f == p->filename().c_str()) { err << "Error: cyclic includes: " << std::endl; for (Model* pe = m; pe; pe = pe->parent()) { err << " " << pe->filename() << std::endl; } goto error; } } ifstream file; if (FileUtils::is_absolute(f) || parentPath == "") { if (filenames.size() == 0) { err << "Internal error." << endl; goto error; } fullname = f; if (FileUtils::file_exists(fullname)) { file.open(fullname.c_str(), std::ios::binary); } } else { includePaths.push_back(parentPath); unsigned int i = 0; for (; i < includePaths.size(); i++) { fullname = includePaths[i] + "/" + f; if (FileUtils::file_exists(fullname)) { file.open(fullname.c_str(), std::ios::binary); if (file.is_open()) break; } } if (file.is_open() && i < includePaths.size() - 1 && parentPath == workingDir && FileUtils::file_path(includePaths[i], workingDir) != FileUtils::file_path(workingDir) && FileUtils::file_exists(workingDir + "/" + f)) { err << "Warning: file " << f << " included from library, but also exists in current working directory" << endl; } includePaths.pop_back(); } if (!file.is_open()) { if (np_ii) { err << np_ii->loc().toString() << ":\n"; err << "MiniZinc: error in include item, cannot open file '" << f << "'." << endl; } else { err << "Error: cannot open file '" << f << "'." << endl; } goto error; } if (verbose) std::cerr << "processing file '" << fullname << "'" << endl; s = get_file_contents(file);
if (m->filepath().size() == 0) m->setFilepath(fullname); isFzn = (fullname.compare(fullname.length() - 4, 4, ".fzn") == 0); isFzn |= (fullname.compare(fullname.length() - 4, 4, ".ozn") == 0); isFzn |= (fullname.compare(fullname.length() - 4, 4, ".szn") == 0); isFzn |= (fullname.compare(fullname.length() - 4, 4, ".mzc") == 0); } else { isFzn = false; fullname = f; s = parentPath; } ParserState pp(fullname, s, err, files, seenModels, m, false, isFzn, parseDocComments); mzn_yylex_init(&pp.yyscanner); mzn_yyset_extra(&pp, pp.yyscanner); mzn_yyparse(&pp); if (pp.yyscanner) mzn_yylex_destroy(pp.yyscanner); if (pp.hadError) { for (unsigned int i = 0; i < pp.syntaxErrors.size(); i++) syntaxErrors.push_back(pp.syntaxErrors[i]); goto error; } }
for (unsigned int i = 0; i < datafiles.size(); i++) { GCLock lock; string f = datafiles[i]; if (f.size() >= 6 && f.substr(f.size() - 5, string::npos) == ".json") { JSONParser jp(env.envi()); jp.parse(model, f); } else { string s; if (f.size() > 5 && f.substr(0, 5) == "cmd:/") { s = f.substr(5); } else { std::ifstream file; file.open(f.c_str(), std::ios::binary); if (!FileUtils::file_exists(f) || !file.is_open()) { err << "Error: cannot open data file '" << f << "'." << endl; goto error; } if (verbose) std::cerr << "processing data file '" << f << "'" << endl; s = get_file_contents(file); }
ParserState pp(f, s, err, files, seenModels, model, true, false, parseDocComments); mzn_yylex_init(&pp.yyscanner); mzn_yyset_extra(&pp, pp.yyscanner); mzn_yyparse(&pp); if (pp.yyscanner) mzn_yylex_destroy(pp.yyscanner); if (pp.hadError) { for (unsigned int i = 0; i < pp.syntaxErrors.size(); i++) syntaxErrors.push_back(pp.syntaxErrors[i]); goto error; } } }
return;error: delete model; model = NULL;}
Model* parse(Env& env, const vector<string>& filenames, const vector<string>& datafiles, const string& textModel, const string& textModelName, const vector<string>& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { if (filenames.empty() && textModel.empty()) { err << "Error: no model given" << std::endl; return NULL; }
Model* model; { GCLock lock; model = new Model(); } std::vector<SyntaxError> se; parse(env, model, filenames, datafiles, textModel, textModelName, ip, ignoreStdlib, parseDocComments, verbose, err, se); return model;}
Model* parseData(Env& env, Model* model, const vector<string>& datafiles, const vector<string>& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { vector<string> filenames; std::vector<SyntaxError> se; parse(env, model, filenames, datafiles, "", "", includePaths, ignoreStdlib, parseDocComments, verbose, err, se); return model;}
Model* parseFromString(Env& env, const string& text, const string& filename, const vector<string>& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err, std::vector<SyntaxError>& syntaxErrors) { vector<string> filenames; vector<string> datafiles; Model* model; { GCLock lock; model = new Model(); } parse(env, model, filenames, datafiles, text, filename, ip, ignoreStdlib, parseDocComments, verbose, err, syntaxErrors); return model;}
} // namespace MiniZinc