# EBNF-Grammar in EBNF

@ comment    = /#.*(?:\n|$)/                    # comments start with '#' and eat all chars up to and including '\n'
@ whitespace = /\s*/                            # whitespace includes linefeed
@ literalws  = right                            # trailing whitespace of literals will be ignored tacitly
@ drop       = whitespace                       # do not include whitespace in concrete syntax tree

#: top-level

syntax     = (~//)? (definition | directive)* §EOF
definition = symbol §"=" expression
directive  = "@" §symbol "=" (regexp | literal | symbol) ( "," (regexp | literal | symbol) )*

#: components

expression = sequence ("|" sequence)*
sequence       = ("§"? term)+                       # "§" means all following terms mandatory
term     = repetition | option
           | flowmarker? (unordered | oneormore | element)

#: flow-operators

flowmarker = "!"  | "&"                         # '!' negative lookahead, '&' positive lookahead
           | "-!" | "-&"                        # '-' negative lookbehind, '-&' positive lookbehind
retrieveop = "::" | ":"                         # '::' pop, ':' retrieve

#: operators

unordered  = interleave ( "^" interleave )+     # "interleaving" elements in arbitrary order
interleave = oneormore | repetition | option | element
oneormore  = element "+"
repetition = element "*"
option     = element "?"

#: elements

element    = retrieveop? symbol !"="           # negative lookahead to be sure it's not a definition
           | literal
           | plaintext
           | regexp
           | whitespace
           | group

group      = "(" §expression ")"

#: leaf-elements

symbol     = /(?!\d)\w+/~                       # e.g. expression, term, parameter_list
literal    = /"(?:(?<!\\)\\"|[^"])*?"/~         # e.g. "(", '+', 'while'
           | /'(?:(?<!\\)\\'|[^'])*?'/~         # whitespace following literals will be ignored tacitly.
plaintext  = /`(?:(?<!\\)\\`|[^`])*?`/~         # like literal but does not eat whitespace
regexp     = /\/(?:(?<!\\)\\(?:\/)|[^\/])*?\//~     # e.g. /\w+/, ~/#.*(?:\n|$)/~
whitespace = /~/~                               # insignificant whitespace

EOF = !/./
