|
|
@ -96,13 +96,59 @@ NL <- '\r\n' / '\r' / '\n' |
|
|
|
|
|
|
|
|
|
|
|
無事CSVフォーマットの文法が完成です。BNFや正規表現に慣れている方は,親近感を感じたのではないでしょうか? |
|
|
|
無事CSVフォーマットの文法が完成です。BNFや正規表現に慣れている方は,親近感を感じたのではないでしょうか? |
|
|
|
|
|
|
|
|
|
|
|
ここでPEGで文法を定義する際によく直面する問題について考慮しましょう。これは構文解析と字句解析が一緒に行われるPEG特有の問題です。 |
|
|
|
ここでPEGで文法を定義する際によく直面する問題について考慮しましょう。 |
|
|
|
|
|
|
|
|
|
|
|
## 空白の除去 |
|
|
|
## 空白の除去 |
|
|
|
|
|
|
|
|
|
|
|
## キーワードの処理 |
|
|
|
PEGの問題の中で一番よく知られているのは「空白」扱いです。Yaccなどでは,Lexなど外部の字句解析器がテキストのトークン分割を行う際に不必要な空白を除去してくれます。PEGでは構文解析と字句解析が明確に分離されていないため,空白除去の処理も通常の構文規則を用いて行う必要があります。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`[123,456,789]`のような数字の配列は,次のように定義できます。 |
|
|
|
|
|
|
|
|
|
|
|
次章では,より複雑なスクリプト言語の文法デザインしてみましょう。 |
|
|
|
ARRAY <- '[' (NUM (',' NUM)*)? ']' |
|
|
|
|
|
|
|
NUM <- [0-9]+ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
しかし括弧やカンマの前後に任意の空白文字を許したい場合は,明示的にその規則を追加する必要があります。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
START <- _ ARRAY |
|
|
|
|
|
|
|
ARRAY <- '[' _ (NUM (',' _ NUM)*)? ']' _ |
|
|
|
|
|
|
|
NUM <- [0-9]+ _ |
|
|
|
|
|
|
|
_ <- [ \t\r\n]* |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`_`が空白規則で,開始規則の先頭と,括弧やカンマや数字などのトークンの直後にこの規則を指定しています。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
このようにPEGでは字句解析器を別途用意する必要はありませんが,自前で空白除去の規則を適切に散りばめなければならず,この点がPEGの弱点と言えるかもしれません。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 空白の間違った扱い |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`if x then y`でも`if(x)then y`でも記述可能なプログラミング言語の文法を考えてみましょう。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IF <- 'if' _ ('(' _)? IDENT (')' _)? 'then' _ EXPR |
|
|
|
|
|
|
|
IDENT <- [a-zA-Z][a-zA-Z0-9_-]* _ |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
_ <- [ \t\r\n]* # 空白文字が0回以上 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
この文法で上の2つの例にマッチさせることができますが,`ifxtheny`にも誤ってマッチしてしまいます。トークン間に必ず空白が必要ということで'_'の規則を次のように変更してみます。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_ <- [ \t\r\n]+ # 空白文字が1回以上 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
今度は正しく`ifxtheny`がエラーとなります。しかし`if(x)then y`は空白を必要ないにもかかわらず,マッチしなくなってしまいました。こうした時は「否定先読み」を使用して,トークンの切れ目を明確にして解決することができます。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IF <- 'if' __ ('(' _)? IDENT (')' _)? 'then' __ EXPR |
|
|
|
|
|
|
|
IDENT <- [a-zA-Z][a-zA-Z0-9_-]* __ |
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
__ <- ![a-zA-Z0-9_-] _ |
|
|
|
|
|
|
|
_ <- [ \t\r\n]* |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`__`は,前のトークンの直後の文字が「名前文字`[a-zA-Z0-9_-]`」ではないことを確認しつつ,0回以上の空白文字を受け入れます。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Unicodeのサポート |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FordのPEGの論文ではUnicode文字については想定されていません。しかし多言語のテキストを扱うにはUnicodeのサポートが必須です。対応は処理系によってまちまちです。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
この本で使用するPEGライブラリ(cpp-peglib)は正式にはUnicodeに未対応ですが,問題なくUTF8のテキストを扱うことができます。U+0800以上の全ての文字を規則名として使用することができます。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
このように幾つかの弱点はあるものの,PEGは十分に実用的な文法定義のための言語です。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
次章では,ついにスクリプト言語の文法デザインに着手しましょう。 |
|
|
|
|
|
|
|
|
|
|
|
[Link_Ford]: http://pdos.csail.mit.edu/papers/parsing:popl04.pdf |
|
|
|
[Link_Ford]: http://pdos.csail.mit.edu/papers/parsing:popl04.pdf |
|
|
|