dcdd144598 2011-02-23 kinaba: #include "stdafx.h" dcdd144598 2011-02-23 kinaba: #include "ip_doc.h" dcdd144598 2011-02-23 kinaba: using namespace editwing; dcdd144598 2011-02-23 kinaba: using namespace editwing::doc; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: //========================================================================= dcdd144598 2011-02-23 kinaba: //---- ip_parse.cpp キーワード解析 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // キーワード定義ファイルに従って、保持する文字列を dcdd144598 2011-02-23 kinaba: // 適切に切り分ける作業がここ。 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: //---- ip_text.cpp 文字列操作・他 dcdd144598 2011-02-23 kinaba: //---- ip_wrap.cpp 折り返し dcdd144598 2011-02-23 kinaba: //---- ip_scroll.cpp スクロール dcdd144598 2011-02-23 kinaba: //---- ip_draw.cpp 描画・他 dcdd144598 2011-02-23 kinaba: //---- ip_cursor.cpp カーソルコントロール dcdd144598 2011-02-23 kinaba: //========================================================================= dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: //========================================================================= dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // 解析結果データ仕様 dcdd144598 2011-02-23 kinaba: // これだけ色々姑息な手段を持ち込んで本当に dcdd144598 2011-02-23 kinaba: // 速くなっているのかどうかは不明…(^^; dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // Line::isLineHeadCommented_ dcdd144598 2011-02-23 kinaba: // 0: 行頭がブロックコメントの内部ではない dcdd144598 2011-02-23 kinaba: // 1: 行頭がブロックコメントの内部 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // Line::commentTransition_ dcdd144598 2011-02-23 kinaba: // 00: 行末は常にコメントの外 dcdd144598 2011-02-23 kinaba: // 01: 行頭と行末はコメント状態が逆転 dcdd144598 2011-02-23 kinaba: // 10: 行頭と行末はコメント状態が同じ dcdd144598 2011-02-23 kinaba: // 11: 行末は常にコメントの中 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // 以上二つのフラグを元に、前の行の情報から今の行の情報を dcdd144598 2011-02-23 kinaba: // this.head = (prev.trans >> prev.head)&1; dcdd144598 2011-02-23 kinaba: // で順次計算していくことが出来る。 dcdd144598 2011-02-23 kinaba: // この計算の際に内部バッファの状態まで書き換えるのは dcdd144598 2011-02-23 kinaba: // コストがでかすぎるので、次に示すフラグを見ながら dcdd144598 2011-02-23 kinaba: // 描画寸前に適宜調整する。 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // Line::commentBitReady_ dcdd144598 2011-02-23 kinaba: // コメントビットが調整済みかどうか dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // Line::str_[] dcdd144598 2011-02-23 kinaba: // UCS-2ベタで、文字列データがそのまま格納される。 dcdd144598 2011-02-23 kinaba: // ただし、パーサの高速化のために最終文字の後ろに dcdd144598 2011-02-23 kinaba: // 0x007fが付加される。 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // Line::flg_ dcdd144598 2011-02-23 kinaba: // 一文字毎に、下のような8bitのフラグを割り当てる dcdd144598 2011-02-23 kinaba: // | aaabbbcd | dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // aaa == "PosInToken" dcdd144598 2011-02-23 kinaba: // 0: トークンの途中 dcdd144598 2011-02-23 kinaba: // 1-6: トークンの頭。次の頭は1-6文字先。 dcdd144598 2011-02-23 kinaba: // 7: トークンの頭。次の頭は7文字以上先。 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // bbb == "TokenType" dcdd144598 2011-02-23 kinaba: // 0: TAB: タブ文字 dcdd144598 2011-02-23 kinaba: // 1: WSP: ホワイトスペース dcdd144598 2011-02-23 kinaba: // 2: TXT: 普通の文字 dcdd144598 2011-02-23 kinaba: // 3: CE: コメント開始タグ dcdd144598 2011-02-23 kinaba: // 4: CB: コメント終了タグ dcdd144598 2011-02-23 kinaba: // 5: LB: 行コメント開始タグ dcdd144598 2011-02-23 kinaba: // 6: Q1: '' 引用符1 dcdd144598 2011-02-23 kinaba: // 7: Q2: "" 引用符2 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // c == "isKeyword?" dcdd144598 2011-02-23 kinaba: // 0: キーワードではない dcdd144598 2011-02-23 kinaba: // 1: キーワード dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // d == "inComment?" dcdd144598 2011-02-23 kinaba: // 0: コメントの中ではない dcdd144598 2011-02-23 kinaba: // 1: コメントの中 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // ----------------------------------------------- dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: namespace { dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: // コメントの中なのか外なのか等を判定するためのオートマトン dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // /* が出たらその後ろはコメントで */ が出たらその後ろはノーマルゾーン dcdd144598 2011-02-23 kinaba: // …という単純な規則では上手く行かない。例えば str"/*"str なんてものが dcdd144598 2011-02-23 kinaba: // 出現した場合に困ってしまう。そこで、 dcdd144598 2011-02-23 kinaba: // ・普通のテキスト dcdd144598 2011-02-23 kinaba: // ・ブロックコメントの中 dcdd144598 2011-02-23 kinaba: // ・行コメントの中 dcdd144598 2011-02-23 kinaba: // ・一重引用符の中 dcdd144598 2011-02-23 kinaba: // ・二重引用符の中 dcdd144598 2011-02-23 kinaba: // の5種類の状態に分けて、それぞれの場合について、どの記号が出たら dcdd144598 2011-02-23 kinaba: // 次にどの状態に移るのか…を処理する必要がある。その状態変化の規則を dcdd144598 2011-02-23 kinaba: // 5x5の2次元配列で与えて管理する。 dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: enum CommentDFASymbol{ sCB, sCE, sLB, sQ1, sQ2, sXXX }; dcdd144598 2011-02-23 kinaba: struct CommentDFA dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // <状態> dcdd144598 2011-02-23 kinaba: // 最下位bitが、現在コメント内かどうかのフラグになります。 dcdd144598 2011-02-23 kinaba: // ブロックコメント中かどうかは (state>>1)&(state) で。 dcdd144598 2011-02-23 kinaba: // 000: normal text 011: in BlockComment dcdd144598 2011-02-23 kinaba: // 001: in LineComment 100: in Quote2 dcdd144598 2011-02-23 kinaba: // 010: in Quote1 dcdd144598 2011-02-23 kinaba: // dcdd144598 2011-02-23 kinaba: // <シンボル> dcdd144598 2011-02-23 kinaba: // C++で言うと下の通り dcdd144598 2011-02-23 kinaba: // 値はTokenTypeフラグとシンクロするようになってます。 dcdd144598 2011-02-23 kinaba: // 000: CE */ 011: Q1 ' dcdd144598 2011-02-23 kinaba: // 001: CB /* 100: Q2 " dcdd144598 2011-02-23 kinaba: // 010: LB // dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 初期状態を指定。コメント内かコメント外か dcdd144598 2011-02-23 kinaba: CommentDFA( bool inComment ) dcdd144598 2011-02-23 kinaba: : state( inComment ? 3 : 0 ) {} dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 入力符号を与えて状態遷移 dcdd144598 2011-02-23 kinaba: void transit( int sym ) dcdd144598 2011-02-23 kinaba: { state = tr_table[state][sym]; } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 現在の状態 dcdd144598 2011-02-23 kinaba: int state; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 状態遷移テーブル dcdd144598 2011-02-23 kinaba: static const int tr_table[5][5]; dcdd144598 2011-02-23 kinaba: }; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: const int CommentDFA::tr_table[5][5] = { dcdd144598 2011-02-23 kinaba: {0,3,1,2,4}, dcdd144598 2011-02-23 kinaba: {1,1,1,1,1}, dcdd144598 2011-02-23 kinaba: {2,2,2,0,2}, dcdd144598 2011-02-23 kinaba: {0,3,3,3,3}, dcdd144598 2011-02-23 kinaba: {4,4,4,4,0}, dcdd144598 2011-02-23 kinaba: }; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: // 単純な、キーワード格納構造体。 dcdd144598 2011-02-23 kinaba: // ChainHashの要素にするためnextポインタがつけてあります。 dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: struct Keyword : public Object dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: unicode* str; dcdd144598 2011-02-23 kinaba: const ulong len; dcdd144598 2011-02-23 kinaba: Keyword* next; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: Keyword( const unicode* s, ulong l ) dcdd144598 2011-02-23 kinaba: : str( new unicode[l+1] ) dcdd144598 2011-02-23 kinaba: , len( l ) dcdd144598 2011-02-23 kinaba: , next( NULL ) dcdd144598 2011-02-23 kinaba: { memmove( str, s, l*sizeof(unicode) ); } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: ~Keyword() dcdd144598 2011-02-23 kinaba: { delete [] str; } dcdd144598 2011-02-23 kinaba: }; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: // サポート関数。Unicodeテキスト同士の比較 dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: static bool compare_s(const unicode* a,const unicode* b,ulong l) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // 大文字小文字を区別 dcdd144598 2011-02-23 kinaba: while( l-- ) dcdd144598 2011-02-23 kinaba: if( *a++ != *b++ ) dcdd144598 2011-02-23 kinaba: return false; dcdd144598 2011-02-23 kinaba: return true; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: static bool compare_i(const unicode* a,const unicode* b,ulong l) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // 大文字小文字を区別しない(雑) dcdd144598 2011-02-23 kinaba: while( l-- ) dcdd144598 2011-02-23 kinaba: if( ((*a++) ^ (*b++)) & 0xdf ) dcdd144598 2011-02-23 kinaba: return false; dcdd144598 2011-02-23 kinaba: return true; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: // 与えられた記号文字列から、コメント開始等の意味のあるトークンを dcdd144598 2011-02-23 kinaba: // 切り出してくるための構造。 dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: class TagMap dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: Keyword* tag_[3]; // 0:CE 1:CB 2:LB dcdd144598 2011-02-23 kinaba: bool esc_, q1_, q2_, map_[128]; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: public: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: TagMap( const unicode* cb, ulong cblen, dcdd144598 2011-02-23 kinaba: const unicode* ce, ulong celen, dcdd144598 2011-02-23 kinaba: const unicode* lb, ulong lblen, dcdd144598 2011-02-23 kinaba: bool q1, bool q2, bool esc ) dcdd144598 2011-02-23 kinaba: : q1_ ( q1 ) dcdd144598 2011-02-23 kinaba: , q2_ ( q2 ) dcdd144598 2011-02-23 kinaba: , esc_( esc ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // '/' で始まる記号は使われているか…? dcdd144598 2011-02-23 kinaba: // みたいな、1文字目のみのチェックに使う表を作成 dcdd144598 2011-02-23 kinaba: tag_[0] = tag_[1] = tag_[2] = NULL; dcdd144598 2011-02-23 kinaba: mem00( map_, sizeof(map_) ); dcdd144598 2011-02-23 kinaba: map_[L'\''] = q1; dcdd144598 2011-02-23 kinaba: map_[L'\"'] = q2; dcdd144598 2011-02-23 kinaba: map_[L'\\'] = esc; dcdd144598 2011-02-23 kinaba: if( celen!=0 ){ map_[*ce]=true; tag_[0]=new Keyword(ce,celen); } dcdd144598 2011-02-23 kinaba: if( cblen!=0 ){ map_[*cb]=true; tag_[1]=new Keyword(cb,cblen); } dcdd144598 2011-02-23 kinaba: if( lblen!=0 ){ map_[*lb]=true; tag_[2]=new Keyword(lb,lblen); } dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: ~TagMap() dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // キーワード解放 dcdd144598 2011-02-23 kinaba: delete tag_[0]; dcdd144598 2011-02-23 kinaba: delete tag_[1]; dcdd144598 2011-02-23 kinaba: delete tag_[2]; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: bool does_esc() dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // \ によるエスケープをするかどうか dcdd144598 2011-02-23 kinaba: return esc_; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: ulong SymbolLoop( dcdd144598 2011-02-23 kinaba: const unicode* str, ulong len, ulong& mlen, int& sym ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // 有意味な記号にマッチするまでループ dcdd144598 2011-02-23 kinaba: // 返値に、マッチするまでに飛ばした文字数、 dcdd144598 2011-02-23 kinaba: // mlen,symに、マッチした記号の情報を返す dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: int i; dcdd144598 2011-02-23 kinaba: ulong ans=0; dcdd144598 2011-02-23 kinaba: for( sym=sXXX, mlen=1; ans<len; ++ans ) dcdd144598 2011-02-23 kinaba: if( map_[str[ans]] ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: for( i=2; i>=0; --i ) dcdd144598 2011-02-23 kinaba: if( tag_[i]!=NULL dcdd144598 2011-02-23 kinaba: && tag_[i]->len <= len-ans dcdd144598 2011-02-23 kinaba: && compare_s( dcdd144598 2011-02-23 kinaba: tag_[i]->str, str+ans, tag_[i]->len ) ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: sym = i; dcdd144598 2011-02-23 kinaba: mlen = tag_[i]->len; dcdd144598 2011-02-23 kinaba: goto symbolfound; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: if( str[ans] == L'\'' ) // 一重引用符 dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: if( q1_ ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: sym = sQ1; dcdd144598 2011-02-23 kinaba: goto symbolfound; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: else if( str[ans] == L'\"' ) // 二重引用符 dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: if( q2_ ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: sym = sQ2; dcdd144598 2011-02-23 kinaba: goto symbolfound; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: else if( str[ans] == L'\\' ) // \ の後の文字はSkip dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: if( esc_ && ans+1<len ) dcdd144598 2011-02-23 kinaba: ++ans; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: symbolfound: dcdd144598 2011-02-23 kinaba: return ans; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: }; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: // 与えられた文字列がキーワードかどうか高速判定するためのハッシュ表 dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: class KeywordMap dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: Keyword* backet_[4096]; dcdd144598 2011-02-23 kinaba: storage<Keyword*> dustbox_; dcdd144598 2011-02-23 kinaba: bool (*compare_)(const unicode*,const unicode*,ulong); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: public: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: KeywordMap( bool bCaseSensitive ) dcdd144598 2011-02-23 kinaba: : compare_( bCaseSensitive ? compare_s : compare_i ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // ハッシュ表初期化 dcdd144598 2011-02-23 kinaba: mem00( backet_, sizeof(backet_) ); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: ~KeywordMap() dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // 解放 dcdd144598 2011-02-23 kinaba: for( ulong i=0; i<dustbox_.size(); ++i ) dcdd144598 2011-02-23 kinaba: delete dustbox_[i]; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: void AddKeyword( const unicode* str, ulong len ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // データ登録 dcdd144598 2011-02-23 kinaba: Keyword* x = new Keyword(str,len); dcdd144598 2011-02-23 kinaba: int h = hash(str,len); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: if( backet_[h] == NULL ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // ハッシュテーブルが空の場合 dcdd144598 2011-02-23 kinaba: backet_[h] = x; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: else dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // チェイン末尾に繋ぐ場合 dcdd144598 2011-02-23 kinaba: Keyword *q=backet_[h],*p=backet_[h]->next; dcdd144598 2011-02-23 kinaba: while( p!=NULL ) dcdd144598 2011-02-23 kinaba: q=p, p=p->next; dcdd144598 2011-02-23 kinaba: q->next = x; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // データクリア用のリストにも入れておく dcdd144598 2011-02-23 kinaba: dustbox_.Add(x); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: ulong isKeyword( const unicode* str, ulong len ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // 登録されているキーワードと一致するか? dcdd144598 2011-02-23 kinaba: for( Keyword* p=backet_[hash(str,len)]; p!=NULL; p=p->next ) dcdd144598 2011-02-23 kinaba: if( p->len==len && compare_( p->str, str, len ) ) dcdd144598 2011-02-23 kinaba: return 2; dcdd144598 2011-02-23 kinaba: return 0; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: private: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: static int hash( const unicode* a, ulong al ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // 12bitに潰すめっちゃ雑なハッシュ関数 dcdd144598 2011-02-23 kinaba: // ルーチン分けるの面倒なので、大文字小文字は常に区別されない。(^^; dcdd144598 2011-02-23 kinaba: int h=0,i=0; dcdd144598 2011-02-23 kinaba: while( al-- ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: h ^= ((*(a++)&0xdf)<<i); dcdd144598 2011-02-23 kinaba: i = (i+5)&7; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: return h&4095; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: }; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: // 以上の道具立てでもって、テキストの解析を行うParser dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: class editwing::doc::Parser dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: KeywordMap kwd_; dcdd144598 2011-02-23 kinaba: TagMap tag_; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: public: dcdd144598 2011-02-23 kinaba: // 初期化1 dcdd144598 2011-02-23 kinaba: Parser( dcdd144598 2011-02-23 kinaba: const unicode* cb, ulong cblen, dcdd144598 2011-02-23 kinaba: const unicode* ce, ulong celen, dcdd144598 2011-02-23 kinaba: const unicode* lb, ulong lblen, dcdd144598 2011-02-23 kinaba: bool q1, bool q2, bool esc, dcdd144598 2011-02-23 kinaba: bool casesensitive dcdd144598 2011-02-23 kinaba: ) dcdd144598 2011-02-23 kinaba: : tag_( cb, cblen, ce, celen, lb, lblen, q1, q2, esc ) dcdd144598 2011-02-23 kinaba: , kwd_( casesensitive ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 初期化2:キーワード追加 dcdd144598 2011-02-23 kinaba: void AddKeyword( const unicode* str, ulong len ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: kwd_.AddKeyword( str, len ); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 行データ解析 dcdd144598 2011-02-23 kinaba: uchar Parse( Line& line, uchar cmst ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: line.TransitCmt( cmst ); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // ASCII振り分けテーブル。 dcdd144598 2011-02-23 kinaba: // シフト無しでTokenTypeに流用出来るようにするため、 dcdd144598 2011-02-23 kinaba: // 値が4飛びになってます dcdd144598 2011-02-23 kinaba: enum { T=0, W=4, A=8, S=12, O=0 }; dcdd144598 2011-02-23 kinaba: static const uchar letter_type[128] = { dcdd144598 2011-02-23 kinaba: O,O,O,O,O,O,O,O,O,T,O,O,O,O,O,O, dcdd144598 2011-02-23 kinaba: O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, dcdd144598 2011-02-23 kinaba: W,S,S,S,S,S,S,S,S,S,S,S,S,S,S,S, dcdd144598 2011-02-23 kinaba: A,A,A,A,A,A,A,A,A,A,S,S,S,S,S,S, dcdd144598 2011-02-23 kinaba: S,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A, dcdd144598 2011-02-23 kinaba: A,A,A,A,A,A,A,A,A,A,A,S,S,S,S,A, dcdd144598 2011-02-23 kinaba: S,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A, dcdd144598 2011-02-23 kinaba: A,A,A,A,A,A,A,A,A,A,A,S,S,S,S,O, dcdd144598 2011-02-23 kinaba: }; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // PosInToken算出用の距離エンコーダ( 5bitシフト済み ) dcdd144598 2011-02-23 kinaba: // ( _d>7 ? 7<<5 : _d<<5 ) dcdd144598 2011-02-23 kinaba: #define tkenc(_d) ( (_d)>7 ? 0xe0 : (_d)<<5 ) dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // コメント状態遷移追跡用オートマトン dcdd144598 2011-02-23 kinaba: CommentDFA dfa[2] = {CommentDFA(false), CommentDFA(true)}; dcdd144598 2011-02-23 kinaba: int& cmtState = dfa[line.isLineHeadCmt()].state; dcdd144598 2011-02-23 kinaba: int commentbit = cmtState&1; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 作業領域 dcdd144598 2011-02-23 kinaba: int sym; dcdd144598 2011-02-23 kinaba: ulong j, k, um, m; dcdd144598 2011-02-23 kinaba: uchar t, f; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // ループ〜 dcdd144598 2011-02-23 kinaba: const unicode* str = line.str(); dcdd144598 2011-02-23 kinaba: uchar* flg = line.flg(); dcdd144598 2011-02-23 kinaba: ulong ie = line.size(); dcdd144598 2011-02-23 kinaba: for( ulong i=0; i<ie; i=j ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: j = i; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // ASCII文字でない場合 dcdd144598 2011-02-23 kinaba: if( str[i] >= 0x007f ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: f = (ALP | commentbit); dcdd144598 2011-02-23 kinaba: if( str[i] == 0x3000 )//L' ' ) dcdd144598 2011-02-23 kinaba: while( str[++j] == 0x3000 ) dcdd144598 2011-02-23 kinaba: flg[j] = f; dcdd144598 2011-02-23 kinaba: else dcdd144598 2011-02-23 kinaba: while( str[++j] >= 0x80 && str[j]!=0x3000 ) dcdd144598 2011-02-23 kinaba: flg[j] = f; dcdd144598 2011-02-23 kinaba: flg[i] = static_cast<uchar>(tkenc(j-i) | f); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: // ASCII文字の場合?? dcdd144598 2011-02-23 kinaba: else dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: t = letter_type[str[i]]; dcdd144598 2011-02-23 kinaba: if( t==S && tag_.does_esc() ) dcdd144598 2011-02-23 kinaba: do dcdd144598 2011-02-23 kinaba: if( j+1<ie && str[j]==L'\\' ) dcdd144598 2011-02-23 kinaba: j++; dcdd144598 2011-02-23 kinaba: while( str[++j]<0x7f && S==letter_type[str[j]] ); dcdd144598 2011-02-23 kinaba: else dcdd144598 2011-02-23 kinaba: while( str[++j]<0x7f && t==letter_type[str[j]] ); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: f = (t | commentbit); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: switch( t ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // アルファベット&数字 dcdd144598 2011-02-23 kinaba: case A: dcdd144598 2011-02-23 kinaba: f |= kwd_.isKeyword( str+i, j-i ); dcdd144598 2011-02-23 kinaba: // fall... dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // タブ・制御文字 dcdd144598 2011-02-23 kinaba: case T: dcdd144598 2011-02-23 kinaba: // fall... dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 半角空白 dcdd144598 2011-02-23 kinaba: case W: dcdd144598 2011-02-23 kinaba: for( k=i+1; k<j; ++k ) dcdd144598 2011-02-23 kinaba: flg[k] = f; dcdd144598 2011-02-23 kinaba: flg[i] = (uchar)(tkenc(j-i)|f); dcdd144598 2011-02-23 kinaba: break; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 記号 dcdd144598 2011-02-23 kinaba: case S: dcdd144598 2011-02-23 kinaba: k = i; dcdd144598 2011-02-23 kinaba: while( k < j ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // マッチしなかった部分 dcdd144598 2011-02-23 kinaba: um = tag_.SymbolLoop( str+k, j-k, m, sym ); dcdd144598 2011-02-23 kinaba: f = (0x20 | ALP | commentbit); dcdd144598 2011-02-23 kinaba: while( um-- ) dcdd144598 2011-02-23 kinaba: flg[k++] = f; dcdd144598 2011-02-23 kinaba: if( k >= j ) dcdd144598 2011-02-23 kinaba: break; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // マッチした部分 dcdd144598 2011-02-23 kinaba: f = (CE | commentbit); dcdd144598 2011-02-23 kinaba: dfa[0].transit( sym ); dcdd144598 2011-02-23 kinaba: dfa[1].transit( sym ); dcdd144598 2011-02-23 kinaba: commentbit = cmtState&1; dcdd144598 2011-02-23 kinaba: if( sym != 0 ) // 0:comment end dcdd144598 2011-02-23 kinaba: f = (((sym+3)<<2) | commentbit); dcdd144598 2011-02-23 kinaba: flg[k++] = (uchar)(tkenc(m)|f); dcdd144598 2011-02-23 kinaba: while( --m ) dcdd144598 2011-02-23 kinaba: flg[k++] = f; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: break; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // transitフラグ更新 dcdd144598 2011-02-23 kinaba: line.SetTransitFlag( dcdd144598 2011-02-23 kinaba: (dfa[1].state & (dfa[1].state<<1)) | dcdd144598 2011-02-23 kinaba: ((dfa[0].state>>1) & dfa[0].state) dcdd144598 2011-02-23 kinaba: ); dcdd144598 2011-02-23 kinaba: line.CommentBitUpdated(); dcdd144598 2011-02-23 kinaba: return line.TransitCmt( cmst ); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // コメントビットを正しく調整 dcdd144598 2011-02-23 kinaba: void SetCommentBit( Line& line ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: CommentDFA dfa( line.isLineHeadCmt()==1 ); dcdd144598 2011-02-23 kinaba: ulong commentbit = dfa.state&1; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // ループ〜 dcdd144598 2011-02-23 kinaba: const unicode* str = line.str(); dcdd144598 2011-02-23 kinaba: uchar* flg = line.flg(); dcdd144598 2011-02-23 kinaba: ulong j,k,ie = line.size(); dcdd144598 2011-02-23 kinaba: for( ulong i=0; i<ie; i=j ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // Tokenの終端を得る dcdd144598 2011-02-23 kinaba: k = (flg[i]>>5); dcdd144598 2011-02-23 kinaba: j = i + k; dcdd144598 2011-02-23 kinaba: if( j >= ie ) dcdd144598 2011-02-23 kinaba: j = ie; dcdd144598 2011-02-23 kinaba: else if( k==7 ) // || k==0 ) dcdd144598 2011-02-23 kinaba: while( (flg[j]>>5)==0 && j<ie ) dcdd144598 2011-02-23 kinaba: ++j; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: k = (flg[i] & 0x1c); dcdd144598 2011-02-23 kinaba: if( k <= CE ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: for( ; i<j; ++i ) dcdd144598 2011-02-23 kinaba: flg[i] = (uchar)((flg[i] & 0xfe) | commentbit); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: if( k >= CE ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: dfa.transit( (k>>2)-3 ); dcdd144598 2011-02-23 kinaba: commentbit = dfa.state&1; dcdd144598 2011-02-23 kinaba: if( k != CE ) dcdd144598 2011-02-23 kinaba: for( ; i<j; ++i ) dcdd144598 2011-02-23 kinaba: flg[i] = (uchar)((flg[i] & 0xfe) | commentbit); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: line.CommentBitUpdated(); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: }; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: // 定義ファイル読みとり処理とか dcdd144598 2011-02-23 kinaba: //------------------------------------------------------------------------- dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: DocImpl::DocImpl( Document& theDoc ) dcdd144598 2011-02-23 kinaba: : doc_ ( theDoc ) dcdd144598 2011-02-23 kinaba: , pEvHan_ ( 2 ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: text_.Add( new Line(L"",0) ); // 最初は一行だけ dcdd144598 2011-02-23 kinaba: SetKeyword( NULL, 0 ); // キーワード無し dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: DocImpl::~DocImpl() dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // このファイルにデストラクタを入れておかないと、 dcdd144598 2011-02-23 kinaba: // delete parser_ が出来なくなる。^^; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: void DocImpl::SetKeyword( const unicode* defbuf, ulong siz ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // BOMがあったらスキップ dcdd144598 2011-02-23 kinaba: if( siz!=0 && *defbuf==0xfeff ) dcdd144598 2011-02-23 kinaba: ++defbuf, --siz; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 読み込み準備 dcdd144598 2011-02-23 kinaba: const unicode* str; dcdd144598 2011-02-23 kinaba: ulong len; dcdd144598 2011-02-23 kinaba: UniReader r( defbuf, siz, &str, &len ); dcdd144598 2011-02-23 kinaba: bool flags[] = {false,false,false,false}; dcdd144598 2011-02-23 kinaba: const unicode* tags[] = {NULL,NULL,NULL}; dcdd144598 2011-02-23 kinaba: ulong taglen[] = {0,0,0}; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: if( siz != 0 ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: // 1行目:フラグ dcdd144598 2011-02-23 kinaba: // case? q1? q2? esc? dcdd144598 2011-02-23 kinaba: r.getLine(); dcdd144598 2011-02-23 kinaba: for( ulong i=0; i<len; ++i ) dcdd144598 2011-02-23 kinaba: flags[i] = (str[i]==L'1'); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 2〜4行目 dcdd144598 2011-02-23 kinaba: // ブロコメ開始記号、ブロコメ終了記号、行コメ記号 dcdd144598 2011-02-23 kinaba: for( int j=0; j<3; ++j ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: r.getLine(); dcdd144598 2011-02-23 kinaba: tags[j] = str; dcdd144598 2011-02-23 kinaba: taglen[j] = len; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // パーサー作成 dcdd144598 2011-02-23 kinaba: aptr<Parser> np( new Parser( dcdd144598 2011-02-23 kinaba: tags[0], taglen[0], tags[1], taglen[1], tags[2], taglen[2], dcdd144598 2011-02-23 kinaba: flags[1], flags[2], flags[3], flags[0] ) ); dcdd144598 2011-02-23 kinaba: parser_ = np; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 5行目以降:キーワードリスト dcdd144598 2011-02-23 kinaba: while( !r.isEmpty() ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: r.getLine(); dcdd144598 2011-02-23 kinaba: if( len != 0 ) dcdd144598 2011-02-23 kinaba: parser_->AddKeyword( str, len ); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 全行解析し直し dcdd144598 2011-02-23 kinaba: ReParse( 0, tln()-1 ); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 変更通知 dcdd144598 2011-02-23 kinaba: Fire_KEYWORDCHANGE(); dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: bool DocImpl::ReParse( ulong s, ulong e ) dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: ulong i; dcdd144598 2011-02-23 kinaba: uchar cmt = text_[s].isLineHeadCmt(); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // まずは変更範囲を再解析 dcdd144598 2011-02-23 kinaba: for( i=s; i<=e; ++i ) dcdd144598 2011-02-23 kinaba: cmt = parser_->Parse( text_[i], cmt ); dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // コメントアウト状態に変化がなかったらここでお終い。 dcdd144598 2011-02-23 kinaba: if( i==tln() || text_[i].isLineHeadCmt()==cmt ) dcdd144598 2011-02-23 kinaba: return false; dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: // 例えば、/* が入力された場合などは、下の方の行まで dcdd144598 2011-02-23 kinaba: // コメントアウト状態の変化を伝達する必要がある。 dcdd144598 2011-02-23 kinaba: do dcdd144598 2011-02-23 kinaba: cmt = text_[i++].TransitCmt( cmt ); dcdd144598 2011-02-23 kinaba: while( i<tln() && text_[i].isLineHeadCmt()!=cmt ); dcdd144598 2011-02-23 kinaba: return true; dcdd144598 2011-02-23 kinaba: } dcdd144598 2011-02-23 kinaba: dcdd144598 2011-02-23 kinaba: void DocImpl::SetCommentBit( const Line& x ) const dcdd144598 2011-02-23 kinaba: { dcdd144598 2011-02-23 kinaba: parser_->SetCommentBit( const_cast<Line&>(x) ); dcdd144598 2011-02-23 kinaba: }