this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Christian Schulte <schulte@gecode.org> 5 * 6 * Copyright: 7 * Christian Schulte, 2004 8 * 9 * This file is part of Gecode, the generic constraint 10 * development environment: 11 * http://www.gecode.org 12 * 13 * Permission is hereby granted, free of charge, to any person obtaining 14 * a copy of this software and associated documentation files (the 15 * "Software"), to deal in the Software without restriction, including 16 * without limitation the rights to use, copy, modify, merge, publish, 17 * distribute, sublicense, and/or sell copies of the Software, and to 18 * permit persons to whom the Software is furnished to do so, subject to 19 * the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be 22 * included in all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 * 32 */ 33 34#include <gecode/minimodel.hh> 35 36namespace Gecode { 37 38 namespace MiniModel { 39 40 class PosSet; 41 /** 42 * \brief Allocator for position sets 43 */ 44 typedef Support::BlockAllocator<PosSet,Region> PosSetAllocator; 45 46 class NodeInfo; 47 class PosInfo; 48 49 } 50 51 /// Implementation of the actual expression tree 52 class REG::Exp { 53 public: 54 /// Reference counter 55 unsigned int use_cnt; 56 /// Number of positions 57 int _n_pos; 58 /** 59 * \brief Type of regular expression 60 */ 61 enum ExpType { 62 ET_SYMBOL, 63 ET_CONC, 64 ET_OR, 65 ET_STAR 66 }; 67 /// Type of regular expression 68 ExpType type; 69 /// Symbol or subexpressions 70 union { 71 /// Symbol 72 int symbol; 73 /// Subexpressions 74 Exp* kids[2]; 75 } data; 76 77 /// Compute the follow positions 78 MiniModel::PosSet* 79 followpos(MiniModel::PosSetAllocator&,MiniModel::PosInfo*); 80 /// Increment use counter of \a e 81 static void inc(Exp* e); 82 /// Decrement use counter of \a e 83 static void dec(Exp* e); 84 /// Return number of positions of \a e 85 static int n_pos(Exp* e); 86 /// Print expression to \a os 87 void toString(std::ostringstream& os) const; 88 /// Print expression 89 std::string toString(void) const; 90 91 static void* operator new(size_t); 92 static void operator delete(void*); 93 private: 94 /// Deallocate memory 95 void dispose(void); 96 }; 97 98 99 /* 100 * Operations on expression nodes 101 * 102 */ 103 104 105 forceinline void* 106 REG::Exp::operator new(size_t s) { 107 return heap.ralloc(s); 108 } 109 forceinline void 110 REG::Exp::operator delete(void*) { 111 // Deallocation happens in dispose 112 } 113 114 void 115 REG::Exp::dispose(void) { 116 Region region; 117 Support::DynamicStack<Exp*,Region> todo(region); 118 todo.push(this); 119 while (!todo.empty()) { 120 Exp* e = todo.pop(); 121 switch (e->type) { 122 case ET_OR: 123 case ET_CONC: 124 if ((e->data.kids[1] != nullptr) && (--e->data.kids[1]->use_cnt == 0)) 125 todo.push(e->data.kids[1]); 126 // fall through 127 case ET_STAR: 128 if ((e->data.kids[0] != nullptr) && (--e->data.kids[0]->use_cnt == 0)) 129 todo.push(e->data.kids[0]); 130 default: ; 131 } 132 heap.rfree(e); 133 } 134 } 135 136 forceinline void 137 REG::Exp::inc(Exp* e) { 138 if (e != nullptr) 139 e->use_cnt++; 140 } 141 forceinline void 142 REG::Exp::dec(Exp* e) { 143 if ((e != nullptr) && (--e->use_cnt == 0)) 144 e->dispose(); 145 } 146 147 148 forceinline int 149 REG::Exp::n_pos(Exp* e) { 150 return (e != nullptr) ? e->_n_pos : 0; 151 } 152 153 void 154 REG::Exp::toString(std::ostringstream& os) const { 155 switch (type) { 156 case ET_SYMBOL: 157 os << "[" << data.symbol << "]"; 158 return; 159 case ET_STAR: 160 { 161 bool par = ((data.kids[0] != nullptr) && 162 ((data.kids[0]->type == ET_CONC) || 163 (data.kids[0]->type == ET_OR))); 164 os << (par ? "*(" : "*"); 165 if (data.kids[0]==nullptr) { 166 os << "[]"; 167 } else { 168 data.kids[0]->toString(os); 169 } 170 os << (par ? ")" : ""); 171 return; 172 } 173 case ET_CONC: 174 { 175 bool par0 = ((data.kids[0] != nullptr) && 176 (data.kids[0]->type == ET_OR)); 177 os << (par0 ? "(" : ""); 178 if (data.kids[0]==nullptr) { 179 os << "[]"; 180 } else { 181 data.kids[0]->toString(os); 182 } 183 os << (par0 ? ")+" : "+"); 184 bool par1 = ((data.kids[1] != nullptr) && 185 (data.kids[1]->type == ET_OR)); 186 os << (par1 ? "(" : ""); 187 if (data.kids[1]==nullptr) { 188 os << "[]"; 189 } else { 190 data.kids[1]->toString(os); 191 } 192 os << (par1 ? ")" : ""); 193 return; 194 } 195 case ET_OR: 196 if (data.kids[0]==nullptr) { 197 os << "[]"; 198 } else { 199 data.kids[0]->toString(os); 200 } 201 os << "|"; 202 if (data.kids[1]==nullptr) { 203 os << "[]"; 204 } else { 205 data.kids[1]->toString(os); 206 } 207 return; 208 default: GECODE_NEVER; 209 } 210 GECODE_NEVER; 211 return; 212 } 213 214 std::string 215 REG::Exp::toString(void) const { 216 std::ostringstream os; 217 toString(os); 218 return os.str(); 219 } 220 221 222 /* 223 * Regular expressions 224 * 225 */ 226 227 forceinline 228 REG::REG(Exp* f) : e(f) {} 229 230 REG::REG(void) : e(nullptr) {} 231 232 REG::REG(const REG& r) : e(r.e) { 233 REG::Exp::inc(e); 234 } 235 236 const REG& 237 REG::operator =(const REG& r) { 238 if (&r != this) { 239 REG::Exp::inc(r.e); 240 REG::Exp::dec(e); 241 e = r.e; 242 } 243 return *this; 244 } 245 246 REG::~REG(void) { 247 REG::Exp::dec(e); 248 } 249 250 REG::REG(int s) : e(new Exp) { 251 e->use_cnt = 1; 252 e->_n_pos = 1; 253 e->type = REG::Exp::ET_SYMBOL; 254 e->data.symbol = s; 255 } 256 257 REG::REG(const IntArgs& x) { 258 int n = x.size(); 259 if (n < 1) 260 throw MiniModel::TooFewArguments("REG"); 261 Region region; 262 Exp** a = region.alloc<Exp*>(n); 263 // Initialize with symbols 264 for (int i=n; i--; ) { 265 a[i] = new Exp(); 266 a[i]->use_cnt = 1; 267 a[i]->_n_pos = 1; 268 a[i]->type = REG::Exp::ET_SYMBOL; 269 a[i]->data.symbol = x[i]; 270 } 271 // Build a balanced tree of alternative nodes 272 for (int m=n; m>1; ) { 273 if (m & 1) { 274 m -= 1; 275 Exp* e1 = a[m]; 276 Exp* e2 = a[0]; 277 a[0] = new Exp; 278 a[0]->use_cnt = 1; 279 a[0]->_n_pos = REG::Exp::n_pos(e1) + REG::Exp::n_pos(e2); 280 a[0]->type = REG::Exp::ET_OR; 281 a[0]->data.kids[0] = e1; 282 a[0]->data.kids[1] = e2; 283 } else { 284 m >>= 1; 285 for (int i=0; i<m; i++) { 286 Exp* e1 = a[2*i]; 287 Exp* e2 = a[2*i+1]; 288 a[i] = new Exp; 289 a[i]->use_cnt = 1; 290 a[i]->_n_pos = REG::Exp::n_pos(e1) + REG::Exp::n_pos(e2); 291 a[i]->type = REG::Exp::ET_OR; 292 a[i]->data.kids[0] = e1; 293 a[i]->data.kids[1] = e2; 294 } 295 } 296 } 297 e = a[0]; 298 } 299 300 REG 301 REG::operator |(const REG& r2) { 302 if (e == r2.e) 303 return *this; 304 Exp* f = new Exp(); 305 f->use_cnt = 1; 306 f->_n_pos = REG::Exp::n_pos(e) + REG::Exp::n_pos(r2.e); 307 f->type = REG::Exp::ET_OR; 308 f->data.kids[0] = e; REG::Exp::inc(e); 309 f->data.kids[1] = r2.e; REG::Exp::inc(r2.e); 310 REG r(f); 311 return r; 312 } 313 314 REG& 315 REG::operator |=(const REG& r2) { 316 if (e == r2.e) 317 return *this; 318 Exp* f = new Exp(); 319 f->use_cnt = 1; 320 f->_n_pos = REG::Exp::n_pos(e) + REG::Exp::n_pos(r2.e); 321 f->type = REG::Exp::ET_OR; 322 f->data.kids[0] = e; 323 f->data.kids[1] = r2.e; REG::Exp::inc(r2.e); 324 e=f; 325 return *this; 326 } 327 328 REG 329 REG::operator +(const REG& r2) { 330 if (e == nullptr) return r2; 331 if (r2.e == nullptr) return *this; 332 Exp* f = new Exp(); 333 f->use_cnt = 1; 334 f->_n_pos = REG::Exp::n_pos(e) + REG::Exp::n_pos(r2.e); 335 f->type = REG::Exp::ET_CONC; 336 f->data.kids[0] = e; REG::Exp::inc(e); 337 f->data.kids[1] = r2.e; REG::Exp::inc(r2.e); 338 REG r(f); 339 return r; 340 } 341 342 REG& 343 REG::operator +=(const REG& r2) { 344 if (r2.e == nullptr) 345 return *this; 346 if (e == nullptr) { 347 e=r2.e; REG::Exp::inc(e); 348 } else { 349 Exp* f = new Exp(); 350 f->use_cnt = 1; 351 f->_n_pos = REG::Exp::n_pos(e) + REG::Exp::n_pos(r2.e); 352 f->type = REG::Exp::ET_CONC; 353 f->data.kids[0] = e; 354 f->data.kids[1] = r2.e; REG::Exp::inc(r2.e); 355 e=f; 356 } 357 return *this; 358 } 359 360 REG 361 REG::operator *(void) { 362 if ((e == nullptr) || (e->type == REG::Exp::ET_STAR)) 363 return *this; 364 Exp* f = new Exp(); 365 f->use_cnt = 1; 366 f->_n_pos = REG::Exp::n_pos(e); 367 f->type = REG::Exp::ET_STAR; 368 f->data.kids[0] = e; REG::Exp::inc(e); 369 REG r(f); 370 return r; 371 } 372 373 REG 374 REG::operator ()(unsigned int n, unsigned int m) { 375 REG r; 376 if ((n>m) || (m == 0)) 377 return r; 378 if (n>0) { 379 unsigned int i = n; 380 REG r0 = *this; 381 while (i>0) 382 if (i & 1) { 383 r = r0+r; i--; 384 } else { 385 r0 = r0+r0; i >>= 1; 386 } 387 } 388 if (m > n) { 389 unsigned int i = m-n; 390 REG s0; 391 s0 = s0 | *this; 392 REG s; 393 while (i>0) 394 if (i & 1) { 395 s = s0+s; i--; 396 } else { 397 s0 = s0+s0; i >>= 1; 398 } 399 r = r + s; 400 } 401 return r; 402 } 403 404 REG 405 REG::operator ()(unsigned int n) { 406 REG r; 407 if (n > 0) { 408 REG r0 = *this; 409 unsigned int i = n; 410 while (i>0) 411 if (i & 1) { 412 r = r0+r; i--; 413 } else { 414 r0 = r0+r0; i >>= 1; 415 } 416 } 417 return r+**this; 418 } 419 420 REG 421 REG::operator +(void) { 422 return this->operator ()(1); 423 } 424 425 std::string 426 REG::toString(void) const { 427 if (e==nullptr) { 428 return "[]"; 429 } 430 return e->toString(); 431 } 432 433 namespace MiniModel { 434 435 /* 436 * Sets of positions 437 * 438 */ 439 440 /** 441 * \brief Order on position sets 442 */ 443 enum PosSetCmp { 444 PSC_LE, 445 PSC_EQ, 446 PSC_GR 447 }; 448 449 /** 450 * \brief Sets of positions 451 */ 452 class PosSet : public Support::BlockClient<PosSet,Region> { 453 // Maintain sets of positions in inverse order 454 // This makes the check whether the last position is included 455 // more efficient. 456 public: 457 int pos; PosSet* next; 458 459 PosSet(void); 460 PosSet(int); 461 462 bool in(int) const; 463 static PosSetCmp cmp(PosSet*,PosSet*); 464 static PosSet* cup(PosSetAllocator&,PosSet*,PosSet*); 465 }; 466 467 468 forceinline 469 PosSet::PosSet(void) {} 470 forceinline 471 PosSet::PosSet(int p) : pos(p), next(nullptr) {} 472 473 474 forceinline bool 475 PosSet::in(int p) const { 476 for (const PosSet* ps = this; ps != nullptr; ps = ps->next) 477 if (ps->pos == p) { 478 return true; 479 } else if (ps->pos < p) { 480 return false; 481 } 482 return false; 483 } 484 485 forceinline PosSetCmp 486 PosSet::cmp(PosSet* ps1, PosSet* ps2) { 487 while ((ps1 != nullptr) && (ps2 != nullptr)) { 488 if (ps1 == ps2) 489 return PSC_EQ; 490 if (ps1->pos < ps2->pos) 491 return PSC_LE; 492 if (ps1->pos > ps2->pos) 493 return PSC_GR; 494 ps1 = ps1->next; ps2 = ps2->next; 495 } 496 if (ps1 == ps2) 497 return PSC_EQ; 498 return ps1 == nullptr ? PSC_LE : PSC_GR; 499 } 500 501 PosSet* 502 PosSet::cup(PosSetAllocator& psm, PosSet* ps1, PosSet* ps2) { 503 PosSet* ps; 504 PosSet** p = &ps; 505 while ((ps1 != nullptr) && (ps2 != nullptr)) { 506 if (ps1 == ps2) { 507 *p = ps1; return ps; 508 } 509 PosSet* n = new (psm) PosSet; 510 *p = n; p = &n->next; 511 if (ps1->pos == ps2->pos) { 512 n->pos = ps1->pos; 513 ps1 = ps1->next; ps2 = ps2->next; 514 } else if (ps1->pos > ps2->pos) { 515 n->pos = ps1->pos; ps1 = ps1->next; 516 } else { 517 n->pos = ps2->pos; ps2 = ps2->next; 518 } 519 } 520 *p = (ps1 != nullptr) ? ps1 : ps2; 521 return ps; 522 } 523 524 525 /// Node information computed during traversal of the expressions 526 class NodeInfo { 527 public: 528 bool nullable; 529 PosSet* firstpos; 530 PosSet* lastpos; 531 NodeInfo(bool n=false, PosSet* fp=nullptr, PosSet* lp=nullptr); 532 }; 533 534 /// Expression information 535 class ExpInfo { 536 public: 537 REG::Exp* exp; 538 bool open; 539 ExpInfo(REG::Exp* e=nullptr); 540 }; 541 542 /** 543 * \brief Information on positions collected during traversal 544 * 545 */ 546 class PosInfo { 547 public: 548 int symbol; 549 PosSet* followpos; 550 }; 551 552 forceinline 553 NodeInfo::NodeInfo(bool n, PosSet* fp, PosSet* lp) 554 : nullable(n), firstpos(fp), lastpos(lp) {} 555 556 forceinline 557 ExpInfo::ExpInfo(REG::Exp* e) 558 : exp(e), open(true) {} 559 560 } 561 562 forceinline MiniModel::PosSet* 563 REG::Exp::followpos(MiniModel::PosSetAllocator& psm, 564 MiniModel::PosInfo* pi) { 565 int p=0; 566 567 using MiniModel::PosSet; 568 using MiniModel::NodeInfo; 569 using MiniModel::ExpInfo; 570 571 Region region; 572 573 Support::DynamicStack<ExpInfo,Region> todo(region); 574 Support::DynamicStack<NodeInfo,Region> done(region); 575 576 // Start with first expression to be processed 577 todo.push(ExpInfo(this)); 578 579 do { 580 if (todo.top().exp == nullptr) { 581 todo.pop(); 582 done.push(NodeInfo(true,nullptr,nullptr)); 583 } else { 584 switch (todo.top().exp->type) { 585 case ET_SYMBOL: 586 { 587 pi[p].symbol = todo.pop().exp->data.symbol; 588 PosSet* ps = new (psm) PosSet(p++); 589 done.push(NodeInfo(false,ps,ps)); 590 } 591 break; 592 case ET_STAR: 593 if (todo.top().open) { 594 // Evaluate subexpression recursively 595 todo.top().open = false; 596 todo.push(todo.top().exp->data.kids[0]); 597 } else { 598 todo.pop(); 599 NodeInfo ni = done.pop(); 600 for (PosSet* ps = ni.lastpos; ps != nullptr; ps = ps->next) 601 pi[ps->pos].followpos = 602 PosSet::cup(psm,pi[ps->pos].followpos,ni.firstpos); 603 done.push(NodeInfo(true,ni.firstpos,ni.lastpos)); 604 } 605 break; 606 case ET_CONC: 607 if (todo.top().open) { 608 // Evaluate subexpressions recursively 609 todo.top().open = false; 610 REG::Exp* e = todo.top().exp; 611 todo.push(e->data.kids[1]); 612 todo.push(e->data.kids[0]); 613 } else { 614 todo.pop(); 615 NodeInfo ni1 = done.pop(); 616 NodeInfo ni0 = done.pop(); 617 for (PosSet* ps = ni0.lastpos; ps != nullptr; ps = ps->next) 618 pi[ps->pos].followpos = 619 PosSet::cup(psm,pi[ps->pos].followpos,ni1.firstpos); 620 done.push(NodeInfo(ni0.nullable & ni1.nullable, 621 ni0.nullable ? 622 PosSet::cup(psm,ni0.firstpos,ni1.firstpos) : ni0.firstpos, 623 ni1.nullable ? 624 PosSet::cup(psm,ni0.lastpos,ni1.lastpos) : ni1.lastpos)); 625 } 626 break; 627 case ET_OR: 628 if (todo.top().open) { 629 // Evaluate subexpressions recursively 630 todo.top().open = false; 631 REG::Exp* e = todo.top().exp; 632 todo.push(e->data.kids[1]); 633 todo.push(e->data.kids[0]); 634 } else { 635 todo.pop(); 636 NodeInfo ni1 = done.pop(); 637 NodeInfo ni0 = done.pop(); 638 done.push(NodeInfo(ni0.nullable | ni1.nullable, 639 PosSet::cup(psm,ni0.firstpos,ni1.firstpos), 640 PosSet::cup(psm,ni0.lastpos,ni1.lastpos))); 641 } 642 break; 643 default: GECODE_NEVER; 644 } 645 } 646 } while (!todo.empty()); 647 return done.top().firstpos; 648 } 649 650 651 namespace MiniModel { 652 653 class StateNode; 654 655 /** 656 * \brief Allocator for state nodes 657 */ 658 typedef Support::BlockAllocator<StateNode,Heap> StatePoolAllocator; 659 660 /** 661 * \brief %Node together with state information 662 */ 663 class StateNode : public Support::BlockClient<StateNode,Heap> { 664 public: 665 PosSet* pos; 666 int state; 667 StateNode* next; 668 StateNode* left; 669 StateNode* right; 670 }; 671 672 /** 673 * \brief %State pool combines a tree of states together with yet unprocessed states 674 */ 675 class StatePool { 676 public: 677 int n_states; 678 StateNode root; 679 StateNode* next; 680 StateNode* all; 681 682 StatePool(PosSet*); 683 684 StateNode* pop(void); 685 bool empty(void) const; 686 687 int state(StatePoolAllocator&, PosSet*); 688 }; 689 690 forceinline 691 StatePool::StatePool(PosSet* ps) { 692 next = &root; 693 all = nullptr; 694 n_states = 1; 695 root.pos = ps; 696 root.state = 0; 697 root.next = nullptr; 698 root.left = nullptr; 699 root.right = nullptr; 700 } 701 702 forceinline StateNode* 703 StatePool::pop(void) { 704 StateNode* n = next; 705 next = n->next; 706 n->next = all; 707 all = n; 708 return n; 709 } 710 711 forceinline bool 712 StatePool::empty(void) const { 713 return next == nullptr; 714 } 715 716 forceinline int 717 StatePool::state(StatePoolAllocator& spm, PosSet* ps) { 718 int d = 0; 719 StateNode** p = nullptr; 720 StateNode* n = &root; 721 do { 722 switch (PosSet::cmp(ps,n->pos)) { 723 case PSC_EQ: return n->state; 724 case PSC_LE: p = &n->left; n = *p; break; 725 case PSC_GR: p = &n->right; n = *p; break; 726 default: GECODE_NEVER; 727 } 728 d++; 729 } while (n != nullptr); 730 n = new (spm) StateNode; *p = n; 731 n->pos = ps; 732 n->state = n_states++; 733 n->next = next; 734 n->left = nullptr; 735 n->right = nullptr; 736 next = n; 737 return n->state; 738 } 739 740 /** 741 * \brief Sort symbols 742 */ 743 class SymbolsInc { 744 public: 745 forceinline bool 746 operator ()(int x, int y) { 747 return x < y; 748 } 749 forceinline static void 750 sort(int s[], int n) { 751 SymbolsInc o; 752 Support::quicksort<int,SymbolsInc>(s,n,o); 753 } 754 }; 755 756 757 /** 758 * \brief For collecting transitions while constructing a %DFA 759 * 760 */ 761 class TransitionBag { 762 private: 763 Support::DynamicArray<DFA::Transition,Heap> t; 764 int n; 765 public: 766 TransitionBag(void); 767 void add(int,int,int); 768 void finish(void); 769 DFA::Transition* transitions(void); 770 }; 771 772 forceinline 773 TransitionBag::TransitionBag(void) : t(heap), n(0) {} 774 775 forceinline void 776 TransitionBag::add(int i_state, int symbol, int o_state) { 777 t[n].i_state = i_state; 778 t[n].symbol = symbol; 779 t[n].o_state = o_state; 780 n++; 781 } 782 783 forceinline void 784 TransitionBag::finish(void) { 785 t[n].i_state = -1; 786 } 787 788 forceinline DFA::Transition* 789 TransitionBag::transitions(void) { 790 return &t[0]; 791 } 792 793 794 /** 795 * \brief For collecting final states while constructing a %DFA 796 * 797 */ 798 class FinalBag { 799 private: 800 Support::DynamicArray<int,Heap> f; 801 int n; 802 public: 803 FinalBag(void); 804 void add(int); 805 void finish(void); 806 int* finals(void); 807 }; 808 809 forceinline 810 FinalBag::FinalBag(void) : f(heap), n(0) {} 811 812 forceinline void 813 FinalBag::add(int state) { 814 f[n++] = state; 815 } 816 817 forceinline void 818 FinalBag::finish(void) { 819 f[n] = -1; 820 } 821 822 forceinline int* 823 FinalBag::finals(void) { 824 return &f[0]; 825 } 826 827 } 828 829 REG::operator DFA(void) { 830 using MiniModel::PosSetAllocator; 831 using MiniModel::StatePoolAllocator; 832 using MiniModel::PosInfo; 833 using MiniModel::PosSet; 834 using MiniModel::NodeInfo; 835 836 using MiniModel::StatePool; 837 using MiniModel::StateNode; 838 839 using MiniModel::TransitionBag; 840 using MiniModel::FinalBag; 841 842 using MiniModel::SymbolsInc; 843 844 Region region; 845 PosSetAllocator psm(region); 846 StatePoolAllocator spm(heap); 847 REG r = *this + REG(Int::Limits::max+1); 848 int n_pos = REG::Exp::n_pos(r.e); 849 850 PosInfo* pi = region.alloc<PosInfo>(n_pos); 851 for (int i=n_pos; i--; ) 852 pi[i].followpos = nullptr; 853 854 PosSet* firstpos = r.e->followpos(psm,&pi[0]); 855 856 // Compute symbols 857 int* symbols = region.alloc<int>(n_pos); 858 for (int i=n_pos; i--; ) 859 symbols[i] = pi[i].symbol; 860 861 SymbolsInc::sort(&symbols[0],n_pos-1); 862 int n_symbols = 1; 863 for (int i = 1; i<n_pos-1; i++) 864 if (symbols[i-1] != symbols[i]) 865 symbols[n_symbols++] = symbols[i]; 866 867 // Compute states and transitions 868 TransitionBag tb; 869 StatePool sp(firstpos); 870 while (!sp.empty()) { 871 StateNode* sn = sp.pop(); 872 for (int i = n_symbols; i--; ) { 873 PosSet* u = nullptr; 874 for (PosSet* ps = sn->pos; ps != nullptr; ps = ps->next) 875 if (pi[ps->pos].symbol == symbols[i]) 876 u = PosSet::cup(psm,u,pi[ps->pos].followpos); 877 if (u != nullptr) 878 tb.add(sn->state,symbols[i],sp.state(spm,u)); 879 } 880 } 881 tb.finish(); 882 883 // Compute final states 884 FinalBag fb; 885 for (StateNode* n = sp.all; n != nullptr; n = n->next) 886 if (n->pos->in(n_pos-1)) 887 fb.add(n->state); 888 fb.finish(); 889 890 return DFA(0,tb.transitions(),fb.finals(),true); 891 } 892 893} 894 895// STATISTICS: minimodel-any 896