From 8fb06b0c55e91d2d097a4d19782e22664a759830 Mon Sep 17 00:00:00 2001 From: David Beazley Date: Wed, 22 Apr 2015 06:59:25 -0500 Subject: Continued work on defaulted states. Some bug fixes. In progress. --- CHANGES | 35 ++++++++++++++++++++--------------- ply/yacc.py | 11 ++++++++--- test/testyacc.py | 2 ++ 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/CHANGES b/CHANGES index 54ffe3b..93c8aa8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,29 +1,34 @@ Version 3.5 --------------------- 04/21/15: beazley - Added optional support for defaulted_states in the parser. - A defaulted_state is a state where the only legal action is - a reduction of a single grammar rule across all valid input + Added support for defaulted_states in the parser. A + defaulted_state is a state where the only legal action is a + reduction of a single grammar rule across all valid input tokens. For such states, the rule is reduced and the reading of the next lookahead token is delayed until it is - actually needed at a later point in time. + actually needed at a later point in time. - This delay in consuming the next lookahead token is a potentially - important feature in advanced parsing applications that require tight - interaction between the lexer and the parser. For example, a grammar - rule change modify the lexer state upon reduction and have such changes + This delay in consuming the next lookahead token is a + potentially important feature in advanced parsing + applications that require tight interaction between the + lexer and the parser. For example, a grammar rule change + modify the lexer state upon reduction and have such changes take effect before the next input token is read. - One potential danger of defaulted_states is that syntax errors might - be deferred to a a later point of processing than where they were detected - in the past. Thus, it's possible that your error handling could change - slightly over previous versions of PLY. + *** POTENTIAL INCOMPATIBILITY *** + One potential danger of defaulted_states is that syntax + errors might be deferred to a a later point of processing + than where they were detected in past versions of PLY. + Thus, it's possible that your error handling could change + slightly on the same inputs. defaulted_states do not change + the overall parsing of the input (i.e., the same grammar is + accepted). - In order to enable defaulted_state support. You need to activate it - explicitly. For example: + If for some reason, you need to disable defaulted states, + you can do this: parser = yacc.yacc() - parser.use_defaulted_states() + parser.defaulted_states = {} 04/21/15: beazley Fixed debug logging in the parser. It wasn't properly reporting goto states diff --git a/ply/yacc.py b/ply/yacc.py index 63d4877..7dcd6c5 100644 --- a/ply/yacc.py +++ b/ply/yacc.py @@ -288,7 +288,8 @@ class LRParser: self.action = lrtab.lr_action self.goto = lrtab.lr_goto self.errorfunc = errorf - self.defaulted_states = { } + self.set_defaulted_states() + self.errorok = True def errok(self): self.errorok = True @@ -301,7 +302,7 @@ class LRParser: self.symstack.append(sym) self.statestack.append(0) - # Defaulted state support (Experimental) + # Defaulted state support. # This method identifies parser states where there is only one possible reduction action. # For such states, the parser can make a choose to make a rule reduction without consuming # the next look-ahead token. This delayed invocation of the tokenizer can be useful in @@ -309,12 +310,16 @@ class LRParser: # each other or change states (i.e., manipulation of scope, lexer states, etc.). # # See: http://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html#Default-Reductions - def use_defaulted_states(self): + def set_defaulted_states(self): + self.defaulted_states = {} for state, actions in self.action.items(): rules = list(actions.values()) if rules and rules[0] < 0 and all(rules[0] == rule for rule in rules): self.defaulted_states[state] = rules[0] + def disable_defaulted_states(self): + self.defaulted_states = {} + def parse(self, input=None, lexer=None, debug=False, tracking=False, tokenfunc=None): if debug or yaccdevel: if isinstance(debug, int): diff --git a/test/testyacc.py b/test/testyacc.py index f8f5f4f..357dcdc 100644 --- a/test/testyacc.py +++ b/test/testyacc.py @@ -199,9 +199,11 @@ class YaccErrorWarningTests(unittest.TestCase): result = sys.stdout.getvalue() self.assert_(check_expected(result, "Group at 3:10 to 3:12\n" + "Undefined name 'a'\n" "Syntax error at 'b'\n" "Syntax error at 4:18 to 4:22\n" "Assignment Error at 2:5 to 5:33\n" + "13\n" )) def test_yacc_error6(self): -- cgit v1.2.1