this repo has no description
at develop 11 kB view raw
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Guido Tack <guido.tack@monash.edu> 6 */ 7 8/* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12/* This (main) file coordinates flattening and solving. 13 * The corresponding modules are flexibly plugged in 14 * as derived classes, prospectively from DLLs. 15 * A flattening module should provide MinZinc::GetFlattener() 16 * A solving module should provide an object of a class derived from SolverFactory. 17 * Need to get more flexible for multi-pass & multi-solving stuff TODO 18 */ 19 20#include <minizinc/file_utils.hh> 21#include <minizinc/json_parser.hh> 22#include <minizinc/parser.hh> 23#include <minizinc/prettyprinter.hh> 24 25#include <fstream> 26 27using namespace std; 28 29int mzn_yylex_init(void** scanner); 30void mzn_yyset_extra(void* user_defined, void* yyscanner); 31int mzn_yyparse(void*); 32int mzn_yylex_destroy(void* scanner); 33 34namespace { 35// fastest way to read a file into a string (especially big files) 36// see: http://insanecoding.blogspot.be/2011/11/how-to-read-in-file-in-c.html 37std::string get_file_contents(std::ifstream& in) { 38 if (in) { 39 std::string contents; 40 in.seekg(0, std::ios::end); 41 contents.resize(static_cast<unsigned int>(in.tellg())); 42 in.seekg(0, std::ios::beg); 43 in.read(&contents[0], contents.size()); 44 in.close(); 45 if (contents.size() > 0 && contents[0] == '@') { 46 contents = MiniZinc::FileUtils::decodeBase64(contents); 47 MiniZinc::FileUtils::inflateString(contents); 48 } 49 return (contents); 50 } 51 throw(errno); 52} 53} // namespace 54 55namespace MiniZinc { 56 57void parse(Env& env, Model*& model, const vector<string>& filenames, 58 const vector<string>& datafiles, const std::string& modelString, 59 const std::string& modelStringName, const vector<string>& ip, bool ignoreStdlib, 60 bool parseDocComments, bool verbose, ostream& err, 61 std::vector<SyntaxError>& syntaxErrors) { 62 vector<string> includePaths; 63 for (unsigned int i = 0; i < ip.size(); i++) includePaths.push_back(ip[i]); 64 65 vector<ParseWorkItem> files; 66 map<string, Model*> seenModels; 67 68 string workingDir = FileUtils::working_directory(); 69 70 if (filenames.size() > 0) { 71 GCLock lock; 72 model->setFilename(FileUtils::base_name(filenames[0])); 73 if (FileUtils::is_absolute(filenames[0])) { 74 files.push_back(ParseWorkItem(model, NULL, "", filenames[0])); 75 } else { 76 files.push_back(ParseWorkItem(model, NULL, "", workingDir + "/" + filenames[0])); 77 } 78 79 for (unsigned int i = 1; i < filenames.size(); i++) { 80 GCLock lock; 81 string fullName = filenames[i]; 82 string baseName = FileUtils::base_name(filenames[i]); 83 if (!FileUtils::is_absolute(fullName)) fullName = workingDir + "/" + fullName; 84 bool isFzn = (baseName.compare(baseName.length() - 4, 4, ".fzn") == 0); 85 if (isFzn) { 86 files.push_back(ParseWorkItem(model, NULL, "", fullName)); 87 } else { 88 Model* includedModel = new Model; 89 includedModel->setFilename(baseName); 90 files.push_back(ParseWorkItem(includedModel, NULL, "", fullName)); 91 seenModels.insert(pair<string, Model*>(baseName, includedModel)); 92 Location loc(ASTString(filenames[i]), 0, 0, 0, 0); 93 IncludeI* inc = new IncludeI(loc, includedModel->filename()); 94 inc->m(includedModel, true); 95 model->addItem(inc); 96 } 97 } 98 if (!modelString.empty()) { 99 Model* includedModel = new Model; 100 includedModel->setFilename(modelStringName); 101 files.push_back(ParseWorkItem(includedModel, NULL, modelString, modelStringName, true)); 102 seenModels.insert(pair<string, Model*>(modelStringName, includedModel)); 103 Location loc(ASTString(modelStringName), 0, 0, 0, 0); 104 IncludeI* inc = new IncludeI(loc, includedModel->filename()); 105 inc->m(includedModel, true); 106 model->addItem(inc); 107 } 108 } else if (!modelString.empty()) { 109 GCLock lock; 110 model->setFilename(modelStringName); 111 files.push_back(ParseWorkItem(model, NULL, modelString, modelStringName, true)); 112 } 113 114 if (!ignoreStdlib) { 115 GCLock lock; 116 Model* stdlib = new Model; 117 stdlib->setFilename("stdlib.mzn"); 118 files.push_back(ParseWorkItem(stdlib, NULL, "./", "stdlib.mzn")); 119 seenModels.insert(pair<string, Model*>("stdlib.mzn", stdlib)); 120 Location stdlibloc(ASTString(model->filename()), 0, 0, 0, 0); 121 IncludeI* stdlibinc = new IncludeI(stdlibloc, stdlib->filename()); 122 stdlibinc->m(stdlib, true); 123 model->addItem(stdlibinc); 124 } 125 126 while (!files.empty()) { 127 GCLock lock; 128 ParseWorkItem& np = files.back(); 129 string parentPath = np.dirName; 130 Model* m = np.m; 131 bool isModelString = np.isModelString; 132 IncludeI* np_ii = np.ii; 133 string f(np.fileName); 134 files.pop_back(); 135 136 std::string s; 137 std::string fullname; 138 bool isFzn; 139 if (!isModelString) { 140 for (Model* p = m->parent(); p; p = p->parent()) { 141 if (f == p->filename().c_str()) { 142 err << "Error: cyclic includes: " << std::endl; 143 for (Model* pe = m; pe; pe = pe->parent()) { 144 err << " " << pe->filename() << std::endl; 145 } 146 goto error; 147 } 148 } 149 ifstream file; 150 if (FileUtils::is_absolute(f) || parentPath == "") { 151 if (filenames.size() == 0) { 152 err << "Internal error." << endl; 153 goto error; 154 } 155 fullname = f; 156 if (FileUtils::file_exists(fullname)) { 157 file.open(fullname.c_str(), std::ios::binary); 158 } 159 } else { 160 includePaths.push_back(parentPath); 161 unsigned int i = 0; 162 for (; i < includePaths.size(); i++) { 163 fullname = includePaths[i] + "/" + f; 164 if (FileUtils::file_exists(fullname)) { 165 file.open(fullname.c_str(), std::ios::binary); 166 if (file.is_open()) break; 167 } 168 } 169 if (file.is_open() && i < includePaths.size() - 1 && parentPath == workingDir && 170 FileUtils::file_path(includePaths[i], workingDir) != FileUtils::file_path(workingDir) && 171 FileUtils::file_exists(workingDir + "/" + f)) { 172 err << "Warning: file " << f 173 << " included from library, but also exists in current working directory" << endl; 174 } 175 includePaths.pop_back(); 176 } 177 if (!file.is_open()) { 178 if (np_ii) { 179 err << np_ii->loc().toString() << ":\n"; 180 err << "MiniZinc: error in include item, cannot open file '" << f << "'." << endl; 181 } else { 182 err << "Error: cannot open file '" << f << "'." << endl; 183 } 184 goto error; 185 } 186 if (verbose) std::cerr << "processing file '" << fullname << "'" << endl; 187 s = get_file_contents(file); 188 189 if (m->filepath().size() == 0) m->setFilepath(fullname); 190 isFzn = (fullname.compare(fullname.length() - 4, 4, ".fzn") == 0); 191 isFzn |= (fullname.compare(fullname.length() - 4, 4, ".ozn") == 0); 192 isFzn |= (fullname.compare(fullname.length() - 4, 4, ".szn") == 0); 193 isFzn |= (fullname.compare(fullname.length() - 4, 4, ".mzc") == 0); 194 } else { 195 isFzn = false; 196 fullname = f; 197 s = parentPath; 198 } 199 ParserState pp(fullname, s, err, files, seenModels, m, false, isFzn, parseDocComments); 200 mzn_yylex_init(&pp.yyscanner); 201 mzn_yyset_extra(&pp, pp.yyscanner); 202 mzn_yyparse(&pp); 203 if (pp.yyscanner) mzn_yylex_destroy(pp.yyscanner); 204 if (pp.hadError) { 205 for (unsigned int i = 0; i < pp.syntaxErrors.size(); i++) 206 syntaxErrors.push_back(pp.syntaxErrors[i]); 207 goto error; 208 } 209 } 210 211 for (unsigned int i = 0; i < datafiles.size(); i++) { 212 GCLock lock; 213 string f = datafiles[i]; 214 if (f.size() >= 6 && f.substr(f.size() - 5, string::npos) == ".json") { 215 JSONParser jp(env.envi()); 216 jp.parse(model, f); 217 } else { 218 string s; 219 if (f.size() > 5 && f.substr(0, 5) == "cmd:/") { 220 s = f.substr(5); 221 } else { 222 std::ifstream file; 223 file.open(f.c_str(), std::ios::binary); 224 if (!FileUtils::file_exists(f) || !file.is_open()) { 225 err << "Error: cannot open data file '" << f << "'." << endl; 226 goto error; 227 } 228 if (verbose) std::cerr << "processing data file '" << f << "'" << endl; 229 s = get_file_contents(file); 230 } 231 232 ParserState pp(f, s, err, files, seenModels, model, true, false, parseDocComments); 233 mzn_yylex_init(&pp.yyscanner); 234 mzn_yyset_extra(&pp, pp.yyscanner); 235 mzn_yyparse(&pp); 236 if (pp.yyscanner) mzn_yylex_destroy(pp.yyscanner); 237 if (pp.hadError) { 238 for (unsigned int i = 0; i < pp.syntaxErrors.size(); i++) 239 syntaxErrors.push_back(pp.syntaxErrors[i]); 240 goto error; 241 } 242 } 243 } 244 245 return; 246error: 247 delete model; 248 model = NULL; 249} 250 251Model* parse(Env& env, const vector<string>& filenames, const vector<string>& datafiles, 252 const string& textModel, const string& textModelName, const vector<string>& ip, 253 bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { 254 if (filenames.empty() && textModel.empty()) { 255 err << "Error: no model given" << std::endl; 256 return NULL; 257 } 258 259 Model* model; 260 { 261 GCLock lock; 262 model = new Model(); 263 } 264 std::vector<SyntaxError> se; 265 parse(env, model, filenames, datafiles, textModel, textModelName, ip, ignoreStdlib, 266 parseDocComments, verbose, err, se); 267 return model; 268} 269 270Model* parseData(Env& env, Model* model, const vector<string>& datafiles, 271 const vector<string>& includePaths, bool ignoreStdlib, bool parseDocComments, 272 bool verbose, ostream& err) { 273 vector<string> filenames; 274 std::vector<SyntaxError> se; 275 parse(env, model, filenames, datafiles, "", "", includePaths, ignoreStdlib, parseDocComments, 276 verbose, err, se); 277 return model; 278} 279 280Model* parseFromString(Env& env, const string& text, const string& filename, 281 const vector<string>& ip, bool ignoreStdlib, bool parseDocComments, 282 bool verbose, ostream& err, std::vector<SyntaxError>& syntaxErrors) { 283 vector<string> filenames; 284 vector<string> datafiles; 285 Model* model; 286 { 287 GCLock lock; 288 model = new Model(); 289 } 290 parse(env, model, filenames, datafiles, text, filename, ip, ignoreStdlib, parseDocComments, 291 verbose, err, syntaxErrors); 292 return model; 293} 294 295} // namespace MiniZinc