The name of the initial branch for new projects is now "main" instead of "master". Existing projects remain unchanged. More information: https://doku.lrz.de/display/PUBLIC/GitLab

Commit e2d7ea45 authored by di68kap's avatar di68kap
Browse files

- MLW: imperium-Beispiel

parent 1937f410
...@@ -771,8 +771,8 @@ class RE(Parser): ...@@ -771,8 +771,8 @@ class RE(Parser):
return None, text return None, text
def __repr__(self): def __repr__(self):
wL = '~' if self.wL else '' wL = '~' if self.wspLeft else ''
wR = '~' if self.wR else '' wR = '~' if self.wspRight else ''
return wL + '/%s/' % self.main.regexp.pattern + wR return wL + '/%s/' % self.main.regexp.pattern + wR
def _grammar_assigned_notifier(self): def _grammar_assigned_notifier(self):
...@@ -854,28 +854,6 @@ class NaryOperator(Parser): ...@@ -854,28 +854,6 @@ class NaryOperator(Parser):
parser.apply(func) parser.apply(func)
class Synonym(UnaryOperator):
"""
Simply calls another parser and encapsulates the result in
another node if that parser matches.
This parser is needed to support synonyms in EBNF, e.g.
jahr = JAHRESZAHL
JAHRESZAHL = /\d\d\d\d/
Otherwise the first line could not be represented by any parser
class, in which case it would be unclear whether the parser
RE('\d\d\d\d') carries the name 'JAHRESZAHL' or 'jahr'
"""
def __call__(self, text: str) -> Tuple[Node, str]:
node, text = self.parser(text)
if node:
return Node(self, node), text
return None, text
def __repr__(self):
return self.name or self.parser.repr
class Optional(UnaryOperator): class Optional(UnaryOperator):
def __init__(self, parser: Parser, name: str = '') -> None: def __init__(self, parser: Parser, name: str = '') -> None:
super(Optional, self).__init__(parser, name) super(Optional, self).__init__(parser, name)
...@@ -1111,6 +1089,7 @@ def iter_right_branch(node) -> Iterator[Node]: ...@@ -1111,6 +1089,7 @@ def iter_right_branch(node) -> Iterator[Node]:
class Lookbehind(FlowOperator): class Lookbehind(FlowOperator):
"""EXPERIMENTAL AND NEVER TESTED!!!"""
def __init__(self, parser: Parser, name: str = '') -> None: def __init__(self, parser: Parser, name: str = '') -> None:
super(Lookbehind, self).__init__(parser, name) super(Lookbehind, self).__init__(parser, name)
print("WARNING: Lookbehind Operator is experimental!") print("WARNING: Lookbehind Operator is experimental!")
...@@ -1142,6 +1121,7 @@ class Lookbehind(FlowOperator): ...@@ -1142,6 +1121,7 @@ class Lookbehind(FlowOperator):
class NegativeLookbehind(Lookbehind): class NegativeLookbehind(Lookbehind):
"""EXPERIMENTAL AND NEVER TESTED!!!"""
def __repr__(self): def __repr__(self):
return '-!' + self.parser.repr return '-!' + self.parser.repr
...@@ -1241,12 +1221,51 @@ class Pop(Retrieve): ...@@ -1241,12 +1221,51 @@ class Pop(Retrieve):
######################################################################## ########################################################################
# #
# Forward class (for recursive symbols) # Aliasing parser classes
# #
######################################################################## ########################################################################
class Synonym(UnaryOperator):
"""
Simply calls another parser and encapsulates the result in
another node if that parser matches.
This parser is needed to support synonyms in EBNF, e.g.
jahr = JAHRESZAHL
JAHRESZAHL = /\d\d\d\d/
Otherwise the first line could not be represented by any parser
class, in which case it would be unclear whether the parser
RE('\d\d\d\d') carries the name 'JAHRESZAHL' or 'jahr'.
"""
def __call__(self, text: str) -> Tuple[Node, str]:
node, text = self.parser(text)
if node:
return Node(self, node), text
return None, text
def __repr__(self):
return self.name or self.parser.repr
class Forward(Parser): class Forward(Parser):
"""Forward allows to declare a parser before it is actually defined.
Forward declarations are needed for parsers that are recursively
nested, e.g.:
class Arithmetic(Grammar):
'''
expression = term { ("+" | "-") term }
term = factor { ("*" | "/") factor }
factor = INTEGER | "(" expression ")"
INTEGER = /\d+/~
'''
expression = Forward()
INTEGER = RE('\\d+')
factor = INTEGER | Token("(") + expression + Token(")")
term = factor + ZeroOrMore((Token("*") | Token("/")) + factor)
expression.set(term + ZeroOrMore((Token("+") | Token("-")) + term))
root__ = expression
"""
def __init__(self): def __init__(self):
Parser.__init__(self) Parser.__init__(self)
self.parser = None self.parser = None
...@@ -1272,8 +1291,8 @@ class Forward(Parser): ...@@ -1272,8 +1291,8 @@ class Forward(Parser):
return s return s
def set(self, parser: Parser): def set(self, parser: Parser):
# assert isinstance(parser, Parser) """Sets the parser to which the calls to this Forward-object
# self.name = parser.name # redundant, see Grammar-constructor shall be delegated."""
self.parser = parser self.parser = parser
def apply(self, func: Parser.ApplyFunc): def apply(self, func: Parser.ApplyFunc):
......
LEMMA imperi|um
inp-erium
GRAMMATIK
-i n. # keine Wortart?
SCHREIBWEISE
script.:
...@@ -25,7 +25,7 @@ from functools import partial ...@@ -25,7 +25,7 @@ from functools import partial
sys.path.extend(['../', './']) sys.path.extend(['../', './'])
from DHParser.toolkit import is_logging, logging, compile_python_object from DHParser.toolkit import is_logging, logging, compile_python_object
from DHParser.parsers import compile_source, Retrieve from DHParser.parsers import compile_source, Retrieve, Grammar, Forward, Token, ZeroOrMore, RE
from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler
from DHParser.dsl import parser_factory, DHPARSER_IMPORTS from DHParser.dsl import parser_factory, DHPARSER_IMPORTS
...@@ -88,32 +88,6 @@ class TestInfiLoopsAndRecursion: ...@@ -88,32 +88,6 @@ class TestInfiLoopsAndRecursion:
assert not syntax_tree.error_flag, syntax_tree.collect_errors() assert not syntax_tree.error_flag, syntax_tree.collect_errors()
assert snippet == str(syntax_tree) assert snippet == str(syntax_tree)
# def test_indirect_left_recursion2(self):
# """This will always fail, because of the precedence rule of the
# "|"-operator. (Note: This is a difference between PEG and
# classical EBNF). DHParser is a PEG-Parser although it uses the
# syntax of classical EBNF."""
# minilang = """
# Expr = //~ (Product | Sum | Value)
# Product = Expr { ('*' | '/') Expr }
# Sum = Expr { ('+' | '-') Expr }
# Value = /[0-9.]+/~ | '(' Expr ')'
# """
# parser = parser_factory(minilang)()
# assert parser
# snippet = "8 * 4"
# syntax_tree = parser(snippet)
# assert not syntax_tree.error_flag, syntax_tree.collect_errors()
# snippet = "7 + 8 * 4"
# syntax_tree = parser(snippet)
# print(syntax_tree.as_sxpr())
# assert not syntax_tree.error_flag, syntax_tree.collect_errors()
# snippet = "9 + 8 * (4 + 3)"
# syntax_tree = parser(snippet)
# assert not syntax_tree.error_flag, syntax_tree.collect_errors()
# assert snippet == str(syntax_tree)
def test_inifinite_loops(self): def test_inifinite_loops(self):
minilang = """not_forever = { // } \n""" minilang = """not_forever = { // } \n"""
snippet = " " snippet = " "
...@@ -191,6 +165,25 @@ class TestGrammar: ...@@ -191,6 +165,25 @@ class TestGrammar:
grammar("kein Haupt", "haupt") grammar("kein Haupt", "haupt")
grammar("so ist es richtig", "haupt") grammar("so ist es richtig", "haupt")
def test_grammar_subclassing(self):
class Arithmetic(Grammar):
'''
expression = term { ("+" | "-") term }
term = factor { ("*" | "/") factor }
factor = INTEGER | "(" expression ")"
INTEGER = /\d+/~
'''
expression = Forward()
INTEGER = RE('\\d+')
factor = INTEGER | Token("(") + expression + Token(")")
term = factor + ZeroOrMore((Token("*") | Token("/")) + factor)
expression.set(term + ZeroOrMore((Token("+") | Token("-")) + term))
root__ = expression
grammar = Arithmetic()
CST = grammar('3+4')
assert not CST.error_flag, CST.as_sxpr()
class TestPopRetrieve: class TestPopRetrieve:
mini_language = """ mini_language = """
......
Markdown is supported
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