Parsec
今はすでにメンテナンスモードらしい
Parsecを使ったparserの作り方には2種類ある
関数を組み合わせて0から作る
パーサコンビネータの勉強には良い
予め用意されたものを拡張する
言語ごとのTokenなどは共通していることが多いのでこっちでやったほうが楽
有名な言語なら定義ファイルが用意されているので、
「あの言語に似てるけど、微妙に異なる言語」を作るなら圧倒的に楽
↑今の理解なので間違っているかもしれないmrsekut.icon
つまり、前者についてのみの解説記事は、後者を選択する場合も役に立つ
逆は成り立たない
後者はレコードに設定を記述する
以下の4つからなる(?)
runParserT関数
一つのparserに対し引数を渡してパターンマッチを行う
paraseTestやparse関数の内部で使われている
単純なparser
一文字をパースする関数
char, digitなど
複数文字をパースする関数
stringのみ
satisfy関数によって定義されている
上の単純なparserを組み合わせて複雑なparserを作る関数
それによって作られたparserを更にパーサコンビネータを使ってparserを作る
最終的に一つの複雑なparserになる
これをrunParserTにわたす
spacesやたら出てくる問題
元のコード
code:hs
-- factor ::= '(' expr ')' | nat
factor :: Parser Expr
factor =
(spaces *> char '(' *> spaces *> expr <* spaces <* char ')' <* spaces)
<|> spaces *> nat <* spaces
-- nat ::= '0' | '1' | '2' | ...
nat :: Parser Expr
nat = Nat . read <$> many1 digit
書き換えたコード
code:hs
-- factor ::= '(' expr ')' | nat
factor :: Parser Expr
factor = (spaces *> char '(' *> skipW expr <* char ')' <* spaces) <|> nat
-- nat ::= '0' | '1' | '2' | ...
nat :: Parser Expr
nat = skipW $ Nat . read <$> many1 digit
-- 前後のwhite_spacesをskipするラッパーを作る
skipW :: Parser Expr -> Parser Expr
skipW p = spaces *> p <* spaces
読んで実装しよう
↑のページの中のリンクを見てスクラッチで書いてみよう
テストの書き方がわからない
まだ調べていない
hccで定義しているexprなどの関数は、
「パーサー」?
「パーサコンビネータ」?
これらのなかでmanyなどのパーサコンビネータはどうやって使う?
これらの見分け方は?
雑メモ
以下同じ
code:hs
relational :: Parser Expr
relational = do
a <- spaces *> add
r <- relOp
b <- add
return $ r a b
code:hs
relational :: Parser Expr
relational = do
a <- spaces *> add
r <- relOp
r a <$> add
関連parserライブラリ
参考
ここのおかげでParser型の意味がわかった
↑ここをドキュメント代わりに使うと良いかも?
そうでもないかもmrsekut.icon