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

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

# Use the LHS terminal to match the identifier, rule name and assignment due to
# confusion between the identifier and RANGE.
# The PEG parser has special rules for matching LHS and RANGE
# so that RANGE is not confused with LHS.
[3] rule        ::= LHS expression

[4] expression  ::= alt

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

[6] seq         ::= diff+

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

[8] postfix     ::= primary POSTFIX?

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

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

@terminals

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

[12] SYMBOL     ::= '<' O_SYMBOL '>' | O_SYMBOL

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

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

[14] RANGE      ::= '[' ((R_CHAR '-' R_CHAR) | (HEX '-' HEX) | R_CHAR | HEX)+ '-'? ']'

[15] O_RANGE    ::= '[^' ((R_CHAR '-' R_CHAR) | (HEX '-' HEX) | R_CHAR | HEX)+ '-'? ']'

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

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

[18] CHAR       ::= [#x9#xA#xD] | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

[19] R_CHAR     ::= CHAR - (']' | '-' | HEX)

[20] POSTFIX    ::= [?*+]

# Ignore all whitespace and comments between non-terminals
[21] PASS       ::= [#x9#xA#xD#x20]
                  | ( ('#' - '#x') | '//' ) [^#xA#xD]*
                  | '/*' (( '*' [^/] )? | [^*] )* '*/'
                  | '(*' (( '*' [^)] )? | [^*] )* '*)'

@pass           PASS