Skip to content

Commit

Permalink
Fix bug in scanning optimization due to unordered state actions
Browse files Browse the repository at this point in the history
Using of priorities for terminals was leading to nondeterministic parses due to
unordered state actions.
Also, this fix make LR table cache file deterministic again.
  • Loading branch information
igordejanovic committed May 3, 2019
1 parent a0032fd commit c6e3226
Showing 1 changed file with 14 additions and 7 deletions.
21 changes: 14 additions & 7 deletions parglare/tables/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def create_load_table(grammar, itemset_type=LR_1, start_production=1,

if in_layout:
# For layout grammars always calculate table.
# This are usually very small grammars so there is no point in
# Those are usually very small grammars so there is no point in
# using cached tables.
return create_table(grammar, itemset_type, start_production,
prefer_shifts, prefer_shifts_over_empty)
Expand Down Expand Up @@ -383,6 +383,7 @@ def __init__(
if calc_finish_flags:
if lexical_disambiguation is None:
lexical_disambiguation = True
self.sort_state_actions()
if lexical_disambiguation:
self.calc_finish_flags()
else:
Expand All @@ -394,12 +395,12 @@ def __init__(
'because calc_finish_flags is not set')
self.calc_conflicts_and_dynamic_terminals()

def calc_finish_flags(self):
def sort_state_actions(self):
"""
Scanning optimization. Preorder actions based on terminal priority
and specificity. Set _finish flags.
State actions need to be sorted in order to utilize scanning
optimization based on explicit or implicit disambiguation.
Also, by sorting actions table save file is made deterministic.
"""

def act_order(act_item):
"""Priority is the strongest property. After that honor string
recognizer over other types of recognizers.
Expand All @@ -419,10 +420,16 @@ def act_order(act_item):
return cmp_str

for state in self.states:
finish_flags = []
state.actions = OrderedDict(sorted(state.actions.items(),
key=act_order, reverse=True))
# Finish flags

def calc_finish_flags(self):
"""
Scanning optimization. Preorder actions based on terminal priority
and specificity. Set _finish flags.
"""
for state in self.states:
finish_flags = []
prior = None
for symbol, act in reversed(list(state.actions.items())):
if symbol.finish is not None:
Expand Down

0 comments on commit c6e3226

Please sign in to comment.