# 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
@ disposable = pure_elem, EOF, AND, OR, ENDL, DEF   # eliminate nodes if possible
@ drop       = whitespace, EOF, AND, OR, ENDL, DEF  # do not include content in the concrete syntax tree


#: top-level

syntax     = [~//] { definition | directive } §EOF
definition = symbol §DEF~ expression ENDL~
directive  = "@" §symbol "="
             (regexp | literal | symbol)
             { "," (regexp | literal | symbol) }

#: components

expression = sequence { OR~ sequence }
sequence   = ["§"] ( interleave | lookaround )  # "§" means all following terms mandatory
             { AND~ ["§"] ( interleave | lookaround ) }
interleave = term { "°" ["§"] term }
lookaround = flowmarker (oneormore | pure_elem)
term       = oneormore | repetition | option | pure_elem

#: elements

pure_elem  = element § !/[?*+]/                 # element strictly without a suffix
element    = [retrieveop] symbol !DEF           # negative lookahead to be sure it's not a definition
           | literal
           | plaintext
           | regexp
           | whitespace
           | group

#: flow-operators

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

#: groups

group      = "(" §expression ")"
oneormore  = "{" expression "}+" | element "+"
repetition = "{" §expression "}" | element "*"
option     = "[" §expression "]" | element "?"

#: 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

#: delimiters

DEF        = `=`                                # alternative: `:=` or `::=`
OR         = `|`                                # alternative: `/` (requires different regex-delimiter!)
AND        = ``                                 # alternative: `,`
ENDL       = ``                                 # alternatvie: `;`

EOF        = !/./                               # if needed, add: [:?DEF] [:?OR] [:?AND] [:?ENDL]
