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):
return None, text
def __repr__(self):
wL = '~' if self.wL else ''
wR = '~' if self.wR else ''
wL = '~' if self.wspLeft else ''
wR = '~' if self.wspRight else ''
return wL + '/%s/' % self.main.regexp.pattern + wR
def _grammar_assigned_notifier(self):
......@@ -854,28 +854,6 @@ class NaryOperator(Parser):
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):
def __init__(self, parser: Parser, name: str = '') -> None:
super(Optional, self).__init__(parser, name)
......@@ -1111,6 +1089,7 @@ def iter_right_branch(node) -> Iterator[Node]:
class Lookbehind(FlowOperator):
"""EXPERIMENTAL AND NEVER TESTED!!!"""
def __init__(self, parser: Parser, name: str = '') -> None:
super(Lookbehind, self).__init__(parser, name)
print("WARNING: Lookbehind Operator is experimental!")
......@@ -1142,6 +1121,7 @@ class Lookbehind(FlowOperator):
class NegativeLookbehind(Lookbehind):
"""EXPERIMENTAL AND NEVER TESTED!!!"""
def __repr__(self):
return '-!' + self.parser.repr
......@@ -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):
"""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):
Parser.__init__(self)
self.parser = None
......@@ -1272,8 +1291,8 @@ class Forward(Parser):
return s
def set(self, parser: Parser):
# assert isinstance(parser, Parser)
# self.name = parser.name # redundant, see Grammar-constructor
"""Sets the parser to which the calls to this Forward-object
shall be delegated."""
self.parser = parser
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
sys.path.extend(['../', './'])
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.dsl import parser_factory, DHPARSER_IMPORTS
......@@ -88,32 +88,6 @@ class TestInfiLoopsAndRecursion:
assert not syntax_tree.error_flag, syntax_tree.collect_errors()
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):
minilang = """not_forever = { // } \n"""
snippet = " "
......@@ -191,6 +165,25 @@ class TestGrammar:
grammar("kein Haupt", "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:
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