静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文...
DESCRIPTION
静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法. 11M37011 市川 和央 千葉研究室. 言語内 DSL. 言語の中に作った小さな言語 目的に応じて最適な文法の言語を利用 データベースは SQL 風の文法、構文解析は BNF など より細粒度な例 : Map は連想配列、文字列のマッチは正規表現 実現には言語拡張が必要 もとの言語とは異なる字句規則 もとの言語では解析できない構文. 言語内 DSL の例. SQL + ユニットテスト + 正規表現 in Java ( 注 ) 普通の Java では書けない. - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/1.jpg)
静的型付け言語における汎用的なユーザ定義演算子を含む式の構文解析手法
11M37011
市川 和央千葉研究室
![Page 2: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/2.jpg)
言語内 DSL• 言語の中に作った小さな言語
• 目的に応じて最適な文法の言語を利用• データベースは SQL 風の文法、構文解析は BNF など• より細粒度な例 : Map は連想配列、文字列のマッチは正規表現
• 実現には言語拡張が必要• もとの言語とは異なる字句規則• もとの言語では解析できない構文
![Page 3: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/3.jpg)
言語内 DSL の例• SQL + ユニットテスト + 正規表現 in Java
• ( 注 ) 普通の Java では書けない@Testpublic void studentNumberTest() { ResultSet ids = select id from students; for (String id : ids.toList()) { assert id matches [0-9]{2}(B|M|D)[0-9]{5}; }}
SQL
正規表現ユニットテスト
![Page 4: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/4.jpg)
ユーザ定義演算子• 演算子として新しい構文を導入する構文拡張手法
• ユーザ定義二項演算子 : Scala など• mixfix operators: Agda など
• 静的型付け言語では composable• 似た構文を持つ演算子を一緒に使っても安全• 型によるオーバーロードを持つため
• 表現力が弱い• 特定の形式を持つ演算子しか導入できない• 字句レベルの拡張はできない
![Page 5: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/5.jpg)
mixfix operators• infix, prefix, postfix, outfix 演算子の総称
• infix : _ op1 _ op2 _ ... _ opn _• prefix : op1 _ op2 _ ... _ opn _• postfix: _ op1 _ op2 _ ... _ opn
• outfix : op1 _ op2 _ ... _ opn
_ はオペランドに対応 : hole と呼ぶ opi はオペレータに対応 : name part と呼ぶ
SQL のselect _ from _
![Page 6: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/6.jpg)
mixfix operators の限界• infix, prefix, postfix, outfix 以外は表現できない
• 連続するオペランドを含む構文は表現できない• 字句規則は変えられない
• ユーザ定義リテラルは作れない
assert _ _ は mixfix に含まれない
正規表現リテラルとして解析する必要 for (String id : ids.toList()) { assert id matches [0-9]{2}(B|M|D)[0-9]{5}; }
![Page 7: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/7.jpg)
提案 : protean operators• 演算子のパターンは hole と name part の並び
• assert _ _ のような演算子を含む• mixfix operators を包含
• 演算子ごとに異なる字句規則• 正規表現の演算子は正規表現のルールを持つ• ユーザ定義リテラルも表現可能
ナイーブな解析手法では時間がかかりすぎる
![Page 8: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/8.jpg)
提案 : 期待される型を利用した再帰下降構文解析• 字句・構文・型解析器が連携
• 期待される型の情報を構文解析器にフィードバック• 利用する演算子によって字句規則を変える
• 型のあわない演算子は解析に使わない• 期待される型の情報から演算子を特定• 不要な解析パスを枝刈り
• メモ化を利用してバックトラックのコストを最小化• 左再帰を許す packrat parsing を利用
![Page 9: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/9.jpg)
具体例assert id matches [0-9]{2}(B|M|D)[0-9]{5};
void 型を期待 => assert _ _ で解析assert id matches [0-9]{2}(B|M|D)[0-9]{5};
String 型を期待 => String 型の変数assert id matches [0-9]{2}(B|M|D)[0-9]{5};
Matcher 型を期待 => matches _ で解析assert id matches [0-9]{2}(B|M|D)[0-9]{5};
Regex 型を期待 => 正規表現の演算子で解析
![Page 10: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/10.jpg)
解析手順1. 型のわからない部分は通常のルールで解析
• 代入文の左辺など2. 型がわかる部分まで解析したら型解析3. 期待される型を特定4. 期待される型を返す演算子を使って構文解析
• name part は対応するトークンを読み込む字句解析• hole は対応する型を期待する型として再帰的に解析
![Page 11: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/11.jpg)
演算子の解析順序• 同じ型を返す演算子の間には順序関係が必要
• どちらの演算子が special case であるか• if _ then _ より if _ then _ else _ を優先• + と * の間の演算子優先順位とは異なる
• 構文解析器はこの順序に従って解析を試す• 成功するまでバックトラックを繰り返す• 成功した時点で終了
スライド中ではコードの上にある方を優先するものとする
![Page 12: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/12.jpg)
演算子優先順位・結合性• コンパイル時の型の書き換えにより実現
• 優先順位を含む型を作る• 結合性に従って型情報を書き換える_:Int + _:Int :: Int ( 優先順位 2, 左結合 )_:Int * _:Int :: Int ( 優先順位 1, 左結合 )
_:Int2 + _:Int1 :: Int2_:Int1 * _:Int0 :: Int1_:Int2 :: Int_:Int1 :: Int2_:Int0 :: Int1
引数の型
返り値の型
![Page 13: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/13.jpg)
サブタイプ関係• 演算子の追加により実現
• サブタイプをスーパータイプに関連付け• 演算子優先順位を考慮
Int <: Num_:Int + _:Int :: Int ( 優先順位 2, 左結合 )_:Int * _:Int :: Int ( 優先順位 1, 左結合 )
_:Int2 + _:Int1 :: Int2_:Int1 * _:Int0 :: Int1_:Int2 :: Int_:Int1 :: Int2_:Int0 :: Int1
_:Int2 :: Num2_:Int1 :: Num1_:Int0 :: Num0_:Num2 :: Num_:Num1 :: Num2_:Num0 :: Num1
![Page 14: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/14.jpg)
実装 : ProteaJ• Java 1.4 に protean operators を導入した言語
• コンパイラを Java で実装• http://www.csg.ci.i.u-tokyo.ac.jp/~ichikawa/ProteaJ.tar.gz
• 演算子モジュールと呼ばれるモジュール機構を持つ• using 節によりインポートして利用できる• 各モジュールが言語内 DSL を表現
![Page 15: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/15.jpg)
議論 :protean operators の解析の難しさ• 複数の DSL の利用は文法規則の曖昧性を発生させる
• 曖昧性は型チェックで解決する必要• 文法の非決定性も多数発生
• 字句規則の追加は特に曖昧性を発生させやすい• 例 : e には 変数、自然対数の底、正規表現リテラル等の解釈がある• 字句規則は衝突が起こりやすい
![Page 16: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/16.jpg)
ナイーブな解析手法• 字句・構文解析でありうる構文木を全て列挙• それぞれの構文木に対して型チェック
![Page 17: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/17.jpg)
ナイーブな手法の計算量• 構文木の列挙にかかるコストは O(|G|*n3)
• |G| は文法サイズ、 n は入力長• 字句・構文規則の追加は |G| を大きくする• n = 文字数なので、 n3 は非常に大きくなる
• 型チェックすべき構文木の数は爆発しやすい• 多くの部分木に影響する曖昧性があると構文木の数が増えやすい• 字句規則は多くの部分木に影響しやすい
DSL の composability が低い
![Page 18: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/18.jpg)
本手法の計算量• 本手法はほとんどの場合に O(n) で解析可能• 解析コストは通常 |G| に依らない
• 期待される型で演算子を限定するため• 同じ型を返す演算子の個数に比例するが、通常これは十分小さい
• 左再帰を許す packrat parsing は大抵の場合に O(n)• 現実的な文法では O(n) となることが知られている
![Page 19: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/19.jpg)
関連研究 : 構文マクロ• ポピュラーな言語拡張手法の1つ
• Lisp, Template Haskell, Nemerle, Boo, ScalaMacros, ...
• コンパイル時に構文木を書き換える• もとの言語と異なるセマンティクスを与えることができる• 構文規則は変えられない
• composable でない• 同じ構文木に対して複数のマクロを定義すると正しく動作しない
![Page 20: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/20.jpg)
関連研究 : リードマクロ• 強力な言語拡張手法の1つ
• Common Lisp, Template Haskell, Converge, ...
• 特定の構文内では字句・構文解析器を切り替える• 字句・構文規則は自由• 特殊な構文を必要とする
• composable でない• リードマクロ中で別のリードマクロを使えない可能性
![Page 21: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/21.jpg)
関連研究 : ユーザ定義の構文• Isabelle, OBJ3
• _ _ のような演算子を定義可能なプログラミング言語• 字句規則は変えることができない• ナイーブな解析手法であるため composability が低い
• Nemerle• ユーザ定義の構文を定義可能なプログラミング言語• 構文の最初の1単語はユニークな識別子でなければならない
![Page 22: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/22.jpg)
関連研究 : 構文解析手法• Metaborg [Bravenboer ら OOPSLA '04]
• 構文規則だけでなく字句規則の拡張も許す• ナイーブな解析手法であるため composability が低い
• Type-oriented island parser [Silkensen ら '12]• 部分木に対して型チェックしつつボトムアップ解析• 構文解析コストが |G| に比例しない• 字句規則は変えることができない
![Page 23: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/23.jpg)
まとめ• 期待される型を利用した再帰下降構文解析を提案
• 型情報を利用して解析パスを枝刈り• ユーザ定義の protean operators を解析可能• ほとんどの場合に O(n) で解析できる
• protean operators• hole と name part の並びで表現される演算子• 演算子ごとに異なる字句規則を持つ
![Page 24: 静的型付け言語における 汎用的なユーザ定義演算子を 含む 式 の 構文 解析手法](https://reader036.vdocuments.net/reader036/viewer/2022081420/5681619a550346895dd14dda/html5/thumbnails/24.jpg)
発表など
• ジェネリクスや期待される型の推論• 代入文を _:TypeName[T] _:Id = _:T のような演算子で表現したい
• ローカル変数宣言などのメタレベルの表現• 演算子にメタレベルの挙動を持たせたい
今後の課題
• PPL2011 ポスター発表• ECOOP 2011 ポスター発表• PPL2012 ポスター発表
• 日本ソフトウェア科学会 第 28回大会 口頭発表「ユーザ定義演算子による内部 DSL の構成法」