コンテンツへ移動

MRI parse.y たぐり読み

parse.y をたぐって読んでみよう企画。どのへんで企画倒れるかの耐久レース。
対象は r35068。2012/3/16 20:45 現在の最新。

program

: top_compstmt

プログラム=スクリプト=ソース、ぐらいのものだと考えていいんじゃないでしょうか。少なくともこの場合。初期化や返り値の保存や色々やってますが、パース自体にはあまり関係なさそうなので無視します。

top_compstmt

in program

: top_stmts opt_terms

top というからには、まあプログラムの最外部分、つまりはプログラム全体と考えていいのではないでしょうか。

opt_terms

in top_compstmt

: /* none */ | terms

terms があってもなくてもいい場合。さて terms とは?

terms

in opt_terms, terms

: term | terms ‘;’

term に ‘;’ 記号が0個以上くっついたもの、と読めます。 ‘;’ がくっついた場合は {yyerrok;} を呼んでいます。つーことはこれは終端記号ですね。term という名前から分かる通り。

term

in terms

: ‘;’ | ‘\n’

ということで、Ruby ではセミコロンと改行を終端として取りうることがわかりました。ところで、セミコロンの場合だけ yyerrok を呼んでいて、改行の場合は呼んでいません。なぜなのかは、たぶん後からわかるはず。

top_stmts

in top_compstmt

: none | top_stmt | top_stmts terms top_stmt | error top_stmt

何も書かれていないか、一つの文か、終端記号(term参照)を間に挟んだ複数の文か、はたまたエラーを含んだ文か。「文」と訳していいかはわかりませんが、まあ読むうちにおいおい分かっていくものとします。none が /* none */ でなくちゃんと要素としてあるのが興味深いですね。また、error があっても受け付けることで、適切な Syntax Error を上げることが出来るようになっている、んだと思います。

none

in top_stmts

: /* none */

内部で { $$ = 0; } しています。「何もない」という値がほしいときに使うのでしょう。というか、$n とかで値を使うことの方が多いでしょうから、むしろ通常は none を使い、明らかに値が必要ない場合には /* none */ でもよい、ぐらいの感覚の方がよさそうです。

top_stmt

in top_stmts

: stmt | keyword_BEGIN ‘{‘ top_compstmt ‘}’

文または BEGIN {} 構文が最外に来るということがわかります。BEGIN はパースの段階ですでに特別扱いなんですね。また、BEGIN の解釈段階で ruby_eval_tree_begin というツリーに top_compstmt が継ぎ足される処理が入っています。名前のとおり、実行時最初に処理されるということだと思われます。

stmt

in top_stmt

: keyword_alias fitem fitem

fitem のエイリアスか、

| keyword_alias tGVAR tGVAR

グローバル変数のエイリアスか、

| keyword_alias tGVAR tBACK_REF

$&, $`, $’, $+ といった正規表現の後方参照に対するエイリアスか、

| keyword_alias tGVAR tNTH_REF

$1 のような正規表現の後方参照に対するエイリアスか、

(※)これは yyerror です。$1 などに別名をつけることはできない様です。へえ、知らなかった。

| keyword_undef undef_list

undef 文か、

(※)中身はなんと $$ = $2; だけ。undef_list として扱われた段階で「そういう」ノードだと扱われるため、わざわざここで NEW_UNDEF とかする必要はないようです。ほほう。

| stmt modifier_if expr_value | stmt modifier_unless expr_value
| stmt modifier_while expr_value | stmt modifier_until expr_value

if, unless, while, until といった条件を取る修飾子を伴った文か、

| stmt modifier_rescue stmt

rescue 修飾子を伴った文か、

| keyword_END ‘{‘ compstmt ‘}’

END {} 構文か、

(※)ここで、BEGIN と違い END はどこにでも置けることが分かります。また、中身を見ても NODE_POSTEXE とかいうノードに普通に変換されるだけなので、あくまで実行時にここを通過した時点でブロックが登録されることが分かります。さらに、in_def || in_single (この辺は後述)で “END in method; use at_exit” なんて警告が出ます。さてそうすると、END 構文が存在する意味は(昔との互換性以外では)何があるのでしょう?るりまを見ても「最初の一回のみ有効」と言う部分しか at_exit との違いが分かりませんでした。

※ TODO

まだ続きますが、fitem が何なのか気になるのでここは一旦後回し。

項目名

in 親集合

: 構成要素

コピペ用のテンプレ。

広告
No comments yet

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。