Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
雰囲気でコンパイラを書いたら大変だった話
Search
MiZUP
October 20, 2017
Programming
2
2.1k
雰囲気でコンパイラを書いたら大変だった話
2017年10月20日に発表した社内勉強会の資料です
MiZUP
October 20, 2017
Tweet
Share
More Decks by MiZUP
See All by MiZUP
RUBYでアッカーマン関数の計算をがんばる方法 / How to write ackermann function in ruby
mizukmb
0
1.3k
新卒がオンプレミスとクラウドコンピューティングを触って感じたこと
mizukmb
0
870
Other Decks in Programming
See All in Programming
Why Jakarta EE Matters to Spring - and Vice Versa
ivargrimstad
0
1.1k
Kaigi on Rails 2024 〜運営の裏側〜
krpk1900
1
210
OSSで起業してもうすぐ10年 / Open Source Conference 2024 Shimane
furukawayasuto
0
100
CSC509 Lecture 13
javiergs
PRO
0
100
Compose 1.7のTextFieldはPOBox Plusで日本語変換できない
tomoya0x00
0
190
Less waste, more joy, and a lot more green: How Quarkus makes Java better
hollycummins
0
100
as(型アサーション)を書く前にできること
marokanatani
10
2.7k
Streams APIとTCPフロー制御 / Web Streams API and TCP flow control
tasshi
2
350
役立つログに取り組もう
irof
28
9.6k
見せてあげますよ、「本物のLaravel批判」ってやつを。
77web
7
7.7k
CSC509 Lecture 12
javiergs
PRO
0
160
距離関数を極める! / SESSIONS 2024
gam0022
0
280
Featured
See All Featured
Side Projects
sachag
452
42k
Happy Clients
brianwarren
98
6.7k
Raft: Consensus for Rubyists
vanstee
136
6.6k
Become a Pro
speakerdeck
PRO
25
5k
RailsConf 2023
tenderlove
29
900
Understanding Cognitive Biases in Performance Measurement
bluesmoon
26
1.4k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.3k
How to train your dragon (web standard)
notwaldorf
88
5.7k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
329
21k
Optimising Largest Contentful Paint
csswizardry
33
2.9k
Six Lessons from altMBA
skipperchong
27
3.5k
Transcript
雰囲気でコンパイラを書いたら 大変だった話 @mizukmb 20, October
コンパイラとは ある規則に沿って書かれた文字列を機械可読可能なコードに翻訳すること var foo = 100; ~~~~~~ ソースコード コンパイル オブジェクト
コード
モチベーション - コンパイラ書いたことがない - コンピュータサイエンスをあまり勉強したことがない - プログラマとして、やっておくべきか… - 枯れた技術の習得 -
この辺の記事を読んで影響を受けている - [二週間で簡単なインタープリタ言語を実装してみた (日記) - プログラムモグモ グ](http://itchyny.hatenablog.com/entry/2017/01/23/100000) - [Cコンパイラをスクラッチから開発してみた(日記) - Qiita](https://qiita.com/ruiu/items/4d471216b71ab48d8b74)
コンパイラの動き
コンパイラの動き 原始プロ グラム 読み込み 字句解析 構文解析 中間語作 成 最適化 コード生成
目的プロ グラム
今回実装した部分 原始プロ グラム 読み込み 字句解析 構文解析 中間語作 成 最適化 コード生成
目的プロ グラム
今回実装した部分 原始プロ グラム 読み込み 字句解析 構文解析 中間語作 成 最適化 コード生成
目的プロ グラム 中間語から Ruby コードを呼び出して直接実行
成果物 mizukmb/my-compiler mizukmb/train-make-ruby-by-ruby - 読み込み〜字句解析〜構文解析〜中間語生成 まで - ↑中間語から Ruby コードを発行し、実行する
- 書籍 『RubyでつくるRuby ゼロから学びなおすプログラミ ング言語入門』 の写経
各処理の詳細
字句解析 規則に沿って並んだ文字や数字の列を意味のある単位に分解していく 空白・インデント・改行などはいい感じに削除する(意味を持たないので) `x = 1 + 10` x …
変数 = … 演算子 1 … 数値リテラル + … 演算子 10 … 数値リテラル
字句解析 - How? 決められた規則を定義する → 決定性有限オートマトンで表現 q2 q0 q1 ‘
英数字 ‘
字句解析 - How? 決められた規則を定義する → 決定性有限オートマトンで表現 →正規表現で書ける `/\A\w*\z/` q2 q0
q1 ‘ 英数字 ‘
字句解析 - How? 種類が定まったらラベルを付けたペアとしてトークンにする ‘foo’ -> (字句解析) -> [‘lit’, ‘foo’]
構文解析 字句解析したトークン列を構文木に変換する [ [ ‘lit’, 1 ], [ ‘op_plus, ‘+’
], [ ‘lit’, 2 ] ] ‘+’ 2 1
構文解析 - How? 解析手法はいっぱいある - 再帰的下向き構文解析 - 上向き構文解析 - LR
構文解析
構文解析 - How? 解析手法はいっぱいある - 再帰的下向き構文解析 ←今回はこれを採用 - 上向き構文解析 -
LR 構文解析
再帰的下向き構文解析 - 解析木を上(根)から下向き(葉に向かって)に作り上げていく - 比較的わかりやすいプログラムが書ける - バックトラック、左再帰性といった問題がある + * 5
[ [ ‘lit’, 5 ], [ ‘op_multi, ‘+’ ], [ ‘lit’, 10 ], [ ‘op_multi’, ‘*’ ], ... ]
再帰的下向き構文解析 - 左再帰性 文法を表現する際、即座に自分自身を呼び出して、無限再帰に陥る問題 ``` E -> E + T
E() { E(); // <- 無限再帰が発生 ‘+’; T(); } ```
再帰的下向き構文解析 - 左再帰性 - 解決策 自分自身を後で読み込むように書き換えれば良い ``` E -> TE’
E’ -> +TE’ | ε T -> i (任意の数列) ```
再帰的下向き構文解析 - バックトラック `A -> α | β` のような「または」という規則があるとき、どちらで解析すればよいか 判断できず、解析に失敗して後戻りが発生してしまうこと。
→解析効率が悪い
再帰的下向き構文解析 - バックトラック - 解決策 解析するトークンのk個先のトークンを先読みして、文法の曖昧さを除去してい く → LL (k)
文法の変換
LL (1) 文法 1個先のトークンを先読みして文法が一意に定まるようになる - First 集合 … 先頭に現れる終端記号の集合 -
Follow 集合 … ある非終端記号の直後に現れる終端記号の集合 - Director 集合 … ある非終端記号を特定の終端記号に展開してよいか判 断できる終端記号の集合 - First 集合と Follow 集合から求まる LL (1) かは全ての Director 集合の積集合が空集合であれば良い
中間語〜コード実行 構文解析済みの中間語を上から順番に実行するだけ 詳しくは書籍『RubyでつくるRuby ゼロから学びなおすプログラミング言語入門 』
製作日記
製作日記 期間: 9月24日〜10月19日
9月24日〜10月10日 様々な誘惑[^1] に負けつつも、書籍『RubyでつくるRuby ゼロから学びなおす プログラミング言語入門』のコードを写経し続ける mizukmb/train-make-ruby-by-ruby [^1]: Splatoon 2, beatmania
IIDX
10月11日 コンパイラを作り始める とりあえず数値リテラルを字句解析できるようにした mizukmb/my-compiler
10月12日 インデントやスペースを使いたかったので大丈夫なように実装 全角スペースも使える。便利ではないと思う mizukmb/my-compiler
10月14日 四則演算ができるように、 + - * / % 演算子を字句解析できるようにした ``` ”1
+ 2" => [[“lit", 1], ["operator_plus", "+"], ["lit", 2]] ``` mizukmb/my-compiler
10月15日 最低限の計算はできるようになったので、数値リテラルと四則演算の構文解析 を実装。四則演算のできる小さなプログラミング言語の完成 ``` ”1 + 2" (字句解析) => [[“lit",
1], ["operator_plus", "+"], ["lit", 2]] (構文解析) => ["+", ["lit", 1], ["lit", 2]] ``` mizukmb/my-compiler
10月16日 数値リテラルと演算子の間にスペースが無くても字句解析できるようにバグ修 正 ``` - 1 + 2 # =>
[["lit", 1], ["operator_plus", "+"], ["lit", 2]] - 1+2 # => [["lit", 1], ["operator_plus", "+"], ["lit", 2]] ``` mizukmb/my-compiler
10月17日 比較演算子 < <= == >= > != の実装 四則演算のときと実装はあまり変わらず。順序だけ気にしていればおk
発表までに FizzBuzz できそう…みたいな叶わぬ夢を見だす mizukmb/my-compiler
10月18日 複文を実装する。字句解析で改行(\n)もトークンとして扱うようにして複文を解 析できるようにした。 ``` “1 + 2\n3 - 4” (字句解析)
=> [[“lit", 1], ["operator_plus", "+"], ["lit", 2], ["newline", "\\n"], ["lit", 3], ["operator_minus", "-"], ["lit", 4]] (構文解析) => [“stmts", ["+", ["lit", 1], ["lit", 2]], ["-", ["lit", 3], ["lit", 4]]] ``` mizukmb/my-compiler
10月18日 - 続き 複文の実装を泥臭くやりすぎて、新しい文の追加や、リファクタリングがやりづ らくなった LL (1) ではない気がする… mizukmb/my-compiler
10月18日 - 続き if 文を実装する。が、前述の通り、複文が動かなくなったり、トークンの読み込 みがおかしくなってすごい悩んだ ``` if (10 >
9 ) { 5 * 100 } ``` mizukmb/my-compiler
10月19日 else を実装しようと試みるが、複文の(ry 実装を断念した。 文字列リテラルを忘れていたので実装 mizukmb/my-compiler
最終成果
最終成果 実装した - 数値、文字列リテラル - 四則演算、比較演算子 - if 文 -
複数式の評価
実演
感想 0からコンパイラ作るのは難しい。けど、オリジナルのプログラミング言語が 様々なプロセスを経て実行されると嬉しい。 一気に実装するのではなく、小さなパーツから少しづつ組み立てていくインクリ メンタルな開発は良かった。コンパイラが少しずつ言葉を覚えて育っていく様子 が見られるのは楽しい
感想(つらい) 理論を十分理解しないまま実装したので途中からコードの設計に無理が出てき た プログラミング言語として実用的ではない。せめて変数は欲しかった
None