Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
サーバサイドエンジニアとして入社したら 全く気付かない間にUnityエンジニアになって コンパ...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
shumon84
December 18, 2019
Technology
1.8k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
サーバサイドエンジニアとして入社したら 全く気付かない間にUnityエンジニアになって コンパイラを作っていた話
shumon84
December 18, 2019
Other Decks in Technology
See All in Technology
コンテナ運用におけるネットワーク・コンテナコストの削減方法/How to Reduce Network and Container Costs in Container Operations
masakiokuda
2
300
CTO Night|NotionのAIエージェントとFDE
kzkhykw1991
0
230
Refining Active Record
shugo
0
170
AIがコードを書く時代に、エンジニアは何で自分の価値を証明するのか / In an era where AI writes code how do engineers prove their value
carta_engineering
3
1.1k
Kiro Crewで「みのるん式」仕事術やってみた
minorun365
PRO
3
740
V8のArray.prototype.flatを最大約20倍速くするまでと、巨大OSSへの大規模コミットの道のり
riyaamemiya
0
310
AI時代のPRレビューにどう向き合うか?
kairim0
1
240
USB PDを使ってスマホを労わりたい
raspython3
0
180
脆弱性診断って、何をしているの? 〜弱点を見つけて、会社の改善につなげるまで〜
keeg
0
930
NDIでApple Vision Proにリアルタイム映像送信
jyouryuusui
0
130
FinOps Agentが生んだ技術負債:コスト自動調査の落とし穴と解消までの道のり
oasis1994liveforever
2
150
「Docker Desktop不要の時代」は 来たのか?
ueponx
0
840
Featured
See All Featured
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
220
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
640
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.4k
How to Talk to Developers About Accessibility
jct
2
580
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
270
The Curious Case for Waylosing
cassininazir
1
570
[RailsConf 2023] Rails as a piece of cake
palkan
59
7.1k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
760
Color Theory Basics | Prateek | Gurzu
gurzu
1
490
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
540
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
800
Transcript
サーバサイドエンジニアとして入社したら 全く気付かないうちにUnityエンジニアになって コンパイラを作っていた話 1 しゅもん(@shumon_84)
自己紹介 2 しゅもん(@shumon_84)
自己紹介 藤田 朱門 (@shumon_84) 株式会社ミクシィ 2019 年度新卒
• デジタルエンターテインメント事業部所属 • 『共闘ことばRPG コトダマン』 のクライアント兼サーバ • 業務では Unity と Java をやっています • 好きな言語は Go • 『Dockerで始めるゲームボーイアドバンス開発入門』 著者 ◦ 技術書典 8 では、新刊で vol.3 を頒布する予定です 3 しゅもん(@shumon_84)
コンパイラを作るまでの経緯 4 しゅもん(@shumon_84)
コンパイラを作るまでの経緯 4月 : サーバサイドエンジニア ( Go ) として新卒配属 ↓
10月 : クライアントエンジニア ( Unity / C# ) に転向して、現在のコトダマンに異動 ↓ 11月 : API が 独自 IDL (インターフェース定義言語) で自動生成されてるけど、コンパイラ貧弱じゃね? ↓ 現在 : コンパイラ自作するぞ 5 しゅもん(@shumon_84)
goyacc について 6 しゅもん(@shumon_84)
goyacc について 文法を食わせると、その文法をパースできるコードを自動生成する「yacc」というツールのGo版。 出力として Go を吐いてくれるパーサジェネレータ 元々 Go
のコンパイラを作るのに使用されていたため、Go1.7までは go tool に標準で入っていた (今のコンパイラは goyacc を使っていない) → 詳しくはドキュメント参照 golang.org/x/tools/cmd/goyacc 7 しゅもん(@shumon_84)
goyacc について ただし goyacc は、あくまでパーサ(構文解析器)を作るだけなので、字句解析器は別途必要 字句解析器は、これまたGoのコンパイラに使われている text/scanner を使えば簡単に作れる
goyacc と text/scanner を使えば、コンパイラ作りのしんどい部分を大幅にスキップできる 8 しゅもん(@shumon_84)
goyacc について goyacc に文法を教えるには、バッカス・ナウア記法という「文法を書くための言語」を使う。 - <文> ::= <宣言> |
<式> ';' - <宣言> ::= <型> <文字列> ';' | <型> <文字列> '=' <式> ';' - <型> ::= <文字列> | <型> '[' ']' | '*' <型> - <式> ::= <数> | <式> <演算子> <式> こんな感じで <文法X> ::= Xの定義1 | Xの定義2 | ...... と書くだけ。多分フィーリングで書ける。 よく言語仕様書とかで、見かけるやつなので馴染み深い人もいるはず。 9 しゅもん(@shumon_84)
goyacc について 具体的な goyacc と text/scanner の使い方については、時間の関係で割愛します 簡単にオレオレ言語の抽象構文木が作れておもしろいので、よかったら一度やってみてください
公式のサンプルプロジェクト が参考になります 10 しゅもん(@shumon_84)
独自 IDL について 11 しゅもん(@shumon_84)
独自 IDL について 独自 IDL と言っても、それほど独特な文法ではない。 • *.str :
型を記述するファイル • *.act : RPCのインターフェースを記述するファイル 12 しゅもん(@shumon_84)
構文解析器を作る 13 しゅもん(@shumon_84)
構文解析器を作る 1. BNF ( バッカス・ナウア記法 ) で *.str と *.act
の文法を定義する 2. text/scanner を使って、 goyacc に対応した独自 IDL 用の字句解析器を作る 3. 抽象構文木のノードになる型を作る 4. parser.yにBNFを書く 5. parser.yに各定義と各ノード型の紐付けを書く 6. parser.y にマッチした定義と対応する型に定義を割り当て、ノードにする処理を書く 7. goyacc で parser.y から parser.go を生成 あとは parser.go に生成された yyParse() という関数に字句解析器を渡すと、抽象構文木を作ってくれる 14 しゅもん(@shumon_84)
構文解析器を作る 構文解析器完成! と思いきや、まだまだ完成ではない。 この構文解析器を使って本物の IDL をパースすると、なにやらエラーが出た 15 しゅもん(@shumon_84)
構文解析器を作る エラーメッセージが貧弱すぎて使い物にならない。 goyacc の生成物に詳細エラー出力オプションも一応存在するが、文面がユーザフレンドリーでない。 せめてファイル名とファイルの行数くらいは出したい。できれば文法をどう間違えたのかも教えてほしい。 まずは自動生成部分 (
yyParse() ) からエラーハンドリングを、外だししていくところから始める 16 しゅもん(@shumon_84)
構文解析器を作る goyacc 生成のパーサの起点になる yyParse() のインターフェースはこんな感じ。 パースに成功したとき 0 を返し、失敗したときは 1
を返す。( C 言語っぽい ) yyParse() は自動生成なので内部エラーを error として返すのは難しい。 17 しゅもん(@shumon_84)
構文解析器を作る エラー発生時は yyLexer.Error() が呼ばれるので、現状はそこでエラーを吐いて os.Exit(1) している。 自分でいじれるのは実質 yyLexer.Error() しかないので、ここから
yyParse の外まで error を流したい。 → panic-recover を使って解決した 18 しゅもん(@shumon_84)
構文解析器を作る yyParse() を Parse() でラップする → lexer.Error() で panic()
を投げるようにする → yyParse() の外まで error が流れてくる → yyParse() をラップした関数で recover() する → recover() した error をラップ関数の外に渡す 19 しゅもん(@shumon_84)
構文解析器を作る このアプローチを取ることで、 • Parse()だけを公開する形でparse package の切り出しが容易になった • 字句解析器を完全に隠蔽できるようになった
• 第1返り値に抽象構文木、第二返り値に error を返す関数になり、Goらしく扱えるようになった 一応、 panic-recover を積極的に使うのは Go のプログラムではアンチパターンとされているけど、 ジャンプが自動生成されたコードの中に閉じていて、人間がメンテする部分のコードからは、 隠蔽されているので許して欲しい 20 しゅもん(@shumon_84)
構文解析器を作る これで error を外に運ぶ仕組みが出来たので、次はエラーメッセージに行数などのメタ情報を埋め込む。 lexer は text/scanner の scanner.Scanner
をコンポジットし、 scanner.Scanner は scanner.Position をコンポジットしているので、 lexer からも Scanner や Position が見えることを利用して、 エラー発生時に読んでいたトークンや、そのトークンがあった行数と桁数をエラーメッセージに付け加える 21 しゅもん(@shumon_84)
構文解析器を作る もう一度実行してみる。 行数などが分かるようになってエラーを起こしてる箇所のアタリをつけられるようになったが、 まだどういった理由でエラーが発生したのかが不明瞭。 次は文脈に沿ったエラー理由を
error に詰めることを考える。 22 しゅもん(@shumon_84)
構文解析器を作る 例えば「セミコロンが抜けている」という文脈依存エラーを出したいなら、BNFを少し工夫するとよい フィールド定義の正しいBNFは次のように表せる - <フィールド> ::= <型> <文字列>
';' ここで、わざと「間違った文法」をBNFに追加する - <フィールド> ::= <型> <文字列> | <型> <文字列> ';' この 赤い方の定義 にマッチしたとき、セミコロンが抜けている旨を error に詰めると、 文脈依存なエラーメッセージが作れる。 23 しゅもん(@shumon_84)
構文解析器を作る もう一度実行してみる。 劇的にエラーメッセージが親切になった。 13行目の “User owner”の後ろにセミコロンが抜けていることが、
エラーメッセージで一目で分かるようになった。 24 しゅもん(@shumon_84)
まとめ 25 しゅもん(@shumon_84)
まとめ • 【実績解除】業務で自作コンパイラ • goyacc があればパーサを作るのは超簡単 • 分かりやすいエラーメッセージを出すのが異常に難しい
• あらかじめ誤った文法を定義しておくのは制御しやすくて便利 • 1つのファイルから複数のコンパイルエラーを検出できない問題がまだ残ってる • 独自IDL使うのやめたら? ◦ わかる〜、でもフレームワークにがっちり組み込まれてて、独自IDLを切り離すのは難しい 26 しゅもん(@shumon_84)
話し切れなかったこと 27 しゅもん(@shumon_84)
話し切れなかったこと • マルチOS対応のために文字コード変換を挟む話 • 通常コメントとドキュメントコメントで別々に扱う仕組みの話 • リファレンスに存在しない文法が存在した話(partial class,
継承) • 意味解析の話 • 解析結果を中間形式に保存して高速化する話 • テンプレートエンジンでコード生成する話 • 並行処理で出力が散らかるのを防ぐ話 このままだと2時間ぐらい話してしまうので、続きは懇親会で! 28 しゅもん(@shumon_84)