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
サーバサイドエンジニアとして入社したら 全く気付かない間にUnityエンジニアになって コンパ...
Search
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
Webとヘルスデータ
yukukotani
0
190
Tab5をRubyで動くパソコンにする
kishima
1
240
コスト最適化の「めんどくさい」を AWS FinOps Agent でチョット楽にする
classmethod_kaz
0
240
スクラムで身についていた動き方を、XPで捉え直してみた
codmoninc
PRO
1
250
薬剤師(ドメインエキスパート)と一緒に育てる薬局向けAIアシスタント
kakehashi
PRO
2
110
PdMをやめて、 "プロダクトビルダー"という 働き方に変えました / PdM to Product Builder
shikichee
2
720
Nav2、Nav3 ... はたまた自作?〜 作って理解する Nav3 の設計意図 〜 / Nav2, Nav3 ... or Build Your Own? — Understanding Nav3's design intent by building it from scratch
yanzm
0
250
Genie Code ワークショップ 基礎編 / Genie-Code-Workshop-fundamental
databricksjapan
PRO
0
370
データエンジニアリングワークショップ:Auto LoaderとSparkで学ぶデータパイプライン構築
databricksjapan
PRO
0
190
AI 駆動 Terraform 開発/SRE_BizReach_MIXI_2
visional_engineering_and_design
2
1.7k
GuardDuty 検知対応を DevOps Agent で効率化しようとしている話 / GuardDuty Investigations with DevOps Agent
masahirokawahara
1
320
Kiro Crewしか勝たん!?
miu_crescent
PRO
0
180
Featured
See All Featured
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
250
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Agile that works and the tools we love
rasmusluckow
331
22k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
My Coaching Mixtape
mlcsv
0
310
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
We Have a Design System, Now What?
morganepeng
55
8.3k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Six Lessons from altMBA
skipperchong
29
4.5k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
490
How to train your dragon (web standard)
notwaldorf
97
6.8k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
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)