GreenPadの正規表現エンジンをC言語に移植してみた
私がGreenPadのファンと言うことは前に述べましたが、なんといってもソースコードがNYSLで公開されているところが大きいです。
これにより、テキストエディタの実装の仕方が確実に理解でき、文字列処理の大半がこのソースで学べるのは資料代が年間ん〜ぜん円の私にはかけがえの無いソースなのです。
実は、私、正規表現が前々から良く理解していなくて、困る事が結構あったのです。*1
なので、正規表現の実装を見れば直感的に分かるかな?
と、思い、C++のRSearch.cppをC言語に移植してみました。
以下に移植時に起こった事、思った事を書いて行こうと思います。
移植時に苦労した所 集
- メモリ管理
いわいるauto_ptrのようなスマートポインタを使っていたのでメモリ管理が一苦労
ガベコレの有難さを知る ○| ̄|_ - トークン解析の所
元ソース
間違い移植ソース
RegToken RegLexer::GetToken()
{
const wchar_t*& x = (*sub_ ? sub_ : pat_);
if( x == end_ ) return R_End;
switch( *x++ )
{
case L'.': return R_Any;
case L'[': return R_Lcl;
case L']': return R_Rcl;
case L'^': return R_Ncl;
case L'-': return R_Range;
case L'(': return R_Lbr;
case L')': return R_Rbr;
case L'|': return R_Bar;
case L'*': return R_Star;
case L'+': return R_Plus;
case L'?': return R_Quest;
case L'\\': if( x==end_ ) return R_End; switch( *x++ ) {
case L't': chr_=L'\t'; return R_Char;
case L'w': sub_=L"[0-9a-zA-Z_]"; return GetToken();
case L'W': sub_=L"[^0-9a-zA-Z_]"; return GetToken();
case L'd': sub_=L"[0-9]"; return GetToken();
case L'D': sub_=L"[^0-9]"; return GetToken();
case L's': sub_=L"[\t ]"; return GetToken();
case L'S': sub_=L"[^\t ]"; return GetToken();
} // fall through...
default:
chr_ = *(x-1);
return R_Char;
}
}
const wchar_t* x = (*p->sub_ ? p->sub_ : p->pat_);
if( x == p->end_ ) return R_End;
switch( *x++ )
{
case L'.': return R_Any;
case L'[': return R_Lcl;
case L']': return R_Rcl;
case L'^': return R_Ncl;
case L'-': return R_Range;
case L'(': return R_Lbr;
case L')': return R_Rbr;
case L'|': return R_Bar;
case L'*': return R_Star;
case L'+': return R_Plus;
case L'?': return R_Quest;
case L'\\':
if( x==p->end_ ) return R_End;
switch( *x++ )
{
case L't': p->chr_=L'\t'; return R_Char;
case L'w': p->sub_=L"[0-9a-zA-Z_]"; return RegLexerGetToken(p);
case L'W': p->sub_=L"[^0-9a-zA-Z_]"; return RegLexerGetToken(p);
case L'd': p->sub_=L"[0-9]"; return RegLexerGetToken(p);
case L'D': p->sub_=L"[^0-9]"; return RegLexerGetToken(p);
case L's': p->sub_=L"[\t ]"; return RegLexerGetToken(p);
case L'S': p->sub_=L"[^\t ]"; return RegLexerGetToken(p);
} // fall through...
default:
p->chr_ = *(x-1);
return R_Char;
}決定稿
static DKC_INLINE int RegLexerGetTokenImpl(RegLexer *p){//const wchar_t* x = (*p->sub_ ? p->sub_ : p->pat_);
const wchar_t *x = L"\0";
int r = R_Char;
if( p->sub_ == p->end_ )
{ r = R_End; goto End;}if(*p->sub_)
x = p->sub_;
else
x = p->pat_;dkcmFORCE_NOT_ASSERT(x > p->end_);
switch( *x++ )
{
case L'.':
r = R_Any;break;
case L'[':
r = R_Lcl;break;
case L']':
r = R_Rcl;break;
case L'^':
r = R_Ncl;break;
case L'-':
r = R_Range;break;
case L'(':
r = R_Lbr;break;
case L')':
r = R_Rbr;break;
case L'|':
r = R_Bar;break;
case L'*':
r = R_Star;break;
case L'+':
r = R_Plus;break;
case L'?':
r = R_Quest;break;
case L'\\':
if( x==p->end_ ){ r = R_End;break;}
switch( *x++ )
{
case L't': p->chr_=L'\t';
r = R_Char;break;
case L'w': p->sub_=L"[0-9a-zA-Z_]";
r = RegLexerGetTokenImpl(p);break;
case L'W': p->sub_=L"[^0-9a-zA-Z_]";
r = RegLexerGetTokenImpl(p);break;
case L'd': p->sub_=L"[0-9]";
r = RegLexerGetTokenImpl(p);break;
case L'D': p->sub_=L"[^0-9]";
r = RegLexerGetTokenImpl(p);break;
case L's': p->sub_=L"[\t ]";
r = RegLexerGetTokenImpl(p);break;
case L'S': p->sub_=L"[^\t ]";
r = RegLexerGetTokenImpl(p);break;
} // fall through...
default:
p->chr_ = *(x-1);
r = R_Char;
}
End:
//update
p->sub_ = x;
return r;}