this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Jip J. Dekker <jip.dekker@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%define api.pure 13%define api.header.include {<minizinc/support/mza_parser.tab.hh>} 14 15%{ 16#include <cstdio> 17#include <list> 18 19#include <minizinc/interpreter.hh> 20 21//Anonymous struct for when yyparse is exported 22typedef struct MZAContext MZAContext; 23#include <minizinc/support/mza_parser.tab.hh> 24 25using namespace MiniZinc; 26 27typedef struct yy_buffer_state *YY_BUFFER_STATE; 28YY_BUFFER_STATE mza_yy_scan_string ( const char* yy_str ); 29 30extern int yylex(YYSTYPE*, YYLTYPE*); 31extern FILE* yyin; 32 33struct ProcPatch { 34 int code; 35 BytecodeProc::Mode mode; 36 std::vector<std::pair<int, std::pair<std::string, int>>> patch; 37 ProcPatch(int code0, BytecodeProc::Mode mode0, std::vector<std::pair<int, std::pair<std::string, int>>> patch0) 38 : code(code0), mode(mode0), patch(std::move(patch0)) {} 39}; 40 41typedef struct MZAContext { 42 std::vector<BytecodeProc>& procs; 43 std::unordered_map<std::string, int>& proc_map; 44 int& max_glob; 45 std::vector<ProcPatch> to_patch; 46 BytecodeStream proc_body; 47 std::unordered_map<std::string, int> labels; 48 std::vector<std::pair<int, std::string>> patch_labels; 49 std::vector<std::pair<int, std::pair<std::string, int>>> patch_procs; 50} MZAContext; 51 52void yyerror(YYLTYPE* location, MZAContext& ctx, const char* s); 53%} 54 55%union { 56 int iValue; 57 char* sValue; 58 MiniZinc::BytecodeStream::Instr bValue; 59 std::list<int>* liValue; 60 std::list<std::string>* sliValue; 61} 62%parse-param {MZAContext& ctx} 63%locations 64%define parse.error verbose 65 66%token<iValue> MZA_INT 67%token<iValue> MZA_REG 68%token<iValue> MZA_MODE 69%token<iValue> MZA_CTX 70%token<sValue> MZA_ID 71 72%token MZA_COLON ":" 73%token MZA_DELAY "D" 74 75%token MZA_GLOBAL "GLOBAL" 76 77%token<bValue> MZA_ADDI 78%token<bValue> MZA_SUBI 79%token<bValue> MZA_MULI 80%token<bValue> MZA_DIVI 81%token<bValue> MZA_MODI 82%token<bValue> MZA_INCI 83%token<bValue> MZA_DECI 84 85%token<bValue> MZA_IMMI 86%token<bValue> MZA_CLEAR 87%token<bValue> MZA_LOAD_GLOBAL 88%token<bValue> MZA_STORE_GLOBAL 89%token<bValue> MZA_MOV 90 91%token<bValue> MZA_JMP 92%token<bValue> MZA_JMPIF 93%token<bValue> MZA_JMPIFNOT 94 95%token<bValue> MZA_EQI 96%token<bValue> MZA_LTI 97%token<bValue> MZA_LEI 98 99%token<bValue> MZA_AND 100%token<bValue> MZA_OR 101%token<bValue> MZA_NOT 102%token<bValue> MZA_XOR 103 104%token<bValue> MZA_ISPAR 105%token<bValue> MZA_ISEMPTY 106%token<bValue> MZA_LENGTH 107%token<bValue> MZA_GET_VEC 108%token<bValue> MZA_GET_ARRAY 109 110%token<bValue> MZA_LB 111%token<bValue> MZA_UB 112%token<bValue> MZA_DOM 113 114%token<bValue> MZA_MAKE_SET 115%token<bValue> MZA_DIFF 116%token<bValue> MZA_INTERSECTION 117%token<bValue> MZA_UNION 118 119%token<bValue> MZA_INTERSECT_DOMAIN 120 121%token<bValue> MZA_OPEN_AGGREGATION 122%token<bValue> MZA_CLOSE_AGGREGATION 123%token<bValue> MZA_SIMPLIFY_LIN 124 125%token<bValue> MZA_PUSH 126%token<bValue> MZA_POP 127%token<bValue> MZA_POST 128 129%token<bValue> MZA_RET 130%token<bValue> MZA_CALL 131%token<bValue> MZA_BUILTIN 132%token<bValue> MZA_TCALL 133 134%token<bValue> MZA_ITER_ARRAY 135%token<bValue> MZA_ITER_VEC 136%token<bValue> MZA_ITER_RANGE 137%token<bValue> MZA_ITER_NEXT 138%token<bValue> MZA_ITER_BREAK 139 140%token<bValue> MZA_TRACE 141%token<bValue> MZA_ABORT 142 143 144%type<iValue> delay instruction mode 145%type<bValue> instr instrI instrIR instrR instrRR instrRS instrRRR instrRRS instrRRIRRR instrS 146%type<sValue> label 147%type<liValue> registers 148%type<sliValue> labels 149 150%start procedures 151 152%% 153 154procedures: 155 /* empty */ 156 | procedures procedure 157 158procedure: 159 ":" MZA_ID ":" mode MZA_INT delay instructions 160 { 161 // Patch jumps with recorded labels 162 for (auto& cl : ctx.patch_labels) { 163 if (ctx.labels.find(cl.second) == ctx.labels.end()) { 164 throw Error("Error: label " + cl.second + " not found\n"); 165 } 166 ctx.proc_body.patchAddress(cl.first, ctx.labels[cl.second]); 167 } 168 ctx.labels.clear(); 169 ctx.patch_labels.clear(); 170 171 ctx.proc_body.setNArgs($5); 172 173 // Add ABORT instruction for error management 174 if (ctx.proc_body.size() > 0) { 175 ctx.proc_body.addInstr(BytecodeStream::ABORT); 176 } 177 // Store procedure in the correct place 178 auto mode = static_cast<BytecodeProc::Mode>($4); 179 auto it = ctx.proc_map.find($2); 180 if (it != ctx.proc_map.end()) { 181 BytecodeProc& bcp = ctx.procs[it->second]; 182 if (bcp.mode[mode].size() > 0) { 183 throw Error("Error: procedure " + std::string($2) + " already defined before with the same mode\n"); 184 } 185 if (bcp.nargs != $5 ) { 186 throw Error("Error: procedure " + std::string($2) + " already defined before with different number of arguments\n"); 187 } 188 bcp.mode[$4] = ctx.proc_body; 189 ctx.to_patch.emplace_back(it->second, mode, ctx.patch_procs); 190 } else { 191 BytecodeProc bcp; 192 bcp.name = $2; 193 bcp.mode[mode] = ctx.proc_body; 194 bcp.nargs = $5; 195 bcp.delay = $6; 196 ctx.proc_map.emplace($2, ctx.procs.size()); 197 ctx.to_patch.emplace_back(ctx.procs.size(), mode, ctx.patch_procs); 198 ctx.procs.push_back(bcp); 199 } 200 ctx.proc_body = BytecodeStream(); 201 ctx.patch_procs.clear(); 202 } 203 204mode: 205 /* empty */ { $$ = BytecodeProc::FUN; } 206 | MZA_MODE 207 208delay: 209 /* empty */ { $$ = 0; } 210 | MZA_DELAY { $$ = 1; } 211 212instructions: 213 /* empty */ 214 | instructions labeled_instr 215 216labeled_instr: 217 labels instruction 218 { 219 for (auto l : *$1) { 220 ctx.labels.emplace(l, $2); 221 } 222 delete $1; 223 } 224 225labels: 226 /* empty */ { $$ = new std::list<std::string>(); } 227 | labels label { $1->push_back($2); $$ = $1; } 228 229label: 230 MZA_ID ":" 231 232instruction: 233 instr 234 { 235 $$ = ctx.proc_body.size(); 236 ctx.proc_body.addInstr($1); 237 } 238 | instrI MZA_INT 239 { 240 $$ = ctx.proc_body.size(); 241 ctx.proc_body.addInstr($1); 242 ctx.proc_body.addIntVal($2); 243 } 244 | instrIR MZA_INT MZA_REG 245 { 246 $$ = ctx.proc_body.size(); 247 ctx.proc_body.addInstr($1); 248 ctx.proc_body.addIntVal($2); 249 ctx.proc_body.addReg($3); 250 } 251 | instrR MZA_REG 252 { 253 $$ = ctx.proc_body.size(); 254 ctx.proc_body.addInstr($1); 255 ctx.proc_body.addReg($2); 256 } 257 | instrRR MZA_REG MZA_REG 258 { 259 $$ = ctx.proc_body.size(); 260 ctx.proc_body.addInstr($1); 261 ctx.proc_body.addReg($2); 262 ctx.proc_body.addReg($3); 263 } 264 | instrRS MZA_REG MZA_ID 265 { 266 $$ = ctx.proc_body.size(); 267 ctx.proc_body.addInstr($1); 268 ctx.proc_body.addReg($2); 269 ctx.patch_labels.emplace_back(ctx.proc_body.size(), $3); 270 ctx.proc_body.addSmallInt(0); 271 } 272 | instrRRS MZA_REG MZA_REG MZA_ID 273 { 274 $$ = ctx.proc_body.size(); 275 ctx.proc_body.addInstr($1); 276 ctx.proc_body.addReg($2); 277 ctx.proc_body.addReg($3); 278 ctx.patch_labels.emplace_back(ctx.proc_body.size(), $4); 279 ctx.proc_body.addSmallInt(0); 280 } 281 | instrRRR MZA_REG MZA_REG MZA_REG 282 { 283 $$ = ctx.proc_body.size(); 284 ctx.proc_body.addInstr($1); 285 ctx.proc_body.addReg($2); 286 ctx.proc_body.addReg($3); 287 ctx.proc_body.addReg($4); 288 } 289 | instrRRIRRR MZA_REG MZA_REG MZA_INT MZA_REG MZA_REG MZA_REG 290 { 291 $$ = ctx.proc_body.size(); 292 ctx.proc_body.addInstr($1); 293 ctx.proc_body.addReg($2); 294 ctx.proc_body.addReg($3); 295 ctx.proc_body.addIntVal($4); 296 ctx.proc_body.addReg($5); 297 ctx.proc_body.addReg($6); 298 ctx.proc_body.addReg($7); 299 } 300 | instrS MZA_ID 301 { 302 $$ = ctx.proc_body.size(); 303 ctx.proc_body.addInstr($1); 304 ctx.patch_labels.emplace_back(ctx.proc_body.size(), $2); 305 ctx.proc_body.addSmallInt(0); 306 } 307 | MZA_CALL MZA_MODE MZA_ID MZA_INT registers 308 { 309 $$ = ctx.proc_body.size(); 310 ctx.proc_body.addInstr($1); 311 ctx.proc_body.addCharVal($2); 312 ctx.patch_procs.emplace_back(ctx.proc_body.size(), std::make_pair($3, $5->size())); 313 ctx.proc_body.addSmallInt(0); 314 ctx.proc_body.addCharVal($4); 315 for (auto arg : *$5) { 316 ctx.proc_body.addReg(arg); 317 } 318 delete $5; 319 } 320 | MZA_BUILTIN MZA_ID registers 321 { 322 $$ = ctx.proc_body.size(); 323 ctx.proc_body.addInstr($1); 324 ctx.patch_procs.emplace_back(ctx.proc_body.size(), std::make_pair($2, $3->size())); 325 ctx.proc_body.addSmallInt(0); 326 for (auto arg : *$3) { 327 ctx.proc_body.addReg(arg); 328 } 329 delete $3; 330 } 331 | MZA_TCALL MZA_MODE MZA_ID MZA_INT 332 { 333 $$ = ctx.proc_body.size(); 334 ctx.proc_body.addInstr($1); 335 ctx.proc_body.addCharVal($2); 336 ctx.patch_procs.emplace_back(ctx.proc_body.size(), std::make_pair($3, -1)); 337 ctx.proc_body.addSmallInt(0); 338 ctx.proc_body.addCharVal($4); 339 } 340 | MZA_OPEN_AGGREGATION MZA_CTX 341 { 342 $$ = ctx.proc_body.size(); 343 ctx.proc_body.addInstr($1); 344 ctx.proc_body.addCharVal($2); 345 } 346 // Special cases: Using aggregation context with the same name as instructions 347 | MZA_OPEN_AGGREGATION MZA_AND 348 { 349 $$ = ctx.proc_body.size(); 350 ctx.proc_body.addInstr($1); 351 ctx.proc_body.addCharVal(AggregationCtx::VCTX_AND); 352 } 353 | MZA_OPEN_AGGREGATION MZA_OR 354 { 355 $$ = ctx.proc_body.size(); 356 ctx.proc_body.addInstr($1); 357 ctx.proc_body.addCharVal(AggregationCtx::VCTX_OR); 358 } 359 // Special cases: Read INT, but adds Reg value on the Stream 360 | MZA_LOAD_GLOBAL MZA_INT MZA_REG 361 { 362 $$ = ctx.proc_body.size(); 363 ctx.proc_body.addInstr($1); 364 ctx.proc_body.addReg($2, true); 365 ctx.max_glob = std::max(ctx.max_glob, $2); 366 ctx.proc_body.addReg($3); 367 } 368 | MZA_STORE_GLOBAL MZA_REG MZA_INT 369 { 370 $$ = ctx.proc_body.size(); 371 ctx.proc_body.addInstr($1); 372 ctx.proc_body.addReg($2); 373 ctx.proc_body.addReg($3, true); 374 ctx.max_glob = std::max(ctx.max_glob, $3); 375 } 376 | MZA_GET_ARRAY MZA_INT registers 377 { 378 $$ = ctx.proc_body.size(); 379 ctx.proc_body.addInstr($1); 380 ctx.proc_body.addIntVal($2); 381 for (auto arg : *$3) { 382 ctx.proc_body.addReg(arg); 383 } 384 delete $3; 385 } 386 387instrIR: 388 MZA_IMMI 389 390instrI: 391 MZA_ITER_BREAK 392 393instrR: 394 MZA_INCI 395 | MZA_DECI 396 | MZA_PUSH 397 | MZA_POP 398 | MZA_POST 399 | MZA_ITER_NEXT 400 | MZA_TRACE 401 402instrRR: 403 MZA_MOV 404 | MZA_NOT 405 | MZA_ISPAR 406 | MZA_ISEMPTY 407 | MZA_LENGTH 408 | MZA_MAKE_SET 409 | MZA_UB 410 | MZA_LB 411 | MZA_DOM 412 | MZA_CLEAR 413 414instrRS: 415 MZA_JMPIF 416 | MZA_JMPIFNOT 417 | MZA_ITER_ARRAY 418 | MZA_ITER_VEC 419 420instrRRR: 421 MZA_ADDI 422 | MZA_SUBI 423 | MZA_MULI 424 | MZA_DIVI 425 | MZA_MODI 426 | MZA_EQI 427 | MZA_LTI 428 | MZA_LEI 429 | MZA_AND 430 | MZA_OR 431 | MZA_XOR 432 | MZA_GET_VEC 433 | MZA_DIFF 434 | MZA_INTERSECTION 435 | MZA_UNION 436 | MZA_INTERSECT_DOMAIN 437 438instrRRS: 439 MZA_ITER_RANGE 440 441instrRRIRRR: 442 MZA_SIMPLIFY_LIN 443 444instrS: 445 MZA_JMP 446 447instr: 448 MZA_RET 449 | MZA_CLOSE_AGGREGATION 450 | MZA_ABORT 451 452 453registers: 454 /* empty */ { $$ = new std::list<int>(); } 455 | registers MZA_REG { $1->push_back($2); $$ = $1; } 456 457%% 458 459#include <minizinc/interpreter/primitives.hh> 460#include <minizinc/interpreter.hh> 461 462void yyerror(YYLTYPE* location, MZAContext& ctx, const char* s) { 463 std::ostringstream oss; 464 oss << "Cannot parse MiniZinc assembly in line " << location->first_line << ": " << std::string(s); 465 throw Error(oss.str()); 466} 467 468std::pair<int, std::vector<BytecodeProc>> parse_mza(const std::string& assembly_str) { 469 std::vector<BytecodeProc> procs; 470 std::unordered_map<std::string, int> proc_map; 471 int max_glob; 472 // Initialise first slots with 473 for (PrimitiveMap::Primitive* p : primitiveMap()) { 474 BytecodeProc bcp; 475 bcp.name = p->name(); 476 bcp.nargs = p->n_args(); 477 bcp.delay = false; 478 procs.push_back(bcp); 479 proc_map.emplace(bcp.name, p->ident()); 480 } 481 mza_yy_scan_string(assembly_str.c_str()); 482 MZAContext ctx = MZAContext{procs, proc_map, max_glob}; 483 int err = yyparse(ctx); 484 if (err != 0) { 485 throw std::runtime_error("Cannot parse MiniZinc assembly: " + std::to_string(err)); 486 } 487 for (auto& p : ctx.to_patch) { 488 int code = p.code; 489 BytecodeProc::Mode mode = p.mode; 490 for (auto& patch : p.patch) { 491 int& nargs = patch.second.second; 492 std::string& name = patch.second.first; 493 494 if (nargs >= 0 && nargs != procs[proc_map[name]].nargs) { 495 throw Error("Error: number of arguments in call to " + patch.second.first + " at position " 496 + std::to_string(patch.second.second) + " has an invalid number of arguments.\n"); 497 } 498 procs[code].mode[mode].patchAddress(patch.first, proc_map[patch.second.first]); 499 } 500 } 501 return {max_glob, procs}; 502}