Commit b7974411 authored by eckhart's avatar eckhart
Browse files

examples/EBNF: difference operator added to FlexibleEBNF.ebnf

parent 4c1114a5
......@@ -2158,7 +2158,7 @@ class Alternative(NaryParser):
EBNF-Notation: ``... | ...``
EBNF-Example: ``sentence = /\d+\.\d+/ | /\d+/``
EBNF-Example: ``number = /\d+\.\d+/ | /\d+/``
"""
def __init__(self, *parsers: Parser) -> None:
......@@ -2217,7 +2217,7 @@ class Interleave(MandatoryNary):
"""Parse elements in arbitrary order.
Examples::
>>> prefixes = Interleave(TKN("A"), TKN("B"))
>>> prefixes = TKN("A") * TKN("B")
>>> Grammar(prefixes)('A B').content
'A B'
>>> Grammar(prefixes)('B A').content
......@@ -2230,6 +2230,10 @@ class Interleave(MandatoryNary):
'B A'
>>> Grammar(prefixes)('B').content
'B'
EBNF-Notation: ``... ° ...``
EBNF-Example: ``float = { /\d/ }+ ° /\./``
"""
def __init__(self, *parsers: Parser,
......@@ -2303,7 +2307,11 @@ class Interleave(MandatoryNary):
return all(r[0] == 0 for r in self.repetitions)
def __repr__(self):
return ' ° '.join(parser.repr for parser in self.parsers)
def rep(parser: Parser) -> str:
return '(' + parser.repr + ')' \
if isinstance(parser, Series) or isinstance(parser, Alternative) else parser.repr
return ' ° '.join(rep(parser) for parser in self.parsers)
def _prepare_combined(self, other: Parser) -> Tuple[Tuple[Parser], int, List[Tuple[int, int]]]:
"""Returns the other's parsers and repetitions if `other` is an Interleave-parser,
......
......@@ -20,8 +20,9 @@ directive = "@" §symbol "="
expression = sequence { :OR~ sequence }
sequence = ["§"] ( interleave | lookaround ) # "§" means all following terms mandatory
{ :AND~ ["§"] ( interleave | lookaround ) }
interleave = term { "°" ["§"] term }
lookaround = flowmarker (oneormore | pure_elem)
interleave = difference { "°" ["§"] difference }
lookaround = flowmarker § (oneormore | pure_elem)
difference = term ["-" § (oneormore | pure_elem)]
term = oneormore | repetition | option | pure_elem
#: elements
......@@ -56,11 +57,12 @@ plaintext = /`(?:(?<!\\)\\`|[^`])*?`/~ # like literal but does not eat
regexp = /\/(?:(?<!\\)\\(?:\/)|[^\/])*?\//~ # e.g. /\w+/, ~/#.*(?:\n|$)/~
whitespace = /~/~ # insignificant whitespace
EOF = !/./ [:?DEF] [:?OR] [:?AND] [:?ENDL]
#: delimiters
DEF = `=` | `:=` | `::=`
OR = `|`
AND = `,` | ``
ENDL = `;` | ``
EOF = !/./ [:?DEF] [:?OR] [:?AND] [:?ENDL] # [:?DEF], [:?OR], ... clear stack by eating stored value
# 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
@ anonymous = pure_elem, EOF
@ drop = whitespace, EOF # do not include these even 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 = difference { "°" ["§"] difference }
lookaround = flowmarker § (oneormore | pure_elem)
difference = term ["-" § (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
EOF = !/./ [:?DEF] [:?OR] [:?AND] [:?ENDL]
#: delimiters
DEF = `=` | `:=` | `::=`
OR = `|`
AND = `,` | ``
ENDL = `;` | ``
# XML
This is a complete XML-Parser, see: https://www.w3.org/TR/REC-xml/
This is a complete XML-Parser, see: <https://www.w3.org/TR/REC-xml/>
Author: Eckhart Arnold <eckhart.arnold@posteo.de>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment