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件の返信