#include #include #include #include #include bool CmpStrEx(const std::string& expr, const std::string& str) { if(expr.empty() || str.empty()) return false; struct State { struct Block { using pBlock=std::unique_ptr; enum Type {NOTDEF,TEXT,OPTIONAL,VARIANTS,DELIM}; size_t b,e; Type type; const struct Block* parent; pBlock next,child; Block() = delete; Block(const struct Block&) = delete; Block(struct Block&&) = delete; bool isText() const {return type==TEXT;} Block(Type t, const struct Block* p=nullptr):b(0),e(0),type(t),parent(p),next(nullptr),child(nullptr) {} Block(size_t bb, size_t ee, const struct Block* p=nullptr):b(bb),e(ee),type(TEXT),parent(p),next(nullptr),child(nullptr) {} }; Block::pBlock Parse(const std::string& str) { size_t e=0; struct Block* blk; struct Block* root; auto c=str[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->isText(); 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); } struct Cursor { const struct Block* block; size_t offset; bool operator <(const struct Cursor& c) const {return blockb+offset];} Cursor(const struct Block* b, size_t o):block(b),offset(o) {} }; using Cursors=std::set; using pCursor=std::set::const_iterator; Block::pBlock root; Cursors cursors; const std::string& s; void InitCursors(const struct 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: {} } } State(const std::string& str):root(Parse(str)),s(str) {InitCursors(root.get());} bool CmpSmb(const char c) { pCursor p=cursors.cbegin(); bool res=false; // Compare symbol with all cursors std::cout<<"--------------\n"; std::cout<<"Symbol: "<block->b+p->offset<<" "<block->b+p->offset]<<"\n"; 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; } }; // Main function struct State st(expr); // Dump code { std::cerr<<"digraph main\n{\nrankdir=TB pack=\"true\" packmode=\"node\";\n"; std::cerr<<"node [fontsize=30, shape=rectangle, style=\"filled,rounded\", fillcolor=azure2, fixedsize=\"false\", margin=0.2, width=1, penwidth=3, fontname=\"Times New Roman\"];\n"; std::cerr<<"edge [arrowsize=1.5, penwidth=3];\n"; const struct State::Block* r=st.root.get(); std::set visited; visited.insert(nullptr); while(true) { if(visited.count(r)==0) { std::string label; if(r->type==State::Block::OPTIONAL) label="[]"; if(r->type==State::Block::VARIANTS) label="()"; if(r->type==State::Block::DELIM) label="|"; if(r->type==State::Block::TEXT) label=expr.substr(r->b,r->e-r->b); std::cerr<<"\""<type==State::Block::TEXT)?",fontcolor=\"red\"":"")<<"];\n"; if(r->child) std::cerr<<"\""< \""<child.get()<<"\";\n"; if(r->next) { std::cerr<<"\""< \""<next.get()<<"\" [color=\"blue\"];\n"; std::cerr<<"{rank=same; "<<"\""<next.get()<<"\";}\n"; } if(r->parent!=nullptr) std::cerr<<"\""< \""<parent<<"\" [color=\"green\", penwidth=1];\n"; visited.insert(r); } if(r->child && visited.count(r->child.get())==0) r=r->child.get(); else if(r->next) r=r->next.get(); else { while(r->parent!=nullptr) { r=r->parent; if(r->next) {r=r->next.get(); break;} } } if(visited.count(r)!=0 && r->parent==nullptr && visited.count(r->next.get())!=0 && visited.count(r->child.get())!=0) break; } std::cerr<<"}\n"; } for(size_t pos=0; pos