Rubyスクリプトの字句解析

Rubyを触っていく中で、「Rubyはどんな過程を経てコードが理解されて処理されるんだろう」と思って書籍を読んでそのアウトプットをしていこうとおもいます。

## 処理の流れ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485775/7e628acd-0c13-02c6-d318-5b5d0e01ec00.png)

全体的な処理の流れはこのような感じです。まずは全体の流れを抑えることが大事になりそうです。
この記事では、字句解析と構文解析までを書こうとおもいます。

## 字句解析
以下のコードを```simple.rb```ファイルに記述し、実行してみます。
```
10.times do |n|
  p n
end

# =>0
1
2
3
4
5
6
7
8
9
```
まず、この文字列に遭遇すると、Rubyは**字句解析**を行います。
>字句解析とは、自然言語の文やプログラミング言語のソースコードなどの文字列を解析して、後半の狭義の構文解析で最小単位（終端記号）となっている「トークン」（字句）の並びを得る手続きである。
wikipediaより

つまり、字句解析しているコードにどんな文字列があって、どんな数字があるのかをという情報を得ることを字句解析というんです。
最初のこの文字列
```
10.times do |n|
```
最初に1から見ていき、次に0を見つけます。その次に「.」が出てきます。このピリオド文字は、小数点のピリオドか字句の区切りの2つの可能性があります。
>字句（じく）とは、プログラミング言語などにおいてソースコードに出現する文字列の中で意味を持つ最小単位で、トークンとも言う。

ピリオド文字の次にｔが出てくるので、ピリオド文字は小数点のピリオドではなく、字句の区切りの役割を持つピリオドであることが分かります。
つまり10は整数のトークンをもつ```tINTEGER```を持つということになります。
つぎにtimesは文字列であるため、```tINDENTIFER```となります。このように続けていくと以下の画像のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485775/965d216e-62e3-e3cc-ef12-dbec543cea2e.png)

トークンの一覧は[こちらのソースコード](https://github.com/ruby/ruby/blob/d92f09a5eea009fa28cd046e9d0eb698e3d94c5c/parse.y#L1156)を参照してみてください

## 構文解析
字句解析がされた後に、**構文解析**が行われます。
構文解析とはRubyが分かるように、トークン列をグループ化する作業のことです。
Rubyは**パーサジェネレータ**を使ってコードを理解しています。RubyはBisonというパーサジェネレータを使っています。
文法規則が記されている```parse.yファイル```をもとにパーサコード(```parse.cファイル```)が作成されます。
実際に、文法規則を見ていきましょう
```
program: top_compstmt
top_compstmt: top_stmts opt_terms
opt_terms: ... | top_stmt | ...
top_stmt: stmt | ...
stmt: ... | expr
expr: ... | arg
arg: ... | primary
primary: ... | method_call brace_block | ...
```
最後に出てくる```primary```の子規則にあるのが、```method_call```と```brace_block```です。
```method_call```をまずは見ていきましょう。
ちなみにソースコードは[こちら](https://github.com/ruby/ruby/blob/b048fd572af71c1015ac6701f718fbcf6dca2fb2/parse.y#L3831)を見てみてください。
```
#=> rubyコード
10.times


#=> 文法規則
method_call: ... | primary_value call_op operation2 opt_paren_args |
```
## method_call
### primary_value
まず、```primary_value```から見ていきましょう
```
primary_value	: primary
primary		: literal #=>他にもあります。Stringなど
literal		: numeric
```
つまり、今回でいえば、```primary_value```には数値が入ります。つまり、10が入ります。

### call_op
つぎにcall_opです。
```
call_op 	: '.'
#=> 他にもあります
```
つまりcall_opはドットが入ります。

### operation2
つぎにoperation2を見ていきます。
```
operation2	: tIDENTIFIER
```
つまり、operations2には識別子が入ります。
### opt_paren_args
```
opt_paren_args	: none
```
今回でいえば```none```になります。他にもありますけどね。

## brace_block
先ほどのセクションでは```10.times```まで見てきましたが、ブロックを見ていきますので識別子が変わります。
それが```brace_block```です。それを見ていきます
ソースコードは[こちら](https://github.com/ruby/ruby/blob/b048fd572af71c1015ac6701f718fbcf6dca2fb2/parse.y#L3906)になります
```
brace_block	:k_do do_body k_end #=> 他にもあります
```
### k_do
```
k_do		: keyword_do
```

### do_body
```
do_body	   :opt_block_param bodystmt
```

### k_end
```
k_end		: keyword_end
```
上記のセクションのように探していくと答えが見つかります。このセクションでは省略させていただきます。答えだけ書くと
・```keyword_do```は予約語である```do```に一致する
・```opt_block_param```はブロック引数である```|n|```に一致する
・```bodystmt```は```puts n```に一致する
・```keyword_end```は予約語である```end```に一致する

## AST(抽象構文木)
Rubyにはコードを変換したトークン列を表示し、コードをどう解析するかを表すRipperライブラリがあります。それをつかって他のコードも見てみましょう。

```simple.rb
require 'ripper'
require 'pp'
code = <<STR
1 + 2 * 3
STR
puts code
pp Ripper.sexp(code)

```
これを実行すると、
```
[:program,
 [[:binary,
   [:@int, "1", [1, 0]],
   :+,
   [:binary, [:@int, "2", [1, 4]], :*, [:@int, "3", [1, 8]]]]]]
```
これだけだと、分からないと思うので図示してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485775/13465d05-5491-3b0d-909c-69cbc5c76898.png)
これを見ると、出力結果の文字列たちの意味も分かってくると思います。
このアルゴリズムは、最初でみた以下のコード
```
10.times do |n|
  p n
end
```
これでも同じように作れます。
なぜいきなり、ASTの話をしたかというと、字句解析がなされたあとに構文解析が行われます。
その構文解析がASTというデータ構造へと変換されるからなんです。

## 結論
RubyプログラムをRubyがどう理解するのかというと、
1. 字句解析が行われ、トークン列へと変換される
2. 変換されたトークン列は構文解析され、ASTというデータ構造へと変換される

次の章では、ASTに変換されたコードが、どのようにコンパイルされるかを見ていきます

【参考文献】

https://www.amazon.co.jp/Ruby%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF-Ruby-Under-Microscope-Shaughnessy/product-reviews/4274050653/ref=cm_cr_dp_d_show_all_btm?ie=UTF8&reviewerType=all_reviews