summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Beazley <dave@dabeaz.com>2015-04-22 06:59:25 -0500
committerDavid Beazley <dave@dabeaz.com>2015-04-22 06:59:25 -0500
commit8fb06b0c55e91d2d097a4d19782e22664a759830 (patch)
tree1fdebe57f15d4edf7fadd2209cee525de3546e14
parentaf651673ba6117a0a5405055a92170fffd028106 (diff)
downloadply-8fb06b0c55e91d2d097a4d19782e22664a759830.tar.gz
Continued work on defaulted states. Some bug fixes. In progress.
-rw-r--r--CHANGES35
-rw-r--r--ply/yacc.py11
-rw-r--r--test/testyacc.py2
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):