raccのparser.rbとcparseの違いでは、入力に対する振る舞いの違いについてのべました。
その後、両者を比較して、振る舞いが異なる原因となるところを見つけました.
ソースは、ruby 1.8.7のsvnのtrunkの最新版です。
パス: .
URL: http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8
リポジトリのルート: http://svn.ruby-lang.org/repos/ruby
リポジトリ UUID: b2dd03c8-39d4-4d8f-98ff-823fe69b080e
リビジョン: 23875
ノード種別: ディレクトリ
準備中の処理: 特になし
最終変更者: svn
最終変更リビジョン: 23875
最終変更日時: 2009-06-28 05:11:49 +0900 (日, 28 6月 2009)
なお以下から入手したracc 1.4.6でもparser.rbの該当個所は変更されていませんでした.
http://rubyforge.org/projects/racc/
違いはcparse.cの452行目から始まる以下の関数内での処理にあります。
452 static void
453 parse_main(struct cparse_params *v, VALUE tok, VALUE val, int resume)
(略)
(ここに来るまでに、エラー回復モードになっています)
591 /* check if we can shift/reduce error token */
592 D_printf("(err) k1=%ld\n", v->curstate);
593 D_printf("(err) k2=%d (error)\n", ERROR_TOKEN);
594 while (1) {
595 tmp = AREF(v->action_pointer, v->curstate);
596 if (NIL_P(tmp)) goto error_pop;
597 D_puts("(err) pointer[k1] ok");
598
599 i = NUM2LONG(tmp) + ERROR_TOKEN;
600 D_printf("(err) i=%ld\n", i);
601 if (i < 0) goto error_pop;
602
603 act_value = AREF(v->action_table, i);
604 if (NIL_P(act_value)) {
605 D_puts("(err) table[i] == nil");
606 goto error_pop;
607 }
608 act = NUM2LONG(act_value);
609 D_printf("(err) table[i]=%ld\n", act);
610
611 tmp = AREF(v->action_check, i);
612 if (NIL_P(tmp)) {
613 D_puts("(err) check[i] == nil");
614 goto error_pop;
615 }
616 if (NUM2LONG(tmp) != v->curstate) {
617 D_puts("(err) check[i] != k1");
618 goto error_pop;
619 }
620
621 D_puts("(err) found: can handle error token");
622 break;
623
624 error_pop:
625 D_puts("(err) act not found: can't handle error token; pop");
626
627 if (RARRAY(v->state)->len < = 1) {
628 v->retval = Qnil;
629 v->fin = CP_FIN_CANTPOP;
630 return;
631 }
632 POP(v->state);
633 POP(v->vstack);
634 v->curstate = num_to_long(LAST_I(v->state));
635 if (v->debug) {
636 POP(v->tstack);
637 rb_funcall(v->parser, id_d_e_pop,
638 3, v->state, v->tstack, v->vstack);
639 }
640 }
この中で、ラベルerror_popを指定したgoto文がありますが、これに該当する処理がparser.rbには存在しません。
ラベルerror_popでは、エラーとなったトークンにに対するアクションが見つからない場合、そのエラートークンを読み込まなかったことにして(スタックからpopして)います。
parser.rbではこの処理に飛ぶかどうかの判定をするところがありません。
また、判定できるように参照するテーブルなどがつくられているかどうかも、不明です。
#まだそこまで調べれていません。
#今回の調査のきっかけとなったケースでは、はエラートークンに対するアクションが得られるのですが、そのアクションをとると、最終的に無限ループにおちいってしまいました。

“raccのparser.rbとcparseの実装上の違い” への1件の返信