R7RS の構文を実装向けに解析表現文法で書き直し

Revised 7 Scheme 2. および 7.1. の read 手続きの入力構文を、実装向けに書き直します。R7RS 文中の説明も解析表現文法に盛り込むことにします。

構文は外部表現の datum から始まります。7.1.1 の記述によると、論理値・文字・数値・縦棒記法でない識別子の 4 種類はデリミタで終端するので、デリミタの先読み一致をつけています。7.1. に、letter、character name、mnemonic escape を除いて、大文字・小文字を区別しないとありますので、それも反映しています。リストとベクタは、末尾再帰のループになります。

input <- atmospher datum EOF

datum <- "#" &delim    # 識別子 |#|
       / "#"[Tt]([Rr][Uu][Ee])? &delim
       / "#"[Ff]([Aa][Ll][Ss][Ee])? &delim
       / "#\\" character &delim
       / &("#"[EeIiBbOoDdXx]) number &delim
       / &(([+-][.]?|[.])?[0-9]) number &delim
       / !(([+-][.]?|[.])?[0-9]) !([.] &delim) number_or_ident
       / "|" identifier
       / ["] string
       / "(" list
       / "#(" vector
       / "#"[Uu]"8(" u8vector
       / (['`] / [,][@]?) atmospher datum
       / "#"[0-9]+ ("=" atmospher datum / "#")

delim <- [ \t\r\n;"|()] / !.

list <- atmospher (")" / datum list_tail)

list_tail <- atmospher (")" / "." &delim atmospher datum atmospher ")" / datum list_tail)

vector <- atmospher (")" / datum vector)

u8vector <- atmospher (")" / number u8vector)

空白・コメント・ディレクティブの並びが atmospher です。ブロック・コメントは入れ子にできます。ディレクティブの終端は R7RS には書いてないのですけど、意図しないトークンが生まれてしまうのを避けるために、独自に追加しています。

atmospher
   <- [ \t\r\n]+ atmospher
    / ";" [^\r\n]* atmospher
    / "#|" block_comment atmospher
    / "#;" atmospher datum atmospher
    / "#!"[Ff][Oo][Ll][Dd]"-"[Cc][Aa][Ss][Ee] &delim atmospher
    / "#!"[Nn][Oo]"-"[Ff][Oo][Ll][Dd]"-"[Cc][Aa][Ss][Ee] &delim atmospher
    /

block_comment
   <- "|#"
    / "#|" block_comment block_comment
    / . block_comment

文字は、名前と16進表記、それ以外の一文字の 3 通りを扱います。16進表記は大文字小文字を区別せず、それ以外の一文字は fold-case ディレクティブの影響を受けず、大文字小文字を区別します。名前は、fold-case ディレクティブで区別せず、デフォルトと no-fold-case ディレクティブで区別します。

character
   <- "alarm" / "backspace" / "tab" / "newline" / "return" / "escape" / "space" / "delete"
         # 以上は #!fold-case のとき大文字小文字を区別しない
         # デフォルトと #!no-fold-case のときは区別する
    / [Xx][0-9A-Fa-f]+
    / .  # 任意の一文字は常に大文字小文字を区別する

number_or_ident は、無限大等の数と縦棒記法でない識別子を扱います。R7RS の peculiar identifier がなくなっているのは、datum の先読み不一致で予め考慮済みだからです。identifier は縦棒表記の識別子を扱います。string は文字列を扱います。

number_or_ident
   <- number &delim
    / [!$%&*+\-./:0-9<=>?A-Z^_a-z~][!$%&*+\-./:0-9<=>?@A-Z^_a-z~]* &delim

identifier
   <- "|"
    / "\\" [abtnr|] identifier
    / "\\x" [0-9A-Fa-f]+ ";" identifier
    / . identifier

string
   <- ["]
    / "\\" [abtnr\\"] string
    / "\\x" [0-9A-Fa-f]+ ";" string
    / "\\"[ \t]*([\n]/[\r][\n]?)[ \t]* string
    / . string

数はシャープ記号のプレフィックスによってふりわけます。

number
   <- "#"[Bb] ("#"[EeIi])? complex2
    / "#"[Oo] ("#"[EeIi])? complex8
    / "#"[Dd] ("#"[EeIi])? complex10
    / "#"[Xx] ("#"[EeIi])? complex16
    / "#"[EeIi]
      ( "#"[Bb] complex2
      / "#"[Oo] complex8
      / "#"[Dd] complex10
      / "#"[Xx] complex16
      / complex10)
    / complex10

10進数だけ、小数部と指数部があります。R7RS は INF と NAN を符号込みになっており、生成規則が複雑になっているので、ここでは符号を別に分けています。

complex10
   <- ureal10
    / ureal10 "@" (ureal10 / [+-] (ureal10 / infnan))
    / ureal10 [+-] (ureal10 / infnan)? [Ii]
    / [+-] (ureal10 / infnan)
    / [+-] (ureal10 / infnan) "@" (ureal10 / [+-] (ureal10 / infnan))
    / [+-] (ureal10 / infnan) ([+-] (ureal10 / infnan)?)? [Ii]
    / [+-] [Ii]

infnan <- [Ii][Nn][Ff][.][0] / [Nn][Aa][Nn][.][0]

ureal10
   <- [0-9]+ ("/" [0-9]+ / [.] [0-9]* suffix? / suffix)?
    / [.] [0-9]+ suffix?

suffix <- [ESFDLesfdl][+-]?[0-9]+

他は、分数と整数だけです。

complex2
   <- ureal2
    / ureal2 "@" (ureal2 / [+-] (ureal2 / infnan))
    / ureal2 [+-] (ureal2 / infnan)? [Ii]
    / [+-] (ureal2 / infnan)
    / [+-] (ureal2 / infnan) "@" (ureal2 / [+-] (ureal2 / infnan))
    / [+-] (ureal2 / infnan) ([+-] (ureal2 / infnan)?)? [Ii]
    / [+-] [Ii]

ureal2 <- [01]+ ("/" [01]+)?

complex8
   <- ureal8
    / ureal8 "@" (ureal8 / [+-] (ureal8 / infnan))
    / ureal8 [+-] (ureal8 / infnan)? [Ii]
    / [+-] (ureal8 / infnan)
    / [+-] (ureal8 / infnan) "@" (ureal8 / [+-] (ureal8 / infnan))
    / [+-] (ureal8 / infnan) ([+-] (ureal8 / infnan)?)? [Ii]
    / [+-] [Ii]

ureal8 <- [0-7]+ ("/" [0-7]+)?

complex16
   <- ureal16
    / ureal16 "@" (ureal16 / [+-] (ureal16 / infnan))
    / ureal16 [+-] (ureal16 / infnan)? [Ii]
    / [+-] (ureal16 / infnan)
    / [+-] (ureal16 / infnan) "@" (ureal16 / [+-] (ureal16 / infnan))
    / [+-] (ureal16 / infnan) ([+-] (ureal16 / infnan)?)? [Ii]
    / [+-] [Ii]

ureal16 <- [0-9A-Fa-f]+ ("/" [0-9A-Fa-f]+)?