せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Ruby】パーサーから見た「a???」が構文エラーとならない理由

 

topic

study about parse.y ...a little.

 
ここの記事を読んでいます。
Rubyソースコード完全解説
パーサーの仕組みが詳しく載っている。
ちょっと難易度が高め!
 

ごめんカッコつけた。。。かなり高め

 
以前「どうしてこれが構文エラーにならないの」問題を考えたことがあったけど、
折角だから、パーサーからも探ってみよう。

なかださんのTweet。


 
無理だよー。。と思うんだけど、見てみよう!

 

そもそもparse.yがない

Ruby200フォルダ下にparse.yがない。
よく分からないけど、githubにコードがあるので、こちらで代用。
ruby/parse.y at trunk · ruby/ruby · GitHub

ここの、parser_yylexがみるべき関数みたい。


 
どこにparse.yがあるのか、なかださんに教えて頂いた。

 
えーどういうことー。
 
ヒントにしたがってyaccの項目を読めば、理解できました。

(記号列だけを見て解析できるようにする)自動化ツールをパーサジェネレータ(parser generator)と言う。
UNIXで一番使われているパーサジェネレータがyaccだ。rubyの パーサも御多分に漏れずこのyaccを使って書かれている。parse.yがその 入力だ。・・・yaccにかけるとCのソースコードができるので、 あとは普段通りそれをコンパイルすればよい。

http://loveruby.net/ja/rhg/book/yacc.html

f:id:sekaiya:20131130204015j:plain
 
つまり、parse.yはコンパイルされてparse.o になっているってこと。
調べてみるとこのファイルはちゃんとあった。
 
Rubyソースコード」には、parse.yが存在している。
「Windows版Rubyバイナリ」をDLしていたから、手元には存在しなかったんだ。
ダウンロード
 
C言語のコンパイルの流れが分かってないからこんな質問しちゃったんだなー。。。

お礼のtweetも済ませて。


 
肝心の中身は。。
 

switch (tok()[0]) {
      case '@': case '$':
        pushback(c);
        break;
      default:
        if ((c == '!' || c == '?') && !peek('=')) {
            tokadd(c);
        }

この箇所で、最初の"?"を識別子としてシフトする。

 

 case '?':
  c = nextc();
  if (!parser_isascii()) {
  }
  else {
      tokadd(c);  #<= (ア)
  }

?の次の文字を取って、
エラーや特殊パターンに当てはまらなかったら(そのまま文字列に)加える。
 
だから、
a???
はa?メソッド(識別子)の、引数「?」です、ということになる。
 
位しか分からなかった。ちょっと貧しい。。
そもそも当たっているのか良く分からない。
 
また再び力がついたら見返してみよう。