Parsec 入門


Parsec でパーサを自動作成する。

パーサの自動作成

Text.Parsec に Text.Parsec.Token と Text.Parsec.Language を追加インポートすると、パーサを自動作成してくれる。詳しい理論は置いておいて、とにかく試してみた。

Prelude> :set prompt "Parsec> "
Parsec> import Text.Parsec
Parsec> import Text.Parsec.Token
Parsec> import Text.Parsec.Language

makeTokenParser

Text.Parsec.Token モジュールの makeTokenParser 関数を使うと、プログラム言語に必要なパーサを自動作成してくれる。ユーザーが用意した言語仕様のデータに makeTokenParser 関数を適用すると、様々なパーサを記述したデータを生成してくれるのだ。

ユーザー定義の言語仕様というのが謎だが、デフォールトのデータが Text.Parsec.Language に emptyDef として定義してある。そこでとにかくそれに makeTokenParser を適用して、mytoken というパーサのいっぱい詰まったデータを作成する。

Parsec> mytoken = makeTokenParser emptyDef

mytoken

mytoken からパーサを引き出すためには、フィールド名でコンテナのパーサを呼び出せばいい。たとえば整数にマッチするパーサは integer というフィールドの中にあるので、integer mytoken のようにすればいい。

また parens というパーサは、カッコの中身を取り出してくれる。

Parsec> parseTest (parens mytoken $ integer mytoken) "(123)"
123

さらに symbol というパーサは引数の文字列のシンボルにマッチする。

Parsec> parseTest (symbol mytoken $ "*") "*"
"*"

驚いたことに、この integer, parens, symbol という3つのパーサだけで、カッコと四則演算の揃った整数の電卓が完成するのだ。実行例を次に示す。

Parsec> :l calculator.hs
[1 of 1] Compiling Calculator ( calculator.hs, interpreted )
Ok, modules loaded: Calculator.
Parsec> parseTest expr "(1+2)*(3+4)"
21

整数の電卓プログラム

整数の電卓のプログラムのソースは次のようになる。

ファイル名:calculator.hs

module Calculator where

import Text.Parsec import qualified Text.Parsec.Token as P import Text.Parsec.Language

mytoken = P.makeTokenParser emptyDef symbol = P.symbol mytoken integer = P.integer mytoken parens = P.parens mytoken

expr = term `chainl1` addop term = factor `chainl1` mulop factor = parens expr <|> integer

mulop = (symbol "*" >> return (*)) <|> (symbol "/" >> return (div)) addop = (symbol "+" >> return (+)) <|> (symbol "-" >> return (-))

emptyDef のような言語仕様のデータの作り方は、Text.Parsec.Language のソースの中に Haskell の言語仕様の例などが定義されているので、Hackage で調べることができる。Parsec で自分仕様の言語のパーサを作ることも夢ではないような気がしてきた。