From 21d4541b3d3caec399a1b87f48dad559bb9d445e Mon Sep 17 00:00:00 2001 From: justincui <7495860+justincui@users.noreply.github.com> Date: Wed, 6 Aug 2025 19:26:53 -0700 Subject: [PATCH 1/2] Update yacc.py to fix a deadlock issue caused by defaulted_state reducing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. The original implementation did not prevent the defaulted_state from reducing in certain cases, which could lead to a deadlock when processing erroneous input. Although the previous condition if len(rules) == 1 and rules[0] < 0: was overly strict and made such a scenario highly unlikely, it was not completely safe. 2. Updated the defaulted_state rule to align with Bison’s behavior for handling defaulted_state reductions, and removed unnecessary lookahead checks to simplify state transitions—making it easier for the parser to trigger lexer state changes. --- src/ply/yacc.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ply/yacc.py b/src/ply/yacc.py index 6528796..f1d584b 100644 --- a/src/ply/yacc.py +++ b/src/ply/yacc.py @@ -255,9 +255,17 @@ def restart(self): def set_defaulted_states(self): self.defaulted_states = {} for state, actions in self.action.items(): + if not actions: + continue rules = list(actions.values()) - if len(rules) == 1 and rules[0] < 0: - self.defaulted_states[state] = rules[0] + first_rule = rules[0] + if first_rule < 0: + if len(rules) == 1: + self.defaulted_states[state] = first_rule + else: + all_rules = set(rules) + if len(all_rules) == 1: + self.defaulted_states[state] = first_rule def disable_defaulted_states(self): self.defaulted_states = {} @@ -324,7 +332,7 @@ def parse(self, input=None, lexer=None, debug=False, tracking=False): if debug: debug.debug('State : %s', state) - if state not in defaulted_states: + if state not in defaulted_states or errorcount>0: if not lookahead: if not lookaheadstack: lookahead = get_token() # Get the next token From 51956adb4ac027458d76873ec9a23df4e3af17f7 Mon Sep 17 00:00:00 2001 From: justincui <7495860+justincui@users.noreply.github.com> Date: Wed, 6 Aug 2025 19:31:13 -0700 Subject: [PATCH 2/2] Update yacc_error5.py to remove the invalid error handling rule. Since we now prevent reductions from defaulted_state during error recovery, error-handling rules that lack a right-hand symbol boundary are no longer meaningful and should be reconsidered or removed. --- tests/yacc_error5.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/yacc_error5.py b/tests/yacc_error5.py index 5d4b683..c59da56 100644 --- a/tests/yacc_error5.py +++ b/tests/yacc_error5.py @@ -21,12 +21,6 @@ def p_statement_assign(t): 'statement : NAME EQUALS expression' names[t[1]] = t[3] -def p_statement_assign_error(t): - 'statement : NAME EQUALS error' - line_start, line_end = t.linespan(3) - pos_start, pos_end = t.lexspan(3) - print("Assignment Error at %d:%d to %d:%d" % (line_start,pos_start,line_end,pos_end)) - def p_statement_expr(t): 'statement : expression' print(t[1])