Peggy: 
新しい時代のパーザジェネレータ

田中英行 tanaka.hideyuki@gmail.com
2011-12-16 @ Haskell忘年会

自己紹介

Peggy: 全く新しいパーザジェネレータ

Peggyとは?

Why Peggy?

既存研究

PEG(Parsing Expression Grammer:解析表現文法) とは

PEGの利点

PEGの欠点

Packrat Parser

Peggy入門

文法概要

-- Peggy QuasiQuoter
[peggy|
parens :: Int -- パーザの型
= "(" parens ")" { $1 + 1 } -- 定義
/ "" { 0 }

hoge :: String = "aiueo" -- 空白・改行は意味を持たない

foo :: ()
= ("abc" / "def") "ghi" -- 任意の式を括弧で囲える
|]

-- main routine
main :: IO ()
main = print . parseString parens "<stdin>" =<< getContents

構文一通り (1)

identChar :: Char = [_a-zA-Z0-9]
ident0 :: String = identChar*
ident1 :: String = identChar+

構文一通り (2)

mbident :: Maybe String = ident?
number :: Int = [0-9]+ { read $1 }

構文一通り (3)

foo :: String = !number ident -- 否定
bar :: String = &ident ident -- 肯定

使いやすさのための工夫(1)

使いやすさのための工夫(2)

forStmt :: Stmt
= "for" "(" expr? ";" expr? ";" expr? ")" stmt
{ ForStmt $1 $2 $3 $4 }
forStmt :: Stmt
= "for" "(" init:expr? ";" cond:expr? ";" post:expr? ")" "{" body:stmt* "}"
{ ForStmt init cond post body }

使いやすさのための工夫(3)

args :: [Expr]
= (expr, ",") -- 0 回以上
args1 :: [Expr]
= (expr; ",") -- 1 回以上

トークン仕様

構文糖衣

token :: String = "hoge" -- トークン
number ::: Int
= [0-9]+ { read $1 }

実際の例

四則演算

exp :: Double
= exp "+" fact { $1 + $2 }
/ exp "-" fact { $1 - $2 }
/ fact
fact :: Double
= fact "*" term { $1 * $2 }
/ fact "/" term { $1 / $2 }
/ term
term :: Double
= "(" exp ")"
/ number
number ::: Double
= ([1-9][0-9]*) { read $1 }

Javaスタイルのネストコメント

program :: ()
= (!"/*" !"*/" . { () } / comment)* !. { () }

comment :: ()
= "/*" commentElem* "*/" { () }

commentElem :: ()
= comment
/ !"*/" . { () }

これがflexとかだと意外と難しい

Unquoter

tensor :: Exp
= ident '_' ident { $$1 !! $$2 }
ident :: String
= [a-z]+ { $1 }
main :: IO ()
main = do
let x = [1, 2, 3]
i = 1
print [tensor|x_i|]

いろいろ例 (1)

いろいろ例 (2)

さらなる例

レポジトリの example ディレクトリに色々あります

https://github.com/tanakh/Peggy/tree/master/example

Future works

Resources

Try and Fork it!!

$ cabal update
$ cabal install peggy


 
 
 
 
 
 
ご清聴ありがとうございました