/* 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.
# Note, for grammars not using identifiers, it is still possible to confuse
# a rule ending with a range the next rule, as it may be interpreted as an identifier.
# In such case, best to enclose the rule in '()'.
[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     ::= ([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)+ '-'? ']' - LHS

[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