セマンティクスを数式で書くパーサジェネレータ
Eclipseのようなリファクタリングやら,コード補完やらの機能を,自分の作った「俺言語」でも使えるように自動生成したい,という目標のもと,パーサジェネレータを製作中.
http://www2.eplang.jp/tonyu/adaptive/AdaptiveParser071023.jar
(jar解凍後,test.batを起動すれば一応動きます)
こんなコードを一応解析できるレベル.
ファイル名: work/test.fproc
type String {} type int {} type Coord { var x as int var y as int } type Equa { var x as int var expr as String } var c as Coord var e as Equa c.x=3 c.y="cde" e.x=c.y e.expr="abc"
解析といっても,
- c.xはint型で,右辺は数値だから代入OK
- c.yはint型なのに,右辺で文字列を代入しようとしているからエラー
とかいう判定ができるくらい.
上の言語の定義ファイルはこんな感じ:
ファイル名: work/fproc.grm
S:= structs vardecls stmts '$ ; structs := e | struct structs ; stmts := e | stmt stmts ; struct := 'type '[a-zA-Z]+ '\{ vardecls '\} { (and (isa $result Type) (eq (nameOf $result) $rl) (eq (varsOf $result) $rrrl) ) }; vardecls := e | vardecl vardecls; vardecl := 'var '[a-zA-Z]+ 'as type { (and (isa $result Var) (eq (typeOf $result) $rrr) (eq (nameOf $result) $rl) (eq (ownerOf $result) (outer Type enclose $result default MAIN)) ) }; stmt := varRef '= val { (and (eq $result (set (addrOf $l) $rr)) (assertEq (typeOf $l) (typeOf $rr)) ) }; varRef := '[a-zA-Z]+ { (varRef MAIN $) } | val '. '[a-zA-Z]+ { (varRef $l $rr) }; val := varRef { (valueOf $) } | num | str; str := '"[a-zA-Z\s]+" { (and (eq (typeOf (string $)) (select _s from Type where (assertEq (nameOf _s) String)) ) (eq $result (string $)) ) } ; num := '[0-9]+ { (and (eq (typeOf (num $)) (select _i from Type where (assertEq (nameOf _i) int)) ) (eq $result (num $)) ) }; type := '[a-zA-Z]+ { (select _t from Type where (assertEq (nameOf _t) $)) } ( (eq (typeOf (valueOf _)) (typeOf _)) (eq (typeOf MAIN) MAIN) (eq (typeOf (varRef _target _name)) (typeOf (select var from Var where (and (assertEq (nameOf var) _name) (assertEq (ownerOf var) (typeOf _target)) ) )) ) )
セマンティクスの書き方
struct := 'type '[a-zA-Z]+ '\{ vardecls '\} { (and (isa $result Type) (eq (nameOf $result) $rl) (eq (varsOf $result) $rrrl) ) };
は,構造体を定義している部分の文法.
構造体の文法は
- 予約語 type
- 任意の英字列
- 記号 {
- 変数宣言
- 記号 }
であり,最後の { .... } の中に定義されたセマンティクスをもつ
セマンティクスはS式で書く(文法定義が面倒だからとりあえずS式)
- 構文 struct のセマンティクス($result)は Type という型の値である
- $result の 名前は, 2番目の要素 ( '[a-zA-Z]+ ) である
- $result がもつ変数は 4番目の要素 ( vardecls ) である
※$rl とか $rrrl の意味:構文木が二分木になっているため,
- 文法木の2番目の要素は「右側の左側(cdr の car )」
- 文法木の4番目の要素は「右側の右側の右側の左側(cdrのcdrのcdrの car )」
みたいな方式で取得する.
outer context
vardecl のところに出現する
(outer Type enclose $result default MAIN)
は,「この値 (Var) の親で, Type を型に持つもの 」 という意味.「親」とか「子」とかは,構文木の親子関係にもとづいて決定する.
ToDo
リファクタリングとコード補完の自動生成(一番肝心なところがまだだったりする