2010-08-03
オートインデント2
前回xyzzyでオートインデントをどうやってるかを追おうと見てみたけど、主要な関数だと思われる up-list がビルトインでXyzzyLispで行われてなかったので、C++のソースを見てみる。
Lisp側のup-listと関連付けられているビルトインのC関数
どうやって関連付けられているのかわからなかった…
DEFCMD3 (up-list, 0, 2, 0, "p"),
- たぶんFup_list()
Fup_list()
syntax.cc:1884
lisp
Fup_list (lisp arg, lisp noerror)
{
return up_down_list (arg, noerror, 0);
}
- 単に up_down_list() 関数の呼び出し
up_down_list()
syntax.cc:1863
static lisp up_down_list (lisp arg, lisp noerror, int downp) { int n = (!arg || arg == Qnil) ? 1 : fixnum_value (arg); if (!n) return Qnil; Window *wp = selected_window (); wp->w_disp_flags |= Window::WDF_GOAL_COLUMN; Buffer *bp = wp->w_bufp; Point &point = wp->w_point; point_t opoint = point.p_point; int status = bp->up_down_list (point, n, downp); if (!status) return Qt; bp->goto_char (point, opoint); if (!noerror || noerror == Qnil) sexp_error (status); return Qnil; }
- 現在のバッファ、ポイントに対して Buffer::up_down_list() メソッドの呼び出し
Buffer::up_down_list()
syntax.cc:1791
int Buffer::up_down_list (Point &point, int n, int downp) const { const syntax_table *tab = xsyntax_table (lsyntax_table); int i = 0; int (Buffer::*skip_white)(Point &, int) const; int (Buffer::*skip_sexp)(Point &) const; int dir; if (n > 0) { dir = 1; skip_white = &Buffer::skip_white_forward; skip_sexp = &Buffer::skip_sexp_forward; } else { dir = -1; n = -n; skip_white = &Buffer::skip_white_backward; skip_sexp = &Buffer::skip_sexp_backward; } while (1) { if (dir < 0 && ((!eobp (point) && bolp (point) && (syntax (tab, point) == SCopen || syntax (tab, point) == SCtag_start)) || !forward_char (point, -1))) return Send_sexp; int status; point_t before; do { before = point.p_point; status = (this->*skip_white)(point, 0); } while (status == Sin_comment && point.p_point != before); if (status && (dir > 0 || status != Sbob)) return status; if (dir > 0 && !eobp (point) && (syntax (tab, point) == SCopen || syntax (tab, point) == SCtag_start)) { if (downp) { forward_char (point, 1); if (++i == n) return 0; } else if (bolp (point)) return Sunmatched_paren; } status = (this->*skip_sexp)(point); if (!downp && status == Send_sexp) { if (dir > 0) forward_char (point, 1); if (++i == n) return 0; } else if (status) return status; if (dir < 0 && bobp (point)) return Sbob; } }
- 結果は引数の point に返る
- 方向によって、skip_sexp でS式を飛ばす
- ネストしたS式は skip_sexp 側で処理するだろうから、このメソッドでは指定個の開き括弧または閉じ括弧を数えるだけ
- skip_sexp の戻り値は、リストの終端だったら Send_sexp が返る?
Buffer::skip_sexp_forward(), Buffer::skip_sexp_backward()
syntax.cc:1490
int Buffer::skip_sexp_forward (Point &point) const { const syntax_table *tab = xsyntax_table (lsyntax_table); int status; if (eobp (point)) return Seob; while (1) { Char c = point.ch (); if (!SBCP (c)) return skip_symbol_forward (point); switch (xchar_syntax (tab, c)) { case SCclose: case SCtag_end: if (escaped_char_p (point)) goto symbol; return Send_sexp; case SCopen: case SCtag_start: case SCmath: if (escaped_char_p (point)) goto symbol; status = goto_matched_close (point, c); if (!status) forward_char (point, 1); return status; case SCstring: if (escaped_char_p (point)) goto symbol; status = skip_string_forward (point, c); if (!status) forward_char (point, 1); return status; case SCword: case SCsymbol: case SCsymbol_prefix: case SCkanji: case SCkana: symbol: return skip_symbol_forward (point); case SCescape: case SCquote: break; default: return 0; } if (!forward_char (point, 1) || eobp (point)) return Seob; } } int Buffer::skip_sexp_backward (Point &point) const { const syntax_table *tab = xsyntax_table (lsyntax_table); if (eobp (point) && !forward_char (point, -1)) return Sbob; while (1) { Char c = point.ch (); if (!SBCP (c)) return skip_symbol_backward (point); switch (xchar_syntax (tab, c)) { case SCopen: case SCtag_start: if (escaped_char_p (point)) goto symbol; return Send_sexp; case SCclose: case SCmath: case SCtag_end: if (escaped_char_p (point)) goto symbol; return goto_matched_open (point, c); case SCstring: if (escaped_char_p (point)) goto symbol; return skip_string_backward (point, c); case SCword: case SCsymbol: case SCsymbol_prefix: case SCkanji: case SCkana: symbol: return skip_symbol_backward (point); case SCescape: case SCquote: break; default: return 0; } if (!forward_char (point, -1)) return Sbob; } }
- 文字によってスキップ
- リストを前方に飛ばすところだけ見ようか。goto_matched_close()
Buffer::goto_matched_close()
syntax.cc:1155
int Buffer::goto_matched_close (Point &point, Char openc) const { const syntax_table *tab = xsyntax_table (lsyntax_table); int depth = 1, status; Char prev_ch = 0; while (1) { if (tab->comment_column >= 0 && !eobp (point)) prev_ch = point.ch (); if (!forward_char (point, 1) || eobp (point)) return Sunmatched_paren; if (tab->comment_column >= 0 && prev_ch == '\n' && column_comment_p (tab, point)) { status = skip_single_char_comment_forward (point); if (status) return status; continue; } Char c = point.ch (); if (!SBCP (c)) continue; if (xcomment_end_first_char_p (tab, c) && forward_comment_end_p (point)) return Sin_comment; if (xcomment_start_first_char_p (tab, c) && forward_comment_start_p (point)) { status = skip_multi_chars_comment_forward (point); if (status) return status; continue; } if (xcplusplus_comment_char_p (tab, c) && !xparse_sexp_ignore_comment_p (tab, c) && forward_cplusplus_comment_p (point)) { status = skip_cplusplus_comment_forward (point); if (status) return status; continue; } switch (xchar_syntax (tab, c)) { case SCclose: case SCtag_end: if (escaped_char_p (point)) break; if (c == xchar_match (tab, openc)) { if (!--depth) return 0; } else return Sunbalanced_paren; break; case SCopen: case SCtag_start: if (escaped_char_p (point)) break; if (c == openc) depth++; else { status = goto_matched_close (point, c); if (status) return status; } break; case SCmath: if (escaped_char_p (point)) break; if (c == openc) return 0; status = goto_matched_close (point, c); if (status) return status; break; case SCstring: if (escaped_char_p (point)) break; status = skip_string_forward (point, c); if (status) return status; break; case SCcomment_start: if (escaped_char_p (point)) break; if (xparse_sexp_ignore_comment_p (tab, c)) break; status = skip_single_char_comment_forward (point); if (status) return status; break; default: break; } } }
syntax()
syntax.cc:745
static inline syntax_code syntax (const syntax_table *tab, const Point &point) { return syntax (tab, point.ch ()); }
- ポイントのキャラを取り出して、別名の syntax() 呼び出し
syntax.cc:737
static inline syntax_code syntax (const syntax_table *tab, Char c) { if (SBCP (c)) return syntax_code (xchar_syntax (tab, c)); return SCkanji; }
- 文字の種類を返す
- syntax_code は単なる enum。この形式のキャストは関数呼び出しと紛らわしいね…
SBCP()
inline int SBCP (Char c) {return c < 256;}
- 多バイト文字じゃないか?
syntax_code
syntax.h:43
enum syntax_code
{
SCwhite,
SCpunct,
SCopen,
SCclose,
SCmath,
SCstring,
SCcomment_start,
SCcomment_end,
SCcplusplus_comment_end,
SCescape,
SCquote,
SCsymbol,
SCword,
SCkana,
SCkanji,
SCjunk,
SCtag_start,
SCtag_end,
SCsymbol_prefix,
SCmax
};
xchar_syntax()
# define xchar_syntax(t, c) ((t)->type[(c)])
- 単なるテーブルからの取り出し
Buffer::forward_char()
move.cc:37
int Buffer::forward_char (Point &point, long nchars) const { long d = min (max (point.p_point + nchars, b_contents.p1), b_contents.p2) - point.p_point; int f = d == nchars; const Chunk *cp = point.p_chunk; if (d > 0) { while (1) { int size = cp->c_used - point.p_offset; if (d <= size) { point.p_point += d; if (d == size && cp->c_next) { cp = cp->c_next; point.p_offset = 0; } else point.p_offset += d; point.p_chunk = (Chunk *)cp; break; } d -= size; point.p_point += size; point.p_offset = 0; cp = cp->c_next; assert (cp); } } else if (d < 0) { while (1) { if (point.p_offset + d >= 0) { point.p_offset += d; point.p_point += d; point.p_chunk = (Chunk *)cp; break; } d += point.p_offset + 1; point.p_point -= point.p_offset + 1; cp = cp->c_prev; assert (cp); point.p_offset = cp->c_used - 1; } } return f; }
Buffer::goto_char()
move.cc:91
void Buffer::goto_char (Point &point, point_t goal) const { goal = min (max (goal, b_contents.p1), b_contents.p2); if (goal < point.p_point / 2) { point.p_point = 0; point.p_chunk = b_chunkb; point.p_offset = 0; } else if (goal > (point.p_point + b_nchars) / 2) { point.p_point = b_nchars; point.p_chunk = b_chunke; point.p_offset = b_chunke->c_used; } forward_char (point, goal - point.p_point); }
結局
- 地道にやるより他ない
- xyzzyのCソースは、クラス別じゃなくて機能別に分かれてて面白いなと思った
コメントを書く
Crystal2012/02/17 14:13I came, I read this atircle, I conquered.
fwxmyan2012/02/17 19:343dPY7L <a href="http://dxrlnazknhlp.com/">dxrlnazknhlp</a>
kwjzdlnzh2012/02/19 22:58ZLwiev , [url=http://uquxvqflsxzz.com/]uquxvqflsxzz[/url], [link=http://rajoylgljzvu.com/]rajoylgljzvu[/link], http://ctutljidkpkm.com/
ueaofsuketf2012/02/22 02:13ZdVikp <a href="http://csbezacksyuz.com/">csbezacksyuz</a>
トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20100803