last_action
):
raise NotImplementedException
- def add_to_symbols(self, pyacc, production, last_action, symbols):
+ def add_to_symbols(
+ self,
+ pyacc,
+ production,
+ last_action,
+ _lr1,
+ symbols
+ ):
return last_action
class Action(Item):
self.repr_serialize(params)
return 'ast.PYACC.Production.Action({0:s})'.format(', '.join(params))
# GENERATE END
+
def post_process(
self,
pyacc,
name_to_symbol,
last_action
):
- production.n_symbols += int(last_action)
+ pyacc.n_productions += int(last_action) # midrule action production
+ production.n_symbols += int(last_action) # midrule action symbol
return True
- def add_to_symbols(self, pyacc, production, last_action, symbols):
- assert last_action is None # no mid-rule actions for now
+
+ def add_to_symbols(
+ self,
+ pyacc,
+ production,
+ last_action,
+ _lr1,
+ symbols
+ ):
+ if last_action is not None:
+ symbols.append(
+ ([], [len(_lr1.productions), len(_lr1.productions) + 1])
+ )
+ _lr1.productions.append(
+ (
+ # symbols (list of terminal_set, nonterminal_set)
+ [],
+ # lookaheads (list of initial_set, can_be_empty)
+ [([], True)],
+ # ref_data
+ last_action
+ )
+ )
for i in self[0]:
if isinstance(i, PYACC.Text.StackLocation):
i.offset = -production.n_symbols
self.repr_serialize(params)
return 'ast.PYACC.Production.SymbolRef({0:s})'.format(', '.join(params))
# GENERATE END
+
def post_process(
self,
pyacc,
name_to_symbol,
last_action
):
- production.n_symbols += int(last_action) + 1
+ pyacc.n_productions += int(last_action) # midrule action production
+ production.n_symbols += int(last_action) + 1 # midrule action symbol
if isinstance(self[0], PYACC.Char):
character = ord(self[0][0].get_text())
assert character != 0 # would conflict with YYEOF
if self.symbol >= 0:
production.last_terminal = self.symbol
return False
- def add_to_symbols(self, pyacc, production, last_action, symbols):
- assert last_action is None # no mid-rule actions for now
+
+ def add_to_symbols(
+ self,
+ pyacc,
+ production,
+ last_action,
+ _lr1,
+ symbols
+ ):
+ if last_action is not None:
+ symbols.append(
+ ([], [len(_lr1.productions), len(_lr1.productions) + 1])
+ )
+ _lr1.productions.append(
+ (
+ # symbols (list of terminal_set, nonterminal_set)
+ [],
+ # lookaheads (list of initial_set, can_be_empty)
+ [([], True)],
+ # ref_data
+ last_action
+ )
+ )
symbols.append(
(pyacc.terminals[self.symbol].character_set, [])
if self.symbol >= 0 else
):
self.lhs_nonterminal = lhs_nonterminal
- self.n_symbols = 0
+ self.n_symbols = 0 # includes midrule actions
self.last_terminal = -1
self.precedence_terminal = -1
last_action = False
last_action
)
- character_set = pyacc.nonterminals[
- self.lhs_nonterminal
- ].character_set
- character = 1 + len(pyacc.productions)
- if len(character_set) and character_set[-1] == character:
- character_set[-1] = character + 1
+ i = pyacc.nonterminals[self.lhs_nonterminal]
+ if len(i.character_set) and i.character_set[-1] == pyacc.n_productions:
+ i.character_set[-1] = pyacc.n_productions + 1
else:
- character_set.extend([character, character + 1])
+ i.character_set.extend([pyacc.n_productions, pyacc.n_productions + 1])
+ pyacc.n_productions += 1
pyacc.productions.append(self)
def add_to_lr1(self, pyacc, _lr1):
symbols = []
lookaheads = []
for i in self:
- last_action = i.add_to_symbols(pyacc, self, last_action, symbols)
+ last_action = i.add_to_symbols(
+ pyacc,
+ self,
+ last_action,
+ _lr1,
+ symbols
+ )
+ assert len(symbols) == self.n_symbols
_lr1.productions.append(
(
# symbols (list of terminal_set, nonterminal_set)
# lookaheads (list of initial_set, can_be_empty)
[([], False) for i in range(len(symbols))] + [([], True)],
# ref_data
- last_action if last_action is not None else PYACC.BracedCode()
+ last_action
)
)
precedence = (
):
pass
- # GENERATE ELEMENT(list(ref) prologue_text, list(ref) terminals, list(ref) nonterminals, list(ref) productions, int first_nonterminal, int start_nonterminal, list(int) associativities) BEGIN
+ # GENERATE ELEMENT(list(ref) prologue_text, list(ref) terminals, list(ref) nonterminals, int n_productions, list(ref) productions, int first_nonterminal, int start_nonterminal, list(int) associativities) BEGIN
def __init__(
self,
tag = 'PYACC',
prologue_text = [],
terminals = [],
nonterminals = [],
+ n_productions = -1,
productions = [],
first_nonterminal = -1,
start_nonterminal = -1,
self.prologue_text = prologue_text
self.terminals = terminals
self.nonterminals = nonterminals
+ self.n_productions = (
+ element.deserialize_int(n_productions)
+ if isinstance(n_productions, str) else
+ n_productions
+ )
self.productions = productions
self.first_nonterminal = (
element.deserialize_int(first_nonterminal)
'nonterminals',
' '.join([element.serialize_ref(i, ref_list) for i in self.nonterminals])
)
+ self.set('n_productions', element.serialize_int(self.n_productions))
self.set(
'productions',
' '.join([element.serialize_ref(i, ref_list) for i in self.productions])
element.deserialize_ref(i, ref_list)
for i in self.get('nonterminals', '').split()
]
+ self.n_productions = element.deserialize_int(self.get('n_productions', '-1'))
self.productions = [
element.deserialize_ref(i, ref_list)
for i in self.get('productions', '').split()
result.prologue_text = self.prologue_text
result.terminals = self.terminals
result.nonterminals = self.nonterminals
+ result.n_productions = self.n_productions
result.productions = self.productions
result.first_nonterminal = self.first_nonterminal
result.start_nonterminal = self.start_nonterminal
', '.join([repr(i) for i in self.nonterminals])
)
)
+ if self.n_productions != -1:
+ params.append(
+ 'n_productions = {0:s}'.format(repr(self.n_productions))
+ )
if len(self.productions):
params.append(
'productions = [{0:s}]'.format(
PYACC.Terminal(name = '$undefined')
]
self.nonterminals = []
+ self.n_productions = 1 # includes start and midrule action productions
self.productions = []
# variables that won't be serialized
# compute productions and nonterminals precedence table
for i in self.productions:
i.add_to_lr1(self, _lr1)
+ assert len(_lr1.productions) == self.n_productions
# propagate lookaheads
modified = True
# generate translate table for nonterminal symbols
# this is effectively a map from productions back to nonterminal symbols
# we do not generate an entry for the first production (start production)
- translate_nonterminals = numpy.zeros(
+ # we generate extra fake entries after end of pyacc.nonterminals for fake
+ # productions due to midrule actions (which leave gaps in the numbering)
+ translate_nonterminals = numpy.full(
(len(lr1dfa.productions) - 1,),
+ -1,
numpy.int16
)
for i in range(len(pyacc.nonterminals)):
pyacc.nonterminals[i].character_set[j] - 1:
pyacc.nonterminals[i].character_set[j + 1] - 1
] = i
+ midrule_actions = [translate_nonterminals == -1]
+ n_midrule_actions = numpy.sum(midrule_actions)
+ translate_nonterminals[midrule_actions] = numpy.arange(
+ len(pyacc.nonterminals),
+ len(pyacc.nonterminals) + n_midrule_actions,
+ dtype = numpy.int16
+ )
# translate and compress the tables
bison_lr1dfa = BisonLR1DFA(
lr1dfa,
len(pyacc.terminals),
translate_terminals,
- len(pyacc.nonterminals),
+ len(pyacc.nonterminals) + n_midrule_actions,
translate_nonterminals
)
for i in pyacc.terminals
] +
['"{0:s}"'.format(i.name) for i in pyacc.nonterminals] +
+ ['"$@{0:d}"'.format(i) for i in range(n_midrule_actions)] +
['YY_NULLPTR']
):
if x + len(i) >= 70:
lr1dfa.productions[i][1].get_text()
)
for i in range(len(lr1dfa.productions))
- if len(lr1dfa.productions[i][1])
+ if lr1dfa.productions[i][1] is not None
]
)
)