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
サーバー常駐型の 簡易障害調査AI エージェントを作ってみた話
masayoshi
0
170
AI for Science時代を切り開く、政府の次世代HPC戦略の展望
gpuunite_official
0
260
三人寄ればチューリング完全
puhitaku
6
3.2k
Introduction to Sansan Meishi Maker Development Engineer
sansan33
PRO
0
460
RelayerというPHPのフレームワークを作った
polidog
PRO
0
140
紙 to デジタル
ichien178
0
150
VLMで2.3万枚のPyCon JP写真を検索!
terapyon
1
570
1.5時間を無駄にして学んだwsl2におけるaptとsnapの選択と仕組み
yosaka0123
0
450
Kiro Crew で始める マルチエージェント開発
miu_crescent
PRO
0
180
「面白い!」を信じ抜け。激動の時代を貫く、オンリーワン・エンジニアの条件
kizawa2020
0
250
The Django UUID Story - DjangoCon US 2026
pauloxnet
0
260
巨大気象データと戦う ― サロゲートモデル学習を高速化する圧縮技術
gpuunite_official
0
280
Featured
See All Featured
Six Lessons from altMBA
skipperchong
29
4.5k
The browser strikes back
jonoalderson
0
1.5k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
2
3.8k
Building the Perfect Custom Keyboard
takai
2
850
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Prompt Engineering for Job Search
mfonobong
0
420
Facilitating Awesome Meetings
lara
57
7.1k
Speed Design
sergeychernyshev
33
2k
Fireside Chat
paigeccino
42
4k
The Pragmatic Product Professional
lauravandoore
37
7.4k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
430
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
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)