16.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit f5965e58 authored by di68kap's avatar di68kap
Browse files

- Grammar class now defines left und right default white space handling, so it...

- Grammar class now defines left und right default white space handling, so it is usually not necessary any more to specify whitespacehandling in the constructor of RE- and Token-objects.

- additions to AST-transformation-table of MLW_compiler.py

- some smaller bugs fixed
parent 4cd00b72
......@@ -15,3 +15,4 @@ testdata/*.pdf
DEBUG*
external_resources/
tmp/
......@@ -428,12 +428,15 @@ class Parser(metaclass=ParserMetaClass):
assert name is None or isinstance(name, str), str(name)
self.name = name or ''
self.headquarter = None # headquarter for global variables etc.
self.reset()
def reset(self):
self.visited = dict()
self.recursion_counter = dict()
self.cycle_detection = set()
def __call__(self, text):
raise NotImplementedError
return None, text # default behaviour: don't match
def __str__(self):
return self.name or self.__class__.__name__
......@@ -445,9 +448,9 @@ class Parser(metaclass=ParserMetaClass):
@headquarter.setter
def headquarter(self, headquarter):
self._headquarter = headquarter
self.changed_HQ(headquarter)
self._headquarter_changed()
def changed_HQ(self, headquarter):
def _headquarter_changed(self):
pass
def apply(self, func):
......@@ -476,48 +479,51 @@ class ParserHeadquarter:
...
symbol = RE('(?!\\d)\\w+')
After the call of this method symbol.name == "symbol"
holds. If the `name` field has been assigned a different
name in the constructor, a ValueError will be raised.
holds. Names assigned via the `name`-parameter of the
constructor will not be overwritten.
"""
if cls.parser_initialization__ == "done":
return
cdict = cls.__dict__
for entry in cdict:
if sane_parser_name(entry): # implies isinstance(parser, Parser) qua convention
parser = cdict[entry]
assert isinstance(parser, Parser), \
"Symbol not ending with '__' should by convention only " \
"be used for parsers."
if isinstance(parser, Forward):
assert not parser.name or parser.name == entry
if parser.name and parser.name != entry:
raise ValueError(("Parser named %s should not be "
" assigned to field with different name: %s"
% (parser.name, entry)))
parser.parser.name = entry
else:
for entry, parser in cdict.items():
if isinstance(parser, Parser):
if not parser.name or parser.name == TOKEN_KEYWORD:
parser.name = entry
if (isinstance(parser, Forward) and not parser.parser.name
or parser.name == TOKEN_KEYWORD):
parser.parser.name = entry
cls.parser_initialization__ = "done"
def __init__(self):
self.all_parsers = set()
self.dirty_flag = False
self._reset()
self._assign_parser_names()
self.root__ = copy.deepcopy(self.__class__.root__)
if self.wspL__:
self.wsp_left_parser__ = RegExp(self.wspL__, WHITESPACE_KEYWORD)
self.wsp_left_parser__.headquarter = self
else:
self.wsp_left_parser__ = lambda t: (None, t)
if self.wspR__:
self.wsp_right_parser__ = RegExp(self.wspR__, WHITESPACE_KEYWORD)
self.wsp_right_parser__.headquarter = self
else:
self.wsp_right_parser__ = lambda t: (None, t)
self.root__.apply(self._add_parser)
def _reset(self):
self.variables = dict() # support for Pop and Retrieve operators
self.last_node = None
self.call_stack = []
self.moving_forward = True
self.unused = True
self.call_stack = [] # support for call stack tracing
self.moving_forward = True # also needed for call stack tracing
def _add_parser(self, parser):
"""Adds the copy of the parser object to this instance of ParserHeadquarter.
"""Adds the copy of the classes parser object to this
particular instance of ParserHeadquarter.
"""
if sane_parser_name(parser.name): # implies isinstance(parser, Parser) qua convention
assert isinstance(parser, Parser), \
"Symbol not ending with '__' should by convention only " \
"be used for parsers."
# overwrite class variable with instance variable!!!
setattr(self, parser.name, parser)
setattr(self, parser.name, parser)
self.all_parsers.add(parser)
parser.headquarter = self
def parse(self, document):
......@@ -528,11 +534,14 @@ class ParserHeadquarter:
Returns:
Node: The root node ot the parse tree.
"""
assert self.unused, ("Parser has been used up. Please create a new "
"instance of the ParserHeadquarter class!")
if self.root__ is None:
raise NotImplementedError()
self.unused = False
if self.dirty_flag:
for parser in self.all_parsers:
parser.reset()
self._reset()
else:
self.dirty_flag = True
parser = self.root__
result = ""
stitches = []
......@@ -651,7 +660,8 @@ class RE(Parser):
main, t = self.main(t)
if main:
wR, t = self.wspRight(t)
result = tuple(nd for nd in (wL, main, wR) if nd)
result = tuple(nd for nd in (wL, main, wR)
if nd and nd.result != '')
return Node(self, result), t
return None, text
......@@ -659,6 +669,13 @@ class RE(Parser):
return Parser.__str__(self) + ('~' if self.wL else '') + \
'/' + self.main.regexp.pattern + '/' + ('~' if self.wR else '')
def _headquarter_changed(self):
if self.headquarter:
if self.wL is None:
self.wspLeft = self.headquarter.wsp_left_parser__
if self.wR is None:
self.wspRight = self.headquarter.wsp_right_parser__
def apply(self, func):
if super(RE, self).apply(func):
if self.wL:
......@@ -685,7 +702,7 @@ def mixin_comment(whitespace, comment):
return wspc
def Token(token, wL='', wR='', name=None):
def Token(token, wL=None, wR=None, name=None):
return RE(escape_re(token), wL, wR, name or TOKEN_KEYWORD)
......@@ -1289,30 +1306,30 @@ class EBNFGrammar(ParserHeadquarter):
EOF = !/./
"""
expression = Forward()
source_hash__ = "205fd680c1c77175b9b9807ea4b96160"
source_hash__ = "10a1a9de25992e0d3df5fee607e27d31"
parser_initialization__ = "upon instatiation"
wsp__ = mixin_comment(whitespace=r'\s*', comment=r'#.*(?:\n|$)')
wspL__ = ''
wspR__ = wsp__
EOF = NegativeLookahead(RE('.'))
list_ = RE('\\w+\\s*(?:,\\s*\\w+\\s*)*', wR=wsp__)
regexp = RE('~?/(?:[^/]|(?<=\\\\)/)*/~?', wR=wsp__)
literal = Alternative(RE('"(?:[^"]|\\\\")*?"', wR=wsp__), RE("'(?:[^']|\\\\')*?'", wR=wsp__))
symbol = RE('(?!\\d)\\w+', wR=wsp__)
repetition = Sequence(Token("{", wR=wsp__), expression, Required(Token("}", wR=wsp__)))
oneormore = Sequence(Token("{", wR=wsp__), expression, Token("}+", wR=wsp__))
option = Sequence(Token("[", wR=wsp__), expression, Required(Token("]", wR=wsp__)))
group = Sequence(Token("(", wR=wsp__), expression, Required(Token(")", wR=wsp__)))
retrieveop = Alternative(Token("::", wR=wsp__), Token(":", wR=wsp__))
flowmarker = Alternative(Token("!", wR=wsp__), Token("&", wR=wsp__), Token("§", wR=wsp__), Token("-!", wR=wsp__),
Token("-&", wR=wsp__))
factor = Alternative(
Sequence(Optional(flowmarker), Optional(retrieveop), symbol, NegativeLookahead(Token("=", wR=wsp__))),
Sequence(Optional(flowmarker), literal), Sequence(Optional(flowmarker), regexp),
Sequence(Optional(flowmarker), group), Sequence(Optional(flowmarker), oneormore), repetition, option)
repetition = Sequence(Token("{"), expression, Required(Token("}")))
oneormore = Sequence(Token("{"), expression, Token("}+"))
option = Sequence(Token("["), expression, Required(Token("]")))
group = Sequence(Token("("), expression, Required(Token(")")))
retrieveop = Alternative(Token("::"), Token(":"))
flowmarker = Alternative(Token("!"), Token("&"), Token("§"), Token("-!"), Token("-&"))
factor = Alternative(Sequence(Optional(flowmarker), Optional(retrieveop), symbol, NegativeLookahead(Token("="))),
Sequence(Optional(flowmarker), literal), Sequence(Optional(flowmarker), regexp),
Sequence(Optional(flowmarker), group), Sequence(Optional(flowmarker), oneormore), repetition,
option)
term = OneOrMore(factor)
expression.set(Sequence(term, ZeroOrMore(Sequence(Token("|", wR=wsp__), term))))
directive = Sequence(Token("@", wR=wsp__), Required(symbol), Required(Token("=", wR=wsp__)),
Alternative(regexp, literal, list_))
definition = Sequence(symbol, Required(Token("=", wR=wsp__)), expression)
expression.set(Sequence(term, ZeroOrMore(Sequence(Token("|"), term))))
directive = Sequence(Token("@"), Required(symbol), Required(Token("=")), Alternative(regexp, literal, list_))
definition = Sequence(symbol, Required(Token("=")), expression)
syntax = Sequence(Optional(RE('', wL=wsp__)), ZeroOrMore(Alternative(definition, directive)), Required(EOF))
root__ = syntax
......@@ -1458,6 +1475,10 @@ class EBNFCompiler(CompilerBase):
(definitions[1], definitions[0]))
self.definition_names = [defn[0] for defn in definitions]
definitions.append(('wspR__', 'wsp__' \
if 'right' in self.directives['literalws'] else "''"))
definitions.append(('wspL__', 'wsp__' \
if 'left' in self.directives['literalws'] else "''"))
definitions.append((WHITESPACE_KEYWORD,
("mixin_comment(whitespace="
"r'{whitespace}', comment=r'{comment}')").
......@@ -1573,17 +1594,13 @@ class EBNFCompiler(CompilerBase):
self.directives[key] = value
elif key == 'literalws':
value = {item.lower() for item in self.compile__(node.result[1])}
conv = {'left': 'wL=' + WHITESPACE_KEYWORD,
'right': 'wR=' + WHITESPACE_KEYWORD}
ws = {conv['left'], conv['right']} if 'both' in value else set()
value.discard('both')
value.discard('none') # 'none' will be overridden if combined with other values
try:
ws |= {conv[it] for it in value}
except KeyError as key_error:
if (len(value - {'left', 'right', 'both', 'none'}) > 0
or ('none' in value and len(value) > 1)):
node.add_error('Directive "literalws" allows the values '
'`left`, `right`, `both` or `none`, '
'but not `%s`' % key_error.args[0])
'but not `%s`' % ", ".join(value))
ws = {'left', 'right'} if 'both' in value \
else {} if 'none' in value else value
self.directives[key] = list(ws)
elif key == 'tokens':
......@@ -1672,8 +1689,7 @@ class EBNFCompiler(CompilerBase):
return node.result
def literal(self, node):
name = self.directives["literalws"] + self._current_name()
return 'Token(' + ', '.join([node.result] + name) + ')'
return 'Token(' + ', '.join([node.result]) + ')'
def regexp(self, node):
name = self._current_name()
......@@ -1953,8 +1969,9 @@ def test(file_name):
grammar = f.read()
compiler_name = os.path.basename(os.path.splitext(file_name)[0])
compiler = EBNFCompiler(compiler_name, grammar)
parser = EBNFGrammar()
result, errors, syntax_tree = full_compilation(grammar,
EBNFGrammar(), EBNFTransTable, compiler)
parser, EBNFTransTable, compiler)
if errors:
print(errors)
sys.exit(1)
......
......@@ -100,9 +100,11 @@ class MLWGrammar(ParserHeadquarter):
DATEI_ENDE = !/./
NIEMALS = /(?!.)/
"""
source_hash__ = "460019891fffc4dbf8d8e8573f5f699c"
source_hash__ = "ae6d6896307766bb8965321636b0ed54"
parser_initialization__ = "upon instatiation"
wsp__ = mixin_comment(whitespace=r'\s*', comment=r'#.*(?:\n|$)')
wspL__ = wsp__
wspR__ = wsp__
NIEMALS = RE('(?!.)')
DATEI_ENDE = NegativeLookahead(RE('.'))
LEER = RE('\\s*')
......@@ -112,37 +114,37 @@ class MLWGrammar(ParserHeadquarter):
WORT_GROSS = RE('[A-ZÄÖÜ][a-zäöüß]+', wR=wsp__)
WORT = RE('[A-ZÄÖÜ]?[a-zäöüß]+', wR=wsp__)
Name = Sequence(WORT, ZeroOrMore(Alternative(WORT, RE('[A-ZÄÖÜÁÀ]\\.'))))
Autorinfo = Sequence(Alternative(Token("AUTORIN", wL=wsp__, wR=wsp__), Token("AUTOR", wL=wsp__, wR=wsp__)), Name)
Zusatz = Sequence(Token("ZUSATZ", wL=wsp__, wR=wsp__), RE('\\s?.*'))
EinBeleg = Sequence(OneOrMore(Sequence(NegativeLookahead(Sequence(RE('\\s*'), Alternative(Token("*", wL=wsp__, wR=wsp__), Token("BEDEUTUNG", wL=wsp__, wR=wsp__), Token("AUTOR", wL=wsp__, wR=wsp__), Token("NAME", wL=wsp__, wR=wsp__), Token("ZUSATZ", wL=wsp__, wR=wsp__)))), RE('\\s?.*'))), Optional(Zusatz))
Belege = Sequence(Token("BELEGE", wL=wsp__, wR=wsp__), ZeroOrMore(Sequence(Token("*", wL=wsp__, wR=wsp__), EinBeleg)))
DeutscheBedeutung = Sequence(Token("DEU", wL=wsp__, wR=wsp__), RE('(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+', wR=wsp__))
LateinischeBedeutung = Sequence(Token("LAT", wL=wsp__, wR=wsp__), RE('(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+', wR=wsp__))
Autorinfo = Sequence(Alternative(Token("AUTORIN"), Token("AUTOR")), Name)
Zusatz = Sequence(Token("ZUSATZ"), RE('\\s?.*'))
EinBeleg = Sequence(OneOrMore(Sequence(NegativeLookahead(Sequence(RE('\\s*'), Alternative(Token("*"), Token("BEDEUTUNG"), Token("AUTOR"), Token("NAME"), Token("ZUSATZ")))), RE('\\s?.*'))), Optional(Zusatz))
Belege = Sequence(Token("BELEGE"), ZeroOrMore(Sequence(Token("*"), EinBeleg)))
DeutscheBedeutung = Sequence(Token("DEU"), RE('(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+', wR=wsp__))
LateinischeBedeutung = Sequence(Token("LAT"), RE('(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+', wR=wsp__))
Interpretamente = Sequence(LateinischeBedeutung, DeutscheBedeutung, Optional(Belege))
Bedeutungskategorie = RE('(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+', wR=wsp__)
Bedeutung = Alternative(Interpretamente, Bedeutungskategorie)
BedeutungsPosition = OneOrMore(Sequence(Token("BEDEUTUNG", wL=wsp__, wR=wsp__), Bedeutung))
BedeutungsPosition = OneOrMore(Sequence(Token("BEDEUTUNG"), Bedeutung))
VerweisZiel = RE('<\\w+>', wR=wsp__, wL=wsp__)
Verweis = RE('>>\\w+', wR=wsp__, wL=wsp__)
Beleg = Verweis
Schreibweise = Alternative(Token("vizreg-", wL=wsp__, wR=wsp__), Token("festregel(a)", wL=wsp__, wR=wsp__), Token("fezdregl(a)", wL=wsp__, wR=wsp__), Token("fat-", wL=wsp__, wR=wsp__))
SWVariante = Sequence(Schreibweise, Token(":", wL=wsp__, wR=wsp__), Beleg)
SWTyp = Alternative(Token("script.", wL=wsp__, wR=wsp__), Token("script. fat-", wL=wsp__, wR=wsp__))
SchreibweisenPosition = Sequence(Token("SCHREIBWEISE", wL=wsp__, wR=wsp__), Required(SWTyp), Token(":", wL=wsp__, wR=wsp__), Required(SWVariante), ZeroOrMore(Sequence(Token(",", wL=wsp__, wR=wsp__), Required(SWVariante))))
Schreibweise = Alternative(Token("vizreg-"), Token("festregel(a)"), Token("fezdregl(a)"), Token("fat-"))
SWVariante = Sequence(Schreibweise, Token(":"), Beleg)
SWTyp = Alternative(Token("script."), Token("script. fat-"))
SchreibweisenPosition = Sequence(Token("SCHREIBWEISE"), Required(SWTyp), Token(":"), Required(SWVariante), ZeroOrMore(Sequence(Token(","), Required(SWVariante))))
ArtikelKopf = SchreibweisenPosition
_genus = Alternative(Token("maskulinum", wL=wsp__, wR=wsp__), Token("m.", wL=wsp__, wR=wsp__), Token("femininum", wL=wsp__, wR=wsp__), Token("f.", wL=wsp__, wR=wsp__), Token("neutrum", wL=wsp__, wR=wsp__), Token("n.", wL=wsp__, wR=wsp__))
_genus = Alternative(Token("maskulinum"), Token("m."), Token("femininum"), Token("f."), Token("neutrum"), Token("n."))
Flexion = RE('-?[a-z]+', wR=wsp__)
Flexionen = Sequence(Flexion, ZeroOrMore(Sequence(Token(",", wL=wsp__, wR=wsp__), Required(Flexion))))
GVariante = Sequence(Flexionen, Optional(_genus), Token(":", wL=wsp__, wR=wsp__), Beleg)
GrammatikVarianten = Sequence(Token(";", wL=wsp__, wR=wsp__), Required(GVariante))
_wortart = Alternative(Token("nomen", wL=wsp__, wR=wsp__), Token("n.", wL=wsp__, wR=wsp__), Token("verb", wL=wsp__, wR=wsp__), Token("v.", wL=wsp__, wR=wsp__), Token("adverb", wL=wsp__, wR=wsp__), Token("adv.", wL=wsp__, wR=wsp__), Token("adjektiv", wL=wsp__, wR=wsp__), Token("adj.", wL=wsp__, wR=wsp__))
GrammatikPosition = Sequence(Token("GRAMMATIK", wL=wsp__, wR=wsp__), Required(_wortart), Required(Token(";", wL=wsp__, wR=wsp__)), Required(Flexionen), Optional(_genus), ZeroOrMore(GrammatikVarianten), Optional(Alternative(Token(";", wL=wsp__, wR=wsp__), Token(".", wL=wsp__, wR=wsp__))))
LVZusatz = Token("sim.", wL=wsp__, wR=wsp__)
Flexionen = Sequence(Flexion, ZeroOrMore(Sequence(Token(","), Required(Flexion))))
GVariante = Sequence(Flexionen, Optional(_genus), Token(":"), Beleg)
GrammatikVarianten = Sequence(Token(";"), Required(GVariante))
_wortart = Alternative(Token("nomen"), Token("n."), Token("verb"), Token("v."), Token("adverb"), Token("adv."), Token("adjektiv"), Token("adj."))
GrammatikPosition = Sequence(Token("GRAMMATIK"), Required(_wortart), Required(Token(";")), Required(Flexionen), Optional(_genus), ZeroOrMore(GrammatikVarianten), Optional(Alternative(Token(";"), Token("."))))
LVZusatz = Token("sim.")
LVariante = RE('(?:[a-z]|-)+', wR=wsp__, wL=wsp__)
LemmaVarianten = Sequence(Token("VARIANTEN", wL=wsp__, wR=wsp__), Required(LVariante), ZeroOrMore(Sequence(Token(",", wL=wsp__, wR=wsp__), Required(LVariante))), Optional(Sequence(Token(";", wL=wsp__, wR=wsp__), Required(LVZusatz))))
_tll = Token("*", wL=wsp__, wR=wsp__)
LemmaVarianten = Sequence(Token("VARIANTEN"), Required(LVariante), ZeroOrMore(Sequence(Token(","), Required(LVariante))), Optional(Sequence(Token(";"), Required(LVZusatz))))
_tll = Token("*")
Lemma = Sequence(Optional(_tll), WORT_KLEIN)
LemmaPosition = Sequence(Token("LEMMA", wL=wsp__, wR=wsp__), Required(Lemma), Optional(LemmaVarianten), Required(GrammatikPosition))
LemmaPosition = Sequence(Token("LEMMA"), Required(Lemma), Optional(LemmaVarianten), Required(GrammatikPosition))
Artikel = Sequence(Optional(LEER), Required(LemmaPosition), Optional(ArtikelKopf), Required(BedeutungsPosition), Required(Autorinfo), Optional(LEER), DATEI_ENDE)
root__ = Artikel
......@@ -157,27 +159,33 @@ def test(node):
assert False, node.parser.name
return node
def test(node):
print(node.as_sexpr())
return node
MLWTransTable = {
# AST Transformations for the MLW-grammar
"Artikel": no_transformation,
"LemmaPosition": no_transformation,
"Lemma":
partial(remove_tokens, tokens={'LEMMA'}),
"_tll":
"LemmaPosition":
[partial(remove_tokens, tokens={'LEMMA'})],
"Lemma": no_transformation,
"_tll, _wortart, _genus":
[remove_expendables, reduce_single_child],
"LemmaVarianten":
[partial(remove_tokens, tokens={'VARIANTEN'}), flatten,
partial(remove_tokens, tokens={',', ';'})],
"LVariante":
[reduce_single_child],
"LVZusatz": no_transformation,
"GrammatikPosition": no_transformation,
"_wortart": no_transformation,
"GrammatikVarianten": no_transformation,
"GVariante": no_transformation,
"Flexionen": no_transformation,
"Flexion": no_transformation,
"_genus": no_transformation,
"LVariante, LVZusatz":
[remove_expendables, reduce_single_child],
"GrammatikPosition":
[partial(remove_tokens, tokens={'GRAMMATIK', ';'}), flatten],
"GrammatikVarianten":
[partial(remove_tokens, tokens={';'}), replace_by_single_child],
"GVariante":
[partial(remove_tokens, tokens={':'})],
"Flexionen":
[flatten, partial(remove_tokens, tokens={',', ';'})],
"Flexion, Verweis":
[remove_expendables, reduce_single_child],
"ArtikelKopf": no_transformation,
"SchreibweisenPosition": no_transformation,
"SWTyp": no_transformation,
......@@ -192,7 +200,6 @@ MLWTransTable = {
"Belege": no_transformation,
"EinBeleg": no_transformation,
"Beleg": no_transformation,
"Verweis": no_transformation,
"VerweisZiel": no_transformation,
"WORT, WORT_KLEIN, WORT_GROSS, GROSSSCHRIFT":
# test,
......
<Artikel>
<LemmaPosition>
<token__>
LEMMA
</token__>
<Lemma>
<_tll>
*
......@@ -13,134 +10,68 @@
</Lemma>
<LemmaVarianten>
<LVariante>
<RegExp>
fasc-itergula
</RegExp>
fasc-itergula
</LVariante>
<LVariante>
<RegExp>
fac-iet-ergula
</RegExp>
fac-iet-ergula
</LVariante>
<LVariante>
<RegExp>
fac-ist-ergula
</RegExp>
fac-ist-ergula
</LVariante>
<LVariante>
<RegExp>
fa-rcu-tergula
</RegExp>
fa-rcu-tergula
</LVariante>
<LVZusatz>
<RegExp>
sim.
</RegExp>
sim.
</LVZusatz>
</LemmaVarianten>
<GrammatikPosition>
<token__>
GRAMMATIK
</token__>
<_wortart>
<token__>
nomen
</token__>
nomen
</_wortart>
<token__>
;
</token__>
<Flexionen>
<Flexion>
<RegExp>
-ar
</RegExp>
-ar
</Flexion>
</Flexionen>
<_genus>
<token__>
f.
</token__>
f.
</_genus>
<ZeroOrMore>
<GrammatikVarianten>
<token__>
;
</token__>
<GVariante>
<Flexionen>
<Flexion>
<RegExp>
-us
</RegExp>
</Flexion>
<Sequence>
<token__>
,
</token__>
<Flexion>
<RegExp>
-i
</RegExp>
</Flexion>
</Sequence>
</Flexionen>
<_genus>
<token__>
m.
</token__>
</_genus>
<token__>
:
</token__>
<Beleg>
<RegExp>
>>beleg_id_1
</RegExp>
</Beleg>
</GVariante>
</GrammatikVarianten>
<GrammatikVarianten>
<token__>
;
</token__>
<GVariante>
<Flexionen>
<Flexion>
<RegExp>
-um
</RegExp>
</Flexion>
<Sequence>
<token__>
,
</token__>
<Flexion>
<RegExp>
-i
</RegExp>
</Flexion>
</Sequence>
</Flexionen>
<_genus>
<token__>
n.
</token__>
</_genus>
<token__>
:
</token__>
<Beleg>
<RegExp>
>>beleg_id_2
</RegExp>
</Beleg>
</GVariante>
</GrammatikVarianten>
</ZeroOrMore>
<GVariante>
<Flexionen>
<Flexion>
-us
</Flexion>
<Flexion>
-i
</Flexion>
</Flexionen>
<_genus>
m.
</_genus>
<Verweis>
>>beleg_id_1
</Verweis>
</GVariante>
<GVariante>
<Flexionen>
<Flexion>
-um
</Flexion>
<Flexion>
-i
</Flexion>
</Flexionen>
<_genus>
n.
</_genus>
<Verweis>
>>beleg_id_2
</Verweis>
</GVariante>
</GrammatikPosition>
</LemmaPosition>
<ArtikelKopf>
<SchreibweisenPosition>
<token__>
SCHREIBWEISE
</token__>
......@@ -161,11 +92,9 @@
<token__>
:
</token__>
<Beleg>
<RegExp>