Compare commits

...

2 commits

Author SHA1 Message Date
03937e62e6 Allow the generator to be a little more declarative 2024-06-01 05:57:16 -07:00
e203e27407 Allow the grammar to specify a preference for a generator
Overridable, like start production
2024-06-01 05:42:40 -07:00
3 changed files with 29 additions and 8 deletions

View file

@ -1,7 +1,7 @@
# This is an example grammar.
import re
from parser import Assoc, Grammar, Nothing, Terminal, rule, seq, Rule
from parser import Assoc, GenerateLALR, GenerateLR1, Grammar, Nothing, Terminal, rule, seq, Rule
ARROW = Terminal("Arrow")
AS = Terminal("As")
@ -54,10 +54,11 @@ RSQUARE = Terminal("RightBracket")
class FineGrammar(Grammar):
generator = GenerateLALR
start = "File"
def __init__(self):
super().__init__(
start="File",
precedence=[
(Assoc.RIGHT, [EQUAL]),
(Assoc.LEFT, [OR]),

View file

@ -258,11 +258,10 @@ class DynamicModule:
class DynamicGrammarModule(DynamicModule):
def __init__(self, file_name, member_name, start_rule, generator):
def __init__(self, file_name, member_name, start_rule):
super().__init__(file_name, member_name)
self.start_rule = start_rule
self.generator = generator
def _predicate(self, member) -> bool:
if not super()._predicate(member):
@ -274,7 +273,7 @@ class DynamicGrammarModule(DynamicModule):
return False
def _transform(self, value):
return value().build_table(start=self.start_rule, generator=self.generator)
return value().build_table(start=self.start_rule)
class DynamicLexerModule(DynamicModule):
@ -319,7 +318,7 @@ class Harness:
self.max_entries = 0
self.grammar_module = DynamicGrammarModule(
self.grammar_file, self.grammar_member, self.start_rule, generator=parser.GenerateLALR
self.grammar_file, self.grammar_member, self.start_rule
)
self.lexer_module = DynamicLexerModule(self.lexer_file, self.lexer_member)

View file

@ -1850,12 +1850,30 @@ class Grammar:
_precedence: dict[str, typing.Tuple[Assoc, int]]
_start: str
_generator: type[GenerateLR0]
def __init__(
self,
start: str | None = None,
precedence: PrecedenceList | None = None,
generator: type[GenerateLR0] | None = None,
):
if start is None:
start = getattr(self, "start", None)
if start is None:
raise ValueError(
"The default start rule must either be specified in the constructor or as an "
"attribute in the class."
)
def __init__(self, start: str, precedence: PrecedenceList | None = None):
if precedence is None:
precedence = getattr(self, "precedence", [])
assert precedence is not None
if generator is None:
generator = getattr(self, "generator", GenerateLALR)
assert generator is not None
precedence_table = {}
for prec, (associativity, symbols) in enumerate(precedence):
for symbol in symbols:
@ -1870,6 +1888,7 @@ class Grammar:
self._precedence = precedence_table
self._start = start
self._generator = generator
def generate_nonterminal_dict(
self, start: str | None = None
@ -1940,7 +1959,7 @@ class Grammar:
return grammar, transparents
def build_table(self, start: str | None, generator=GenerateLALR):
def build_table(self, start: str | None, generator=None):
"""Construct a parse table for this grammar, starting at the named
nonterminal rule.
"""
@ -1948,6 +1967,8 @@ class Grammar:
start = self._start
desugared, transparents = self.desugar(start)
if generator is None:
generator = self._generator
gen = generator(start, desugared, precedence=self._precedence, transparents=transparents)
table = gen.gen_table()
return table