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. # This is an example grammar.
import re 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") ARROW = Terminal("Arrow")
AS = Terminal("As") AS = Terminal("As")
@ -54,10 +54,11 @@ RSQUARE = Terminal("RightBracket")
class FineGrammar(Grammar): class FineGrammar(Grammar):
generator = GenerateLALR
start = "File"
def __init__(self): def __init__(self):
super().__init__( super().__init__(
start="File",
precedence=[ precedence=[
(Assoc.RIGHT, [EQUAL]), (Assoc.RIGHT, [EQUAL]),
(Assoc.LEFT, [OR]), (Assoc.LEFT, [OR]),

View file

@ -258,11 +258,10 @@ class DynamicModule:
class DynamicGrammarModule(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) super().__init__(file_name, member_name)
self.start_rule = start_rule self.start_rule = start_rule
self.generator = generator
def _predicate(self, member) -> bool: def _predicate(self, member) -> bool:
if not super()._predicate(member): if not super()._predicate(member):
@ -274,7 +273,7 @@ class DynamicGrammarModule(DynamicModule):
return False return False
def _transform(self, value): 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): class DynamicLexerModule(DynamicModule):
@ -319,7 +318,7 @@ class Harness:
self.max_entries = 0 self.max_entries = 0
self.grammar_module = DynamicGrammarModule( 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) 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]] _precedence: dict[str, typing.Tuple[Assoc, int]]
_start: str _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: if precedence is None:
precedence = getattr(self, "precedence", []) precedence = getattr(self, "precedence", [])
assert precedence is not None assert precedence is not None
if generator is None:
generator = getattr(self, "generator", GenerateLALR)
assert generator is not None
precedence_table = {} precedence_table = {}
for prec, (associativity, symbols) in enumerate(precedence): for prec, (associativity, symbols) in enumerate(precedence):
for symbol in symbols: for symbol in symbols:
@ -1870,6 +1888,7 @@ class Grammar:
self._precedence = precedence_table self._precedence = precedence_table
self._start = start self._start = start
self._generator = generator
def generate_nonterminal_dict( def generate_nonterminal_dict(
self, start: str | None = None self, start: str | None = None
@ -1940,7 +1959,7 @@ class Grammar:
return grammar, transparents 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 """Construct a parse table for this grammar, starting at the named
nonterminal rule. nonterminal rule.
""" """
@ -1948,6 +1967,8 @@ class Grammar:
start = self._start start = self._start
desugared, transparents = self.desugar(start) desugared, transparents = self.desugar(start)
if generator is None:
generator = self._generator
gen = generator(start, desugared, precedence=self._precedence, transparents=transparents) gen = generator(start, desugared, precedence=self._precedence, transparents=transparents)
table = gen.gen_table() table = gen.gen_table()
return table return table