#include "modgmt_strcomp.h" TemplateComparator::Block::pBlock TemplateComparator::Parse() { size_t e=0; struct Block* blk; struct Block* root; auto c=s[e]; bool init,next; // First symbol if('['==c || '('==c) blk=new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS); else blk=new Block(e,e+1); root=blk; init=root->type!=Block::TEXT; next=!init; e++; while(enext:blk->child).reset(new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS,(next?blk->parent:blk))); blk=(next?blk->next:blk->child).get(); init=true; next=false; break; } case ']': case ')': { blk=const_cast(blk->parent); init=true; next=true; break; } case '|': {blk->next.reset(new Block(Block::DELIM,blk->parent)); blk=blk->next.get(); init=next=true; break;} default: { if(init) { (next?blk->next:blk->child).reset(new Block(e,e+1,(next?blk->parent:blk))); blk=(next?blk->next:blk->child).get(); } else blk->e=e+1; init=false; next=true; } } e++; } return Block::pBlock(root); } void TemplateComparator::InitCursors(const struct TemplateComparator::Block* blk) { switch(blk->type) { case Block::TEXT: {cursors.insert({blk,0}); break;} case Block::OPTIONAL: { auto b=blk; InitCursors(b->child.get()); while(true) { if(!b->next) break; b=b->next.get(); InitCursors(b); if(b->type!=Block::OPTIONAL) break; } break; } case Block::VARIANTS: { auto b=blk->child.get(); while(true) { InitCursors(b); while(b->type!=Block::DELIM) { if(!b->next) break; b=b->next.get(); } if(!b->next) break; b=b->next.get(); } } default: {} } } bool TemplateComparator::CmpSmb(const char c) { pCursor p=cursors.cbegin(); bool res=false; // Compare symbol with all cursors while(p!=cursors.end()) { if(p->compare(s,c)) {res=true; p++;} else p=cursors.erase(p); } Cursors old(std::move(cursors)); for(const auto& p:old) { auto blk=p.block; // Increment cursors if(blk->b+p.offset+1e) cursors.insert({blk,p.offset+1}); // Advance in current block else // Move to next block { if(!blk->next || blk->next->type==Block::DELIM) // End of chain, must go up { while(blk->parent!=nullptr) { blk=blk->parent; if(!blk->next || blk->next->type==Block::DELIM) continue; InitCursors(blk->next.get()); } } else InitCursors(blk->next.get()); // Next block in chain } // Try to leave optional blocks blk=p.block; while(blk->parent!=nullptr) { blk=blk->parent; if(blk->type!=Block::OPTIONAL || !blk->next || blk->next->type==Block::DELIM) continue; InitCursors(blk->next.get()); } } return res; }