You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
cpp-peglib/tutorial/chap_02.md

108 lines
5.6 KiB

# はじめてのPEG
PEGは言語の文法を定義するための言語で、2004年に[Bryan Ford][Link_Ford]によって発表されました。記法はBNFに似ていますが、言語の構文を定義するだけでなく字句の定義も同一のファイルでに含めることができます。
PEGの文法ファイルは「構文規則名(N) <- (e)」で表される複数の構文規則で構成されます例えば簡単な日付フォーマットはこんな感じで定義できるでしょう
```
# Ex) 12:34 p.m.
DATE <- NUMBER ':' NUMBER ' ' SUFFIX
NUMBER <- [0-9]+
SUFFIX <- 'a.m.' / 'p.m.'
```
PEGパーサーはこの文法ファイルの開始規則DATEに対して入力テキストがマッチするか判定します式の中で他の規則が参照されている場合再帰的にマッチを試みます
式には次のようなものがあります
* `N`構文規則の参照
* `'...'`または`"..."`(文字列
* `.`任意の文字
* `[...]`文字クラス。[a-zA-Z0-9-_])
* `e1 e2`連続
* `e1 / e2`優先順位付き選択。`e1`が失敗した時のみ`e2`を試みる
* `e*`0回以上の繰り返し
* `e+`1回以上の繰り返し
* `e?`オプション
* `(e)`グルーピング
* `&e`肯定先読み
* `!e`否定先読み
ではもう少し複雑な例を見てみましょう
## CSVフォーマットの定義
CSVには様々な方言があるので今回は以下の仕様を満たすものとします
* CSVファイルは一つ以上フィールドでなる一つ以上の行の集まり
* フィールドはダブルクォート無しと有りある
* ダブルクォート無しのフィールドにはカンマとダブルクォートを含むことができない
* ダブルクォート有りのフィールドにはダブルクォート以外の全ての文字と連続したダブルクォートを含むことができる
文法は以下のようになります
```
CSV <- RECORD (NL RECORD)* NL?
RECORD <- FIELD (',' FIELD)*
FIELD <- DQ_FIELD / NO_DQUOTE_FIELD
NO_DQUOTE_FIELD <- (![,"\r\n] .)*
DQ_FIELD <- '"' (!["] . / '""')* '"'
NL <- '\r\n' / '\r' / '\n'
```
個々の規則をボトムアップで見ていきましょう最初はダブルクォート無しのフィールドです
NO_DQUOTE_FIELD <- (![,"\r\n] .)*
この規則はカンマダブルクォート改行以外の任意の文字の0回以上の繰り返しを意味します規則を構成する個々の要素を見てみましょう
`.`は任意の文字にマッチします。`[,"\r\n]`はカンマダブルクォート改行文字のいずれかにマッチします外側の`()*`は0回以上の繰り返しを意味しますどれも正規表現と全く同じですね
`!`否定先読み演算子で後続の`[,"\r\n]`がマッチしなければマッチしたことになりますまたマッチしたとしても現在処理している入力テキストの位置は進めません
続いてダブルクォート有りのフィールドです
DQ_FIELD <- '"' (!["] . / '""')* '"'
この規則は両端にダブルクォートがあってその間はダブルクォートでない任意の文字か2連続するダブルクォートの0以上の繰り返しという意味です
ではこの2つの規則をまとめましょう
FIELD <- DQ_FIELD / NO_DQUOTE_FIELD
これはDQ_FIELDかNO_DQUOTE_FIELDにマッチを意味します。`/`優先順位付き選択Priority Choise)」と呼ばれ左の要素から順番にマッチを試みますある要素がマッチした時点で式の評価は終了します
ですからDQ_FIELDとNO_DQUOTE_FIELDの順序はとても重要ですもしこの順序を逆にするとダブルクォート文字列はNO_DQUOTE_FIELDの規則で誤ってマッチしてしまいDQ_FIELDとしては認識されなくなってしまいます。(ダブルクォート文字列は最初のクオート無しのフィールド規則で長さ0のフィールドとしてマッチしてしまい続くダブルクォート有りのフィールド規則はスキップされてしまいます。)
次に改行文字を定義しましょう
NL <- '\r\n' / '\r' / '\n'
この場合も要素の順序に気をつけてください。`\r\n`を`\r`の後に置くと,`\r\n`は決してマッチしなくなってしまいます。
続いてレコード規則を定義します。
RECORD <- FIELD (',' FIELD)*
これは「1回以上のFIELDの繰り返し」を意味します。この形式は,「要素が最低1回以上出現するリスト」を表現するイディオムです。(「要素が0回以上出現するリスト」は`(ELEM (DELM ELEM)*)?`で表します。)
最後に開始規則であるCSV規則を定義します
CSV <- RECORD (NL RECORD)* NL?
無事CSVフォーマットの文法が完成ですBNFや正規表現に慣れている方は親近感を感じたのではないでしょうか
ここでPEGで文法を定義する際によく直面する問題について考慮しましょうこれは構文解析と字句解析が一緒に行われるPEG特有の問題です
## 空白の除去
## キーワードの処理
次章ではより複雑なスクリプト言語の文法デザインしてみましょう
[Link_Ford]: http://pdos.csail.mit.edu/papers/parsing:popl04.pdf