You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
2.8 KiB
139 lines
2.8 KiB
#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(e<s.length()) |
|
{ |
|
c=s[e]; |
|
|
|
switch(c) |
|
{ |
|
case '[': |
|
case '(': |
|
{ |
|
(next?blk->next: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<struct Block*>(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+1<blk->e) 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; |
|
}
|
|
|