Commit a0ac8cf6 authored by di68kap's avatar di68kap

- added `start_parser` parameter to `GrammarBase.parse` in order to allow fine...

- added `start_parser` parameter to `GrammarBase.parse` in order to allow fine grained testing of ENBF syntax descriptions;
- added `dsl.suite_outdated`
- further corrections
parent 592bc036
......@@ -29,7 +29,7 @@ try:
except ImportError:
import re
from .ebnf import EBNFGrammar, EBNF_ASTPipeline, EBNFCompiler
from .ebnf import EBNFGrammar, EBNF_ASTPipeline, EBNFCompiler, grammar_changed
from .toolkit import load_if_file, is_python_code, compile_python_object
from .parsers import GrammarBase, CompilerBase, full_compilation, nil_scanner
from .syntaxtree import Node
......@@ -51,6 +51,7 @@ SECTION_MARKER = """\n
\n"""
RX_SECTION_MARKER = re.compile(SECTION_MARKER.format(marker=r'.*?SECTION.*?'))
RX_WHITESPACE = re.compile('\s*')
SYMBOLS_SECTION = "SYMBOLS SECTION - Can be edited. Changes will be preserved."
SCANNER_SECTION = "SCANNER SECTION - Can be edited. Changes will be preserved."
......@@ -82,10 +83,10 @@ class CompilationError(Exception):
self.AST = AST
def __str__(self):
return self.error_messages
return '\n'.join(self.error_messages)
DHPARSER_IMPORTS = """
DHPARSER_IMPORTS = '''
from functools import partial
import sys
try:
......@@ -101,7 +102,7 @@ from DHParser.syntaxtree import Node, remove_enclosing_delimiters, remove_childr
reduce_single_child, replace_by_single_child, remove_whitespace, TOKEN_KEYWORD, \\
no_operation, remove_expendables, remove_tokens, flatten, WHITESPACE_KEYWORD, \\
is_whitespace, is_expendable
"""
'''
DHPARSER_COMPILER = '''
......@@ -153,42 +154,14 @@ def get_grammar_instance(grammar):
return parser_root, grammar_src
def load_compiler_suite(compiler_suite):
"""Extracts a compiler suite from file or string ``compiler suite``
and returns it as a tuple (scanner, parser, ast, compiler).
"""
global RX_SECTION_MARKER
assert isinstance(compiler_suite, str)
source = load_if_file(compiler_suite)
if is_python_code(compiler_suite):
try:
intro, imports, scanner_py, parser_py, ast_py, compiler_py, outro = \
RX_SECTION_MARKER.split(source)
except ValueError as error:
raise ValueError('File "' + compiler_suite + '" seems to be corrupted. '
'Please delete or repair file manually.')
scanner = compile_python_object(imports + scanner_py, '\w*Scanner$')
ast = compile_python_object(imports + ast_py, '\w*Pipeline$')
compiler = compile_python_object(imports + compiler_py, '\w*Compiler$')
else:
# assume source is an ebnf grammar
parser_py, errors, AST = full_compilation(
source, None, EBNFGrammar(), EBNF_ASTPipeline, EBNFCompiler())
if errors:
raise GrammarError('\n\n'.join(errors), source)
scanner = nil_scanner
ast = EBNF_ASTPipeline
compiler = EBNFCompiler()
parser = compile_python_object(DHPARSER_IMPORTS + parser_py, '\w*Grammar$')()
return scanner, parser, ast, compiler
def compileDSL(text_or_file, dsl_grammar, ast_pipeline, compiler,
scanner=nil_scanner):
"""Compiles a text in a domain specific language (DSL) with an
EBNF-specified grammar. Returns the compiled text or raises a
compilation error.
Raises:
CompilationError if any errors occured during compilation
"""
assert isinstance(text_or_file, str)
assert isinstance(compiler, CompilerBase)
......@@ -196,7 +169,7 @@ def compileDSL(text_or_file, dsl_grammar, ast_pipeline, compiler,
parser_root, grammar_src = get_grammar_instance(dsl_grammar)
src = load_if_file(text_or_file)
result, errors, AST = full_compilation(src, scanner, parser_root, ast_pipeline, compiler)
if errors: raise CompilationError('\n\n'.join(errors), src, grammar_src, AST)
if errors: raise CompilationError(errors, src, grammar_src, AST)
return result
......@@ -228,6 +201,62 @@ def compileEBNF(ebnf_src, ebnf_grammar_obj=None, source_only=False):
compile_python_object(DHPARSER_IMPORTS + grammar_src, '\w*Grammar$')
def load_compiler_suite(compiler_suite):
"""Extracts a compiler suite from file or string ``compiler suite``
and returns it as a tuple (scanner, parser, ast, compiler).
"""
global RX_SECTION_MARKER
assert isinstance(compiler_suite, str)
source = load_if_file(compiler_suite)
if is_python_code(compiler_suite):
try:
intro, imports, scanner_py, parser_py, ast_py, compiler_py, outro = \
RX_SECTION_MARKER.split(source)
except ValueError as error:
raise AssertionError('File "' + compiler_suite + '" seems to be corrupted. '
'Please delete or repair file manually.')
scanner = compile_python_object(imports + scanner_py, '\w*Scanner$')
ast = compile_python_object(imports + ast_py, '\w*Pipeline$')
compiler = compile_python_object(imports + compiler_py, '\w*Compiler$')
else:
# assume source is an ebnf grammar
parser_py, errors, AST = full_compilation(
source, None, EBNFGrammar(), EBNF_ASTPipeline, EBNFCompiler())
if errors:
raise GrammarError('\n\n'.join(errors), source)
scanner = nil_scanner
ast = EBNF_ASTPipeline
compiler = EBNFCompiler()
parser = compile_python_object(DHPARSER_IMPORTS + parser_py, '\w*Grammar$')()
return scanner, parser, ast, compiler
def suite_outdated(compiler_suite, grammar_source):
"""Returns ``True`` if the ``compile_suite`` needs to be updated.
An update is needed, if either the grammar in the compieler suite
does not reflect the latest changes of ``grammar_source`` or if
sections from the compiler suite have diligently been overwritten
with whitespace order to trigger their recreation. Note: Do not
delete or overwrite the section marker itself.
Parameters:
compiler_suite: the parser class representing the grammar
or the file name of a compiler suite containing the grammar
grammar_source: File name or string representation of the
EBNF code of the grammar
Returns (bool):
True, if ``compiler_suite`` seems to be out of date.
"""
try:
scanner, grammar, ast, compiler = load_compiler_suite(compiler_suite)
return grammar_changed(grammar, grammar_source)
except ValueError:
return True
def run_compiler(source_file, compiler_suite="", extension=".xml"):
"""Compiles the a source file with a given compiler and writes the
result to a file.
......@@ -243,19 +272,19 @@ def run_compiler(source_file, compiler_suite="", extension=".xml"):
occurred.
"""
filepath = os.path.normpath(source_file)
with open(source_file, encoding="utf-8") as f:
source = f.read()
# with open(source_file, encoding="utf-8") as f:
# source = f.read()
rootname = os.path.splitext(filepath)[0]
compiler_name = os.path.basename(rootname)
if compiler_suite:
scanner, parser, trans, cclass = load_compiler_suite(compiler_suite)
compiler = cclass()
compiler1 = cclass()
else:
scanner = nil_scanner
parser = EBNFGrammar()
trans = EBNF_ASTPipeline
compiler = EBNFCompiler(compiler_name, source)
result, errors, ast = full_compilation(source, scanner, parser, trans, compiler)
compiler1 = EBNFCompiler(compiler_name, source_file)
result, errors, ast = full_compilation(source_file, scanner, parser, trans, compiler1)
if errors:
return errors
......@@ -267,20 +296,29 @@ def run_compiler(source_file, compiler_suite="", extension=".xml"):
try:
f = open(rootname + '_compiler.py', 'r', encoding="utf-8")
source = f.read()
intro, imports, scanner, parser, ast, compiler, outro = RX_SECTION_MARKER.split(source)
sections = RX_SECTION_MARKER.split(source)
intro, imports, scanner, parser, ast, compiler, outro = sections
except (PermissionError, FileNotFoundError, IOError) as error:
intro = '#!/usr/bin/python'
outro = DHPARSER_COMPILER.format(NAME=compiler_name)
imports = DHPARSER_IMPORTS
scanner = compiler.gen_scanner_skeleton()
ast = compiler.gen_AST_skeleton()
compiler = compiler.gen_compiler_skeleton()
intro, imports, scanner, parser, ast, compiler, outro = '', '', '', '', '', '', ''
except ValueError as error:
raise ValueError('File "' + rootname + '_compiler.py" seems to be corrupted. '
'Please delete or repair file manually!')
finally:
if f: f.close()
if RX_WHITESPACE.fullmatch(intro):
intro = '#!/usr/bin/python'
if RX_WHITESPACE.fullmatch(outro):
outro = DHPARSER_COMPILER.format(NAME=compiler_name)
if RX_WHITESPACE.fullmatch(imports):
imports = DHPARSER_IMPORTS
if RX_WHITESPACE.fullmatch(scanner):
scanner = compiler1.gen_scanner_skeleton()
if RX_WHITESPACE.fullmatch(ast):
ast = compiler1.gen_AST_skeleton()
if RX_WHITESPACE.fullmatch(compiler):
compiler = compiler1.gen_compiler_skeleton()
try:
f = open(rootname + '_compiler.py', 'w', encoding="utf-8")
f.write(intro)
......
......@@ -315,7 +315,9 @@ class EBNFCompiler(CompilerBase):
def definition(self, node):
rule = node.result[0].result
if rule in EBNFCompiler.RESERVED_SYMBOLS:
if rule in self.rules:
node.add_error('A rule with name "%s" has already been defined.' % rule)
elif rule in EBNFCompiler.RESERVED_SYMBOLS:
node.add_error('Symbol "%s" is a reserved symbol.' % rule)
elif not sane_parser_name(rule):
node.add_error('Illegal symbol "%s". Symbols must not start or '
......@@ -326,9 +328,6 @@ class EBNFCompiler(CompilerBase):
elif keyword.iskeyword(rule):
node.add_error('Python keyword "%s" may not be used as a symbol. '
% rule + '(This may change in the furute.)')
elif rule in self.rules:
node.add_error('A rule with name "%s" has already been defined.' %
rule)
try:
self.rules.add(rule)
defn = self.compile__(node.result[1])
......@@ -377,6 +376,9 @@ class EBNFCompiler(CompilerBase):
value = escape_re(value[1:-1])
elif value[0] + value[-1] == '//':
value = self._check_rx(node, value[1:-1])
if key == 'whitespace' and not re.match(value, ''):
node.add_error("Implicit whitespace should always match the empty string, "
"/%s/ does not." % value)
self.directives[key] = value
elif key == 'literalws':
......@@ -500,16 +502,16 @@ class EBNFCompiler(CompilerBase):
return set(item.result.strip() for item in node.result)
def grammar_changed(grammar_source, grammar_class):
"""Returns `True` if `grammar_class` does not reflect the latest
changes of `grammar_source`
def grammar_changed(grammar_class, grammar_source):
"""Returns ``True`` if ``grammar_class`` does not reflect the latest
changes of ``grammar_source``
Parameters:
grammar_source: File name or string representation of the
EBNF code of the grammar
grammar_class: the parser class representing the grammar
or the file name of a compiler suite containing the grammar
grammar_source: File name or string representation of the
EBNF code of the grammar
Returns (bool):
True, if the source text of the grammar is different from the
source from which the grammar class was generated
......
......@@ -58,6 +58,7 @@ try:
import regex as re
except ImportError:
import re
import sys
from .toolkit import IS_LOGGING, LOGS_DIR, escape_re, sane_parser_name, smart_list
from .syntaxtree import WHITESPACE_KEYWORD, TOKEN_KEYWORD, ZOMBIE_PARSER, Node, \
......@@ -265,14 +266,22 @@ class GrammarBase:
...
symbol = RE('(?!\\d)\\w+')
After the call of this method symbol.name == "symbol"
holds. Names assigned via the `name`-parameter of the
constructor will not be overwritten.
holds. Names assigned via the ``name``-parameter of the
constructor will not be overwritten. Parser names starting or
ending with a double underscore like ``root__`` will be
ignored. See ``toolkit.sane_parser_name()``
Attention: If there exists more than one reference to the same
parser, only the first one will be chosen for python versions
greater or equal 3.6. For python version <= 3.5 an arbitrarily
selected reference will be chosen. See PEP 520
(www.python.org/dev/peps/pep-0520/) for an explanation of why.
"""
if cls.parser_initialization__ == "done":
return
cdict = cls.__dict__
for entry, parser in cdict.items():
if isinstance(parser, Parser):
if isinstance(parser, Parser) and sane_parser_name(entry):
if not parser.name or parser.name == TOKEN_KEYWORD:
parser.name = entry
if (isinstance(parser, Forward) and (not parser.parser.name
......@@ -301,6 +310,9 @@ class GrammarBase:
self.wsp_right_parser__ = ZOMBIE_PARSER
self.root__.apply(self._add_parser)
def __getitem__(self, key):
return self.__dict__[key]
def _reset(self):
self.variables = dict() # support for Pop and Retrieve operators
self.document = "" # source document
......@@ -318,7 +330,7 @@ class GrammarBase:
self.all_parsers.add(parser)
parser.grammar = self
def parse(self, document):
def parse(self, document, start_parser="root__"):
"""Parses a document with with parser-combinators.
Args:
......@@ -335,10 +347,10 @@ class GrammarBase:
else:
self.dirty_flag = True
self.document = document
parser = self.root__
result = ""
parser = self[start_parser]
stitches = []
rest = document
result = Node(None, '')
while rest and len(stitches) < MAX_DROPOUTS:
result, rest = parser(rest)
if rest:
......
......@@ -105,8 +105,8 @@ def LOGS_DIR() -> str:
with open(info_file_name, 'w') as f:
f.write("This directory has been created by DHParser to store log files from\n"
"parsing. ANY FILE IN THIS DIRECTORY CAN BE OVERWRITTEN! Therefore,\n"
"do not place any files here or edit existing files in this directory\n"
"manually.\n")
"do not place any files here and do not bother editing files in this\n"
"directory as any changes will get lost.\n")
return dirname
......@@ -274,8 +274,10 @@ def compile_python_object(python_src, catch_obj_regex):
namespace = {}
exec(code, namespace) # safety risk?
matches = [key for key in namespace.keys() if catch_obj_regex.match(key)]
if len(matches) > 1:
raise AssertionError("Ambigous matches for %s : %s" %
(str(catch_obj_regex), str(matches)))
if len(matches) == 0:
raise ValueError("No object matching /%s/ defined in source code." %
catch_obj_regex.pattern)
elif len(matches) > 1:
raise ValueError("Ambigous matches for %s : %s" %
(str(catch_obj_regex), str(matches)))
return namespace[matches[0]] if matches else None
......@@ -4,7 +4,6 @@
@ whitespace = /[\t ]*/ # Zeilensprünge zählen nicht als Leerraum
@ literalws = both # Leerraum vor und nach Literalen wird automatisch entfernt
Artikel = [LEER]
§LemmaPosition [ArtikelKopf] §BedeutungsPosition §Autorinfo
[LEER] DATEI_ENDE
......@@ -34,7 +33,6 @@ _wortart = "nomen" | "n." |
"adverb" | "adv." |
"adjektiv" | "adj."
GrammatikVarianten = TRENNER GVariante
GVariante = Flexionen [_genus] ":" Beleg
......@@ -71,7 +69,8 @@ Interpretamente = LateinischeBedeutung [LEER] §DeutscheBedeutung [LEER]
LateinischeBedeutung = "LAT" /(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+/~
DeutscheBedeutung = "DEU" /(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+/~
Belege = "BELEGE" [LEER] { "*" EinBeleg }
EinBeleg = { !(/\s*/ ("*" | "BEDEUTUNG" | "AUTOR" | "NAME" | "ZUSATZ")) /\s*.*\s*/ }+
EinBeleg = { !([LEER] ("*" | "BEDEUTUNG" | "AUTOR" | "NAME" | "ZUSATZ"))
/\s*.*\s*/ }+
[Zusatz]
Zusatz = "ZUSATZ" /\s*.*/ TRENNER
......@@ -79,21 +78,23 @@ Zusatz = "ZUSATZ" /\s*.*/ TRENNER
#### AUTOR/AUTORIN ###########################################################
Autorinfo = ("AUTORIN" | "AUTOR") Name
Name = WORT { WORT | /[A-ZÄÖÜÁÀ]\./ }
Name = WORT { WORT | NAMENS_ABKÜRZUNG }
#### ATOMARE AUSDRÜCKE #######################################################
#### MISZELLANEEN ############################################################
NAMENS_ABKÜRZUNG = /[A-ZÄÖÜÁÀ]\./
WORT = /[A-ZÄÖÜ]?[a-zäöüß]+/~
WORT_GROSS = /[A-ZÄÖÜ][a-zäöüß]+/~
WORT_KLEIN = /[a-zäöüß]+/~
LAT_WORT = /[a-z]+/~
GROSSSCHRIFT = /[A-ZÄÖÜ]+/~
WORT = /[A-ZÄÖÜ]?[a-zäöüß]+/~
WORT_GROSS = /[A-ZÄÖÜ][a-zäöüß]+/~
WORT_KLEIN = /[a-zäöüß]+/~
LAT_WORT = /[a-z]+/~
GROSSSCHRIFT = /[A-ZÄÖÜ]+/~
TRENNER = /\s*;\s*/ | { ZSPRUNG }+
ZSPRUNG = /\n/~
TRENNER = /\s*;\s*/ | { ZSPRUNG }+
ZSPRUNG = /\n/~
LEER = /\s+/ # horizontaler und(!) vertikaler Leerraum
DATEI_ENDE = !/./
NIEMALS = /(?!.)/
LEER = /\s+/ # horizontaler und(!) vertikaler Leerraum
DATEI_ENDE = !/./
NIEMALS = /(?!.)/
#!/usr/bin/python
#######################################################################
#
# SYMBOLS SECTION - Can be edited. Changes will be preserved.
#
#######################################################################
from functools import partial
import sys
try:
......@@ -23,7 +24,6 @@ from DHParser.syntaxtree import Node, remove_enclosing_delimiters, remove_childr
no_operation, remove_expendables, remove_tokens, flatten, WHITESPACE_KEYWORD, \
is_whitespace, is_expendable
#######################################################################
#
# SCANNER SECTION - Can be edited. Changes will be preserved.
......@@ -33,7 +33,6 @@ from DHParser.syntaxtree import Node, remove_enclosing_delimiters, remove_childr
def MLWScanner(text):
return text
#######################################################################
#
# PARSER SECTION - Don't edit! CHANGES WILL BE OVERWRITTEN!
......@@ -49,7 +48,6 @@ class MLWGrammar(GrammarBase):
@ whitespace = /[\t ]*/ # Zeilensprünge zählen nicht als Leerraum
@ literalws = both # Leerraum vor und nach Literalen wird automatisch entfernt
Artikel = [LEER]
§LemmaPosition [ArtikelKopf] §BedeutungsPosition §Autorinfo
[LEER] DATEI_ENDE
......@@ -79,7 +77,6 @@ class MLWGrammar(GrammarBase):
"adverb" | "adv." |
"adjektiv" | "adj."
GrammatikVarianten = TRENNER GVariante
GVariante = Flexionen [_genus] ":" Beleg
......@@ -116,7 +113,8 @@ class MLWGrammar(GrammarBase):
LateinischeBedeutung = "LAT" /(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+/~
DeutscheBedeutung = "DEU" /(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+/~
Belege = "BELEGE" [LEER] { "*" EinBeleg }
EinBeleg = { !(/\s*/ ("*" | "BEDEUTUNG" | "AUTOR" | "NAME" | "ZUSATZ")) /\s*.*\s*/ }+
EinBeleg = { !([LEER] ("*" | "BEDEUTUNG" | "AUTOR" | "NAME" | "ZUSATZ"))
/\s*.*\s*/ }+
[Zusatz]
Zusatz = "ZUSATZ" /\s*.*/ TRENNER
......@@ -124,25 +122,27 @@ class MLWGrammar(GrammarBase):
#### AUTOR/AUTORIN ###########################################################
Autorinfo = ("AUTORIN" | "AUTOR") Name
Name = WORT { WORT | /[A-ZÄÖÜÁÀ]\./ }
Name = WORT { WORT | NAMENS_ABKÜRZUNG }
#### ATOMARE AUSDRÜCKE #######################################################
#### MISZELLANEEN ############################################################
NAMENS_ABKÜRZUNG = /[A-ZÄÖÜÁÀ]\./
WORT = /[A-ZÄÖÜ]?[a-zäöüß]+/~
WORT_GROSS = /[A-ZÄÖÜ][a-zäöüß]+/~
WORT_KLEIN = /[a-zäöüß]+/~
LAT_WORT = /[a-z]+/~
GROSSSCHRIFT = /[A-ZÄÖÜ]+/~
WORT = /[A-ZÄÖÜ]?[a-zäöüß]+/~
WORT_GROSS = /[A-ZÄÖÜ][a-zäöüß]+/~
WORT_KLEIN = /[a-zäöüß]+/~
LAT_WORT = /[a-z]+/~
GROSSSCHRIFT = /[A-ZÄÖÜ]+/~
TRENNER = /\s*;\s*/ | { ZSPRUNG }+
ZSPRUNG = /\n/~
TRENNER = /\s*;\s*/ | { ZSPRUNG }+
ZSPRUNG = /\n/~
LEER = /\s+/ # horizontaler und(!) vertikaler Leerraum
DATEI_ENDE = !/./
NIEMALS = /(?!.)/
LEER = /\s+/ # horizontaler und(!) vertikaler Leerraum
DATEI_ENDE = !/./
NIEMALS = /(?!.)/
"""
source_hash__ = "c679466fdd21965264a35c185e2224a0"
source_hash__ = "c286ef13eadbfca1130da7eee9f4011c"
parser_initialization__ = "upon instatiation"
COMMENT__ = r'#.*(?:\n|$)'
WSP__ = mixin_comment(whitespace=r'[\t ]*', comment=r'#.*(?:\n|$)')
......@@ -158,10 +158,11 @@ class MLWGrammar(GrammarBase):
WORT_KLEIN = RE('[a-zäöüß]+', wL='')
WORT_GROSS = RE('[A-ZÄÖÜ][a-zäöüß]+', wL='')
WORT = RE('[A-ZÄÖÜ]?[a-zäöüß]+', wL='')
Name = Sequence(WORT, ZeroOrMore(Alternative(WORT, RE('[A-ZÄÖÜÁÀ]\\.', wR='', wL=''))))
NAMENS_ABKÜRZUNG = RE('[A-ZÄÖÜÁÀ]\\.', wR='', wL='')
Name = Sequence(WORT, ZeroOrMore(Alternative(WORT, NAMENS_ABKÜRZUNG)))
Autorinfo = Sequence(Alternative(Token("AUTORIN"), Token("AUTOR")), Name)
Zusatz = Sequence(Token("ZUSATZ"), RE('\\s*.*', wR='', wL=''), TRENNER)
EinBeleg = Sequence(OneOrMore(Sequence(NegativeLookahead(Sequence(RE('\\s*', wR='', wL=''), Alternative(Token("*"), Token("BEDEUTUNG"), Token("AUTOR"), Token("NAME"), Token("ZUSATZ")))), RE('\\s*.*\\s*', wR='', wL=''))), Optional(Zusatz))
EinBeleg = Sequence(OneOrMore(Sequence(NegativeLookahead(Sequence(Optional(LEER), Alternative(Token("*"), Token("BEDEUTUNG"), Token("AUTOR"), Token("NAME"), Token("ZUSATZ")))), RE('\\s*.*\\s*', wR='', wL=''))), Optional(Zusatz))
Belege = Sequence(Token("BELEGE"), Optional(LEER), ZeroOrMore(Sequence(Token("*"), EinBeleg)))
DeutscheBedeutung = Sequence(Token("DEU"), RE('(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+', wL=''))
LateinischeBedeutung = Sequence(Token("LAT"), RE('(?:(?![A-ZÄÖÜ][A-ZÄÖÜ]).)+', wL=''))
......@@ -284,7 +285,6 @@ MLW_ASTTransform = {
MLW_ASTPipeline = [MLW_ASTTransform]
#######################################################################
#
# COMPILER SECTION - Can be edited. Changes will be preserved.
......@@ -428,14 +428,12 @@ class MLWCompiler(CompilerBase):
def NIEMALS(self, node):
pass
#######################################################################
#
# END OF DHPARSER-SECTIONS
#
#######################################################################
def compile_MLW(source):
"""Compiles ``source`` and returns (result, errors, ast).
"""
......@@ -452,4 +450,4 @@ if __name__ == "__main__":
else:
print(result)
else:
print("Usage: MLW_compiler.py [FILENAME]")
print("Usage: MLW_compiler.py [FILENAME]")
\ No newline at end of file
......@@ -34,7 +34,7 @@ MLW_compiler = os.path.join('..', 'MLW_compiler.py')
toolkit.logging_off()
if (not os.path.exists(MLW_compiler) or
grammar_changed(MLW_ebnf, MLW_compiler)):
grammar_changed(MLW_compiler, MLW_ebnf)):
print("recompiling parser")
errors = run_compiler(MLW_ebnf)
if errors:
......
......@@ -39,7 +39,6 @@ BELEGE
VII. 92,6 fascercule tres. 21,20 IIII festregele.
ZUSATZ saepe.
BEDEUTUNG
LAT capital, rica
......
......@@ -7,15 +7,21 @@
#######################################################################
from functools import partial
import sys
try:
import regex as re
except ImportError:
import re
from DHParser.toolkit import load_if_file
from DHParser.parsers import GrammarBase, CompilerBase, Alternative, Pop, Retrieve, Sequence, RE, Capture, \
ZeroOrMore, NegativeLookahead, mixin_comment, full_compilation
from DHParser.syntaxtree import no_operation
from DHParser.toolkit import load_if_file
from DHParser.parsers import GrammarBase, CompilerBase, nil_scanner, \
Lookbehind, Lookahead, Alternative, Pop, Required, Token, \
Optional, NegativeLookbehind, OneOrMore, RegExp, Retrieve, Sequence, RE, Capture, \
ZeroOrMore, Forward, NegativeLookahead, mixin_comment, full_compilation
from DHParser.syntaxtree import Node, remove_enclosing_delimiters, remove_children_if, \
reduce_single_child, replace_by_single_child, remove_whitespace, TOKEN_KEYWORD, \
no_operation, remove_expendables, remove_tokens, flatten, WHITESPACE_KEYWORD, \
is_whitespace, is_expendable
#######################################################################
......@@ -116,9 +122,8 @@ class PopRetrieveCompiler(CompilerBase):
def compile_PopRetrieve(source):
"""Compiles ``source`` and returns (result, errors, ast).
"""
source_text = load_if_file(source)
return full_compilation(source_text, PopRetrieveScanner,
PopRetrieveGrammar(), PopRetrieve_ASTPipeline, PopRetrieveCompiler())
return full_compilation(source, PopRetrieveScanner,
PopRetrieveGrammar(), PopRetrieve_ASTPipeline, PopRetrieveCompiler())
if __name__ == "__main__":
if len(sys.argv) > 1:
......
......@@ -23,40 +23,43 @@ limitations under the License.
import os
import sys
sys.path.append(os.path.abspath('../../'))
from DHParser.dsl import run_compiler
from DHParser.ebnf import grammar_changed
from DHParser.dsl import run_compiler, suite_outdated
if (not os.path.exists('PopRetrieve_compiler.py') or