raccのparser.rbとcparseの実装上の違い

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件のコメント

  1. ピンバック: racc 1.3のcparseで無限ループ発生 « northern-cross blog

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です