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.2k
雰囲気でコンパイラを書いたら大変だった話
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
42 best practices for Symfony, a decade later
tucksaun
1
180
Keeping it Ruby: Why Your Product Needs a Ruby SDK - RubyWorld 2024
envek
0
180
快速入門可觀測性
blueswen
0
340
HTTP compression in PHP and Symfony apps
dunglas
2
1.7k
Symfony Mapper Component
soyuka
2
730
Асинхронность неизбежна: как мы проектировали сервис уведомлений
lamodatech
0
720
あれやってみてー駆動から成長を加速させる / areyattemite-driven
nashiusagi
1
200
プロダクトの品質に コミットする / Commit to Product Quality
pekepek
2
770
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
170
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
120
たのしいparse.y
ydah
3
120
Scalaから始めるOpenFeature入門 / Scalaわいわい勉強会 #4
arthur1
1
310
Featured
See All Featured
Building Adaptive Systems
keathley
38
2.3k
GraphQLの誤解/rethinking-graphql
sonatard
67
10k
Building Your Own Lightsaber
phodgson
103
6.1k
Optimising Largest Contentful Paint
csswizardry
33
3k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Building Flexible Design Systems
yeseniaperezcruz
327
38k
Fireside Chat
paigeccino
34
3.1k
How to train your dragon (web standard)
notwaldorf
88
5.7k
The Pragmatic Product Professional
lauravandoore
32
6.3k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
5
440
Writing Fast Ruby
sferik
628
61k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
32
2.7k
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