狠狠撸

狠狠撸Share a Scribd company logo
何となく勉強した
気分になれる
パーサ入門
2015/02/13?第2回パーサ勉強会
株式会社達人出版会/一般社団法人日本Rubyの会
高橋征義 @takahashim
自己紹介
?高橋征義
?Re:VIEWコミッタ
?北大工学部情報工学科言語情報工学講座出身
?もう少し真面目に勉強していれば…
?株式会社達人出版会代表取締役
?ITエンジニア向け電子書籍の制作?販売
?一般社団法人日本Rubyの会代表理事
本日のお题
Parser
閑話休題:読み方
?パーサ
?パーサー
?パーザー
?/pɑrs?r/
本日の流れ
?パーサとは何か: 2015年版
?パーサと文法
?正規文法と文脈自由文法
?PEGとPackrat Parser
【 注意】だいぶざっくり
した話も含むので,あまり
真に受けないで下さい。
(期末試験なら追試かもしれないレベル)
現代的な
パーサの定義
文字列から
ツリー(AST)を
作るもの
「現代的」とは
?「最近流行りの」くらいの意味
?伝統的には字句解析?構文解析?意味解析に分
かれて、ツリーを作らない場合も多い
?最近は字句解析と構文解析が一体化し両方パー
サが頑張る場合も多い(YACCとかは別)
?今の計算機ならツリーを作る時間的?空間的コ
ストは大きくない(昔は大きかった)
?空前のASTブーム
ASTとは
?Abstract Syntax Tree、抽象構文木
?木: いわゆるツリー、数学用語
?ノードとノードを線(edge)でつないだもの
で、ループしてない(ループがあるものはグラフと呼ぶ)
?抽象: 具体的ではない
?空白を落としたり、文末のセミコロンは落と
したりしている場合もある
?元のソースの行数や文字数も落ちていること
がある
ASTの例
Doc
Header
Text
Paragraph Image Paragr
はじめに
Text
本書は
パーサ
Inline
Bold
Text
Text
を…
Src
img1.jpg
※いろいろ端折ってます
空前のASTブーム
?既存言語をいじって俺言語を作りたい
?最適化、構文の好みなど
?実際には俺言語を既存言語に変換して実行する
?以前のハックは文字列変換やバイトコード変換が
多かった(※個人の主観です)
?最近はASTで変換するのが流行
?JavaScript方面のAltJSブームのせい?
?2015年ならとりあえずASTは作る方向で
字句解析と構文解析
?欧米語っぽい概念
?日本語(膠着語)だといろいろ辛さがあふれる
“I have a pen”
I have a pen
文
主語 動詞 名詞句
I have a pen
↓字句解析(文字列→単語列)
↓構文解析(単語列→ツリー)
文法とパーサ
?文法とパーサは(混同しがちだけど)別物
?文法: どういう順番に要素が並ぶかを表した文法
規則(ルール)の集まり
?どう実行するかは決めてない
?パーサ: 文法を元に実際に文字列をバラしていく
プログラム
?日本語でいうと「構文解析器」
文法の例
?MicroMark (Markdownのサブセット)
?見出し (「#」で始まる行、#の数がレベルに
なる)
?パラグラフ(空行で区切られた文字列。改行
は無視する)
MicroMark文法
start = doc
doc = block+
block = headline / blankline / paragraph
headline = "#"+ " " textline
paragraph = textline+ blankline
textline = !headline inline+ "n"
inline = char
char = [^n]
blankline = "n"
MicroMark文法
開始 = 文書
文書 = ブロック+
ブロック = 見出し / 改行 / パラグラフ
見出し = "#"+ " " テキスト行
パラグラフ = テキスト行+ 改行
テキスト行 = !見出し インライン+ "n"
インライン = 文字
文字 = [^n]
改行 = "n"
PEG.js
?JavaScriptのPEGライブラリ
?オンラインで試せるので便利
http://pegjs.org/
MicroMark for PEG.js
start = doc
doc = block:block+ { return "<body>"+block.join("")+"</body>"; }
block = headline / blankline / paragraph
headline = pre?x:"#"+ " " textline:textline
{ return "<h" + pre?x.length + ">" + textline + "</h" + pre?x.length+">"; }
paragraph = textline:textline+ blankline { return "<p>" + textline.join("") +"</p>"; }
textline = !headline inline:inline+ "n" { return inline.join(""); }
inline = char
char = ch:[^n] { return ch; }
blankline = "n" { return ""; }
https://gist.github.com/takahashim/150faec504955ef7b0f7
これをhttp://pegjs.org/onlineの
左側に貼れば試せます。
何となく勉强した気分になれるパーサ入门
文法と言語
?ある文法規則に適合する( その文法のパーサ
でパースできる)文の集合全体を「言語」と呼
ぶ
文法
MicroMark
(micromark_syn.txt)
パーサジェネレータ PEG.js
パーサ
PEG.js +
micromark_syn.txt
言語
MicroMarkで表現できる
文書全て
文法と言語
?文法規則によって言語の複雑さが決まる
?弱い文法だと複雑な言語は表現できない
?文法の古典的な分類:チョムスキー階層
チョムスキー is 誰
?言語学に数学を持ち込
んで熱狂と阿鼻叫喚を
巻き起こした20世紀を
代表する言語学者(存
命、昨年来日した)
?10年単位で基本理論の
変革が行われてみんな
大変だった
?政治的活動も重要だそ
うですが話すと長そう
なので割愛
http://en.wikipedia.org/wiki/Noam_Chomsky
チョムスキー is 誰http://www.max.hi-ho.ne.jp/miyairi/nihongobunpou02.html
←チョムスキー
以前の文法
チョムスキー
以後の文法?→
※ちょっと誇張気味ですが、こ
れぐらいインパクトがあったら
しい
http://ocw.kyushu-u.ac.jp/0005/0003/lecture/3_1.pdf
チョムスキー階層
正規文法
文脈自由文法
文脈依存文法
(帰納的に可算な( 計算可能な)文法)
制約
大
小
チョムスキー階層
?普通のプログラマが知っておくべきほぼ唯一の
チョムスキーの仕事
?他の仕事は各自の趣味に応じてどうぞ
?(言語学的な仕事とはあんまり関係ない)
?文法の複雑さを4つ(3+1)に分類
チョムスキー階層
正規文法
文脈自由文法
文脈依存文法
(帰納的に可算な( 計算可能な)文法)
制約
大
小
文脈自由文法
?CFG, context free grammar
?普通のBNFで表現できる文法
?BNFはCFGの記法の一つ、らしい
?プログラミング言語、マークアップ言語とかは
だいたいコレ(+α)
?+αがあると文脈依存文法の範囲になる
?-αのことも多い
CFGの例
start = exp
exp = primary + exp
? primary - exp
? primary
primary = integer
? ( exp )
integer = [0-9]+
start = exp
exp = exp + exp
? exp - exp
? ( exp )
? primary
primary = integer
integer = [0-9]+
PEGやLLで
使える文法
PEGやLLでは
使えない文法
左再帰
?左辺と同じ記号が右辺の左側にあるやつ
?左再帰なルール
?「式 ← 式 + 数値」
?「式 ← 式 + 式」
?LLやPEGでは左再帰ルールはNG
?「式 ← 数値 + 式」(右再帰)ならOK
?左再帰があったら頑張って書き直す
正規文法
?Regular Grammar
?いわゆる正規表現というのはこれに由来
?「正規」という訳語は良くないのでは…とい
う意見もある
?入れ子が表現できない程度の記述力しかないの
で、プログラミング言語とかには不向き
?伝統的には字句解析に使われていたりする
正規文法とパーサ
?ホットなネタはあんまりなさそう
?効率の改良の話ならある
?最近のプログラミング言語の正規表現は正規
文法の範囲を越える謎機能が付いているので
そのパーサの作り方とかはある
?【 注意】いわゆる正規表現を駆使してパーサを
作る話とは全く関係ないです(上記の通りそも
そも正規文法ではない場合もあるし)
CFGとパーサ
?こちらは21世紀になっても熱い
?古典的な話題:LL, LR(LALR, GLR等)
?YACCはLALR(1)パーサを作るパーサジェネ
レータ
?21世紀の話題:PEG、LL(*)
?LL(*)はANTLRが頑張ってるそうです
?もちろん21世紀でもLLやLALRも使われてい
ます
パーサと時間効率
?実行時間の効率性を表すにはO(オー、オーダ
ー)を使う
?O(n)は入力文字数に比例
?O(n?)は入力文字数の2乗に比例
?文字数が10倍になると100倍時間がかかる
?文字数が100倍になると10000倍に…
?できればO(n)のアルゴリズムを使いたい
?素朴すぎるパーサはO(n?)になったりO(n?)になっ
たりする(場合もある)
20世紀のパーサ
?「YACC」派と「手書きでLL」派が主流?
?YACC(LALRパーサジェネレータ)
?速い(O(n) で動く)
?メモリ消費も少ない
?手書きするよりは正確(なはず)
?LL(再帰下降パーサ)
?速い(O(n) で動く)
?人間が読みやすい(LALRはでかい表を作るの
で人間が読んでデバッグするのは困難)
21世紀のパーサ
?メモリも計算機速度も潤沢になったので気にせ
ず使いたい
?PEG(+ Packrat Parser)
?開発速度を高めたい
?ANTLRworks
ANTLRWorks
http://www.antlr3.org/works/screenshots/debugger.png
PEG
?PEG(Parser Expression Grammar)は文法
?素朴にパーサを作ることもできるが、遅い
?現実的にはPackrat Parserを使う
?CFGに似ているが、曖昧性がない
?CFGでは「AまたはB」になっているものが、
PEGでは「AでなければB」になる(Bかもし
れないけどAならAに決めておいて、ダメなら
バックトラック(後戻りしてやり直し)する)
PEGの例
start = exp
exp = primary + exp
/ primary - exp
/ primary ←これが先頭に来るとNG
primary = integer
/ ( exp )
integer = [0-9]+
Packrat Parser
?PEGで書かれた文法を理解して構文解析をする
パーサ
?バックトラックせずにメモ化を使うことで、速
度効率を高める(翱(苍)になる)
?メモリ効率は悪い
?遅延評価のある関数型言語だとメモ化を意識し
なくてすむ(らしい)
?関数型じゃなくてもメモ化するコードを書け
ば良いので問題ない
PEGとCFG
?能力的にはCFGよりも弱いらしい
?PEGで表現できないCFGがある
?が、現実的にはCFG並みの能力があると思っ
て問題なさそう
?構文規則の並び順によって解析結果が変わるの
で、順番には要注意
まとめ
?パーサは文字列からASTを作ったりする
?文法とパーサはちょっと違う
?ふつうの言語は文脈自由文法 α
?LLとかLALRは詳しい本やサイトを参考にして
ください
?21世紀は手書きLLとYACC以外にもPEGとかの
選択肢が増えた
?Packrat Parserを使えばPEGは 翱(苍)になる

More Related Content

何となく勉强した気分になれるパーサ入门