Packrat Parser for S-exp PEG

S式で定義したPEGから、パーサを作れたらいいなーと思ってパーサジェネレータを製作中。パーサジェネレータの、S式で表現したPEGをパースする部分ができあがってきた。

;;
;; multitive '+' additive / multitive
;; 
(parse '(< multitive lval > #\+ < additive rval > :return (+ lval rval)
         / < multitive val > :return val ))

< Identifier CaptureName > で、Identifierにマッチした部分をCaptureNameに束縛、:returnで返す値を計算する。これは、(Identifier CaptureName)のようにS式で構造化された表現にするか迷ってたんだけど、とりあえず今は簡単のために完全にフラットなシンボル/リテラルの列になるようにしてある。ただ、今のままだと < と > の前後にスペースが必要であまり美しくないので、いずれ変えると思う。その場合、括弧のネストができなさそうな気がする。

上のPEGをパースした構文木は次のようになる。

(:alter
 (:sequence
  ((:identifier multitive :capture lval)
   #\+
   (:identifier additive :capture rval))
  :callback (+ lval rval))
 (:sequence
  ((:identifier multitive :capture val))
  :callback val))

パーサが一通りできた後は、構文木からパーサを生成する処理を書く。とりあえず構文木からRuiさんのPEGライブラリを使ってパーサを生成してみて、それから自前でパーサを生成できるようになるところまでが当面の目標。

S式PEGパーサを書くにあたって、S式PEGをPEG*1で定義したんだけど、その段階で結構混乱した。自分が記述しているのが、どのレベルの文法なのか、つまりメタ言語としてのPEGなのか、S式PEGなのかが頭の中でごっちゃになって大変だった。言語処理系っておもしろい。

*1:対象が文字列じゃないから、厳密には違うっぽい