Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Open sidebar
badw-it
DHParser
Commits
e2d7ea45
Commit
e2d7ea45
authored
Jul 12, 2017
by
di68kap
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
- MLW: imperium-Beispiel
parent
1937f410
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
77 additions
and
54 deletions
+77
-54
DHParser/parsers.py
DHParser/parsers.py
+46
-27
examples/MLW/Beispiele/imperium.mlw
examples/MLW/Beispiele/imperium.mlw
+11
-0
test/test_parsers.py
test/test_parsers.py
+20
-27
No files found.
DHParser/parsers.py
View file @
e2d7ea45
...
...
@@ -771,8 +771,8 @@ class RE(Parser):
return
None
,
text
def
__repr__
(
self
):
wL
=
'~'
if
self
.
w
L
else
''
wR
=
'~'
if
self
.
w
R
else
''
wL
=
'~'
if
self
.
w
spLeft
else
''
wR
=
'~'
if
self
.
w
spRight
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
):
...
...
examples/MLW/Beispiele/imperium.mlw
0 → 100644
View file @
e2d7ea45
LEMMA imperi|um
inp-erium
GRAMMATIK
-i n. # keine Wortart?
SCHREIBWEISE
script.:
test/test_parsers.py
View file @
e2d7ea45
...
...
@@ -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
=
"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment