wvogel日記

自分用の技術備忘録が多めです.

Peggy練習(2)

昔同好会で友人が作ったゲームエンジンスクリプトパーサーのようなものを書いてみた。
とはいっても、細かいことは覚えてないのだけれど。

mes("発話者","発言内容");
img(レイヤー番号,x座標,y座標,"ファイル名");
のような感じだった記憶がある。

また、背景画像は恒にレイヤー番号0,座標=(0,0)だと仮定し、
さらにレイヤー番号だけの記述も可として、
img("ファイル名");
img(レイヤー番号,"ファイル名");
の記述も許す。

さて、どんな風に書くんだろうと思いながら、
Peggyで適当に書いてみたら....動いた!!
呆気ないほど簡単だった。

{-# Language TemplateHaskell , QuasiQuotes ,FlexibleContexts #-}

import Text.Peggy

data Script
 = Mes   {name     ::String,
          sentence ::String}
  |Img  {layer    ::Int,
         x        ::Int,
         y        ::Int,
         filepath ::String}
  |Sound {filepath ::String,
          isOn     ::Bool}
  deriving (Show)
[peggy|
scripts :: [Script]
 =  script* !.	--0個以上のスクリプト

script :: Script
 = "mes(" parseMes ");"    { $1 }
 / "img(" parseImg ");"    { $1 }
 / "music(" parseMusic ");"{ $1 }
 / '\n' script             { $1 }
 / '\r' script             { $1 }

parseMes :: Script
 = scString "," scString { mesScr  $1 $2 }
 / scString              { mes1Scr $1}

parseImg :: Script
 = num "," num "," num "," scString { imgScr  $1 $2 $3 $4 }
 / num "," scString                 { img1Scr $1 $2 }
 / scString                         { img2Scr $1 }

parseMusic :: Script
 = scString "," scMusicBool { soundScr $1 $2 }

scMusicBool :: Bool
 = "\"" "on"  "\"" { True }
 / "\"" "off" "\"" { False }

scString ::: String
 = '\"' scChar* '\"'

scChar :: Char
 = [0-9a-zA-Z .,'_!?]

num ::: Int
 = [1-9] [0-9]* {read ($1 : $2)}
 / [0]          {0}
|]

mesScr a b = Mes {name = a , sentence = b}
mes1Scr a  = Mes {name = "", sentence = a}

imgScr a b c d = Img {layer = a,x = b,y = c,filepath = d}
img1Scr a b    = Img {layer = a,x = 0,y = 0,filepath = b}
img2Scr a      = Img {layer = 0,x = 0,y = 0,filepath = a}

soundScr a b = Sound {filepath = a , isOn = b}