/* An EBNF grammar for EBNF */
[1] ebnf        ::= (declaration | rule)*

[2] declaration ::= '@terminals' | pass

[3] rule        ::= LHS expression

# Use a terminal to match the identifier, rule name and assignment due to
# confusion between the identifier RANGE

[4] expression  ::= alt

[5] alt         ::= seq ('|' seq)*

[6] seq         ::= diff+

[7] diff        ::= postfix ('-' postfix)?

[8] postfix     ::= primary POSTFIX?

[9] primary     ::= HEX
                |   SYMBOL
                |   RANGE
                |   O_RANGE
                |   STRING1
                |   STRING2
                |   '(' expression ')'

[10] pass       ::= '@pass' expression

@terminals

[11] LHS        ::= ('[' SYMBOL+ ']')? SYMBOL "::="

[12] SYMBOL     ::= ([a-z] | [A-Z] | [0-9] | "_" | ".")+

[13] HEX        ::= '#x' ([0-9]|[a-f]|[A-F])+

# Range is any combination of R_CHAR '-' R_CHAR or R_CHAR+
[14] RANGE      ::= '[' ((R_BEGIN (HEX | R_CHAR)) | (HEX | R_CHAR))+ ']'

# Range is any combination of R_CHAR '-' R_CHAR or R_CHAR+ preceded by ^
[15] O_RANGE    ::= '[^' ((R_BEGIN (HEX | R_CHAR)) | (HEX | R_CHAR))+ ']'

# Strings are unescaped Unicode, excepting control characters and hash (#)
[16] STRING1    ::= '"' (CHAR - '"')* '"'

[17] STRING2    ::= "'" (CHAR - "'"))* "'"

[18] CHAR       ::= HEX
                  | [#x20#x21#x22]
                  | [#x24-#x00FFFFFF]

[19] R_CHAR     ::= CHAR - ']'

[20] R_BEGIN    ::= (HEX | R_CHAR) "-"

# Should be able to do this inline, but not until terminal regular expressions are created automatically
[21] POSTFIX    ::= [?*+]

[22] PASS       ::= ( [#x00-#x20]
                    | ( '#' | '//' ) [^#x0A#x0D]*
                    | '/*' (( '*' [^/] )? | [^*] )* '*/'
                    | '(*' (( '*' [^)] )? | [^*] )* '*)'
                    )+

# Should be able to do this inline, but not until terminal regular expressions are created automatically
@pass           PASS