xref: /aosp_15_r20/external/libchrome/third_party/ply/yacc.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2*635a8641SAndroid Build Coastguard Worker# ply: yacc.py
3*635a8641SAndroid Build Coastguard Worker#
4*635a8641SAndroid Build Coastguard Worker# Copyright (C) 2001-2011,
5*635a8641SAndroid Build Coastguard Worker# David M. Beazley (Dabeaz LLC)
6*635a8641SAndroid Build Coastguard Worker# All rights reserved.
7*635a8641SAndroid Build Coastguard Worker#
8*635a8641SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without
9*635a8641SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are
10*635a8641SAndroid Build Coastguard Worker# met:
11*635a8641SAndroid Build Coastguard Worker#
12*635a8641SAndroid Build Coastguard Worker# * Redistributions of source code must retain the above copyright notice,
13*635a8641SAndroid Build Coastguard Worker#   this list of conditions and the following disclaimer.
14*635a8641SAndroid Build Coastguard Worker# * Redistributions in binary form must reproduce the above copyright notice,
15*635a8641SAndroid Build Coastguard Worker#   this list of conditions and the following disclaimer in the documentation
16*635a8641SAndroid Build Coastguard Worker#   and/or other materials provided with the distribution.
17*635a8641SAndroid Build Coastguard Worker# * Neither the name of the David Beazley or Dabeaz LLC may be used to
18*635a8641SAndroid Build Coastguard Worker#   endorse or promote products derived from this software without
19*635a8641SAndroid Build Coastguard Worker#  specific prior written permission.
20*635a8641SAndroid Build Coastguard Worker#
21*635a8641SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*635a8641SAndroid Build Coastguard Worker# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*635a8641SAndroid Build Coastguard Worker# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24*635a8641SAndroid Build Coastguard Worker# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25*635a8641SAndroid Build Coastguard Worker# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26*635a8641SAndroid Build Coastguard Worker# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27*635a8641SAndroid Build Coastguard Worker# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28*635a8641SAndroid Build Coastguard Worker# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29*635a8641SAndroid Build Coastguard Worker# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30*635a8641SAndroid Build Coastguard Worker# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*635a8641SAndroid Build Coastguard Worker# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
33*635a8641SAndroid Build Coastguard Worker#
34*635a8641SAndroid Build Coastguard Worker# This implements an LR parser that is constructed from grammar rules defined
35*635a8641SAndroid Build Coastguard Worker# as Python functions. The grammer is specified by supplying the BNF inside
36*635a8641SAndroid Build Coastguard Worker# Python documentation strings.  The inspiration for this technique was borrowed
37*635a8641SAndroid Build Coastguard Worker# from John Aycock's Spark parsing system.  PLY might be viewed as cross between
38*635a8641SAndroid Build Coastguard Worker# Spark and the GNU bison utility.
39*635a8641SAndroid Build Coastguard Worker#
40*635a8641SAndroid Build Coastguard Worker# The current implementation is only somewhat object-oriented. The
41*635a8641SAndroid Build Coastguard Worker# LR parser itself is defined in terms of an object (which allows multiple
42*635a8641SAndroid Build Coastguard Worker# parsers to co-exist).  However, most of the variables used during table
43*635a8641SAndroid Build Coastguard Worker# construction are defined in terms of global variables.  Users shouldn't
44*635a8641SAndroid Build Coastguard Worker# notice unless they are trying to define multiple parsers at the same
45*635a8641SAndroid Build Coastguard Worker# time using threads (in which case they should have their head examined).
46*635a8641SAndroid Build Coastguard Worker#
47*635a8641SAndroid Build Coastguard Worker# This implementation supports both SLR and LALR(1) parsing.  LALR(1)
48*635a8641SAndroid Build Coastguard Worker# support was originally implemented by Elias Ioup ([email protected]),
49*635a8641SAndroid Build Coastguard Worker# using the algorithm found in Aho, Sethi, and Ullman "Compilers: Principles,
50*635a8641SAndroid Build Coastguard Worker# Techniques, and Tools" (The Dragon Book).  LALR(1) has since been replaced
51*635a8641SAndroid Build Coastguard Worker# by the more efficient DeRemer and Pennello algorithm.
52*635a8641SAndroid Build Coastguard Worker#
53*635a8641SAndroid Build Coastguard Worker# :::::::: WARNING :::::::
54*635a8641SAndroid Build Coastguard Worker#
55*635a8641SAndroid Build Coastguard Worker# Construction of LR parsing tables is fairly complicated and expensive.
56*635a8641SAndroid Build Coastguard Worker# To make this module run fast, a *LOT* of work has been put into
57*635a8641SAndroid Build Coastguard Worker# optimization---often at the expensive of readability and what might
58*635a8641SAndroid Build Coastguard Worker# consider to be good Python "coding style."   Modify the code at your
59*635a8641SAndroid Build Coastguard Worker# own risk!
60*635a8641SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------
61*635a8641SAndroid Build Coastguard Worker
62*635a8641SAndroid Build Coastguard Worker__version__    = "3.4"
63*635a8641SAndroid Build Coastguard Worker__tabversion__ = "3.2"       # Table version
64*635a8641SAndroid Build Coastguard Worker
65*635a8641SAndroid Build Coastguard Worker#-----------------------------------------------------------------------------
66*635a8641SAndroid Build Coastguard Worker#                     === User configurable parameters ===
67*635a8641SAndroid Build Coastguard Worker#
68*635a8641SAndroid Build Coastguard Worker# Change these to modify the default behavior of yacc (if you wish)
69*635a8641SAndroid Build Coastguard Worker#-----------------------------------------------------------------------------
70*635a8641SAndroid Build Coastguard Worker
71*635a8641SAndroid Build Coastguard Workeryaccdebug   = 1                # Debugging mode.  If set, yacc generates a
72*635a8641SAndroid Build Coastguard Worker                               # a 'parser.out' file in the current directory
73*635a8641SAndroid Build Coastguard Worker
74*635a8641SAndroid Build Coastguard Workerdebug_file  = 'parser.out'     # Default name of the debugging file
75*635a8641SAndroid Build Coastguard Workertab_module  = 'parsetab'       # Default name of the table module
76*635a8641SAndroid Build Coastguard Workerdefault_lr  = 'LALR'           # Default LR table generation method
77*635a8641SAndroid Build Coastguard Worker
78*635a8641SAndroid Build Coastguard Workererror_count = 3                # Number of symbols that must be shifted to leave recovery mode
79*635a8641SAndroid Build Coastguard Worker
80*635a8641SAndroid Build Coastguard Workeryaccdevel   = 0                # Set to True if developing yacc.  This turns off optimized
81*635a8641SAndroid Build Coastguard Worker                               # implementations of certain functions.
82*635a8641SAndroid Build Coastguard Worker
83*635a8641SAndroid Build Coastguard Workerresultlimit = 40               # Size limit of results when running in debug mode.
84*635a8641SAndroid Build Coastguard Worker
85*635a8641SAndroid Build Coastguard Workerpickle_protocol = 0            # Protocol to use when writing pickle files
86*635a8641SAndroid Build Coastguard Worker
87*635a8641SAndroid Build Coastguard Workerimport re, types, sys, os.path
88*635a8641SAndroid Build Coastguard Worker
89*635a8641SAndroid Build Coastguard Worker# Compatibility function for python 2.6/3.0
90*635a8641SAndroid Build Coastguard Workerif sys.version_info[0] < 3:
91*635a8641SAndroid Build Coastguard Worker    def func_code(f):
92*635a8641SAndroid Build Coastguard Worker        return f.func_code
93*635a8641SAndroid Build Coastguard Workerelse:
94*635a8641SAndroid Build Coastguard Worker    def func_code(f):
95*635a8641SAndroid Build Coastguard Worker        return f.__code__
96*635a8641SAndroid Build Coastguard Worker
97*635a8641SAndroid Build Coastguard Worker# Compatibility
98*635a8641SAndroid Build Coastguard Workertry:
99*635a8641SAndroid Build Coastguard Worker    MAXINT = sys.maxint
100*635a8641SAndroid Build Coastguard Workerexcept AttributeError:
101*635a8641SAndroid Build Coastguard Worker    MAXINT = sys.maxsize
102*635a8641SAndroid Build Coastguard Worker
103*635a8641SAndroid Build Coastguard Worker# Python 2.x/3.0 compatibility.
104*635a8641SAndroid Build Coastguard Workerdef load_ply_lex():
105*635a8641SAndroid Build Coastguard Worker    if sys.version_info[0] < 3:
106*635a8641SAndroid Build Coastguard Worker        import lex
107*635a8641SAndroid Build Coastguard Worker    else:
108*635a8641SAndroid Build Coastguard Worker        import ply.lex as lex
109*635a8641SAndroid Build Coastguard Worker    return lex
110*635a8641SAndroid Build Coastguard Worker
111*635a8641SAndroid Build Coastguard Worker# This object is a stand-in for a logging object created by the
112*635a8641SAndroid Build Coastguard Worker# logging module.   PLY will use this by default to create things
113*635a8641SAndroid Build Coastguard Worker# such as the parser.out file.  If a user wants more detailed
114*635a8641SAndroid Build Coastguard Worker# information, they can create their own logging object and pass
115*635a8641SAndroid Build Coastguard Worker# it into PLY.
116*635a8641SAndroid Build Coastguard Worker
117*635a8641SAndroid Build Coastguard Workerclass PlyLogger(object):
118*635a8641SAndroid Build Coastguard Worker    def __init__(self,f):
119*635a8641SAndroid Build Coastguard Worker        self.f = f
120*635a8641SAndroid Build Coastguard Worker    def debug(self,msg,*args,**kwargs):
121*635a8641SAndroid Build Coastguard Worker        self.f.write((msg % args) + "\n")
122*635a8641SAndroid Build Coastguard Worker    info     = debug
123*635a8641SAndroid Build Coastguard Worker
124*635a8641SAndroid Build Coastguard Worker    def warning(self,msg,*args,**kwargs):
125*635a8641SAndroid Build Coastguard Worker        self.f.write("WARNING: "+ (msg % args) + "\n")
126*635a8641SAndroid Build Coastguard Worker
127*635a8641SAndroid Build Coastguard Worker    def error(self,msg,*args,**kwargs):
128*635a8641SAndroid Build Coastguard Worker        self.f.write("ERROR: " + (msg % args) + "\n")
129*635a8641SAndroid Build Coastguard Worker
130*635a8641SAndroid Build Coastguard Worker    critical = debug
131*635a8641SAndroid Build Coastguard Worker
132*635a8641SAndroid Build Coastguard Worker# Null logger is used when no output is generated. Does nothing.
133*635a8641SAndroid Build Coastguard Workerclass NullLogger(object):
134*635a8641SAndroid Build Coastguard Worker    def __getattribute__(self,name):
135*635a8641SAndroid Build Coastguard Worker        return self
136*635a8641SAndroid Build Coastguard Worker    def __call__(self,*args,**kwargs):
137*635a8641SAndroid Build Coastguard Worker        return self
138*635a8641SAndroid Build Coastguard Worker
139*635a8641SAndroid Build Coastguard Worker# Exception raised for yacc-related errors
140*635a8641SAndroid Build Coastguard Workerclass YaccError(Exception):   pass
141*635a8641SAndroid Build Coastguard Worker
142*635a8641SAndroid Build Coastguard Worker# Format the result message that the parser produces when running in debug mode.
143*635a8641SAndroid Build Coastguard Workerdef format_result(r):
144*635a8641SAndroid Build Coastguard Worker    repr_str = repr(r)
145*635a8641SAndroid Build Coastguard Worker    if '\n' in repr_str: repr_str = repr(repr_str)
146*635a8641SAndroid Build Coastguard Worker    if len(repr_str) > resultlimit:
147*635a8641SAndroid Build Coastguard Worker        repr_str = repr_str[:resultlimit]+" ..."
148*635a8641SAndroid Build Coastguard Worker    result = "<%s @ 0x%x> (%s)" % (type(r).__name__,id(r),repr_str)
149*635a8641SAndroid Build Coastguard Worker    return result
150*635a8641SAndroid Build Coastguard Worker
151*635a8641SAndroid Build Coastguard Worker
152*635a8641SAndroid Build Coastguard Worker# Format stack entries when the parser is running in debug mode
153*635a8641SAndroid Build Coastguard Workerdef format_stack_entry(r):
154*635a8641SAndroid Build Coastguard Worker    repr_str = repr(r)
155*635a8641SAndroid Build Coastguard Worker    if '\n' in repr_str: repr_str = repr(repr_str)
156*635a8641SAndroid Build Coastguard Worker    if len(repr_str) < 16:
157*635a8641SAndroid Build Coastguard Worker        return repr_str
158*635a8641SAndroid Build Coastguard Worker    else:
159*635a8641SAndroid Build Coastguard Worker        return "<%s @ 0x%x>" % (type(r).__name__,id(r))
160*635a8641SAndroid Build Coastguard Worker
161*635a8641SAndroid Build Coastguard Worker#-----------------------------------------------------------------------------
162*635a8641SAndroid Build Coastguard Worker#                        ===  LR Parsing Engine ===
163*635a8641SAndroid Build Coastguard Worker#
164*635a8641SAndroid Build Coastguard Worker# The following classes are used for the LR parser itself.  These are not
165*635a8641SAndroid Build Coastguard Worker# used during table construction and are independent of the actual LR
166*635a8641SAndroid Build Coastguard Worker# table generation algorithm
167*635a8641SAndroid Build Coastguard Worker#-----------------------------------------------------------------------------
168*635a8641SAndroid Build Coastguard Worker
169*635a8641SAndroid Build Coastguard Worker# This class is used to hold non-terminal grammar symbols during parsing.
170*635a8641SAndroid Build Coastguard Worker# It normally has the following attributes set:
171*635a8641SAndroid Build Coastguard Worker#        .type       = Grammar symbol type
172*635a8641SAndroid Build Coastguard Worker#        .value      = Symbol value
173*635a8641SAndroid Build Coastguard Worker#        .lineno     = Starting line number
174*635a8641SAndroid Build Coastguard Worker#        .endlineno  = Ending line number (optional, set automatically)
175*635a8641SAndroid Build Coastguard Worker#        .lexpos     = Starting lex position
176*635a8641SAndroid Build Coastguard Worker#        .endlexpos  = Ending lex position (optional, set automatically)
177*635a8641SAndroid Build Coastguard Worker
178*635a8641SAndroid Build Coastguard Workerclass YaccSymbol:
179*635a8641SAndroid Build Coastguard Worker    def __str__(self):    return self.type
180*635a8641SAndroid Build Coastguard Worker    def __repr__(self):   return str(self)
181*635a8641SAndroid Build Coastguard Worker
182*635a8641SAndroid Build Coastguard Worker# This class is a wrapper around the objects actually passed to each
183*635a8641SAndroid Build Coastguard Worker# grammar rule.   Index lookup and assignment actually assign the
184*635a8641SAndroid Build Coastguard Worker# .value attribute of the underlying YaccSymbol object.
185*635a8641SAndroid Build Coastguard Worker# The lineno() method returns the line number of a given
186*635a8641SAndroid Build Coastguard Worker# item (or 0 if not defined).   The linespan() method returns
187*635a8641SAndroid Build Coastguard Worker# a tuple of (startline,endline) representing the range of lines
188*635a8641SAndroid Build Coastguard Worker# for a symbol.  The lexspan() method returns a tuple (lexpos,endlexpos)
189*635a8641SAndroid Build Coastguard Worker# representing the range of positional information for a symbol.
190*635a8641SAndroid Build Coastguard Worker
191*635a8641SAndroid Build Coastguard Workerclass YaccProduction:
192*635a8641SAndroid Build Coastguard Worker    def __init__(self,s,stack=None):
193*635a8641SAndroid Build Coastguard Worker        self.slice = s
194*635a8641SAndroid Build Coastguard Worker        self.stack = stack
195*635a8641SAndroid Build Coastguard Worker        self.lexer = None
196*635a8641SAndroid Build Coastguard Worker        self.parser= None
197*635a8641SAndroid Build Coastguard Worker    def __getitem__(self,n):
198*635a8641SAndroid Build Coastguard Worker        if type(n) is slice:
199*635a8641SAndroid Build Coastguard Worker            return [s.value for s in self.slice[n]]
200*635a8641SAndroid Build Coastguard Worker        else:
201*635a8641SAndroid Build Coastguard Worker            if n >= 0: return self.slice[n].value
202*635a8641SAndroid Build Coastguard Worker            else: return self.stack[n].value
203*635a8641SAndroid Build Coastguard Worker
204*635a8641SAndroid Build Coastguard Worker    def __setitem__(self,n,v):
205*635a8641SAndroid Build Coastguard Worker        self.slice[n].value = v
206*635a8641SAndroid Build Coastguard Worker
207*635a8641SAndroid Build Coastguard Worker    def __getslice__(self,i,j):
208*635a8641SAndroid Build Coastguard Worker        return [s.value for s in self.slice[i:j]]
209*635a8641SAndroid Build Coastguard Worker
210*635a8641SAndroid Build Coastguard Worker    def __len__(self):
211*635a8641SAndroid Build Coastguard Worker        return len(self.slice)
212*635a8641SAndroid Build Coastguard Worker
213*635a8641SAndroid Build Coastguard Worker    def lineno(self,n):
214*635a8641SAndroid Build Coastguard Worker        return getattr(self.slice[n],"lineno",0)
215*635a8641SAndroid Build Coastguard Worker
216*635a8641SAndroid Build Coastguard Worker    def set_lineno(self,n,lineno):
217*635a8641SAndroid Build Coastguard Worker        self.slice[n].lineno = lineno
218*635a8641SAndroid Build Coastguard Worker
219*635a8641SAndroid Build Coastguard Worker    def linespan(self,n):
220*635a8641SAndroid Build Coastguard Worker        startline = getattr(self.slice[n],"lineno",0)
221*635a8641SAndroid Build Coastguard Worker        endline = getattr(self.slice[n],"endlineno",startline)
222*635a8641SAndroid Build Coastguard Worker        return startline,endline
223*635a8641SAndroid Build Coastguard Worker
224*635a8641SAndroid Build Coastguard Worker    def lexpos(self,n):
225*635a8641SAndroid Build Coastguard Worker        return getattr(self.slice[n],"lexpos",0)
226*635a8641SAndroid Build Coastguard Worker
227*635a8641SAndroid Build Coastguard Worker    def lexspan(self,n):
228*635a8641SAndroid Build Coastguard Worker        startpos = getattr(self.slice[n],"lexpos",0)
229*635a8641SAndroid Build Coastguard Worker        endpos = getattr(self.slice[n],"endlexpos",startpos)
230*635a8641SAndroid Build Coastguard Worker        return startpos,endpos
231*635a8641SAndroid Build Coastguard Worker
232*635a8641SAndroid Build Coastguard Worker    def error(self):
233*635a8641SAndroid Build Coastguard Worker       raise SyntaxError
234*635a8641SAndroid Build Coastguard Worker
235*635a8641SAndroid Build Coastguard Worker
236*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
237*635a8641SAndroid Build Coastguard Worker#                               == LRParser ==
238*635a8641SAndroid Build Coastguard Worker#
239*635a8641SAndroid Build Coastguard Worker# The LR Parsing engine.
240*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
241*635a8641SAndroid Build Coastguard Worker
242*635a8641SAndroid Build Coastguard Workerclass LRParser:
243*635a8641SAndroid Build Coastguard Worker    def __init__(self,lrtab,errorf):
244*635a8641SAndroid Build Coastguard Worker        self.productions = lrtab.lr_productions
245*635a8641SAndroid Build Coastguard Worker        self.action      = lrtab.lr_action
246*635a8641SAndroid Build Coastguard Worker        self.goto        = lrtab.lr_goto
247*635a8641SAndroid Build Coastguard Worker        self.errorfunc   = errorf
248*635a8641SAndroid Build Coastguard Worker
249*635a8641SAndroid Build Coastguard Worker    def errok(self):
250*635a8641SAndroid Build Coastguard Worker        self.errorok     = 1
251*635a8641SAndroid Build Coastguard Worker
252*635a8641SAndroid Build Coastguard Worker    def restart(self):
253*635a8641SAndroid Build Coastguard Worker        del self.statestack[:]
254*635a8641SAndroid Build Coastguard Worker        del self.symstack[:]
255*635a8641SAndroid Build Coastguard Worker        sym = YaccSymbol()
256*635a8641SAndroid Build Coastguard Worker        sym.type = '$end'
257*635a8641SAndroid Build Coastguard Worker        self.symstack.append(sym)
258*635a8641SAndroid Build Coastguard Worker        self.statestack.append(0)
259*635a8641SAndroid Build Coastguard Worker
260*635a8641SAndroid Build Coastguard Worker    def parse(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None):
261*635a8641SAndroid Build Coastguard Worker        if debug or yaccdevel:
262*635a8641SAndroid Build Coastguard Worker            if isinstance(debug,int):
263*635a8641SAndroid Build Coastguard Worker                debug = PlyLogger(sys.stderr)
264*635a8641SAndroid Build Coastguard Worker            return self.parsedebug(input,lexer,debug,tracking,tokenfunc)
265*635a8641SAndroid Build Coastguard Worker        elif tracking:
266*635a8641SAndroid Build Coastguard Worker            return self.parseopt(input,lexer,debug,tracking,tokenfunc)
267*635a8641SAndroid Build Coastguard Worker        else:
268*635a8641SAndroid Build Coastguard Worker            return self.parseopt_notrack(input,lexer,debug,tracking,tokenfunc)
269*635a8641SAndroid Build Coastguard Worker
270*635a8641SAndroid Build Coastguard Worker
271*635a8641SAndroid Build Coastguard Worker    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
272*635a8641SAndroid Build Coastguard Worker    # parsedebug().
273*635a8641SAndroid Build Coastguard Worker    #
274*635a8641SAndroid Build Coastguard Worker    # This is the debugging enabled version of parse().  All changes made to the
275*635a8641SAndroid Build Coastguard Worker    # parsing engine should be made here.   For the non-debugging version,
276*635a8641SAndroid Build Coastguard Worker    # copy this code to a method parseopt() and delete all of the sections
277*635a8641SAndroid Build Coastguard Worker    # enclosed in:
278*635a8641SAndroid Build Coastguard Worker    #
279*635a8641SAndroid Build Coastguard Worker    #      #--! DEBUG
280*635a8641SAndroid Build Coastguard Worker    #      statements
281*635a8641SAndroid Build Coastguard Worker    #      #--! DEBUG
282*635a8641SAndroid Build Coastguard Worker    #
283*635a8641SAndroid Build Coastguard Worker    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
284*635a8641SAndroid Build Coastguard Worker
285*635a8641SAndroid Build Coastguard Worker    def parsedebug(self,input=None,lexer=None,debug=None,tracking=0,tokenfunc=None):
286*635a8641SAndroid Build Coastguard Worker        lookahead = None                 # Current lookahead symbol
287*635a8641SAndroid Build Coastguard Worker        lookaheadstack = [ ]             # Stack of lookahead symbols
288*635a8641SAndroid Build Coastguard Worker        actions = self.action            # Local reference to action table (to avoid lookup on self.)
289*635a8641SAndroid Build Coastguard Worker        goto    = self.goto              # Local reference to goto table (to avoid lookup on self.)
290*635a8641SAndroid Build Coastguard Worker        prod    = self.productions       # Local reference to production list (to avoid lookup on self.)
291*635a8641SAndroid Build Coastguard Worker        pslice  = YaccProduction(None)   # Production object passed to grammar rules
292*635a8641SAndroid Build Coastguard Worker        errorcount = 0                   # Used during error recovery
293*635a8641SAndroid Build Coastguard Worker
294*635a8641SAndroid Build Coastguard Worker        # --! DEBUG
295*635a8641SAndroid Build Coastguard Worker        debug.info("PLY: PARSE DEBUG START")
296*635a8641SAndroid Build Coastguard Worker        # --! DEBUG
297*635a8641SAndroid Build Coastguard Worker
298*635a8641SAndroid Build Coastguard Worker        # If no lexer was given, we will try to use the lex module
299*635a8641SAndroid Build Coastguard Worker        if not lexer:
300*635a8641SAndroid Build Coastguard Worker            lex = load_ply_lex()
301*635a8641SAndroid Build Coastguard Worker            lexer = lex.lexer
302*635a8641SAndroid Build Coastguard Worker
303*635a8641SAndroid Build Coastguard Worker        # Set up the lexer and parser objects on pslice
304*635a8641SAndroid Build Coastguard Worker        pslice.lexer = lexer
305*635a8641SAndroid Build Coastguard Worker        pslice.parser = self
306*635a8641SAndroid Build Coastguard Worker
307*635a8641SAndroid Build Coastguard Worker        # If input was supplied, pass to lexer
308*635a8641SAndroid Build Coastguard Worker        if input is not None:
309*635a8641SAndroid Build Coastguard Worker            lexer.input(input)
310*635a8641SAndroid Build Coastguard Worker
311*635a8641SAndroid Build Coastguard Worker        if tokenfunc is None:
312*635a8641SAndroid Build Coastguard Worker           # Tokenize function
313*635a8641SAndroid Build Coastguard Worker           get_token = lexer.token
314*635a8641SAndroid Build Coastguard Worker        else:
315*635a8641SAndroid Build Coastguard Worker           get_token = tokenfunc
316*635a8641SAndroid Build Coastguard Worker
317*635a8641SAndroid Build Coastguard Worker        # Set up the state and symbol stacks
318*635a8641SAndroid Build Coastguard Worker
319*635a8641SAndroid Build Coastguard Worker        statestack = [ ]                # Stack of parsing states
320*635a8641SAndroid Build Coastguard Worker        self.statestack = statestack
321*635a8641SAndroid Build Coastguard Worker        symstack   = [ ]                # Stack of grammar symbols
322*635a8641SAndroid Build Coastguard Worker        self.symstack = symstack
323*635a8641SAndroid Build Coastguard Worker
324*635a8641SAndroid Build Coastguard Worker        pslice.stack = symstack         # Put in the production
325*635a8641SAndroid Build Coastguard Worker        errtoken   = None               # Err token
326*635a8641SAndroid Build Coastguard Worker
327*635a8641SAndroid Build Coastguard Worker        # The start state is assumed to be (0,$end)
328*635a8641SAndroid Build Coastguard Worker
329*635a8641SAndroid Build Coastguard Worker        statestack.append(0)
330*635a8641SAndroid Build Coastguard Worker        sym = YaccSymbol()
331*635a8641SAndroid Build Coastguard Worker        sym.type = "$end"
332*635a8641SAndroid Build Coastguard Worker        symstack.append(sym)
333*635a8641SAndroid Build Coastguard Worker        state = 0
334*635a8641SAndroid Build Coastguard Worker        while 1:
335*635a8641SAndroid Build Coastguard Worker            # Get the next symbol on the input.  If a lookahead symbol
336*635a8641SAndroid Build Coastguard Worker            # is already set, we just use that. Otherwise, we'll pull
337*635a8641SAndroid Build Coastguard Worker            # the next token off of the lookaheadstack or from the lexer
338*635a8641SAndroid Build Coastguard Worker
339*635a8641SAndroid Build Coastguard Worker            # --! DEBUG
340*635a8641SAndroid Build Coastguard Worker            debug.debug('')
341*635a8641SAndroid Build Coastguard Worker            debug.debug('State  : %s', state)
342*635a8641SAndroid Build Coastguard Worker            # --! DEBUG
343*635a8641SAndroid Build Coastguard Worker
344*635a8641SAndroid Build Coastguard Worker            if not lookahead:
345*635a8641SAndroid Build Coastguard Worker                if not lookaheadstack:
346*635a8641SAndroid Build Coastguard Worker                    lookahead = get_token()     # Get the next token
347*635a8641SAndroid Build Coastguard Worker                else:
348*635a8641SAndroid Build Coastguard Worker                    lookahead = lookaheadstack.pop()
349*635a8641SAndroid Build Coastguard Worker                if not lookahead:
350*635a8641SAndroid Build Coastguard Worker                    lookahead = YaccSymbol()
351*635a8641SAndroid Build Coastguard Worker                    lookahead.type = "$end"
352*635a8641SAndroid Build Coastguard Worker
353*635a8641SAndroid Build Coastguard Worker            # --! DEBUG
354*635a8641SAndroid Build Coastguard Worker            debug.debug('Stack  : %s',
355*635a8641SAndroid Build Coastguard Worker                        ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip())
356*635a8641SAndroid Build Coastguard Worker            # --! DEBUG
357*635a8641SAndroid Build Coastguard Worker
358*635a8641SAndroid Build Coastguard Worker            # Check the action table
359*635a8641SAndroid Build Coastguard Worker            ltype = lookahead.type
360*635a8641SAndroid Build Coastguard Worker            t = actions[state].get(ltype)
361*635a8641SAndroid Build Coastguard Worker
362*635a8641SAndroid Build Coastguard Worker            if t is not None:
363*635a8641SAndroid Build Coastguard Worker                if t > 0:
364*635a8641SAndroid Build Coastguard Worker                    # shift a symbol on the stack
365*635a8641SAndroid Build Coastguard Worker                    statestack.append(t)
366*635a8641SAndroid Build Coastguard Worker                    state = t
367*635a8641SAndroid Build Coastguard Worker
368*635a8641SAndroid Build Coastguard Worker                    # --! DEBUG
369*635a8641SAndroid Build Coastguard Worker                    debug.debug("Action : Shift and goto state %s", t)
370*635a8641SAndroid Build Coastguard Worker                    # --! DEBUG
371*635a8641SAndroid Build Coastguard Worker
372*635a8641SAndroid Build Coastguard Worker                    symstack.append(lookahead)
373*635a8641SAndroid Build Coastguard Worker                    lookahead = None
374*635a8641SAndroid Build Coastguard Worker
375*635a8641SAndroid Build Coastguard Worker                    # Decrease error count on successful shift
376*635a8641SAndroid Build Coastguard Worker                    if errorcount: errorcount -=1
377*635a8641SAndroid Build Coastguard Worker                    continue
378*635a8641SAndroid Build Coastguard Worker
379*635a8641SAndroid Build Coastguard Worker                if t < 0:
380*635a8641SAndroid Build Coastguard Worker                    # reduce a symbol on the stack, emit a production
381*635a8641SAndroid Build Coastguard Worker                    p = prod[-t]
382*635a8641SAndroid Build Coastguard Worker                    pname = p.name
383*635a8641SAndroid Build Coastguard Worker                    plen  = p.len
384*635a8641SAndroid Build Coastguard Worker
385*635a8641SAndroid Build Coastguard Worker                    # Get production function
386*635a8641SAndroid Build Coastguard Worker                    sym = YaccSymbol()
387*635a8641SAndroid Build Coastguard Worker                    sym.type = pname       # Production name
388*635a8641SAndroid Build Coastguard Worker                    sym.value = None
389*635a8641SAndroid Build Coastguard Worker
390*635a8641SAndroid Build Coastguard Worker                    # --! DEBUG
391*635a8641SAndroid Build Coastguard Worker                    if plen:
392*635a8641SAndroid Build Coastguard Worker                        debug.info("Action : Reduce rule [%s] with %s and goto state %d", p.str, "["+",".join([format_stack_entry(_v.value) for _v in symstack[-plen:]])+"]",-t)
393*635a8641SAndroid Build Coastguard Worker                    else:
394*635a8641SAndroid Build Coastguard Worker                        debug.info("Action : Reduce rule [%s] with %s and goto state %d", p.str, [],-t)
395*635a8641SAndroid Build Coastguard Worker
396*635a8641SAndroid Build Coastguard Worker                    # --! DEBUG
397*635a8641SAndroid Build Coastguard Worker
398*635a8641SAndroid Build Coastguard Worker                    if plen:
399*635a8641SAndroid Build Coastguard Worker                        targ = symstack[-plen-1:]
400*635a8641SAndroid Build Coastguard Worker                        targ[0] = sym
401*635a8641SAndroid Build Coastguard Worker
402*635a8641SAndroid Build Coastguard Worker                        # --! TRACKING
403*635a8641SAndroid Build Coastguard Worker                        if tracking:
404*635a8641SAndroid Build Coastguard Worker                           t1 = targ[1]
405*635a8641SAndroid Build Coastguard Worker                           sym.lineno = t1.lineno
406*635a8641SAndroid Build Coastguard Worker                           sym.lexpos = t1.lexpos
407*635a8641SAndroid Build Coastguard Worker                           t1 = targ[-1]
408*635a8641SAndroid Build Coastguard Worker                           sym.endlineno = getattr(t1,"endlineno",t1.lineno)
409*635a8641SAndroid Build Coastguard Worker                           sym.endlexpos = getattr(t1,"endlexpos",t1.lexpos)
410*635a8641SAndroid Build Coastguard Worker
411*635a8641SAndroid Build Coastguard Worker                        # --! TRACKING
412*635a8641SAndroid Build Coastguard Worker
413*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
414*635a8641SAndroid Build Coastguard Worker                        # The code enclosed in this section is duplicated
415*635a8641SAndroid Build Coastguard Worker                        # below as a performance optimization.  Make sure
416*635a8641SAndroid Build Coastguard Worker                        # changes get made in both locations.
417*635a8641SAndroid Build Coastguard Worker
418*635a8641SAndroid Build Coastguard Worker                        pslice.slice = targ
419*635a8641SAndroid Build Coastguard Worker
420*635a8641SAndroid Build Coastguard Worker                        try:
421*635a8641SAndroid Build Coastguard Worker                            # Call the grammar rule with our special slice object
422*635a8641SAndroid Build Coastguard Worker                            del symstack[-plen:]
423*635a8641SAndroid Build Coastguard Worker                            del statestack[-plen:]
424*635a8641SAndroid Build Coastguard Worker                            p.callable(pslice)
425*635a8641SAndroid Build Coastguard Worker                            # --! DEBUG
426*635a8641SAndroid Build Coastguard Worker                            debug.info("Result : %s", format_result(pslice[0]))
427*635a8641SAndroid Build Coastguard Worker                            # --! DEBUG
428*635a8641SAndroid Build Coastguard Worker                            symstack.append(sym)
429*635a8641SAndroid Build Coastguard Worker                            state = goto[statestack[-1]][pname]
430*635a8641SAndroid Build Coastguard Worker                            statestack.append(state)
431*635a8641SAndroid Build Coastguard Worker                        except SyntaxError:
432*635a8641SAndroid Build Coastguard Worker                            # If an error was set. Enter error recovery state
433*635a8641SAndroid Build Coastguard Worker                            lookaheadstack.append(lookahead)
434*635a8641SAndroid Build Coastguard Worker                            symstack.pop()
435*635a8641SAndroid Build Coastguard Worker                            statestack.pop()
436*635a8641SAndroid Build Coastguard Worker                            state = statestack[-1]
437*635a8641SAndroid Build Coastguard Worker                            sym.type = 'error'
438*635a8641SAndroid Build Coastguard Worker                            lookahead = sym
439*635a8641SAndroid Build Coastguard Worker                            errorcount = error_count
440*635a8641SAndroid Build Coastguard Worker                            self.errorok = 0
441*635a8641SAndroid Build Coastguard Worker                        continue
442*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
443*635a8641SAndroid Build Coastguard Worker
444*635a8641SAndroid Build Coastguard Worker                    else:
445*635a8641SAndroid Build Coastguard Worker
446*635a8641SAndroid Build Coastguard Worker                        # --! TRACKING
447*635a8641SAndroid Build Coastguard Worker                        if tracking:
448*635a8641SAndroid Build Coastguard Worker                           sym.lineno = lexer.lineno
449*635a8641SAndroid Build Coastguard Worker                           sym.lexpos = lexer.lexpos
450*635a8641SAndroid Build Coastguard Worker                        # --! TRACKING
451*635a8641SAndroid Build Coastguard Worker
452*635a8641SAndroid Build Coastguard Worker                        targ = [ sym ]
453*635a8641SAndroid Build Coastguard Worker
454*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
455*635a8641SAndroid Build Coastguard Worker                        # The code enclosed in this section is duplicated
456*635a8641SAndroid Build Coastguard Worker                        # above as a performance optimization.  Make sure
457*635a8641SAndroid Build Coastguard Worker                        # changes get made in both locations.
458*635a8641SAndroid Build Coastguard Worker
459*635a8641SAndroid Build Coastguard Worker                        pslice.slice = targ
460*635a8641SAndroid Build Coastguard Worker
461*635a8641SAndroid Build Coastguard Worker                        try:
462*635a8641SAndroid Build Coastguard Worker                            # Call the grammar rule with our special slice object
463*635a8641SAndroid Build Coastguard Worker                            p.callable(pslice)
464*635a8641SAndroid Build Coastguard Worker                            # --! DEBUG
465*635a8641SAndroid Build Coastguard Worker                            debug.info("Result : %s", format_result(pslice[0]))
466*635a8641SAndroid Build Coastguard Worker                            # --! DEBUG
467*635a8641SAndroid Build Coastguard Worker                            symstack.append(sym)
468*635a8641SAndroid Build Coastguard Worker                            state = goto[statestack[-1]][pname]
469*635a8641SAndroid Build Coastguard Worker                            statestack.append(state)
470*635a8641SAndroid Build Coastguard Worker                        except SyntaxError:
471*635a8641SAndroid Build Coastguard Worker                            # If an error was set. Enter error recovery state
472*635a8641SAndroid Build Coastguard Worker                            lookaheadstack.append(lookahead)
473*635a8641SAndroid Build Coastguard Worker                            symstack.pop()
474*635a8641SAndroid Build Coastguard Worker                            statestack.pop()
475*635a8641SAndroid Build Coastguard Worker                            state = statestack[-1]
476*635a8641SAndroid Build Coastguard Worker                            sym.type = 'error'
477*635a8641SAndroid Build Coastguard Worker                            lookahead = sym
478*635a8641SAndroid Build Coastguard Worker                            errorcount = error_count
479*635a8641SAndroid Build Coastguard Worker                            self.errorok = 0
480*635a8641SAndroid Build Coastguard Worker                        continue
481*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
482*635a8641SAndroid Build Coastguard Worker
483*635a8641SAndroid Build Coastguard Worker                if t == 0:
484*635a8641SAndroid Build Coastguard Worker                    n = symstack[-1]
485*635a8641SAndroid Build Coastguard Worker                    result = getattr(n,"value",None)
486*635a8641SAndroid Build Coastguard Worker                    # --! DEBUG
487*635a8641SAndroid Build Coastguard Worker                    debug.info("Done   : Returning %s", format_result(result))
488*635a8641SAndroid Build Coastguard Worker                    debug.info("PLY: PARSE DEBUG END")
489*635a8641SAndroid Build Coastguard Worker                    # --! DEBUG
490*635a8641SAndroid Build Coastguard Worker                    return result
491*635a8641SAndroid Build Coastguard Worker
492*635a8641SAndroid Build Coastguard Worker            if t == None:
493*635a8641SAndroid Build Coastguard Worker
494*635a8641SAndroid Build Coastguard Worker                # --! DEBUG
495*635a8641SAndroid Build Coastguard Worker                debug.error('Error  : %s',
496*635a8641SAndroid Build Coastguard Worker                            ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip())
497*635a8641SAndroid Build Coastguard Worker                # --! DEBUG
498*635a8641SAndroid Build Coastguard Worker
499*635a8641SAndroid Build Coastguard Worker                # We have some kind of parsing error here.  To handle
500*635a8641SAndroid Build Coastguard Worker                # this, we are going to push the current token onto
501*635a8641SAndroid Build Coastguard Worker                # the tokenstack and replace it with an 'error' token.
502*635a8641SAndroid Build Coastguard Worker                # If there are any synchronization rules, they may
503*635a8641SAndroid Build Coastguard Worker                # catch it.
504*635a8641SAndroid Build Coastguard Worker                #
505*635a8641SAndroid Build Coastguard Worker                # In addition to pushing the error token, we call call
506*635a8641SAndroid Build Coastguard Worker                # the user defined p_error() function if this is the
507*635a8641SAndroid Build Coastguard Worker                # first syntax error.  This function is only called if
508*635a8641SAndroid Build Coastguard Worker                # errorcount == 0.
509*635a8641SAndroid Build Coastguard Worker                if errorcount == 0 or self.errorok:
510*635a8641SAndroid Build Coastguard Worker                    errorcount = error_count
511*635a8641SAndroid Build Coastguard Worker                    self.errorok = 0
512*635a8641SAndroid Build Coastguard Worker                    errtoken = lookahead
513*635a8641SAndroid Build Coastguard Worker                    if errtoken.type == "$end":
514*635a8641SAndroid Build Coastguard Worker                        errtoken = None               # End of file!
515*635a8641SAndroid Build Coastguard Worker                    if self.errorfunc:
516*635a8641SAndroid Build Coastguard Worker                        global errok,token,restart
517*635a8641SAndroid Build Coastguard Worker                        errok = self.errok        # Set some special functions available in error recovery
518*635a8641SAndroid Build Coastguard Worker                        token = get_token
519*635a8641SAndroid Build Coastguard Worker                        restart = self.restart
520*635a8641SAndroid Build Coastguard Worker                        if errtoken and not hasattr(errtoken,'lexer'):
521*635a8641SAndroid Build Coastguard Worker                            errtoken.lexer = lexer
522*635a8641SAndroid Build Coastguard Worker                        tok = self.errorfunc(errtoken)
523*635a8641SAndroid Build Coastguard Worker                        del errok, token, restart   # Delete special functions
524*635a8641SAndroid Build Coastguard Worker
525*635a8641SAndroid Build Coastguard Worker                        if self.errorok:
526*635a8641SAndroid Build Coastguard Worker                            # User must have done some kind of panic
527*635a8641SAndroid Build Coastguard Worker                            # mode recovery on their own.  The
528*635a8641SAndroid Build Coastguard Worker                            # returned token is the next lookahead
529*635a8641SAndroid Build Coastguard Worker                            lookahead = tok
530*635a8641SAndroid Build Coastguard Worker                            errtoken = None
531*635a8641SAndroid Build Coastguard Worker                            continue
532*635a8641SAndroid Build Coastguard Worker                    else:
533*635a8641SAndroid Build Coastguard Worker                        if errtoken:
534*635a8641SAndroid Build Coastguard Worker                            if hasattr(errtoken,"lineno"): lineno = lookahead.lineno
535*635a8641SAndroid Build Coastguard Worker                            else: lineno = 0
536*635a8641SAndroid Build Coastguard Worker                            if lineno:
537*635a8641SAndroid Build Coastguard Worker                                sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type))
538*635a8641SAndroid Build Coastguard Worker                            else:
539*635a8641SAndroid Build Coastguard Worker                                sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type)
540*635a8641SAndroid Build Coastguard Worker                        else:
541*635a8641SAndroid Build Coastguard Worker                            sys.stderr.write("yacc: Parse error in input. EOF\n")
542*635a8641SAndroid Build Coastguard Worker                            return
543*635a8641SAndroid Build Coastguard Worker
544*635a8641SAndroid Build Coastguard Worker                else:
545*635a8641SAndroid Build Coastguard Worker                    errorcount = error_count
546*635a8641SAndroid Build Coastguard Worker
547*635a8641SAndroid Build Coastguard Worker                # case 1:  the statestack only has 1 entry on it.  If we're in this state, the
548*635a8641SAndroid Build Coastguard Worker                # entire parse has been rolled back and we're completely hosed.   The token is
549*635a8641SAndroid Build Coastguard Worker                # discarded and we just keep going.
550*635a8641SAndroid Build Coastguard Worker
551*635a8641SAndroid Build Coastguard Worker                if len(statestack) <= 1 and lookahead.type != "$end":
552*635a8641SAndroid Build Coastguard Worker                    lookahead = None
553*635a8641SAndroid Build Coastguard Worker                    errtoken = None
554*635a8641SAndroid Build Coastguard Worker                    state = 0
555*635a8641SAndroid Build Coastguard Worker                    # Nuke the pushback stack
556*635a8641SAndroid Build Coastguard Worker                    del lookaheadstack[:]
557*635a8641SAndroid Build Coastguard Worker                    continue
558*635a8641SAndroid Build Coastguard Worker
559*635a8641SAndroid Build Coastguard Worker                # case 2: the statestack has a couple of entries on it, but we're
560*635a8641SAndroid Build Coastguard Worker                # at the end of the file. nuke the top entry and generate an error token
561*635a8641SAndroid Build Coastguard Worker
562*635a8641SAndroid Build Coastguard Worker                # Start nuking entries on the stack
563*635a8641SAndroid Build Coastguard Worker                if lookahead.type == "$end":
564*635a8641SAndroid Build Coastguard Worker                    # Whoa. We're really hosed here. Bail out
565*635a8641SAndroid Build Coastguard Worker                    return
566*635a8641SAndroid Build Coastguard Worker
567*635a8641SAndroid Build Coastguard Worker                if lookahead.type != 'error':
568*635a8641SAndroid Build Coastguard Worker                    sym = symstack[-1]
569*635a8641SAndroid Build Coastguard Worker                    if sym.type == 'error':
570*635a8641SAndroid Build Coastguard Worker                        # Hmmm. Error is on top of stack, we'll just nuke input
571*635a8641SAndroid Build Coastguard Worker                        # symbol and continue
572*635a8641SAndroid Build Coastguard Worker                        lookahead = None
573*635a8641SAndroid Build Coastguard Worker                        continue
574*635a8641SAndroid Build Coastguard Worker                    t = YaccSymbol()
575*635a8641SAndroid Build Coastguard Worker                    t.type = 'error'
576*635a8641SAndroid Build Coastguard Worker                    if hasattr(lookahead,"lineno"):
577*635a8641SAndroid Build Coastguard Worker                        t.lineno = lookahead.lineno
578*635a8641SAndroid Build Coastguard Worker                    t.value = lookahead
579*635a8641SAndroid Build Coastguard Worker                    lookaheadstack.append(lookahead)
580*635a8641SAndroid Build Coastguard Worker                    lookahead = t
581*635a8641SAndroid Build Coastguard Worker                else:
582*635a8641SAndroid Build Coastguard Worker                    symstack.pop()
583*635a8641SAndroid Build Coastguard Worker                    statestack.pop()
584*635a8641SAndroid Build Coastguard Worker                    state = statestack[-1]       # Potential bug fix
585*635a8641SAndroid Build Coastguard Worker
586*635a8641SAndroid Build Coastguard Worker                continue
587*635a8641SAndroid Build Coastguard Worker
588*635a8641SAndroid Build Coastguard Worker            # Call an error function here
589*635a8641SAndroid Build Coastguard Worker            raise RuntimeError("yacc: internal parser error!!!\n")
590*635a8641SAndroid Build Coastguard Worker
591*635a8641SAndroid Build Coastguard Worker    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
592*635a8641SAndroid Build Coastguard Worker    # parseopt().
593*635a8641SAndroid Build Coastguard Worker    #
594*635a8641SAndroid Build Coastguard Worker    # Optimized version of parse() method.  DO NOT EDIT THIS CODE DIRECTLY.
595*635a8641SAndroid Build Coastguard Worker    # Edit the debug version above, then copy any modifications to the method
596*635a8641SAndroid Build Coastguard Worker    # below while removing #--! DEBUG sections.
597*635a8641SAndroid Build Coastguard Worker    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
598*635a8641SAndroid Build Coastguard Worker
599*635a8641SAndroid Build Coastguard Worker
600*635a8641SAndroid Build Coastguard Worker    def parseopt(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None):
601*635a8641SAndroid Build Coastguard Worker        lookahead = None                 # Current lookahead symbol
602*635a8641SAndroid Build Coastguard Worker        lookaheadstack = [ ]             # Stack of lookahead symbols
603*635a8641SAndroid Build Coastguard Worker        actions = self.action            # Local reference to action table (to avoid lookup on self.)
604*635a8641SAndroid Build Coastguard Worker        goto    = self.goto              # Local reference to goto table (to avoid lookup on self.)
605*635a8641SAndroid Build Coastguard Worker        prod    = self.productions       # Local reference to production list (to avoid lookup on self.)
606*635a8641SAndroid Build Coastguard Worker        pslice  = YaccProduction(None)   # Production object passed to grammar rules
607*635a8641SAndroid Build Coastguard Worker        errorcount = 0                   # Used during error recovery
608*635a8641SAndroid Build Coastguard Worker
609*635a8641SAndroid Build Coastguard Worker        # If no lexer was given, we will try to use the lex module
610*635a8641SAndroid Build Coastguard Worker        if not lexer:
611*635a8641SAndroid Build Coastguard Worker            lex = load_ply_lex()
612*635a8641SAndroid Build Coastguard Worker            lexer = lex.lexer
613*635a8641SAndroid Build Coastguard Worker
614*635a8641SAndroid Build Coastguard Worker        # Set up the lexer and parser objects on pslice
615*635a8641SAndroid Build Coastguard Worker        pslice.lexer = lexer
616*635a8641SAndroid Build Coastguard Worker        pslice.parser = self
617*635a8641SAndroid Build Coastguard Worker
618*635a8641SAndroid Build Coastguard Worker        # If input was supplied, pass to lexer
619*635a8641SAndroid Build Coastguard Worker        if input is not None:
620*635a8641SAndroid Build Coastguard Worker            lexer.input(input)
621*635a8641SAndroid Build Coastguard Worker
622*635a8641SAndroid Build Coastguard Worker        if tokenfunc is None:
623*635a8641SAndroid Build Coastguard Worker           # Tokenize function
624*635a8641SAndroid Build Coastguard Worker           get_token = lexer.token
625*635a8641SAndroid Build Coastguard Worker        else:
626*635a8641SAndroid Build Coastguard Worker           get_token = tokenfunc
627*635a8641SAndroid Build Coastguard Worker
628*635a8641SAndroid Build Coastguard Worker        # Set up the state and symbol stacks
629*635a8641SAndroid Build Coastguard Worker
630*635a8641SAndroid Build Coastguard Worker        statestack = [ ]                # Stack of parsing states
631*635a8641SAndroid Build Coastguard Worker        self.statestack = statestack
632*635a8641SAndroid Build Coastguard Worker        symstack   = [ ]                # Stack of grammar symbols
633*635a8641SAndroid Build Coastguard Worker        self.symstack = symstack
634*635a8641SAndroid Build Coastguard Worker
635*635a8641SAndroid Build Coastguard Worker        pslice.stack = symstack         # Put in the production
636*635a8641SAndroid Build Coastguard Worker        errtoken   = None               # Err token
637*635a8641SAndroid Build Coastguard Worker
638*635a8641SAndroid Build Coastguard Worker        # The start state is assumed to be (0,$end)
639*635a8641SAndroid Build Coastguard Worker
640*635a8641SAndroid Build Coastguard Worker        statestack.append(0)
641*635a8641SAndroid Build Coastguard Worker        sym = YaccSymbol()
642*635a8641SAndroid Build Coastguard Worker        sym.type = '$end'
643*635a8641SAndroid Build Coastguard Worker        symstack.append(sym)
644*635a8641SAndroid Build Coastguard Worker        state = 0
645*635a8641SAndroid Build Coastguard Worker        while 1:
646*635a8641SAndroid Build Coastguard Worker            # Get the next symbol on the input.  If a lookahead symbol
647*635a8641SAndroid Build Coastguard Worker            # is already set, we just use that. Otherwise, we'll pull
648*635a8641SAndroid Build Coastguard Worker            # the next token off of the lookaheadstack or from the lexer
649*635a8641SAndroid Build Coastguard Worker
650*635a8641SAndroid Build Coastguard Worker            if not lookahead:
651*635a8641SAndroid Build Coastguard Worker                if not lookaheadstack:
652*635a8641SAndroid Build Coastguard Worker                    lookahead = get_token()     # Get the next token
653*635a8641SAndroid Build Coastguard Worker                else:
654*635a8641SAndroid Build Coastguard Worker                    lookahead = lookaheadstack.pop()
655*635a8641SAndroid Build Coastguard Worker                if not lookahead:
656*635a8641SAndroid Build Coastguard Worker                    lookahead = YaccSymbol()
657*635a8641SAndroid Build Coastguard Worker                    lookahead.type = '$end'
658*635a8641SAndroid Build Coastguard Worker
659*635a8641SAndroid Build Coastguard Worker            # Check the action table
660*635a8641SAndroid Build Coastguard Worker            ltype = lookahead.type
661*635a8641SAndroid Build Coastguard Worker            t = actions[state].get(ltype)
662*635a8641SAndroid Build Coastguard Worker
663*635a8641SAndroid Build Coastguard Worker            if t is not None:
664*635a8641SAndroid Build Coastguard Worker                if t > 0:
665*635a8641SAndroid Build Coastguard Worker                    # shift a symbol on the stack
666*635a8641SAndroid Build Coastguard Worker                    statestack.append(t)
667*635a8641SAndroid Build Coastguard Worker                    state = t
668*635a8641SAndroid Build Coastguard Worker
669*635a8641SAndroid Build Coastguard Worker                    symstack.append(lookahead)
670*635a8641SAndroid Build Coastguard Worker                    lookahead = None
671*635a8641SAndroid Build Coastguard Worker
672*635a8641SAndroid Build Coastguard Worker                    # Decrease error count on successful shift
673*635a8641SAndroid Build Coastguard Worker                    if errorcount: errorcount -=1
674*635a8641SAndroid Build Coastguard Worker                    continue
675*635a8641SAndroid Build Coastguard Worker
676*635a8641SAndroid Build Coastguard Worker                if t < 0:
677*635a8641SAndroid Build Coastguard Worker                    # reduce a symbol on the stack, emit a production
678*635a8641SAndroid Build Coastguard Worker                    p = prod[-t]
679*635a8641SAndroid Build Coastguard Worker                    pname = p.name
680*635a8641SAndroid Build Coastguard Worker                    plen  = p.len
681*635a8641SAndroid Build Coastguard Worker
682*635a8641SAndroid Build Coastguard Worker                    # Get production function
683*635a8641SAndroid Build Coastguard Worker                    sym = YaccSymbol()
684*635a8641SAndroid Build Coastguard Worker                    sym.type = pname       # Production name
685*635a8641SAndroid Build Coastguard Worker                    sym.value = None
686*635a8641SAndroid Build Coastguard Worker
687*635a8641SAndroid Build Coastguard Worker                    if plen:
688*635a8641SAndroid Build Coastguard Worker                        targ = symstack[-plen-1:]
689*635a8641SAndroid Build Coastguard Worker                        targ[0] = sym
690*635a8641SAndroid Build Coastguard Worker
691*635a8641SAndroid Build Coastguard Worker                        # --! TRACKING
692*635a8641SAndroid Build Coastguard Worker                        if tracking:
693*635a8641SAndroid Build Coastguard Worker                           t1 = targ[1]
694*635a8641SAndroid Build Coastguard Worker                           sym.lineno = t1.lineno
695*635a8641SAndroid Build Coastguard Worker                           sym.lexpos = t1.lexpos
696*635a8641SAndroid Build Coastguard Worker                           t1 = targ[-1]
697*635a8641SAndroid Build Coastguard Worker                           sym.endlineno = getattr(t1,"endlineno",t1.lineno)
698*635a8641SAndroid Build Coastguard Worker                           sym.endlexpos = getattr(t1,"endlexpos",t1.lexpos)
699*635a8641SAndroid Build Coastguard Worker
700*635a8641SAndroid Build Coastguard Worker                        # --! TRACKING
701*635a8641SAndroid Build Coastguard Worker
702*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
703*635a8641SAndroid Build Coastguard Worker                        # The code enclosed in this section is duplicated
704*635a8641SAndroid Build Coastguard Worker                        # below as a performance optimization.  Make sure
705*635a8641SAndroid Build Coastguard Worker                        # changes get made in both locations.
706*635a8641SAndroid Build Coastguard Worker
707*635a8641SAndroid Build Coastguard Worker                        pslice.slice = targ
708*635a8641SAndroid Build Coastguard Worker
709*635a8641SAndroid Build Coastguard Worker                        try:
710*635a8641SAndroid Build Coastguard Worker                            # Call the grammar rule with our special slice object
711*635a8641SAndroid Build Coastguard Worker                            del symstack[-plen:]
712*635a8641SAndroid Build Coastguard Worker                            del statestack[-plen:]
713*635a8641SAndroid Build Coastguard Worker                            p.callable(pslice)
714*635a8641SAndroid Build Coastguard Worker                            symstack.append(sym)
715*635a8641SAndroid Build Coastguard Worker                            state = goto[statestack[-1]][pname]
716*635a8641SAndroid Build Coastguard Worker                            statestack.append(state)
717*635a8641SAndroid Build Coastguard Worker                        except SyntaxError:
718*635a8641SAndroid Build Coastguard Worker                            # If an error was set. Enter error recovery state
719*635a8641SAndroid Build Coastguard Worker                            lookaheadstack.append(lookahead)
720*635a8641SAndroid Build Coastguard Worker                            symstack.pop()
721*635a8641SAndroid Build Coastguard Worker                            statestack.pop()
722*635a8641SAndroid Build Coastguard Worker                            state = statestack[-1]
723*635a8641SAndroid Build Coastguard Worker                            sym.type = 'error'
724*635a8641SAndroid Build Coastguard Worker                            lookahead = sym
725*635a8641SAndroid Build Coastguard Worker                            errorcount = error_count
726*635a8641SAndroid Build Coastguard Worker                            self.errorok = 0
727*635a8641SAndroid Build Coastguard Worker                        continue
728*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
729*635a8641SAndroid Build Coastguard Worker
730*635a8641SAndroid Build Coastguard Worker                    else:
731*635a8641SAndroid Build Coastguard Worker
732*635a8641SAndroid Build Coastguard Worker                        # --! TRACKING
733*635a8641SAndroid Build Coastguard Worker                        if tracking:
734*635a8641SAndroid Build Coastguard Worker                           sym.lineno = lexer.lineno
735*635a8641SAndroid Build Coastguard Worker                           sym.lexpos = lexer.lexpos
736*635a8641SAndroid Build Coastguard Worker                        # --! TRACKING
737*635a8641SAndroid Build Coastguard Worker
738*635a8641SAndroid Build Coastguard Worker                        targ = [ sym ]
739*635a8641SAndroid Build Coastguard Worker
740*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
741*635a8641SAndroid Build Coastguard Worker                        # The code enclosed in this section is duplicated
742*635a8641SAndroid Build Coastguard Worker                        # above as a performance optimization.  Make sure
743*635a8641SAndroid Build Coastguard Worker                        # changes get made in both locations.
744*635a8641SAndroid Build Coastguard Worker
745*635a8641SAndroid Build Coastguard Worker                        pslice.slice = targ
746*635a8641SAndroid Build Coastguard Worker
747*635a8641SAndroid Build Coastguard Worker                        try:
748*635a8641SAndroid Build Coastguard Worker                            # Call the grammar rule with our special slice object
749*635a8641SAndroid Build Coastguard Worker                            p.callable(pslice)
750*635a8641SAndroid Build Coastguard Worker                            symstack.append(sym)
751*635a8641SAndroid Build Coastguard Worker                            state = goto[statestack[-1]][pname]
752*635a8641SAndroid Build Coastguard Worker                            statestack.append(state)
753*635a8641SAndroid Build Coastguard Worker                        except SyntaxError:
754*635a8641SAndroid Build Coastguard Worker                            # If an error was set. Enter error recovery state
755*635a8641SAndroid Build Coastguard Worker                            lookaheadstack.append(lookahead)
756*635a8641SAndroid Build Coastguard Worker                            symstack.pop()
757*635a8641SAndroid Build Coastguard Worker                            statestack.pop()
758*635a8641SAndroid Build Coastguard Worker                            state = statestack[-1]
759*635a8641SAndroid Build Coastguard Worker                            sym.type = 'error'
760*635a8641SAndroid Build Coastguard Worker                            lookahead = sym
761*635a8641SAndroid Build Coastguard Worker                            errorcount = error_count
762*635a8641SAndroid Build Coastguard Worker                            self.errorok = 0
763*635a8641SAndroid Build Coastguard Worker                        continue
764*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
765*635a8641SAndroid Build Coastguard Worker
766*635a8641SAndroid Build Coastguard Worker                if t == 0:
767*635a8641SAndroid Build Coastguard Worker                    n = symstack[-1]
768*635a8641SAndroid Build Coastguard Worker                    return getattr(n,"value",None)
769*635a8641SAndroid Build Coastguard Worker
770*635a8641SAndroid Build Coastguard Worker            if t == None:
771*635a8641SAndroid Build Coastguard Worker
772*635a8641SAndroid Build Coastguard Worker                # We have some kind of parsing error here.  To handle
773*635a8641SAndroid Build Coastguard Worker                # this, we are going to push the current token onto
774*635a8641SAndroid Build Coastguard Worker                # the tokenstack and replace it with an 'error' token.
775*635a8641SAndroid Build Coastguard Worker                # If there are any synchronization rules, they may
776*635a8641SAndroid Build Coastguard Worker                # catch it.
777*635a8641SAndroid Build Coastguard Worker                #
778*635a8641SAndroid Build Coastguard Worker                # In addition to pushing the error token, we call call
779*635a8641SAndroid Build Coastguard Worker                # the user defined p_error() function if this is the
780*635a8641SAndroid Build Coastguard Worker                # first syntax error.  This function is only called if
781*635a8641SAndroid Build Coastguard Worker                # errorcount == 0.
782*635a8641SAndroid Build Coastguard Worker                if errorcount == 0 or self.errorok:
783*635a8641SAndroid Build Coastguard Worker                    errorcount = error_count
784*635a8641SAndroid Build Coastguard Worker                    self.errorok = 0
785*635a8641SAndroid Build Coastguard Worker                    errtoken = lookahead
786*635a8641SAndroid Build Coastguard Worker                    if errtoken.type == '$end':
787*635a8641SAndroid Build Coastguard Worker                        errtoken = None               # End of file!
788*635a8641SAndroid Build Coastguard Worker                    if self.errorfunc:
789*635a8641SAndroid Build Coastguard Worker                        global errok,token,restart
790*635a8641SAndroid Build Coastguard Worker                        errok = self.errok        # Set some special functions available in error recovery
791*635a8641SAndroid Build Coastguard Worker                        token = get_token
792*635a8641SAndroid Build Coastguard Worker                        restart = self.restart
793*635a8641SAndroid Build Coastguard Worker                        if errtoken and not hasattr(errtoken,'lexer'):
794*635a8641SAndroid Build Coastguard Worker                            errtoken.lexer = lexer
795*635a8641SAndroid Build Coastguard Worker                        tok = self.errorfunc(errtoken)
796*635a8641SAndroid Build Coastguard Worker                        del errok, token, restart   # Delete special functions
797*635a8641SAndroid Build Coastguard Worker
798*635a8641SAndroid Build Coastguard Worker                        if self.errorok:
799*635a8641SAndroid Build Coastguard Worker                            # User must have done some kind of panic
800*635a8641SAndroid Build Coastguard Worker                            # mode recovery on their own.  The
801*635a8641SAndroid Build Coastguard Worker                            # returned token is the next lookahead
802*635a8641SAndroid Build Coastguard Worker                            lookahead = tok
803*635a8641SAndroid Build Coastguard Worker                            errtoken = None
804*635a8641SAndroid Build Coastguard Worker                            continue
805*635a8641SAndroid Build Coastguard Worker                    else:
806*635a8641SAndroid Build Coastguard Worker                        if errtoken:
807*635a8641SAndroid Build Coastguard Worker                            if hasattr(errtoken,"lineno"): lineno = lookahead.lineno
808*635a8641SAndroid Build Coastguard Worker                            else: lineno = 0
809*635a8641SAndroid Build Coastguard Worker                            if lineno:
810*635a8641SAndroid Build Coastguard Worker                                sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type))
811*635a8641SAndroid Build Coastguard Worker                            else:
812*635a8641SAndroid Build Coastguard Worker                                sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type)
813*635a8641SAndroid Build Coastguard Worker                        else:
814*635a8641SAndroid Build Coastguard Worker                            sys.stderr.write("yacc: Parse error in input. EOF\n")
815*635a8641SAndroid Build Coastguard Worker                            return
816*635a8641SAndroid Build Coastguard Worker
817*635a8641SAndroid Build Coastguard Worker                else:
818*635a8641SAndroid Build Coastguard Worker                    errorcount = error_count
819*635a8641SAndroid Build Coastguard Worker
820*635a8641SAndroid Build Coastguard Worker                # case 1:  the statestack only has 1 entry on it.  If we're in this state, the
821*635a8641SAndroid Build Coastguard Worker                # entire parse has been rolled back and we're completely hosed.   The token is
822*635a8641SAndroid Build Coastguard Worker                # discarded and we just keep going.
823*635a8641SAndroid Build Coastguard Worker
824*635a8641SAndroid Build Coastguard Worker                if len(statestack) <= 1 and lookahead.type != '$end':
825*635a8641SAndroid Build Coastguard Worker                    lookahead = None
826*635a8641SAndroid Build Coastguard Worker                    errtoken = None
827*635a8641SAndroid Build Coastguard Worker                    state = 0
828*635a8641SAndroid Build Coastguard Worker                    # Nuke the pushback stack
829*635a8641SAndroid Build Coastguard Worker                    del lookaheadstack[:]
830*635a8641SAndroid Build Coastguard Worker                    continue
831*635a8641SAndroid Build Coastguard Worker
832*635a8641SAndroid Build Coastguard Worker                # case 2: the statestack has a couple of entries on it, but we're
833*635a8641SAndroid Build Coastguard Worker                # at the end of the file. nuke the top entry and generate an error token
834*635a8641SAndroid Build Coastguard Worker
835*635a8641SAndroid Build Coastguard Worker                # Start nuking entries on the stack
836*635a8641SAndroid Build Coastguard Worker                if lookahead.type == '$end':
837*635a8641SAndroid Build Coastguard Worker                    # Whoa. We're really hosed here. Bail out
838*635a8641SAndroid Build Coastguard Worker                    return
839*635a8641SAndroid Build Coastguard Worker
840*635a8641SAndroid Build Coastguard Worker                if lookahead.type != 'error':
841*635a8641SAndroid Build Coastguard Worker                    sym = symstack[-1]
842*635a8641SAndroid Build Coastguard Worker                    if sym.type == 'error':
843*635a8641SAndroid Build Coastguard Worker                        # Hmmm. Error is on top of stack, we'll just nuke input
844*635a8641SAndroid Build Coastguard Worker                        # symbol and continue
845*635a8641SAndroid Build Coastguard Worker                        lookahead = None
846*635a8641SAndroid Build Coastguard Worker                        continue
847*635a8641SAndroid Build Coastguard Worker                    t = YaccSymbol()
848*635a8641SAndroid Build Coastguard Worker                    t.type = 'error'
849*635a8641SAndroid Build Coastguard Worker                    if hasattr(lookahead,"lineno"):
850*635a8641SAndroid Build Coastguard Worker                        t.lineno = lookahead.lineno
851*635a8641SAndroid Build Coastguard Worker                    t.value = lookahead
852*635a8641SAndroid Build Coastguard Worker                    lookaheadstack.append(lookahead)
853*635a8641SAndroid Build Coastguard Worker                    lookahead = t
854*635a8641SAndroid Build Coastguard Worker                else:
855*635a8641SAndroid Build Coastguard Worker                    symstack.pop()
856*635a8641SAndroid Build Coastguard Worker                    statestack.pop()
857*635a8641SAndroid Build Coastguard Worker                    state = statestack[-1]       # Potential bug fix
858*635a8641SAndroid Build Coastguard Worker
859*635a8641SAndroid Build Coastguard Worker                continue
860*635a8641SAndroid Build Coastguard Worker
861*635a8641SAndroid Build Coastguard Worker            # Call an error function here
862*635a8641SAndroid Build Coastguard Worker            raise RuntimeError("yacc: internal parser error!!!\n")
863*635a8641SAndroid Build Coastguard Worker
864*635a8641SAndroid Build Coastguard Worker    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
865*635a8641SAndroid Build Coastguard Worker    # parseopt_notrack().
866*635a8641SAndroid Build Coastguard Worker    #
867*635a8641SAndroid Build Coastguard Worker    # Optimized version of parseopt() with line number tracking removed.
868*635a8641SAndroid Build Coastguard Worker    # DO NOT EDIT THIS CODE DIRECTLY. Copy the optimized version and remove
869*635a8641SAndroid Build Coastguard Worker    # code in the #--! TRACKING sections
870*635a8641SAndroid Build Coastguard Worker    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
871*635a8641SAndroid Build Coastguard Worker
872*635a8641SAndroid Build Coastguard Worker    def parseopt_notrack(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None):
873*635a8641SAndroid Build Coastguard Worker        lookahead = None                 # Current lookahead symbol
874*635a8641SAndroid Build Coastguard Worker        lookaheadstack = [ ]             # Stack of lookahead symbols
875*635a8641SAndroid Build Coastguard Worker        actions = self.action            # Local reference to action table (to avoid lookup on self.)
876*635a8641SAndroid Build Coastguard Worker        goto    = self.goto              # Local reference to goto table (to avoid lookup on self.)
877*635a8641SAndroid Build Coastguard Worker        prod    = self.productions       # Local reference to production list (to avoid lookup on self.)
878*635a8641SAndroid Build Coastguard Worker        pslice  = YaccProduction(None)   # Production object passed to grammar rules
879*635a8641SAndroid Build Coastguard Worker        errorcount = 0                   # Used during error recovery
880*635a8641SAndroid Build Coastguard Worker
881*635a8641SAndroid Build Coastguard Worker        # If no lexer was given, we will try to use the lex module
882*635a8641SAndroid Build Coastguard Worker        if not lexer:
883*635a8641SAndroid Build Coastguard Worker            lex = load_ply_lex()
884*635a8641SAndroid Build Coastguard Worker            lexer = lex.lexer
885*635a8641SAndroid Build Coastguard Worker
886*635a8641SAndroid Build Coastguard Worker        # Set up the lexer and parser objects on pslice
887*635a8641SAndroid Build Coastguard Worker        pslice.lexer = lexer
888*635a8641SAndroid Build Coastguard Worker        pslice.parser = self
889*635a8641SAndroid Build Coastguard Worker
890*635a8641SAndroid Build Coastguard Worker        # If input was supplied, pass to lexer
891*635a8641SAndroid Build Coastguard Worker        if input is not None:
892*635a8641SAndroid Build Coastguard Worker            lexer.input(input)
893*635a8641SAndroid Build Coastguard Worker
894*635a8641SAndroid Build Coastguard Worker        if tokenfunc is None:
895*635a8641SAndroid Build Coastguard Worker           # Tokenize function
896*635a8641SAndroid Build Coastguard Worker           get_token = lexer.token
897*635a8641SAndroid Build Coastguard Worker        else:
898*635a8641SAndroid Build Coastguard Worker           get_token = tokenfunc
899*635a8641SAndroid Build Coastguard Worker
900*635a8641SAndroid Build Coastguard Worker        # Set up the state and symbol stacks
901*635a8641SAndroid Build Coastguard Worker
902*635a8641SAndroid Build Coastguard Worker        statestack = [ ]                # Stack of parsing states
903*635a8641SAndroid Build Coastguard Worker        self.statestack = statestack
904*635a8641SAndroid Build Coastguard Worker        symstack   = [ ]                # Stack of grammar symbols
905*635a8641SAndroid Build Coastguard Worker        self.symstack = symstack
906*635a8641SAndroid Build Coastguard Worker
907*635a8641SAndroid Build Coastguard Worker        pslice.stack = symstack         # Put in the production
908*635a8641SAndroid Build Coastguard Worker        errtoken   = None               # Err token
909*635a8641SAndroid Build Coastguard Worker
910*635a8641SAndroid Build Coastguard Worker        # The start state is assumed to be (0,$end)
911*635a8641SAndroid Build Coastguard Worker
912*635a8641SAndroid Build Coastguard Worker        statestack.append(0)
913*635a8641SAndroid Build Coastguard Worker        sym = YaccSymbol()
914*635a8641SAndroid Build Coastguard Worker        sym.type = '$end'
915*635a8641SAndroid Build Coastguard Worker        symstack.append(sym)
916*635a8641SAndroid Build Coastguard Worker        state = 0
917*635a8641SAndroid Build Coastguard Worker        while 1:
918*635a8641SAndroid Build Coastguard Worker            # Get the next symbol on the input.  If a lookahead symbol
919*635a8641SAndroid Build Coastguard Worker            # is already set, we just use that. Otherwise, we'll pull
920*635a8641SAndroid Build Coastguard Worker            # the next token off of the lookaheadstack or from the lexer
921*635a8641SAndroid Build Coastguard Worker
922*635a8641SAndroid Build Coastguard Worker            if not lookahead:
923*635a8641SAndroid Build Coastguard Worker                if not lookaheadstack:
924*635a8641SAndroid Build Coastguard Worker                    lookahead = get_token()     # Get the next token
925*635a8641SAndroid Build Coastguard Worker                else:
926*635a8641SAndroid Build Coastguard Worker                    lookahead = lookaheadstack.pop()
927*635a8641SAndroid Build Coastguard Worker                if not lookahead:
928*635a8641SAndroid Build Coastguard Worker                    lookahead = YaccSymbol()
929*635a8641SAndroid Build Coastguard Worker                    lookahead.type = '$end'
930*635a8641SAndroid Build Coastguard Worker
931*635a8641SAndroid Build Coastguard Worker            # Check the action table
932*635a8641SAndroid Build Coastguard Worker            ltype = lookahead.type
933*635a8641SAndroid Build Coastguard Worker            t = actions[state].get(ltype)
934*635a8641SAndroid Build Coastguard Worker
935*635a8641SAndroid Build Coastguard Worker            if t is not None:
936*635a8641SAndroid Build Coastguard Worker                if t > 0:
937*635a8641SAndroid Build Coastguard Worker                    # shift a symbol on the stack
938*635a8641SAndroid Build Coastguard Worker                    statestack.append(t)
939*635a8641SAndroid Build Coastguard Worker                    state = t
940*635a8641SAndroid Build Coastguard Worker
941*635a8641SAndroid Build Coastguard Worker                    symstack.append(lookahead)
942*635a8641SAndroid Build Coastguard Worker                    lookahead = None
943*635a8641SAndroid Build Coastguard Worker
944*635a8641SAndroid Build Coastguard Worker                    # Decrease error count on successful shift
945*635a8641SAndroid Build Coastguard Worker                    if errorcount: errorcount -=1
946*635a8641SAndroid Build Coastguard Worker                    continue
947*635a8641SAndroid Build Coastguard Worker
948*635a8641SAndroid Build Coastguard Worker                if t < 0:
949*635a8641SAndroid Build Coastguard Worker                    # reduce a symbol on the stack, emit a production
950*635a8641SAndroid Build Coastguard Worker                    p = prod[-t]
951*635a8641SAndroid Build Coastguard Worker                    pname = p.name
952*635a8641SAndroid Build Coastguard Worker                    plen  = p.len
953*635a8641SAndroid Build Coastguard Worker
954*635a8641SAndroid Build Coastguard Worker                    # Get production function
955*635a8641SAndroid Build Coastguard Worker                    sym = YaccSymbol()
956*635a8641SAndroid Build Coastguard Worker                    sym.type = pname       # Production name
957*635a8641SAndroid Build Coastguard Worker                    sym.value = None
958*635a8641SAndroid Build Coastguard Worker
959*635a8641SAndroid Build Coastguard Worker                    if plen:
960*635a8641SAndroid Build Coastguard Worker                        targ = symstack[-plen-1:]
961*635a8641SAndroid Build Coastguard Worker                        targ[0] = sym
962*635a8641SAndroid Build Coastguard Worker
963*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
964*635a8641SAndroid Build Coastguard Worker                        # The code enclosed in this section is duplicated
965*635a8641SAndroid Build Coastguard Worker                        # below as a performance optimization.  Make sure
966*635a8641SAndroid Build Coastguard Worker                        # changes get made in both locations.
967*635a8641SAndroid Build Coastguard Worker
968*635a8641SAndroid Build Coastguard Worker                        pslice.slice = targ
969*635a8641SAndroid Build Coastguard Worker
970*635a8641SAndroid Build Coastguard Worker                        try:
971*635a8641SAndroid Build Coastguard Worker                            # Call the grammar rule with our special slice object
972*635a8641SAndroid Build Coastguard Worker                            del symstack[-plen:]
973*635a8641SAndroid Build Coastguard Worker                            del statestack[-plen:]
974*635a8641SAndroid Build Coastguard Worker                            p.callable(pslice)
975*635a8641SAndroid Build Coastguard Worker                            symstack.append(sym)
976*635a8641SAndroid Build Coastguard Worker                            state = goto[statestack[-1]][pname]
977*635a8641SAndroid Build Coastguard Worker                            statestack.append(state)
978*635a8641SAndroid Build Coastguard Worker                        except SyntaxError:
979*635a8641SAndroid Build Coastguard Worker                            # If an error was set. Enter error recovery state
980*635a8641SAndroid Build Coastguard Worker                            lookaheadstack.append(lookahead)
981*635a8641SAndroid Build Coastguard Worker                            symstack.pop()
982*635a8641SAndroid Build Coastguard Worker                            statestack.pop()
983*635a8641SAndroid Build Coastguard Worker                            state = statestack[-1]
984*635a8641SAndroid Build Coastguard Worker                            sym.type = 'error'
985*635a8641SAndroid Build Coastguard Worker                            lookahead = sym
986*635a8641SAndroid Build Coastguard Worker                            errorcount = error_count
987*635a8641SAndroid Build Coastguard Worker                            self.errorok = 0
988*635a8641SAndroid Build Coastguard Worker                        continue
989*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
990*635a8641SAndroid Build Coastguard Worker
991*635a8641SAndroid Build Coastguard Worker                    else:
992*635a8641SAndroid Build Coastguard Worker
993*635a8641SAndroid Build Coastguard Worker                        targ = [ sym ]
994*635a8641SAndroid Build Coastguard Worker
995*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
996*635a8641SAndroid Build Coastguard Worker                        # The code enclosed in this section is duplicated
997*635a8641SAndroid Build Coastguard Worker                        # above as a performance optimization.  Make sure
998*635a8641SAndroid Build Coastguard Worker                        # changes get made in both locations.
999*635a8641SAndroid Build Coastguard Worker
1000*635a8641SAndroid Build Coastguard Worker                        pslice.slice = targ
1001*635a8641SAndroid Build Coastguard Worker
1002*635a8641SAndroid Build Coastguard Worker                        try:
1003*635a8641SAndroid Build Coastguard Worker                            # Call the grammar rule with our special slice object
1004*635a8641SAndroid Build Coastguard Worker                            p.callable(pslice)
1005*635a8641SAndroid Build Coastguard Worker                            symstack.append(sym)
1006*635a8641SAndroid Build Coastguard Worker                            state = goto[statestack[-1]][pname]
1007*635a8641SAndroid Build Coastguard Worker                            statestack.append(state)
1008*635a8641SAndroid Build Coastguard Worker                        except SyntaxError:
1009*635a8641SAndroid Build Coastguard Worker                            # If an error was set. Enter error recovery state
1010*635a8641SAndroid Build Coastguard Worker                            lookaheadstack.append(lookahead)
1011*635a8641SAndroid Build Coastguard Worker                            symstack.pop()
1012*635a8641SAndroid Build Coastguard Worker                            statestack.pop()
1013*635a8641SAndroid Build Coastguard Worker                            state = statestack[-1]
1014*635a8641SAndroid Build Coastguard Worker                            sym.type = 'error'
1015*635a8641SAndroid Build Coastguard Worker                            lookahead = sym
1016*635a8641SAndroid Build Coastguard Worker                            errorcount = error_count
1017*635a8641SAndroid Build Coastguard Worker                            self.errorok = 0
1018*635a8641SAndroid Build Coastguard Worker                        continue
1019*635a8641SAndroid Build Coastguard Worker                        # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1020*635a8641SAndroid Build Coastguard Worker
1021*635a8641SAndroid Build Coastguard Worker                if t == 0:
1022*635a8641SAndroid Build Coastguard Worker                    n = symstack[-1]
1023*635a8641SAndroid Build Coastguard Worker                    return getattr(n,"value",None)
1024*635a8641SAndroid Build Coastguard Worker
1025*635a8641SAndroid Build Coastguard Worker            if t == None:
1026*635a8641SAndroid Build Coastguard Worker
1027*635a8641SAndroid Build Coastguard Worker                # We have some kind of parsing error here.  To handle
1028*635a8641SAndroid Build Coastguard Worker                # this, we are going to push the current token onto
1029*635a8641SAndroid Build Coastguard Worker                # the tokenstack and replace it with an 'error' token.
1030*635a8641SAndroid Build Coastguard Worker                # If there are any synchronization rules, they may
1031*635a8641SAndroid Build Coastguard Worker                # catch it.
1032*635a8641SAndroid Build Coastguard Worker                #
1033*635a8641SAndroid Build Coastguard Worker                # In addition to pushing the error token, we call call
1034*635a8641SAndroid Build Coastguard Worker                # the user defined p_error() function if this is the
1035*635a8641SAndroid Build Coastguard Worker                # first syntax error.  This function is only called if
1036*635a8641SAndroid Build Coastguard Worker                # errorcount == 0.
1037*635a8641SAndroid Build Coastguard Worker                if errorcount == 0 or self.errorok:
1038*635a8641SAndroid Build Coastguard Worker                    errorcount = error_count
1039*635a8641SAndroid Build Coastguard Worker                    self.errorok = 0
1040*635a8641SAndroid Build Coastguard Worker                    errtoken = lookahead
1041*635a8641SAndroid Build Coastguard Worker                    if errtoken.type == '$end':
1042*635a8641SAndroid Build Coastguard Worker                        errtoken = None               # End of file!
1043*635a8641SAndroid Build Coastguard Worker                    if self.errorfunc:
1044*635a8641SAndroid Build Coastguard Worker                        global errok,token,restart
1045*635a8641SAndroid Build Coastguard Worker                        errok = self.errok        # Set some special functions available in error recovery
1046*635a8641SAndroid Build Coastguard Worker                        token = get_token
1047*635a8641SAndroid Build Coastguard Worker                        restart = self.restart
1048*635a8641SAndroid Build Coastguard Worker                        if errtoken and not hasattr(errtoken,'lexer'):
1049*635a8641SAndroid Build Coastguard Worker                            errtoken.lexer = lexer
1050*635a8641SAndroid Build Coastguard Worker                        tok = self.errorfunc(errtoken)
1051*635a8641SAndroid Build Coastguard Worker                        del errok, token, restart   # Delete special functions
1052*635a8641SAndroid Build Coastguard Worker
1053*635a8641SAndroid Build Coastguard Worker                        if self.errorok:
1054*635a8641SAndroid Build Coastguard Worker                            # User must have done some kind of panic
1055*635a8641SAndroid Build Coastguard Worker                            # mode recovery on their own.  The
1056*635a8641SAndroid Build Coastguard Worker                            # returned token is the next lookahead
1057*635a8641SAndroid Build Coastguard Worker                            lookahead = tok
1058*635a8641SAndroid Build Coastguard Worker                            errtoken = None
1059*635a8641SAndroid Build Coastguard Worker                            continue
1060*635a8641SAndroid Build Coastguard Worker                    else:
1061*635a8641SAndroid Build Coastguard Worker                        if errtoken:
1062*635a8641SAndroid Build Coastguard Worker                            if hasattr(errtoken,"lineno"): lineno = lookahead.lineno
1063*635a8641SAndroid Build Coastguard Worker                            else: lineno = 0
1064*635a8641SAndroid Build Coastguard Worker                            if lineno:
1065*635a8641SAndroid Build Coastguard Worker                                sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type))
1066*635a8641SAndroid Build Coastguard Worker                            else:
1067*635a8641SAndroid Build Coastguard Worker                                sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type)
1068*635a8641SAndroid Build Coastguard Worker                        else:
1069*635a8641SAndroid Build Coastguard Worker                            sys.stderr.write("yacc: Parse error in input. EOF\n")
1070*635a8641SAndroid Build Coastguard Worker                            return
1071*635a8641SAndroid Build Coastguard Worker
1072*635a8641SAndroid Build Coastguard Worker                else:
1073*635a8641SAndroid Build Coastguard Worker                    errorcount = error_count
1074*635a8641SAndroid Build Coastguard Worker
1075*635a8641SAndroid Build Coastguard Worker                # case 1:  the statestack only has 1 entry on it.  If we're in this state, the
1076*635a8641SAndroid Build Coastguard Worker                # entire parse has been rolled back and we're completely hosed.   The token is
1077*635a8641SAndroid Build Coastguard Worker                # discarded and we just keep going.
1078*635a8641SAndroid Build Coastguard Worker
1079*635a8641SAndroid Build Coastguard Worker                if len(statestack) <= 1 and lookahead.type != '$end':
1080*635a8641SAndroid Build Coastguard Worker                    lookahead = None
1081*635a8641SAndroid Build Coastguard Worker                    errtoken = None
1082*635a8641SAndroid Build Coastguard Worker                    state = 0
1083*635a8641SAndroid Build Coastguard Worker                    # Nuke the pushback stack
1084*635a8641SAndroid Build Coastguard Worker                    del lookaheadstack[:]
1085*635a8641SAndroid Build Coastguard Worker                    continue
1086*635a8641SAndroid Build Coastguard Worker
1087*635a8641SAndroid Build Coastguard Worker                # case 2: the statestack has a couple of entries on it, but we're
1088*635a8641SAndroid Build Coastguard Worker                # at the end of the file. nuke the top entry and generate an error token
1089*635a8641SAndroid Build Coastguard Worker
1090*635a8641SAndroid Build Coastguard Worker                # Start nuking entries on the stack
1091*635a8641SAndroid Build Coastguard Worker                if lookahead.type == '$end':
1092*635a8641SAndroid Build Coastguard Worker                    # Whoa. We're really hosed here. Bail out
1093*635a8641SAndroid Build Coastguard Worker                    return
1094*635a8641SAndroid Build Coastguard Worker
1095*635a8641SAndroid Build Coastguard Worker                if lookahead.type != 'error':
1096*635a8641SAndroid Build Coastguard Worker                    sym = symstack[-1]
1097*635a8641SAndroid Build Coastguard Worker                    if sym.type == 'error':
1098*635a8641SAndroid Build Coastguard Worker                        # Hmmm. Error is on top of stack, we'll just nuke input
1099*635a8641SAndroid Build Coastguard Worker                        # symbol and continue
1100*635a8641SAndroid Build Coastguard Worker                        lookahead = None
1101*635a8641SAndroid Build Coastguard Worker                        continue
1102*635a8641SAndroid Build Coastguard Worker                    t = YaccSymbol()
1103*635a8641SAndroid Build Coastguard Worker                    t.type = 'error'
1104*635a8641SAndroid Build Coastguard Worker                    if hasattr(lookahead,"lineno"):
1105*635a8641SAndroid Build Coastguard Worker                        t.lineno = lookahead.lineno
1106*635a8641SAndroid Build Coastguard Worker                    t.value = lookahead
1107*635a8641SAndroid Build Coastguard Worker                    lookaheadstack.append(lookahead)
1108*635a8641SAndroid Build Coastguard Worker                    lookahead = t
1109*635a8641SAndroid Build Coastguard Worker                else:
1110*635a8641SAndroid Build Coastguard Worker                    symstack.pop()
1111*635a8641SAndroid Build Coastguard Worker                    statestack.pop()
1112*635a8641SAndroid Build Coastguard Worker                    state = statestack[-1]       # Potential bug fix
1113*635a8641SAndroid Build Coastguard Worker
1114*635a8641SAndroid Build Coastguard Worker                continue
1115*635a8641SAndroid Build Coastguard Worker
1116*635a8641SAndroid Build Coastguard Worker            # Call an error function here
1117*635a8641SAndroid Build Coastguard Worker            raise RuntimeError("yacc: internal parser error!!!\n")
1118*635a8641SAndroid Build Coastguard Worker
1119*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1120*635a8641SAndroid Build Coastguard Worker#                          === Grammar Representation ===
1121*635a8641SAndroid Build Coastguard Worker#
1122*635a8641SAndroid Build Coastguard Worker# The following functions, classes, and variables are used to represent and
1123*635a8641SAndroid Build Coastguard Worker# manipulate the rules that make up a grammar.
1124*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1125*635a8641SAndroid Build Coastguard Worker
1126*635a8641SAndroid Build Coastguard Workerimport re
1127*635a8641SAndroid Build Coastguard Worker
1128*635a8641SAndroid Build Coastguard Worker# regex matching identifiers
1129*635a8641SAndroid Build Coastguard Worker_is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$')
1130*635a8641SAndroid Build Coastguard Worker
1131*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1132*635a8641SAndroid Build Coastguard Worker# class Production:
1133*635a8641SAndroid Build Coastguard Worker#
1134*635a8641SAndroid Build Coastguard Worker# This class stores the raw information about a single production or grammar rule.
1135*635a8641SAndroid Build Coastguard Worker# A grammar rule refers to a specification such as this:
1136*635a8641SAndroid Build Coastguard Worker#
1137*635a8641SAndroid Build Coastguard Worker#       expr : expr PLUS term
1138*635a8641SAndroid Build Coastguard Worker#
1139*635a8641SAndroid Build Coastguard Worker# Here are the basic attributes defined on all productions
1140*635a8641SAndroid Build Coastguard Worker#
1141*635a8641SAndroid Build Coastguard Worker#       name     - Name of the production.  For example 'expr'
1142*635a8641SAndroid Build Coastguard Worker#       prod     - A list of symbols on the right side ['expr','PLUS','term']
1143*635a8641SAndroid Build Coastguard Worker#       prec     - Production precedence level
1144*635a8641SAndroid Build Coastguard Worker#       number   - Production number.
1145*635a8641SAndroid Build Coastguard Worker#       func     - Function that executes on reduce
1146*635a8641SAndroid Build Coastguard Worker#       file     - File where production function is defined
1147*635a8641SAndroid Build Coastguard Worker#       lineno   - Line number where production function is defined
1148*635a8641SAndroid Build Coastguard Worker#
1149*635a8641SAndroid Build Coastguard Worker# The following attributes are defined or optional.
1150*635a8641SAndroid Build Coastguard Worker#
1151*635a8641SAndroid Build Coastguard Worker#       len       - Length of the production (number of symbols on right hand side)
1152*635a8641SAndroid Build Coastguard Worker#       usyms     - Set of unique symbols found in the production
1153*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1154*635a8641SAndroid Build Coastguard Worker
1155*635a8641SAndroid Build Coastguard Workerclass Production(object):
1156*635a8641SAndroid Build Coastguard Worker    reduced = 0
1157*635a8641SAndroid Build Coastguard Worker    def __init__(self,number,name,prod,precedence=('right',0),func=None,file='',line=0):
1158*635a8641SAndroid Build Coastguard Worker        self.name     = name
1159*635a8641SAndroid Build Coastguard Worker        self.prod     = tuple(prod)
1160*635a8641SAndroid Build Coastguard Worker        self.number   = number
1161*635a8641SAndroid Build Coastguard Worker        self.func     = func
1162*635a8641SAndroid Build Coastguard Worker        self.callable = None
1163*635a8641SAndroid Build Coastguard Worker        self.file     = file
1164*635a8641SAndroid Build Coastguard Worker        self.line     = line
1165*635a8641SAndroid Build Coastguard Worker        self.prec     = precedence
1166*635a8641SAndroid Build Coastguard Worker
1167*635a8641SAndroid Build Coastguard Worker        # Internal settings used during table construction
1168*635a8641SAndroid Build Coastguard Worker
1169*635a8641SAndroid Build Coastguard Worker        self.len  = len(self.prod)   # Length of the production
1170*635a8641SAndroid Build Coastguard Worker
1171*635a8641SAndroid Build Coastguard Worker        # Create a list of unique production symbols used in the production
1172*635a8641SAndroid Build Coastguard Worker        self.usyms = [ ]
1173*635a8641SAndroid Build Coastguard Worker        for s in self.prod:
1174*635a8641SAndroid Build Coastguard Worker            if s not in self.usyms:
1175*635a8641SAndroid Build Coastguard Worker                self.usyms.append(s)
1176*635a8641SAndroid Build Coastguard Worker
1177*635a8641SAndroid Build Coastguard Worker        # List of all LR items for the production
1178*635a8641SAndroid Build Coastguard Worker        self.lr_items = []
1179*635a8641SAndroid Build Coastguard Worker        self.lr_next = None
1180*635a8641SAndroid Build Coastguard Worker
1181*635a8641SAndroid Build Coastguard Worker        # Create a string representation
1182*635a8641SAndroid Build Coastguard Worker        if self.prod:
1183*635a8641SAndroid Build Coastguard Worker            self.str = "%s -> %s" % (self.name," ".join(self.prod))
1184*635a8641SAndroid Build Coastguard Worker        else:
1185*635a8641SAndroid Build Coastguard Worker            self.str = "%s -> <empty>" % self.name
1186*635a8641SAndroid Build Coastguard Worker
1187*635a8641SAndroid Build Coastguard Worker    def __str__(self):
1188*635a8641SAndroid Build Coastguard Worker        return self.str
1189*635a8641SAndroid Build Coastguard Worker
1190*635a8641SAndroid Build Coastguard Worker    def __repr__(self):
1191*635a8641SAndroid Build Coastguard Worker        return "Production("+str(self)+")"
1192*635a8641SAndroid Build Coastguard Worker
1193*635a8641SAndroid Build Coastguard Worker    def __len__(self):
1194*635a8641SAndroid Build Coastguard Worker        return len(self.prod)
1195*635a8641SAndroid Build Coastguard Worker
1196*635a8641SAndroid Build Coastguard Worker    def __nonzero__(self):
1197*635a8641SAndroid Build Coastguard Worker        return 1
1198*635a8641SAndroid Build Coastguard Worker
1199*635a8641SAndroid Build Coastguard Worker    def __getitem__(self,index):
1200*635a8641SAndroid Build Coastguard Worker        return self.prod[index]
1201*635a8641SAndroid Build Coastguard Worker
1202*635a8641SAndroid Build Coastguard Worker    # Return the nth lr_item from the production (or None if at the end)
1203*635a8641SAndroid Build Coastguard Worker    def lr_item(self,n):
1204*635a8641SAndroid Build Coastguard Worker        if n > len(self.prod): return None
1205*635a8641SAndroid Build Coastguard Worker        p = LRItem(self,n)
1206*635a8641SAndroid Build Coastguard Worker
1207*635a8641SAndroid Build Coastguard Worker        # Precompute the list of productions immediately following.  Hack. Remove later
1208*635a8641SAndroid Build Coastguard Worker        try:
1209*635a8641SAndroid Build Coastguard Worker            p.lr_after = Prodnames[p.prod[n+1]]
1210*635a8641SAndroid Build Coastguard Worker        except (IndexError,KeyError):
1211*635a8641SAndroid Build Coastguard Worker            p.lr_after = []
1212*635a8641SAndroid Build Coastguard Worker        try:
1213*635a8641SAndroid Build Coastguard Worker            p.lr_before = p.prod[n-1]
1214*635a8641SAndroid Build Coastguard Worker        except IndexError:
1215*635a8641SAndroid Build Coastguard Worker            p.lr_before = None
1216*635a8641SAndroid Build Coastguard Worker
1217*635a8641SAndroid Build Coastguard Worker        return p
1218*635a8641SAndroid Build Coastguard Worker
1219*635a8641SAndroid Build Coastguard Worker    # Bind the production function name to a callable
1220*635a8641SAndroid Build Coastguard Worker    def bind(self,pdict):
1221*635a8641SAndroid Build Coastguard Worker        if self.func:
1222*635a8641SAndroid Build Coastguard Worker            self.callable = pdict[self.func]
1223*635a8641SAndroid Build Coastguard Worker
1224*635a8641SAndroid Build Coastguard Worker# This class serves as a minimal standin for Production objects when
1225*635a8641SAndroid Build Coastguard Worker# reading table data from files.   It only contains information
1226*635a8641SAndroid Build Coastguard Worker# actually used by the LR parsing engine, plus some additional
1227*635a8641SAndroid Build Coastguard Worker# debugging information.
1228*635a8641SAndroid Build Coastguard Workerclass MiniProduction(object):
1229*635a8641SAndroid Build Coastguard Worker    def __init__(self,str,name,len,func,file,line):
1230*635a8641SAndroid Build Coastguard Worker        self.name     = name
1231*635a8641SAndroid Build Coastguard Worker        self.len      = len
1232*635a8641SAndroid Build Coastguard Worker        self.func     = func
1233*635a8641SAndroid Build Coastguard Worker        self.callable = None
1234*635a8641SAndroid Build Coastguard Worker        self.file     = file
1235*635a8641SAndroid Build Coastguard Worker        self.line     = line
1236*635a8641SAndroid Build Coastguard Worker        self.str      = str
1237*635a8641SAndroid Build Coastguard Worker    def __str__(self):
1238*635a8641SAndroid Build Coastguard Worker        return self.str
1239*635a8641SAndroid Build Coastguard Worker    def __repr__(self):
1240*635a8641SAndroid Build Coastguard Worker        return "MiniProduction(%s)" % self.str
1241*635a8641SAndroid Build Coastguard Worker
1242*635a8641SAndroid Build Coastguard Worker    # Bind the production function name to a callable
1243*635a8641SAndroid Build Coastguard Worker    def bind(self,pdict):
1244*635a8641SAndroid Build Coastguard Worker        if self.func:
1245*635a8641SAndroid Build Coastguard Worker            self.callable = pdict[self.func]
1246*635a8641SAndroid Build Coastguard Worker
1247*635a8641SAndroid Build Coastguard Worker
1248*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1249*635a8641SAndroid Build Coastguard Worker# class LRItem
1250*635a8641SAndroid Build Coastguard Worker#
1251*635a8641SAndroid Build Coastguard Worker# This class represents a specific stage of parsing a production rule.  For
1252*635a8641SAndroid Build Coastguard Worker# example:
1253*635a8641SAndroid Build Coastguard Worker#
1254*635a8641SAndroid Build Coastguard Worker#       expr : expr . PLUS term
1255*635a8641SAndroid Build Coastguard Worker#
1256*635a8641SAndroid Build Coastguard Worker# In the above, the "." represents the current location of the parse.  Here
1257*635a8641SAndroid Build Coastguard Worker# basic attributes:
1258*635a8641SAndroid Build Coastguard Worker#
1259*635a8641SAndroid Build Coastguard Worker#       name       - Name of the production.  For example 'expr'
1260*635a8641SAndroid Build Coastguard Worker#       prod       - A list of symbols on the right side ['expr','.', 'PLUS','term']
1261*635a8641SAndroid Build Coastguard Worker#       number     - Production number.
1262*635a8641SAndroid Build Coastguard Worker#
1263*635a8641SAndroid Build Coastguard Worker#       lr_next      Next LR item. Example, if we are ' expr -> expr . PLUS term'
1264*635a8641SAndroid Build Coastguard Worker#                    then lr_next refers to 'expr -> expr PLUS . term'
1265*635a8641SAndroid Build Coastguard Worker#       lr_index   - LR item index (location of the ".") in the prod list.
1266*635a8641SAndroid Build Coastguard Worker#       lookaheads - LALR lookahead symbols for this item
1267*635a8641SAndroid Build Coastguard Worker#       len        - Length of the production (number of symbols on right hand side)
1268*635a8641SAndroid Build Coastguard Worker#       lr_after    - List of all productions that immediately follow
1269*635a8641SAndroid Build Coastguard Worker#       lr_before   - Grammar symbol immediately before
1270*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1271*635a8641SAndroid Build Coastguard Worker
1272*635a8641SAndroid Build Coastguard Workerclass LRItem(object):
1273*635a8641SAndroid Build Coastguard Worker    def __init__(self,p,n):
1274*635a8641SAndroid Build Coastguard Worker        self.name       = p.name
1275*635a8641SAndroid Build Coastguard Worker        self.prod       = list(p.prod)
1276*635a8641SAndroid Build Coastguard Worker        self.number     = p.number
1277*635a8641SAndroid Build Coastguard Worker        self.lr_index   = n
1278*635a8641SAndroid Build Coastguard Worker        self.lookaheads = { }
1279*635a8641SAndroid Build Coastguard Worker        self.prod.insert(n,".")
1280*635a8641SAndroid Build Coastguard Worker        self.prod       = tuple(self.prod)
1281*635a8641SAndroid Build Coastguard Worker        self.len        = len(self.prod)
1282*635a8641SAndroid Build Coastguard Worker        self.usyms      = p.usyms
1283*635a8641SAndroid Build Coastguard Worker
1284*635a8641SAndroid Build Coastguard Worker    def __str__(self):
1285*635a8641SAndroid Build Coastguard Worker        if self.prod:
1286*635a8641SAndroid Build Coastguard Worker            s = "%s -> %s" % (self.name," ".join(self.prod))
1287*635a8641SAndroid Build Coastguard Worker        else:
1288*635a8641SAndroid Build Coastguard Worker            s = "%s -> <empty>" % self.name
1289*635a8641SAndroid Build Coastguard Worker        return s
1290*635a8641SAndroid Build Coastguard Worker
1291*635a8641SAndroid Build Coastguard Worker    def __repr__(self):
1292*635a8641SAndroid Build Coastguard Worker        return "LRItem("+str(self)+")"
1293*635a8641SAndroid Build Coastguard Worker
1294*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1295*635a8641SAndroid Build Coastguard Worker# rightmost_terminal()
1296*635a8641SAndroid Build Coastguard Worker#
1297*635a8641SAndroid Build Coastguard Worker# Return the rightmost terminal from a list of symbols.  Used in add_production()
1298*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1299*635a8641SAndroid Build Coastguard Workerdef rightmost_terminal(symbols, terminals):
1300*635a8641SAndroid Build Coastguard Worker    i = len(symbols) - 1
1301*635a8641SAndroid Build Coastguard Worker    while i >= 0:
1302*635a8641SAndroid Build Coastguard Worker        if symbols[i] in terminals:
1303*635a8641SAndroid Build Coastguard Worker            return symbols[i]
1304*635a8641SAndroid Build Coastguard Worker        i -= 1
1305*635a8641SAndroid Build Coastguard Worker    return None
1306*635a8641SAndroid Build Coastguard Worker
1307*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1308*635a8641SAndroid Build Coastguard Worker#                           === GRAMMAR CLASS ===
1309*635a8641SAndroid Build Coastguard Worker#
1310*635a8641SAndroid Build Coastguard Worker# The following class represents the contents of the specified grammar along
1311*635a8641SAndroid Build Coastguard Worker# with various computed properties such as first sets, follow sets, LR items, etc.
1312*635a8641SAndroid Build Coastguard Worker# This data is used for critical parts of the table generation process later.
1313*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1314*635a8641SAndroid Build Coastguard Worker
1315*635a8641SAndroid Build Coastguard Workerclass GrammarError(YaccError): pass
1316*635a8641SAndroid Build Coastguard Worker
1317*635a8641SAndroid Build Coastguard Workerclass Grammar(object):
1318*635a8641SAndroid Build Coastguard Worker    def __init__(self,terminals):
1319*635a8641SAndroid Build Coastguard Worker        self.Productions  = [None]  # A list of all of the productions.  The first
1320*635a8641SAndroid Build Coastguard Worker                                    # entry is always reserved for the purpose of
1321*635a8641SAndroid Build Coastguard Worker                                    # building an augmented grammar
1322*635a8641SAndroid Build Coastguard Worker
1323*635a8641SAndroid Build Coastguard Worker        self.Prodnames    = { }     # A dictionary mapping the names of nonterminals to a list of all
1324*635a8641SAndroid Build Coastguard Worker                                    # productions of that nonterminal.
1325*635a8641SAndroid Build Coastguard Worker
1326*635a8641SAndroid Build Coastguard Worker        self.Prodmap      = { }     # A dictionary that is only used to detect duplicate
1327*635a8641SAndroid Build Coastguard Worker                                    # productions.
1328*635a8641SAndroid Build Coastguard Worker
1329*635a8641SAndroid Build Coastguard Worker        self.Terminals    = { }     # A dictionary mapping the names of terminal symbols to a
1330*635a8641SAndroid Build Coastguard Worker                                    # list of the rules where they are used.
1331*635a8641SAndroid Build Coastguard Worker
1332*635a8641SAndroid Build Coastguard Worker        for term in terminals:
1333*635a8641SAndroid Build Coastguard Worker            self.Terminals[term] = []
1334*635a8641SAndroid Build Coastguard Worker
1335*635a8641SAndroid Build Coastguard Worker        self.Terminals['error'] = []
1336*635a8641SAndroid Build Coastguard Worker
1337*635a8641SAndroid Build Coastguard Worker        self.Nonterminals = { }     # A dictionary mapping names of nonterminals to a list
1338*635a8641SAndroid Build Coastguard Worker                                    # of rule numbers where they are used.
1339*635a8641SAndroid Build Coastguard Worker
1340*635a8641SAndroid Build Coastguard Worker        self.First        = { }     # A dictionary of precomputed FIRST(x) symbols
1341*635a8641SAndroid Build Coastguard Worker
1342*635a8641SAndroid Build Coastguard Worker        self.Follow       = { }     # A dictionary of precomputed FOLLOW(x) symbols
1343*635a8641SAndroid Build Coastguard Worker
1344*635a8641SAndroid Build Coastguard Worker        self.Precedence   = { }     # Precedence rules for each terminal. Contains tuples of the
1345*635a8641SAndroid Build Coastguard Worker                                    # form ('right',level) or ('nonassoc', level) or ('left',level)
1346*635a8641SAndroid Build Coastguard Worker
1347*635a8641SAndroid Build Coastguard Worker        self.UsedPrecedence = { }   # Precedence rules that were actually used by the grammer.
1348*635a8641SAndroid Build Coastguard Worker                                    # This is only used to provide error checking and to generate
1349*635a8641SAndroid Build Coastguard Worker                                    # a warning about unused precedence rules.
1350*635a8641SAndroid Build Coastguard Worker
1351*635a8641SAndroid Build Coastguard Worker        self.Start = None           # Starting symbol for the grammar
1352*635a8641SAndroid Build Coastguard Worker
1353*635a8641SAndroid Build Coastguard Worker
1354*635a8641SAndroid Build Coastguard Worker    def __len__(self):
1355*635a8641SAndroid Build Coastguard Worker        return len(self.Productions)
1356*635a8641SAndroid Build Coastguard Worker
1357*635a8641SAndroid Build Coastguard Worker    def __getitem__(self,index):
1358*635a8641SAndroid Build Coastguard Worker        return self.Productions[index]
1359*635a8641SAndroid Build Coastguard Worker
1360*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1361*635a8641SAndroid Build Coastguard Worker    # set_precedence()
1362*635a8641SAndroid Build Coastguard Worker    #
1363*635a8641SAndroid Build Coastguard Worker    # Sets the precedence for a given terminal. assoc is the associativity such as
1364*635a8641SAndroid Build Coastguard Worker    # 'left','right', or 'nonassoc'.  level is a numeric level.
1365*635a8641SAndroid Build Coastguard Worker    #
1366*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1367*635a8641SAndroid Build Coastguard Worker
1368*635a8641SAndroid Build Coastguard Worker    def set_precedence(self,term,assoc,level):
1369*635a8641SAndroid Build Coastguard Worker        assert self.Productions == [None],"Must call set_precedence() before add_production()"
1370*635a8641SAndroid Build Coastguard Worker        if term in self.Precedence:
1371*635a8641SAndroid Build Coastguard Worker            raise GrammarError("Precedence already specified for terminal '%s'" % term)
1372*635a8641SAndroid Build Coastguard Worker        if assoc not in ['left','right','nonassoc']:
1373*635a8641SAndroid Build Coastguard Worker            raise GrammarError("Associativity must be one of 'left','right', or 'nonassoc'")
1374*635a8641SAndroid Build Coastguard Worker        self.Precedence[term] = (assoc,level)
1375*635a8641SAndroid Build Coastguard Worker
1376*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1377*635a8641SAndroid Build Coastguard Worker    # add_production()
1378*635a8641SAndroid Build Coastguard Worker    #
1379*635a8641SAndroid Build Coastguard Worker    # Given an action function, this function assembles a production rule and
1380*635a8641SAndroid Build Coastguard Worker    # computes its precedence level.
1381*635a8641SAndroid Build Coastguard Worker    #
1382*635a8641SAndroid Build Coastguard Worker    # The production rule is supplied as a list of symbols.   For example,
1383*635a8641SAndroid Build Coastguard Worker    # a rule such as 'expr : expr PLUS term' has a production name of 'expr' and
1384*635a8641SAndroid Build Coastguard Worker    # symbols ['expr','PLUS','term'].
1385*635a8641SAndroid Build Coastguard Worker    #
1386*635a8641SAndroid Build Coastguard Worker    # Precedence is determined by the precedence of the right-most non-terminal
1387*635a8641SAndroid Build Coastguard Worker    # or the precedence of a terminal specified by %prec.
1388*635a8641SAndroid Build Coastguard Worker    #
1389*635a8641SAndroid Build Coastguard Worker    # A variety of error checks are performed to make sure production symbols
1390*635a8641SAndroid Build Coastguard Worker    # are valid and that %prec is used correctly.
1391*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1392*635a8641SAndroid Build Coastguard Worker
1393*635a8641SAndroid Build Coastguard Worker    def add_production(self,prodname,syms,func=None,file='',line=0):
1394*635a8641SAndroid Build Coastguard Worker
1395*635a8641SAndroid Build Coastguard Worker        if prodname in self.Terminals:
1396*635a8641SAndroid Build Coastguard Worker            raise GrammarError("%s:%d: Illegal rule name '%s'. Already defined as a token" % (file,line,prodname))
1397*635a8641SAndroid Build Coastguard Worker        if prodname == 'error':
1398*635a8641SAndroid Build Coastguard Worker            raise GrammarError("%s:%d: Illegal rule name '%s'. error is a reserved word" % (file,line,prodname))
1399*635a8641SAndroid Build Coastguard Worker        if not _is_identifier.match(prodname):
1400*635a8641SAndroid Build Coastguard Worker            raise GrammarError("%s:%d: Illegal rule name '%s'" % (file,line,prodname))
1401*635a8641SAndroid Build Coastguard Worker
1402*635a8641SAndroid Build Coastguard Worker        # Look for literal tokens
1403*635a8641SAndroid Build Coastguard Worker        for n,s in enumerate(syms):
1404*635a8641SAndroid Build Coastguard Worker            if s[0] in "'\"":
1405*635a8641SAndroid Build Coastguard Worker                 try:
1406*635a8641SAndroid Build Coastguard Worker                     c = eval(s)
1407*635a8641SAndroid Build Coastguard Worker                     if (len(c) > 1):
1408*635a8641SAndroid Build Coastguard Worker                          raise GrammarError("%s:%d: Literal token %s in rule '%s' may only be a single character" % (file,line,s, prodname))
1409*635a8641SAndroid Build Coastguard Worker                     if not c in self.Terminals:
1410*635a8641SAndroid Build Coastguard Worker                          self.Terminals[c] = []
1411*635a8641SAndroid Build Coastguard Worker                     syms[n] = c
1412*635a8641SAndroid Build Coastguard Worker                     continue
1413*635a8641SAndroid Build Coastguard Worker                 except SyntaxError:
1414*635a8641SAndroid Build Coastguard Worker                     pass
1415*635a8641SAndroid Build Coastguard Worker            if not _is_identifier.match(s) and s != '%prec':
1416*635a8641SAndroid Build Coastguard Worker                raise GrammarError("%s:%d: Illegal name '%s' in rule '%s'" % (file,line,s, prodname))
1417*635a8641SAndroid Build Coastguard Worker
1418*635a8641SAndroid Build Coastguard Worker        # Determine the precedence level
1419*635a8641SAndroid Build Coastguard Worker        if '%prec' in syms:
1420*635a8641SAndroid Build Coastguard Worker            if syms[-1] == '%prec':
1421*635a8641SAndroid Build Coastguard Worker                raise GrammarError("%s:%d: Syntax error. Nothing follows %%prec" % (file,line))
1422*635a8641SAndroid Build Coastguard Worker            if syms[-2] != '%prec':
1423*635a8641SAndroid Build Coastguard Worker                raise GrammarError("%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule" % (file,line))
1424*635a8641SAndroid Build Coastguard Worker            precname = syms[-1]
1425*635a8641SAndroid Build Coastguard Worker            prodprec = self.Precedence.get(precname,None)
1426*635a8641SAndroid Build Coastguard Worker            if not prodprec:
1427*635a8641SAndroid Build Coastguard Worker                raise GrammarError("%s:%d: Nothing known about the precedence of '%s'" % (file,line,precname))
1428*635a8641SAndroid Build Coastguard Worker            else:
1429*635a8641SAndroid Build Coastguard Worker                self.UsedPrecedence[precname] = 1
1430*635a8641SAndroid Build Coastguard Worker            del syms[-2:]     # Drop %prec from the rule
1431*635a8641SAndroid Build Coastguard Worker        else:
1432*635a8641SAndroid Build Coastguard Worker            # If no %prec, precedence is determined by the rightmost terminal symbol
1433*635a8641SAndroid Build Coastguard Worker            precname = rightmost_terminal(syms,self.Terminals)
1434*635a8641SAndroid Build Coastguard Worker            prodprec = self.Precedence.get(precname,('right',0))
1435*635a8641SAndroid Build Coastguard Worker
1436*635a8641SAndroid Build Coastguard Worker        # See if the rule is already in the rulemap
1437*635a8641SAndroid Build Coastguard Worker        map = "%s -> %s" % (prodname,syms)
1438*635a8641SAndroid Build Coastguard Worker        if map in self.Prodmap:
1439*635a8641SAndroid Build Coastguard Worker            m = self.Prodmap[map]
1440*635a8641SAndroid Build Coastguard Worker            raise GrammarError("%s:%d: Duplicate rule %s. " % (file,line, m) +
1441*635a8641SAndroid Build Coastguard Worker                               "Previous definition at %s:%d" % (m.file, m.line))
1442*635a8641SAndroid Build Coastguard Worker
1443*635a8641SAndroid Build Coastguard Worker        # From this point on, everything is valid.  Create a new Production instance
1444*635a8641SAndroid Build Coastguard Worker        pnumber  = len(self.Productions)
1445*635a8641SAndroid Build Coastguard Worker        if not prodname in self.Nonterminals:
1446*635a8641SAndroid Build Coastguard Worker            self.Nonterminals[prodname] = [ ]
1447*635a8641SAndroid Build Coastguard Worker
1448*635a8641SAndroid Build Coastguard Worker        # Add the production number to Terminals and Nonterminals
1449*635a8641SAndroid Build Coastguard Worker        for t in syms:
1450*635a8641SAndroid Build Coastguard Worker            if t in self.Terminals:
1451*635a8641SAndroid Build Coastguard Worker                self.Terminals[t].append(pnumber)
1452*635a8641SAndroid Build Coastguard Worker            else:
1453*635a8641SAndroid Build Coastguard Worker                if not t in self.Nonterminals:
1454*635a8641SAndroid Build Coastguard Worker                    self.Nonterminals[t] = [ ]
1455*635a8641SAndroid Build Coastguard Worker                self.Nonterminals[t].append(pnumber)
1456*635a8641SAndroid Build Coastguard Worker
1457*635a8641SAndroid Build Coastguard Worker        # Create a production and add it to the list of productions
1458*635a8641SAndroid Build Coastguard Worker        p = Production(pnumber,prodname,syms,prodprec,func,file,line)
1459*635a8641SAndroid Build Coastguard Worker        self.Productions.append(p)
1460*635a8641SAndroid Build Coastguard Worker        self.Prodmap[map] = p
1461*635a8641SAndroid Build Coastguard Worker
1462*635a8641SAndroid Build Coastguard Worker        # Add to the global productions list
1463*635a8641SAndroid Build Coastguard Worker        try:
1464*635a8641SAndroid Build Coastguard Worker            self.Prodnames[prodname].append(p)
1465*635a8641SAndroid Build Coastguard Worker        except KeyError:
1466*635a8641SAndroid Build Coastguard Worker            self.Prodnames[prodname] = [ p ]
1467*635a8641SAndroid Build Coastguard Worker        return 0
1468*635a8641SAndroid Build Coastguard Worker
1469*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1470*635a8641SAndroid Build Coastguard Worker    # set_start()
1471*635a8641SAndroid Build Coastguard Worker    #
1472*635a8641SAndroid Build Coastguard Worker    # Sets the starting symbol and creates the augmented grammar.  Production
1473*635a8641SAndroid Build Coastguard Worker    # rule 0 is S' -> start where start is the start symbol.
1474*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1475*635a8641SAndroid Build Coastguard Worker
1476*635a8641SAndroid Build Coastguard Worker    def set_start(self,start=None):
1477*635a8641SAndroid Build Coastguard Worker        if not start:
1478*635a8641SAndroid Build Coastguard Worker            start = self.Productions[1].name
1479*635a8641SAndroid Build Coastguard Worker        if start not in self.Nonterminals:
1480*635a8641SAndroid Build Coastguard Worker            raise GrammarError("start symbol %s undefined" % start)
1481*635a8641SAndroid Build Coastguard Worker        self.Productions[0] = Production(0,"S'",[start])
1482*635a8641SAndroid Build Coastguard Worker        self.Nonterminals[start].append(0)
1483*635a8641SAndroid Build Coastguard Worker        self.Start = start
1484*635a8641SAndroid Build Coastguard Worker
1485*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1486*635a8641SAndroid Build Coastguard Worker    # find_unreachable()
1487*635a8641SAndroid Build Coastguard Worker    #
1488*635a8641SAndroid Build Coastguard Worker    # Find all of the nonterminal symbols that can't be reached from the starting
1489*635a8641SAndroid Build Coastguard Worker    # symbol.  Returns a list of nonterminals that can't be reached.
1490*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1491*635a8641SAndroid Build Coastguard Worker
1492*635a8641SAndroid Build Coastguard Worker    def find_unreachable(self):
1493*635a8641SAndroid Build Coastguard Worker
1494*635a8641SAndroid Build Coastguard Worker        # Mark all symbols that are reachable from a symbol s
1495*635a8641SAndroid Build Coastguard Worker        def mark_reachable_from(s):
1496*635a8641SAndroid Build Coastguard Worker            if reachable[s]:
1497*635a8641SAndroid Build Coastguard Worker                # We've already reached symbol s.
1498*635a8641SAndroid Build Coastguard Worker                return
1499*635a8641SAndroid Build Coastguard Worker            reachable[s] = 1
1500*635a8641SAndroid Build Coastguard Worker            for p in self.Prodnames.get(s,[]):
1501*635a8641SAndroid Build Coastguard Worker                for r in p.prod:
1502*635a8641SAndroid Build Coastguard Worker                    mark_reachable_from(r)
1503*635a8641SAndroid Build Coastguard Worker
1504*635a8641SAndroid Build Coastguard Worker        reachable   = { }
1505*635a8641SAndroid Build Coastguard Worker        for s in list(self.Terminals) + list(self.Nonterminals):
1506*635a8641SAndroid Build Coastguard Worker            reachable[s] = 0
1507*635a8641SAndroid Build Coastguard Worker
1508*635a8641SAndroid Build Coastguard Worker        mark_reachable_from( self.Productions[0].prod[0] )
1509*635a8641SAndroid Build Coastguard Worker
1510*635a8641SAndroid Build Coastguard Worker        return [s for s in list(self.Nonterminals)
1511*635a8641SAndroid Build Coastguard Worker                        if not reachable[s]]
1512*635a8641SAndroid Build Coastguard Worker
1513*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1514*635a8641SAndroid Build Coastguard Worker    # infinite_cycles()
1515*635a8641SAndroid Build Coastguard Worker    #
1516*635a8641SAndroid Build Coastguard Worker    # This function looks at the various parsing rules and tries to detect
1517*635a8641SAndroid Build Coastguard Worker    # infinite recursion cycles (grammar rules where there is no possible way
1518*635a8641SAndroid Build Coastguard Worker    # to derive a string of only terminals).
1519*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1520*635a8641SAndroid Build Coastguard Worker
1521*635a8641SAndroid Build Coastguard Worker    def infinite_cycles(self):
1522*635a8641SAndroid Build Coastguard Worker        terminates = {}
1523*635a8641SAndroid Build Coastguard Worker
1524*635a8641SAndroid Build Coastguard Worker        # Terminals:
1525*635a8641SAndroid Build Coastguard Worker        for t in self.Terminals:
1526*635a8641SAndroid Build Coastguard Worker            terminates[t] = 1
1527*635a8641SAndroid Build Coastguard Worker
1528*635a8641SAndroid Build Coastguard Worker        terminates['$end'] = 1
1529*635a8641SAndroid Build Coastguard Worker
1530*635a8641SAndroid Build Coastguard Worker        # Nonterminals:
1531*635a8641SAndroid Build Coastguard Worker
1532*635a8641SAndroid Build Coastguard Worker        # Initialize to false:
1533*635a8641SAndroid Build Coastguard Worker        for n in self.Nonterminals:
1534*635a8641SAndroid Build Coastguard Worker            terminates[n] = 0
1535*635a8641SAndroid Build Coastguard Worker
1536*635a8641SAndroid Build Coastguard Worker        # Then propagate termination until no change:
1537*635a8641SAndroid Build Coastguard Worker        while 1:
1538*635a8641SAndroid Build Coastguard Worker            some_change = 0
1539*635a8641SAndroid Build Coastguard Worker            for (n,pl) in self.Prodnames.items():
1540*635a8641SAndroid Build Coastguard Worker                # Nonterminal n terminates iff any of its productions terminates.
1541*635a8641SAndroid Build Coastguard Worker                for p in pl:
1542*635a8641SAndroid Build Coastguard Worker                    # Production p terminates iff all of its rhs symbols terminate.
1543*635a8641SAndroid Build Coastguard Worker                    for s in p.prod:
1544*635a8641SAndroid Build Coastguard Worker                        if not terminates[s]:
1545*635a8641SAndroid Build Coastguard Worker                            # The symbol s does not terminate,
1546*635a8641SAndroid Build Coastguard Worker                            # so production p does not terminate.
1547*635a8641SAndroid Build Coastguard Worker                            p_terminates = 0
1548*635a8641SAndroid Build Coastguard Worker                            break
1549*635a8641SAndroid Build Coastguard Worker                    else:
1550*635a8641SAndroid Build Coastguard Worker                        # didn't break from the loop,
1551*635a8641SAndroid Build Coastguard Worker                        # so every symbol s terminates
1552*635a8641SAndroid Build Coastguard Worker                        # so production p terminates.
1553*635a8641SAndroid Build Coastguard Worker                        p_terminates = 1
1554*635a8641SAndroid Build Coastguard Worker
1555*635a8641SAndroid Build Coastguard Worker                    if p_terminates:
1556*635a8641SAndroid Build Coastguard Worker                        # symbol n terminates!
1557*635a8641SAndroid Build Coastguard Worker                        if not terminates[n]:
1558*635a8641SAndroid Build Coastguard Worker                            terminates[n] = 1
1559*635a8641SAndroid Build Coastguard Worker                            some_change = 1
1560*635a8641SAndroid Build Coastguard Worker                        # Don't need to consider any more productions for this n.
1561*635a8641SAndroid Build Coastguard Worker                        break
1562*635a8641SAndroid Build Coastguard Worker
1563*635a8641SAndroid Build Coastguard Worker            if not some_change:
1564*635a8641SAndroid Build Coastguard Worker                break
1565*635a8641SAndroid Build Coastguard Worker
1566*635a8641SAndroid Build Coastguard Worker        infinite = []
1567*635a8641SAndroid Build Coastguard Worker        for (s,term) in terminates.items():
1568*635a8641SAndroid Build Coastguard Worker            if not term:
1569*635a8641SAndroid Build Coastguard Worker                if not s in self.Prodnames and not s in self.Terminals and s != 'error':
1570*635a8641SAndroid Build Coastguard Worker                    # s is used-but-not-defined, and we've already warned of that,
1571*635a8641SAndroid Build Coastguard Worker                    # so it would be overkill to say that it's also non-terminating.
1572*635a8641SAndroid Build Coastguard Worker                    pass
1573*635a8641SAndroid Build Coastguard Worker                else:
1574*635a8641SAndroid Build Coastguard Worker                    infinite.append(s)
1575*635a8641SAndroid Build Coastguard Worker
1576*635a8641SAndroid Build Coastguard Worker        return infinite
1577*635a8641SAndroid Build Coastguard Worker
1578*635a8641SAndroid Build Coastguard Worker
1579*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1580*635a8641SAndroid Build Coastguard Worker    # undefined_symbols()
1581*635a8641SAndroid Build Coastguard Worker    #
1582*635a8641SAndroid Build Coastguard Worker    # Find all symbols that were used the grammar, but not defined as tokens or
1583*635a8641SAndroid Build Coastguard Worker    # grammar rules.  Returns a list of tuples (sym, prod) where sym in the symbol
1584*635a8641SAndroid Build Coastguard Worker    # and prod is the production where the symbol was used.
1585*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1586*635a8641SAndroid Build Coastguard Worker    def undefined_symbols(self):
1587*635a8641SAndroid Build Coastguard Worker        result = []
1588*635a8641SAndroid Build Coastguard Worker        for p in self.Productions:
1589*635a8641SAndroid Build Coastguard Worker            if not p: continue
1590*635a8641SAndroid Build Coastguard Worker
1591*635a8641SAndroid Build Coastguard Worker            for s in p.prod:
1592*635a8641SAndroid Build Coastguard Worker                if not s in self.Prodnames and not s in self.Terminals and s != 'error':
1593*635a8641SAndroid Build Coastguard Worker                    result.append((s,p))
1594*635a8641SAndroid Build Coastguard Worker        return result
1595*635a8641SAndroid Build Coastguard Worker
1596*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1597*635a8641SAndroid Build Coastguard Worker    # unused_terminals()
1598*635a8641SAndroid Build Coastguard Worker    #
1599*635a8641SAndroid Build Coastguard Worker    # Find all terminals that were defined, but not used by the grammar.  Returns
1600*635a8641SAndroid Build Coastguard Worker    # a list of all symbols.
1601*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1602*635a8641SAndroid Build Coastguard Worker    def unused_terminals(self):
1603*635a8641SAndroid Build Coastguard Worker        unused_tok = []
1604*635a8641SAndroid Build Coastguard Worker        for s,v in self.Terminals.items():
1605*635a8641SAndroid Build Coastguard Worker            if s != 'error' and not v:
1606*635a8641SAndroid Build Coastguard Worker                unused_tok.append(s)
1607*635a8641SAndroid Build Coastguard Worker
1608*635a8641SAndroid Build Coastguard Worker        return unused_tok
1609*635a8641SAndroid Build Coastguard Worker
1610*635a8641SAndroid Build Coastguard Worker    # ------------------------------------------------------------------------------
1611*635a8641SAndroid Build Coastguard Worker    # unused_rules()
1612*635a8641SAndroid Build Coastguard Worker    #
1613*635a8641SAndroid Build Coastguard Worker    # Find all grammar rules that were defined,  but not used (maybe not reachable)
1614*635a8641SAndroid Build Coastguard Worker    # Returns a list of productions.
1615*635a8641SAndroid Build Coastguard Worker    # ------------------------------------------------------------------------------
1616*635a8641SAndroid Build Coastguard Worker
1617*635a8641SAndroid Build Coastguard Worker    def unused_rules(self):
1618*635a8641SAndroid Build Coastguard Worker        unused_prod = []
1619*635a8641SAndroid Build Coastguard Worker        for s,v in self.Nonterminals.items():
1620*635a8641SAndroid Build Coastguard Worker            if not v:
1621*635a8641SAndroid Build Coastguard Worker                p = self.Prodnames[s][0]
1622*635a8641SAndroid Build Coastguard Worker                unused_prod.append(p)
1623*635a8641SAndroid Build Coastguard Worker        return unused_prod
1624*635a8641SAndroid Build Coastguard Worker
1625*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1626*635a8641SAndroid Build Coastguard Worker    # unused_precedence()
1627*635a8641SAndroid Build Coastguard Worker    #
1628*635a8641SAndroid Build Coastguard Worker    # Returns a list of tuples (term,precedence) corresponding to precedence
1629*635a8641SAndroid Build Coastguard Worker    # rules that were never used by the grammar.  term is the name of the terminal
1630*635a8641SAndroid Build Coastguard Worker    # on which precedence was applied and precedence is a string such as 'left' or
1631*635a8641SAndroid Build Coastguard Worker    # 'right' corresponding to the type of precedence.
1632*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1633*635a8641SAndroid Build Coastguard Worker
1634*635a8641SAndroid Build Coastguard Worker    def unused_precedence(self):
1635*635a8641SAndroid Build Coastguard Worker        unused = []
1636*635a8641SAndroid Build Coastguard Worker        for termname in self.Precedence:
1637*635a8641SAndroid Build Coastguard Worker            if not (termname in self.Terminals or termname in self.UsedPrecedence):
1638*635a8641SAndroid Build Coastguard Worker                unused.append((termname,self.Precedence[termname][0]))
1639*635a8641SAndroid Build Coastguard Worker
1640*635a8641SAndroid Build Coastguard Worker        return unused
1641*635a8641SAndroid Build Coastguard Worker
1642*635a8641SAndroid Build Coastguard Worker    # -------------------------------------------------------------------------
1643*635a8641SAndroid Build Coastguard Worker    # _first()
1644*635a8641SAndroid Build Coastguard Worker    #
1645*635a8641SAndroid Build Coastguard Worker    # Compute the value of FIRST1(beta) where beta is a tuple of symbols.
1646*635a8641SAndroid Build Coastguard Worker    #
1647*635a8641SAndroid Build Coastguard Worker    # During execution of compute_first1, the result may be incomplete.
1648*635a8641SAndroid Build Coastguard Worker    # Afterward (e.g., when called from compute_follow()), it will be complete.
1649*635a8641SAndroid Build Coastguard Worker    # -------------------------------------------------------------------------
1650*635a8641SAndroid Build Coastguard Worker    def _first(self,beta):
1651*635a8641SAndroid Build Coastguard Worker
1652*635a8641SAndroid Build Coastguard Worker        # We are computing First(x1,x2,x3,...,xn)
1653*635a8641SAndroid Build Coastguard Worker        result = [ ]
1654*635a8641SAndroid Build Coastguard Worker        for x in beta:
1655*635a8641SAndroid Build Coastguard Worker            x_produces_empty = 0
1656*635a8641SAndroid Build Coastguard Worker
1657*635a8641SAndroid Build Coastguard Worker            # Add all the non-<empty> symbols of First[x] to the result.
1658*635a8641SAndroid Build Coastguard Worker            for f in self.First[x]:
1659*635a8641SAndroid Build Coastguard Worker                if f == '<empty>':
1660*635a8641SAndroid Build Coastguard Worker                    x_produces_empty = 1
1661*635a8641SAndroid Build Coastguard Worker                else:
1662*635a8641SAndroid Build Coastguard Worker                    if f not in result: result.append(f)
1663*635a8641SAndroid Build Coastguard Worker
1664*635a8641SAndroid Build Coastguard Worker            if x_produces_empty:
1665*635a8641SAndroid Build Coastguard Worker                # We have to consider the next x in beta,
1666*635a8641SAndroid Build Coastguard Worker                # i.e. stay in the loop.
1667*635a8641SAndroid Build Coastguard Worker                pass
1668*635a8641SAndroid Build Coastguard Worker            else:
1669*635a8641SAndroid Build Coastguard Worker                # We don't have to consider any further symbols in beta.
1670*635a8641SAndroid Build Coastguard Worker                break
1671*635a8641SAndroid Build Coastguard Worker        else:
1672*635a8641SAndroid Build Coastguard Worker            # There was no 'break' from the loop,
1673*635a8641SAndroid Build Coastguard Worker            # so x_produces_empty was true for all x in beta,
1674*635a8641SAndroid Build Coastguard Worker            # so beta produces empty as well.
1675*635a8641SAndroid Build Coastguard Worker            result.append('<empty>')
1676*635a8641SAndroid Build Coastguard Worker
1677*635a8641SAndroid Build Coastguard Worker        return result
1678*635a8641SAndroid Build Coastguard Worker
1679*635a8641SAndroid Build Coastguard Worker    # -------------------------------------------------------------------------
1680*635a8641SAndroid Build Coastguard Worker    # compute_first()
1681*635a8641SAndroid Build Coastguard Worker    #
1682*635a8641SAndroid Build Coastguard Worker    # Compute the value of FIRST1(X) for all symbols
1683*635a8641SAndroid Build Coastguard Worker    # -------------------------------------------------------------------------
1684*635a8641SAndroid Build Coastguard Worker    def compute_first(self):
1685*635a8641SAndroid Build Coastguard Worker        if self.First:
1686*635a8641SAndroid Build Coastguard Worker            return self.First
1687*635a8641SAndroid Build Coastguard Worker
1688*635a8641SAndroid Build Coastguard Worker        # Terminals:
1689*635a8641SAndroid Build Coastguard Worker        for t in self.Terminals:
1690*635a8641SAndroid Build Coastguard Worker            self.First[t] = [t]
1691*635a8641SAndroid Build Coastguard Worker
1692*635a8641SAndroid Build Coastguard Worker        self.First['$end'] = ['$end']
1693*635a8641SAndroid Build Coastguard Worker
1694*635a8641SAndroid Build Coastguard Worker        # Nonterminals:
1695*635a8641SAndroid Build Coastguard Worker
1696*635a8641SAndroid Build Coastguard Worker        # Initialize to the empty set:
1697*635a8641SAndroid Build Coastguard Worker        for n in self.Nonterminals:
1698*635a8641SAndroid Build Coastguard Worker            self.First[n] = []
1699*635a8641SAndroid Build Coastguard Worker
1700*635a8641SAndroid Build Coastguard Worker        # Then propagate symbols until no change:
1701*635a8641SAndroid Build Coastguard Worker        while 1:
1702*635a8641SAndroid Build Coastguard Worker            some_change = 0
1703*635a8641SAndroid Build Coastguard Worker            for n in self.Nonterminals:
1704*635a8641SAndroid Build Coastguard Worker                for p in self.Prodnames[n]:
1705*635a8641SAndroid Build Coastguard Worker                    for f in self._first(p.prod):
1706*635a8641SAndroid Build Coastguard Worker                        if f not in self.First[n]:
1707*635a8641SAndroid Build Coastguard Worker                            self.First[n].append( f )
1708*635a8641SAndroid Build Coastguard Worker                            some_change = 1
1709*635a8641SAndroid Build Coastguard Worker            if not some_change:
1710*635a8641SAndroid Build Coastguard Worker                break
1711*635a8641SAndroid Build Coastguard Worker
1712*635a8641SAndroid Build Coastguard Worker        return self.First
1713*635a8641SAndroid Build Coastguard Worker
1714*635a8641SAndroid Build Coastguard Worker    # ---------------------------------------------------------------------
1715*635a8641SAndroid Build Coastguard Worker    # compute_follow()
1716*635a8641SAndroid Build Coastguard Worker    #
1717*635a8641SAndroid Build Coastguard Worker    # Computes all of the follow sets for every non-terminal symbol.  The
1718*635a8641SAndroid Build Coastguard Worker    # follow set is the set of all symbols that might follow a given
1719*635a8641SAndroid Build Coastguard Worker    # non-terminal.  See the Dragon book, 2nd Ed. p. 189.
1720*635a8641SAndroid Build Coastguard Worker    # ---------------------------------------------------------------------
1721*635a8641SAndroid Build Coastguard Worker    def compute_follow(self,start=None):
1722*635a8641SAndroid Build Coastguard Worker        # If already computed, return the result
1723*635a8641SAndroid Build Coastguard Worker        if self.Follow:
1724*635a8641SAndroid Build Coastguard Worker            return self.Follow
1725*635a8641SAndroid Build Coastguard Worker
1726*635a8641SAndroid Build Coastguard Worker        # If first sets not computed yet, do that first.
1727*635a8641SAndroid Build Coastguard Worker        if not self.First:
1728*635a8641SAndroid Build Coastguard Worker            self.compute_first()
1729*635a8641SAndroid Build Coastguard Worker
1730*635a8641SAndroid Build Coastguard Worker        # Add '$end' to the follow list of the start symbol
1731*635a8641SAndroid Build Coastguard Worker        for k in self.Nonterminals:
1732*635a8641SAndroid Build Coastguard Worker            self.Follow[k] = [ ]
1733*635a8641SAndroid Build Coastguard Worker
1734*635a8641SAndroid Build Coastguard Worker        if not start:
1735*635a8641SAndroid Build Coastguard Worker            start = self.Productions[1].name
1736*635a8641SAndroid Build Coastguard Worker
1737*635a8641SAndroid Build Coastguard Worker        self.Follow[start] = [ '$end' ]
1738*635a8641SAndroid Build Coastguard Worker
1739*635a8641SAndroid Build Coastguard Worker        while 1:
1740*635a8641SAndroid Build Coastguard Worker            didadd = 0
1741*635a8641SAndroid Build Coastguard Worker            for p in self.Productions[1:]:
1742*635a8641SAndroid Build Coastguard Worker                # Here is the production set
1743*635a8641SAndroid Build Coastguard Worker                for i in range(len(p.prod)):
1744*635a8641SAndroid Build Coastguard Worker                    B = p.prod[i]
1745*635a8641SAndroid Build Coastguard Worker                    if B in self.Nonterminals:
1746*635a8641SAndroid Build Coastguard Worker                        # Okay. We got a non-terminal in a production
1747*635a8641SAndroid Build Coastguard Worker                        fst = self._first(p.prod[i+1:])
1748*635a8641SAndroid Build Coastguard Worker                        hasempty = 0
1749*635a8641SAndroid Build Coastguard Worker                        for f in fst:
1750*635a8641SAndroid Build Coastguard Worker                            if f != '<empty>' and f not in self.Follow[B]:
1751*635a8641SAndroid Build Coastguard Worker                                self.Follow[B].append(f)
1752*635a8641SAndroid Build Coastguard Worker                                didadd = 1
1753*635a8641SAndroid Build Coastguard Worker                            if f == '<empty>':
1754*635a8641SAndroid Build Coastguard Worker                                hasempty = 1
1755*635a8641SAndroid Build Coastguard Worker                        if hasempty or i == (len(p.prod)-1):
1756*635a8641SAndroid Build Coastguard Worker                            # Add elements of follow(a) to follow(b)
1757*635a8641SAndroid Build Coastguard Worker                            for f in self.Follow[p.name]:
1758*635a8641SAndroid Build Coastguard Worker                                if f not in self.Follow[B]:
1759*635a8641SAndroid Build Coastguard Worker                                    self.Follow[B].append(f)
1760*635a8641SAndroid Build Coastguard Worker                                    didadd = 1
1761*635a8641SAndroid Build Coastguard Worker            if not didadd: break
1762*635a8641SAndroid Build Coastguard Worker        return self.Follow
1763*635a8641SAndroid Build Coastguard Worker
1764*635a8641SAndroid Build Coastguard Worker
1765*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1766*635a8641SAndroid Build Coastguard Worker    # build_lritems()
1767*635a8641SAndroid Build Coastguard Worker    #
1768*635a8641SAndroid Build Coastguard Worker    # This function walks the list of productions and builds a complete set of the
1769*635a8641SAndroid Build Coastguard Worker    # LR items.  The LR items are stored in two ways:  First, they are uniquely
1770*635a8641SAndroid Build Coastguard Worker    # numbered and placed in the list _lritems.  Second, a linked list of LR items
1771*635a8641SAndroid Build Coastguard Worker    # is built for each production.  For example:
1772*635a8641SAndroid Build Coastguard Worker    #
1773*635a8641SAndroid Build Coastguard Worker    #   E -> E PLUS E
1774*635a8641SAndroid Build Coastguard Worker    #
1775*635a8641SAndroid Build Coastguard Worker    # Creates the list
1776*635a8641SAndroid Build Coastguard Worker    #
1777*635a8641SAndroid Build Coastguard Worker    #  [E -> . E PLUS E, E -> E . PLUS E, E -> E PLUS . E, E -> E PLUS E . ]
1778*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
1779*635a8641SAndroid Build Coastguard Worker
1780*635a8641SAndroid Build Coastguard Worker    def build_lritems(self):
1781*635a8641SAndroid Build Coastguard Worker        for p in self.Productions:
1782*635a8641SAndroid Build Coastguard Worker            lastlri = p
1783*635a8641SAndroid Build Coastguard Worker            i = 0
1784*635a8641SAndroid Build Coastguard Worker            lr_items = []
1785*635a8641SAndroid Build Coastguard Worker            while 1:
1786*635a8641SAndroid Build Coastguard Worker                if i > len(p):
1787*635a8641SAndroid Build Coastguard Worker                    lri = None
1788*635a8641SAndroid Build Coastguard Worker                else:
1789*635a8641SAndroid Build Coastguard Worker                    lri = LRItem(p,i)
1790*635a8641SAndroid Build Coastguard Worker                    # Precompute the list of productions immediately following
1791*635a8641SAndroid Build Coastguard Worker                    try:
1792*635a8641SAndroid Build Coastguard Worker                        lri.lr_after = self.Prodnames[lri.prod[i+1]]
1793*635a8641SAndroid Build Coastguard Worker                    except (IndexError,KeyError):
1794*635a8641SAndroid Build Coastguard Worker                        lri.lr_after = []
1795*635a8641SAndroid Build Coastguard Worker                    try:
1796*635a8641SAndroid Build Coastguard Worker                        lri.lr_before = lri.prod[i-1]
1797*635a8641SAndroid Build Coastguard Worker                    except IndexError:
1798*635a8641SAndroid Build Coastguard Worker                        lri.lr_before = None
1799*635a8641SAndroid Build Coastguard Worker
1800*635a8641SAndroid Build Coastguard Worker                lastlri.lr_next = lri
1801*635a8641SAndroid Build Coastguard Worker                if not lri: break
1802*635a8641SAndroid Build Coastguard Worker                lr_items.append(lri)
1803*635a8641SAndroid Build Coastguard Worker                lastlri = lri
1804*635a8641SAndroid Build Coastguard Worker                i += 1
1805*635a8641SAndroid Build Coastguard Worker            p.lr_items = lr_items
1806*635a8641SAndroid Build Coastguard Worker
1807*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1808*635a8641SAndroid Build Coastguard Worker#                            == Class LRTable ==
1809*635a8641SAndroid Build Coastguard Worker#
1810*635a8641SAndroid Build Coastguard Worker# This basic class represents a basic table of LR parsing information.
1811*635a8641SAndroid Build Coastguard Worker# Methods for generating the tables are not defined here.  They are defined
1812*635a8641SAndroid Build Coastguard Worker# in the derived class LRGeneratedTable.
1813*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1814*635a8641SAndroid Build Coastguard Worker
1815*635a8641SAndroid Build Coastguard Workerclass VersionError(YaccError): pass
1816*635a8641SAndroid Build Coastguard Worker
1817*635a8641SAndroid Build Coastguard Workerclass LRTable(object):
1818*635a8641SAndroid Build Coastguard Worker    def __init__(self):
1819*635a8641SAndroid Build Coastguard Worker        self.lr_action = None
1820*635a8641SAndroid Build Coastguard Worker        self.lr_goto = None
1821*635a8641SAndroid Build Coastguard Worker        self.lr_productions = None
1822*635a8641SAndroid Build Coastguard Worker        self.lr_method = None
1823*635a8641SAndroid Build Coastguard Worker
1824*635a8641SAndroid Build Coastguard Worker    def read_table(self,module):
1825*635a8641SAndroid Build Coastguard Worker        if isinstance(module,types.ModuleType):
1826*635a8641SAndroid Build Coastguard Worker            parsetab = module
1827*635a8641SAndroid Build Coastguard Worker        else:
1828*635a8641SAndroid Build Coastguard Worker            if sys.version_info[0] < 3:
1829*635a8641SAndroid Build Coastguard Worker                exec("import %s as parsetab" % module)
1830*635a8641SAndroid Build Coastguard Worker            else:
1831*635a8641SAndroid Build Coastguard Worker                env = { }
1832*635a8641SAndroid Build Coastguard Worker                exec("import %s as parsetab" % module, env, env)
1833*635a8641SAndroid Build Coastguard Worker                parsetab = env['parsetab']
1834*635a8641SAndroid Build Coastguard Worker
1835*635a8641SAndroid Build Coastguard Worker        if parsetab._tabversion != __tabversion__:
1836*635a8641SAndroid Build Coastguard Worker            raise VersionError("yacc table file version is out of date")
1837*635a8641SAndroid Build Coastguard Worker
1838*635a8641SAndroid Build Coastguard Worker        self.lr_action = parsetab._lr_action
1839*635a8641SAndroid Build Coastguard Worker        self.lr_goto = parsetab._lr_goto
1840*635a8641SAndroid Build Coastguard Worker
1841*635a8641SAndroid Build Coastguard Worker        self.lr_productions = []
1842*635a8641SAndroid Build Coastguard Worker        for p in parsetab._lr_productions:
1843*635a8641SAndroid Build Coastguard Worker            self.lr_productions.append(MiniProduction(*p))
1844*635a8641SAndroid Build Coastguard Worker
1845*635a8641SAndroid Build Coastguard Worker        self.lr_method = parsetab._lr_method
1846*635a8641SAndroid Build Coastguard Worker        return parsetab._lr_signature
1847*635a8641SAndroid Build Coastguard Worker
1848*635a8641SAndroid Build Coastguard Worker    def read_pickle(self,filename):
1849*635a8641SAndroid Build Coastguard Worker        try:
1850*635a8641SAndroid Build Coastguard Worker            import cPickle as pickle
1851*635a8641SAndroid Build Coastguard Worker        except ImportError:
1852*635a8641SAndroid Build Coastguard Worker            import pickle
1853*635a8641SAndroid Build Coastguard Worker
1854*635a8641SAndroid Build Coastguard Worker        in_f = open(filename,"rb")
1855*635a8641SAndroid Build Coastguard Worker
1856*635a8641SAndroid Build Coastguard Worker        tabversion = pickle.load(in_f)
1857*635a8641SAndroid Build Coastguard Worker        if tabversion != __tabversion__:
1858*635a8641SAndroid Build Coastguard Worker            raise VersionError("yacc table file version is out of date")
1859*635a8641SAndroid Build Coastguard Worker        self.lr_method = pickle.load(in_f)
1860*635a8641SAndroid Build Coastguard Worker        signature      = pickle.load(in_f)
1861*635a8641SAndroid Build Coastguard Worker        self.lr_action = pickle.load(in_f)
1862*635a8641SAndroid Build Coastguard Worker        self.lr_goto   = pickle.load(in_f)
1863*635a8641SAndroid Build Coastguard Worker        productions    = pickle.load(in_f)
1864*635a8641SAndroid Build Coastguard Worker
1865*635a8641SAndroid Build Coastguard Worker        self.lr_productions = []
1866*635a8641SAndroid Build Coastguard Worker        for p in productions:
1867*635a8641SAndroid Build Coastguard Worker            self.lr_productions.append(MiniProduction(*p))
1868*635a8641SAndroid Build Coastguard Worker
1869*635a8641SAndroid Build Coastguard Worker        in_f.close()
1870*635a8641SAndroid Build Coastguard Worker        return signature
1871*635a8641SAndroid Build Coastguard Worker
1872*635a8641SAndroid Build Coastguard Worker    # Bind all production function names to callable objects in pdict
1873*635a8641SAndroid Build Coastguard Worker    def bind_callables(self,pdict):
1874*635a8641SAndroid Build Coastguard Worker        for p in self.lr_productions:
1875*635a8641SAndroid Build Coastguard Worker            p.bind(pdict)
1876*635a8641SAndroid Build Coastguard Worker
1877*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1878*635a8641SAndroid Build Coastguard Worker#                           === LR Generator ===
1879*635a8641SAndroid Build Coastguard Worker#
1880*635a8641SAndroid Build Coastguard Worker# The following classes and functions are used to generate LR parsing tables on
1881*635a8641SAndroid Build Coastguard Worker# a grammar.
1882*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1883*635a8641SAndroid Build Coastguard Worker
1884*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1885*635a8641SAndroid Build Coastguard Worker# digraph()
1886*635a8641SAndroid Build Coastguard Worker# traverse()
1887*635a8641SAndroid Build Coastguard Worker#
1888*635a8641SAndroid Build Coastguard Worker# The following two functions are used to compute set valued functions
1889*635a8641SAndroid Build Coastguard Worker# of the form:
1890*635a8641SAndroid Build Coastguard Worker#
1891*635a8641SAndroid Build Coastguard Worker#     F(x) = F'(x) U U{F(y) | x R y}
1892*635a8641SAndroid Build Coastguard Worker#
1893*635a8641SAndroid Build Coastguard Worker# This is used to compute the values of Read() sets as well as FOLLOW sets
1894*635a8641SAndroid Build Coastguard Worker# in LALR(1) generation.
1895*635a8641SAndroid Build Coastguard Worker#
1896*635a8641SAndroid Build Coastguard Worker# Inputs:  X    - An input set
1897*635a8641SAndroid Build Coastguard Worker#          R    - A relation
1898*635a8641SAndroid Build Coastguard Worker#          FP   - Set-valued function
1899*635a8641SAndroid Build Coastguard Worker# ------------------------------------------------------------------------------
1900*635a8641SAndroid Build Coastguard Worker
1901*635a8641SAndroid Build Coastguard Workerdef digraph(X,R,FP):
1902*635a8641SAndroid Build Coastguard Worker    N = { }
1903*635a8641SAndroid Build Coastguard Worker    for x in X:
1904*635a8641SAndroid Build Coastguard Worker       N[x] = 0
1905*635a8641SAndroid Build Coastguard Worker    stack = []
1906*635a8641SAndroid Build Coastguard Worker    F = { }
1907*635a8641SAndroid Build Coastguard Worker    for x in X:
1908*635a8641SAndroid Build Coastguard Worker        if N[x] == 0: traverse(x,N,stack,F,X,R,FP)
1909*635a8641SAndroid Build Coastguard Worker    return F
1910*635a8641SAndroid Build Coastguard Worker
1911*635a8641SAndroid Build Coastguard Workerdef traverse(x,N,stack,F,X,R,FP):
1912*635a8641SAndroid Build Coastguard Worker    stack.append(x)
1913*635a8641SAndroid Build Coastguard Worker    d = len(stack)
1914*635a8641SAndroid Build Coastguard Worker    N[x] = d
1915*635a8641SAndroid Build Coastguard Worker    F[x] = FP(x)             # F(X) <- F'(x)
1916*635a8641SAndroid Build Coastguard Worker
1917*635a8641SAndroid Build Coastguard Worker    rel = R(x)               # Get y's related to x
1918*635a8641SAndroid Build Coastguard Worker    for y in rel:
1919*635a8641SAndroid Build Coastguard Worker        if N[y] == 0:
1920*635a8641SAndroid Build Coastguard Worker             traverse(y,N,stack,F,X,R,FP)
1921*635a8641SAndroid Build Coastguard Worker        N[x] = min(N[x],N[y])
1922*635a8641SAndroid Build Coastguard Worker        for a in F.get(y,[]):
1923*635a8641SAndroid Build Coastguard Worker            if a not in F[x]: F[x].append(a)
1924*635a8641SAndroid Build Coastguard Worker    if N[x] == d:
1925*635a8641SAndroid Build Coastguard Worker       N[stack[-1]] = MAXINT
1926*635a8641SAndroid Build Coastguard Worker       F[stack[-1]] = F[x]
1927*635a8641SAndroid Build Coastguard Worker       element = stack.pop()
1928*635a8641SAndroid Build Coastguard Worker       while element != x:
1929*635a8641SAndroid Build Coastguard Worker           N[stack[-1]] = MAXINT
1930*635a8641SAndroid Build Coastguard Worker           F[stack[-1]] = F[x]
1931*635a8641SAndroid Build Coastguard Worker           element = stack.pop()
1932*635a8641SAndroid Build Coastguard Worker
1933*635a8641SAndroid Build Coastguard Workerclass LALRError(YaccError): pass
1934*635a8641SAndroid Build Coastguard Worker
1935*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1936*635a8641SAndroid Build Coastguard Worker#                             == LRGeneratedTable ==
1937*635a8641SAndroid Build Coastguard Worker#
1938*635a8641SAndroid Build Coastguard Worker# This class implements the LR table generation algorithm.  There are no
1939*635a8641SAndroid Build Coastguard Worker# public methods except for write()
1940*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
1941*635a8641SAndroid Build Coastguard Worker
1942*635a8641SAndroid Build Coastguard Workerclass LRGeneratedTable(LRTable):
1943*635a8641SAndroid Build Coastguard Worker    def __init__(self,grammar,method='LALR',log=None):
1944*635a8641SAndroid Build Coastguard Worker        if method not in ['SLR','LALR']:
1945*635a8641SAndroid Build Coastguard Worker            raise LALRError("Unsupported method %s" % method)
1946*635a8641SAndroid Build Coastguard Worker
1947*635a8641SAndroid Build Coastguard Worker        self.grammar = grammar
1948*635a8641SAndroid Build Coastguard Worker        self.lr_method = method
1949*635a8641SAndroid Build Coastguard Worker
1950*635a8641SAndroid Build Coastguard Worker        # Set up the logger
1951*635a8641SAndroid Build Coastguard Worker        if not log:
1952*635a8641SAndroid Build Coastguard Worker            log = NullLogger()
1953*635a8641SAndroid Build Coastguard Worker        self.log = log
1954*635a8641SAndroid Build Coastguard Worker
1955*635a8641SAndroid Build Coastguard Worker        # Internal attributes
1956*635a8641SAndroid Build Coastguard Worker        self.lr_action     = {}        # Action table
1957*635a8641SAndroid Build Coastguard Worker        self.lr_goto       = {}        # Goto table
1958*635a8641SAndroid Build Coastguard Worker        self.lr_productions  = grammar.Productions    # Copy of grammar Production array
1959*635a8641SAndroid Build Coastguard Worker        self.lr_goto_cache = {}        # Cache of computed gotos
1960*635a8641SAndroid Build Coastguard Worker        self.lr0_cidhash   = {}        # Cache of closures
1961*635a8641SAndroid Build Coastguard Worker
1962*635a8641SAndroid Build Coastguard Worker        self._add_count    = 0         # Internal counter used to detect cycles
1963*635a8641SAndroid Build Coastguard Worker
1964*635a8641SAndroid Build Coastguard Worker        # Diagonistic information filled in by the table generator
1965*635a8641SAndroid Build Coastguard Worker        self.sr_conflict   = 0
1966*635a8641SAndroid Build Coastguard Worker        self.rr_conflict   = 0
1967*635a8641SAndroid Build Coastguard Worker        self.conflicts     = []        # List of conflicts
1968*635a8641SAndroid Build Coastguard Worker
1969*635a8641SAndroid Build Coastguard Worker        self.sr_conflicts  = []
1970*635a8641SAndroid Build Coastguard Worker        self.rr_conflicts  = []
1971*635a8641SAndroid Build Coastguard Worker
1972*635a8641SAndroid Build Coastguard Worker        # Build the tables
1973*635a8641SAndroid Build Coastguard Worker        self.grammar.build_lritems()
1974*635a8641SAndroid Build Coastguard Worker        self.grammar.compute_first()
1975*635a8641SAndroid Build Coastguard Worker        self.grammar.compute_follow()
1976*635a8641SAndroid Build Coastguard Worker        self.lr_parse_table()
1977*635a8641SAndroid Build Coastguard Worker
1978*635a8641SAndroid Build Coastguard Worker    # Compute the LR(0) closure operation on I, where I is a set of LR(0) items.
1979*635a8641SAndroid Build Coastguard Worker
1980*635a8641SAndroid Build Coastguard Worker    def lr0_closure(self,I):
1981*635a8641SAndroid Build Coastguard Worker        self._add_count += 1
1982*635a8641SAndroid Build Coastguard Worker
1983*635a8641SAndroid Build Coastguard Worker        # Add everything in I to J
1984*635a8641SAndroid Build Coastguard Worker        J = I[:]
1985*635a8641SAndroid Build Coastguard Worker        didadd = 1
1986*635a8641SAndroid Build Coastguard Worker        while didadd:
1987*635a8641SAndroid Build Coastguard Worker            didadd = 0
1988*635a8641SAndroid Build Coastguard Worker            for j in J:
1989*635a8641SAndroid Build Coastguard Worker                for x in j.lr_after:
1990*635a8641SAndroid Build Coastguard Worker                    if getattr(x,"lr0_added",0) == self._add_count: continue
1991*635a8641SAndroid Build Coastguard Worker                    # Add B --> .G to J
1992*635a8641SAndroid Build Coastguard Worker                    J.append(x.lr_next)
1993*635a8641SAndroid Build Coastguard Worker                    x.lr0_added = self._add_count
1994*635a8641SAndroid Build Coastguard Worker                    didadd = 1
1995*635a8641SAndroid Build Coastguard Worker
1996*635a8641SAndroid Build Coastguard Worker        return J
1997*635a8641SAndroid Build Coastguard Worker
1998*635a8641SAndroid Build Coastguard Worker    # Compute the LR(0) goto function goto(I,X) where I is a set
1999*635a8641SAndroid Build Coastguard Worker    # of LR(0) items and X is a grammar symbol.   This function is written
2000*635a8641SAndroid Build Coastguard Worker    # in a way that guarantees uniqueness of the generated goto sets
2001*635a8641SAndroid Build Coastguard Worker    # (i.e. the same goto set will never be returned as two different Python
2002*635a8641SAndroid Build Coastguard Worker    # objects).  With uniqueness, we can later do fast set comparisons using
2003*635a8641SAndroid Build Coastguard Worker    # id(obj) instead of element-wise comparison.
2004*635a8641SAndroid Build Coastguard Worker
2005*635a8641SAndroid Build Coastguard Worker    def lr0_goto(self,I,x):
2006*635a8641SAndroid Build Coastguard Worker        # First we look for a previously cached entry
2007*635a8641SAndroid Build Coastguard Worker        g = self.lr_goto_cache.get((id(I),x),None)
2008*635a8641SAndroid Build Coastguard Worker        if g: return g
2009*635a8641SAndroid Build Coastguard Worker
2010*635a8641SAndroid Build Coastguard Worker        # Now we generate the goto set in a way that guarantees uniqueness
2011*635a8641SAndroid Build Coastguard Worker        # of the result
2012*635a8641SAndroid Build Coastguard Worker
2013*635a8641SAndroid Build Coastguard Worker        s = self.lr_goto_cache.get(x,None)
2014*635a8641SAndroid Build Coastguard Worker        if not s:
2015*635a8641SAndroid Build Coastguard Worker            s = { }
2016*635a8641SAndroid Build Coastguard Worker            self.lr_goto_cache[x] = s
2017*635a8641SAndroid Build Coastguard Worker
2018*635a8641SAndroid Build Coastguard Worker        gs = [ ]
2019*635a8641SAndroid Build Coastguard Worker        for p in I:
2020*635a8641SAndroid Build Coastguard Worker            n = p.lr_next
2021*635a8641SAndroid Build Coastguard Worker            if n and n.lr_before == x:
2022*635a8641SAndroid Build Coastguard Worker                s1 = s.get(id(n),None)
2023*635a8641SAndroid Build Coastguard Worker                if not s1:
2024*635a8641SAndroid Build Coastguard Worker                    s1 = { }
2025*635a8641SAndroid Build Coastguard Worker                    s[id(n)] = s1
2026*635a8641SAndroid Build Coastguard Worker                gs.append(n)
2027*635a8641SAndroid Build Coastguard Worker                s = s1
2028*635a8641SAndroid Build Coastguard Worker        g = s.get('$end',None)
2029*635a8641SAndroid Build Coastguard Worker        if not g:
2030*635a8641SAndroid Build Coastguard Worker            if gs:
2031*635a8641SAndroid Build Coastguard Worker                g = self.lr0_closure(gs)
2032*635a8641SAndroid Build Coastguard Worker                s['$end'] = g
2033*635a8641SAndroid Build Coastguard Worker            else:
2034*635a8641SAndroid Build Coastguard Worker                s['$end'] = gs
2035*635a8641SAndroid Build Coastguard Worker        self.lr_goto_cache[(id(I),x)] = g
2036*635a8641SAndroid Build Coastguard Worker        return g
2037*635a8641SAndroid Build Coastguard Worker
2038*635a8641SAndroid Build Coastguard Worker    # Compute the LR(0) sets of item function
2039*635a8641SAndroid Build Coastguard Worker    def lr0_items(self):
2040*635a8641SAndroid Build Coastguard Worker
2041*635a8641SAndroid Build Coastguard Worker        C = [ self.lr0_closure([self.grammar.Productions[0].lr_next]) ]
2042*635a8641SAndroid Build Coastguard Worker        i = 0
2043*635a8641SAndroid Build Coastguard Worker        for I in C:
2044*635a8641SAndroid Build Coastguard Worker            self.lr0_cidhash[id(I)] = i
2045*635a8641SAndroid Build Coastguard Worker            i += 1
2046*635a8641SAndroid Build Coastguard Worker
2047*635a8641SAndroid Build Coastguard Worker        # Loop over the items in C and each grammar symbols
2048*635a8641SAndroid Build Coastguard Worker        i = 0
2049*635a8641SAndroid Build Coastguard Worker        while i < len(C):
2050*635a8641SAndroid Build Coastguard Worker            I = C[i]
2051*635a8641SAndroid Build Coastguard Worker            i += 1
2052*635a8641SAndroid Build Coastguard Worker
2053*635a8641SAndroid Build Coastguard Worker            # Collect all of the symbols that could possibly be in the goto(I,X) sets
2054*635a8641SAndroid Build Coastguard Worker            asyms = { }
2055*635a8641SAndroid Build Coastguard Worker            for ii in I:
2056*635a8641SAndroid Build Coastguard Worker                for s in ii.usyms:
2057*635a8641SAndroid Build Coastguard Worker                    asyms[s] = None
2058*635a8641SAndroid Build Coastguard Worker
2059*635a8641SAndroid Build Coastguard Worker            for x in asyms:
2060*635a8641SAndroid Build Coastguard Worker                g = self.lr0_goto(I,x)
2061*635a8641SAndroid Build Coastguard Worker                if not g:  continue
2062*635a8641SAndroid Build Coastguard Worker                if id(g) in self.lr0_cidhash: continue
2063*635a8641SAndroid Build Coastguard Worker                self.lr0_cidhash[id(g)] = len(C)
2064*635a8641SAndroid Build Coastguard Worker                C.append(g)
2065*635a8641SAndroid Build Coastguard Worker
2066*635a8641SAndroid Build Coastguard Worker        return C
2067*635a8641SAndroid Build Coastguard Worker
2068*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2069*635a8641SAndroid Build Coastguard Worker    #                       ==== LALR(1) Parsing ====
2070*635a8641SAndroid Build Coastguard Worker    #
2071*635a8641SAndroid Build Coastguard Worker    # LALR(1) parsing is almost exactly the same as SLR except that instead of
2072*635a8641SAndroid Build Coastguard Worker    # relying upon Follow() sets when performing reductions, a more selective
2073*635a8641SAndroid Build Coastguard Worker    # lookahead set that incorporates the state of the LR(0) machine is utilized.
2074*635a8641SAndroid Build Coastguard Worker    # Thus, we mainly just have to focus on calculating the lookahead sets.
2075*635a8641SAndroid Build Coastguard Worker    #
2076*635a8641SAndroid Build Coastguard Worker    # The method used here is due to DeRemer and Pennelo (1982).
2077*635a8641SAndroid Build Coastguard Worker    #
2078*635a8641SAndroid Build Coastguard Worker    # DeRemer, F. L., and T. J. Pennelo: "Efficient Computation of LALR(1)
2079*635a8641SAndroid Build Coastguard Worker    #     Lookahead Sets", ACM Transactions on Programming Languages and Systems,
2080*635a8641SAndroid Build Coastguard Worker    #     Vol. 4, No. 4, Oct. 1982, pp. 615-649
2081*635a8641SAndroid Build Coastguard Worker    #
2082*635a8641SAndroid Build Coastguard Worker    # Further details can also be found in:
2083*635a8641SAndroid Build Coastguard Worker    #
2084*635a8641SAndroid Build Coastguard Worker    #  J. Tremblay and P. Sorenson, "The Theory and Practice of Compiler Writing",
2085*635a8641SAndroid Build Coastguard Worker    #      McGraw-Hill Book Company, (1985).
2086*635a8641SAndroid Build Coastguard Worker    #
2087*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2088*635a8641SAndroid Build Coastguard Worker
2089*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2090*635a8641SAndroid Build Coastguard Worker    # compute_nullable_nonterminals()
2091*635a8641SAndroid Build Coastguard Worker    #
2092*635a8641SAndroid Build Coastguard Worker    # Creates a dictionary containing all of the non-terminals that might produce
2093*635a8641SAndroid Build Coastguard Worker    # an empty production.
2094*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2095*635a8641SAndroid Build Coastguard Worker
2096*635a8641SAndroid Build Coastguard Worker    def compute_nullable_nonterminals(self):
2097*635a8641SAndroid Build Coastguard Worker        nullable = {}
2098*635a8641SAndroid Build Coastguard Worker        num_nullable = 0
2099*635a8641SAndroid Build Coastguard Worker        while 1:
2100*635a8641SAndroid Build Coastguard Worker           for p in self.grammar.Productions[1:]:
2101*635a8641SAndroid Build Coastguard Worker               if p.len == 0:
2102*635a8641SAndroid Build Coastguard Worker                    nullable[p.name] = 1
2103*635a8641SAndroid Build Coastguard Worker                    continue
2104*635a8641SAndroid Build Coastguard Worker               for t in p.prod:
2105*635a8641SAndroid Build Coastguard Worker                    if not t in nullable: break
2106*635a8641SAndroid Build Coastguard Worker               else:
2107*635a8641SAndroid Build Coastguard Worker                    nullable[p.name] = 1
2108*635a8641SAndroid Build Coastguard Worker           if len(nullable) == num_nullable: break
2109*635a8641SAndroid Build Coastguard Worker           num_nullable = len(nullable)
2110*635a8641SAndroid Build Coastguard Worker        return nullable
2111*635a8641SAndroid Build Coastguard Worker
2112*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2113*635a8641SAndroid Build Coastguard Worker    # find_nonterminal_trans(C)
2114*635a8641SAndroid Build Coastguard Worker    #
2115*635a8641SAndroid Build Coastguard Worker    # Given a set of LR(0) items, this functions finds all of the non-terminal
2116*635a8641SAndroid Build Coastguard Worker    # transitions.    These are transitions in which a dot appears immediately before
2117*635a8641SAndroid Build Coastguard Worker    # a non-terminal.   Returns a list of tuples of the form (state,N) where state
2118*635a8641SAndroid Build Coastguard Worker    # is the state number and N is the nonterminal symbol.
2119*635a8641SAndroid Build Coastguard Worker    #
2120*635a8641SAndroid Build Coastguard Worker    # The input C is the set of LR(0) items.
2121*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2122*635a8641SAndroid Build Coastguard Worker
2123*635a8641SAndroid Build Coastguard Worker    def find_nonterminal_transitions(self,C):
2124*635a8641SAndroid Build Coastguard Worker         trans = []
2125*635a8641SAndroid Build Coastguard Worker         for state in range(len(C)):
2126*635a8641SAndroid Build Coastguard Worker             for p in C[state]:
2127*635a8641SAndroid Build Coastguard Worker                 if p.lr_index < p.len - 1:
2128*635a8641SAndroid Build Coastguard Worker                      t = (state,p.prod[p.lr_index+1])
2129*635a8641SAndroid Build Coastguard Worker                      if t[1] in self.grammar.Nonterminals:
2130*635a8641SAndroid Build Coastguard Worker                            if t not in trans: trans.append(t)
2131*635a8641SAndroid Build Coastguard Worker             state = state + 1
2132*635a8641SAndroid Build Coastguard Worker         return trans
2133*635a8641SAndroid Build Coastguard Worker
2134*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2135*635a8641SAndroid Build Coastguard Worker    # dr_relation()
2136*635a8641SAndroid Build Coastguard Worker    #
2137*635a8641SAndroid Build Coastguard Worker    # Computes the DR(p,A) relationships for non-terminal transitions.  The input
2138*635a8641SAndroid Build Coastguard Worker    # is a tuple (state,N) where state is a number and N is a nonterminal symbol.
2139*635a8641SAndroid Build Coastguard Worker    #
2140*635a8641SAndroid Build Coastguard Worker    # Returns a list of terminals.
2141*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2142*635a8641SAndroid Build Coastguard Worker
2143*635a8641SAndroid Build Coastguard Worker    def dr_relation(self,C,trans,nullable):
2144*635a8641SAndroid Build Coastguard Worker        dr_set = { }
2145*635a8641SAndroid Build Coastguard Worker        state,N = trans
2146*635a8641SAndroid Build Coastguard Worker        terms = []
2147*635a8641SAndroid Build Coastguard Worker
2148*635a8641SAndroid Build Coastguard Worker        g = self.lr0_goto(C[state],N)
2149*635a8641SAndroid Build Coastguard Worker        for p in g:
2150*635a8641SAndroid Build Coastguard Worker           if p.lr_index < p.len - 1:
2151*635a8641SAndroid Build Coastguard Worker               a = p.prod[p.lr_index+1]
2152*635a8641SAndroid Build Coastguard Worker               if a in self.grammar.Terminals:
2153*635a8641SAndroid Build Coastguard Worker                   if a not in terms: terms.append(a)
2154*635a8641SAndroid Build Coastguard Worker
2155*635a8641SAndroid Build Coastguard Worker        # This extra bit is to handle the start state
2156*635a8641SAndroid Build Coastguard Worker        if state == 0 and N == self.grammar.Productions[0].prod[0]:
2157*635a8641SAndroid Build Coastguard Worker           terms.append('$end')
2158*635a8641SAndroid Build Coastguard Worker
2159*635a8641SAndroid Build Coastguard Worker        return terms
2160*635a8641SAndroid Build Coastguard Worker
2161*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2162*635a8641SAndroid Build Coastguard Worker    # reads_relation()
2163*635a8641SAndroid Build Coastguard Worker    #
2164*635a8641SAndroid Build Coastguard Worker    # Computes the READS() relation (p,A) READS (t,C).
2165*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2166*635a8641SAndroid Build Coastguard Worker
2167*635a8641SAndroid Build Coastguard Worker    def reads_relation(self,C, trans, empty):
2168*635a8641SAndroid Build Coastguard Worker        # Look for empty transitions
2169*635a8641SAndroid Build Coastguard Worker        rel = []
2170*635a8641SAndroid Build Coastguard Worker        state, N = trans
2171*635a8641SAndroid Build Coastguard Worker
2172*635a8641SAndroid Build Coastguard Worker        g = self.lr0_goto(C[state],N)
2173*635a8641SAndroid Build Coastguard Worker        j = self.lr0_cidhash.get(id(g),-1)
2174*635a8641SAndroid Build Coastguard Worker        for p in g:
2175*635a8641SAndroid Build Coastguard Worker            if p.lr_index < p.len - 1:
2176*635a8641SAndroid Build Coastguard Worker                 a = p.prod[p.lr_index + 1]
2177*635a8641SAndroid Build Coastguard Worker                 if a in empty:
2178*635a8641SAndroid Build Coastguard Worker                      rel.append((j,a))
2179*635a8641SAndroid Build Coastguard Worker
2180*635a8641SAndroid Build Coastguard Worker        return rel
2181*635a8641SAndroid Build Coastguard Worker
2182*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2183*635a8641SAndroid Build Coastguard Worker    # compute_lookback_includes()
2184*635a8641SAndroid Build Coastguard Worker    #
2185*635a8641SAndroid Build Coastguard Worker    # Determines the lookback and includes relations
2186*635a8641SAndroid Build Coastguard Worker    #
2187*635a8641SAndroid Build Coastguard Worker    # LOOKBACK:
2188*635a8641SAndroid Build Coastguard Worker    #
2189*635a8641SAndroid Build Coastguard Worker    # This relation is determined by running the LR(0) state machine forward.
2190*635a8641SAndroid Build Coastguard Worker    # For example, starting with a production "N : . A B C", we run it forward
2191*635a8641SAndroid Build Coastguard Worker    # to obtain "N : A B C ."   We then build a relationship between this final
2192*635a8641SAndroid Build Coastguard Worker    # state and the starting state.   These relationships are stored in a dictionary
2193*635a8641SAndroid Build Coastguard Worker    # lookdict.
2194*635a8641SAndroid Build Coastguard Worker    #
2195*635a8641SAndroid Build Coastguard Worker    # INCLUDES:
2196*635a8641SAndroid Build Coastguard Worker    #
2197*635a8641SAndroid Build Coastguard Worker    # Computes the INCLUDE() relation (p,A) INCLUDES (p',B).
2198*635a8641SAndroid Build Coastguard Worker    #
2199*635a8641SAndroid Build Coastguard Worker    # This relation is used to determine non-terminal transitions that occur
2200*635a8641SAndroid Build Coastguard Worker    # inside of other non-terminal transition states.   (p,A) INCLUDES (p', B)
2201*635a8641SAndroid Build Coastguard Worker    # if the following holds:
2202*635a8641SAndroid Build Coastguard Worker    #
2203*635a8641SAndroid Build Coastguard Worker    #       B -> LAT, where T -> epsilon and p' -L-> p
2204*635a8641SAndroid Build Coastguard Worker    #
2205*635a8641SAndroid Build Coastguard Worker    # L is essentially a prefix (which may be empty), T is a suffix that must be
2206*635a8641SAndroid Build Coastguard Worker    # able to derive an empty string.  State p' must lead to state p with the string L.
2207*635a8641SAndroid Build Coastguard Worker    #
2208*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2209*635a8641SAndroid Build Coastguard Worker
2210*635a8641SAndroid Build Coastguard Worker    def compute_lookback_includes(self,C,trans,nullable):
2211*635a8641SAndroid Build Coastguard Worker
2212*635a8641SAndroid Build Coastguard Worker        lookdict = {}          # Dictionary of lookback relations
2213*635a8641SAndroid Build Coastguard Worker        includedict = {}       # Dictionary of include relations
2214*635a8641SAndroid Build Coastguard Worker
2215*635a8641SAndroid Build Coastguard Worker        # Make a dictionary of non-terminal transitions
2216*635a8641SAndroid Build Coastguard Worker        dtrans = {}
2217*635a8641SAndroid Build Coastguard Worker        for t in trans:
2218*635a8641SAndroid Build Coastguard Worker            dtrans[t] = 1
2219*635a8641SAndroid Build Coastguard Worker
2220*635a8641SAndroid Build Coastguard Worker        # Loop over all transitions and compute lookbacks and includes
2221*635a8641SAndroid Build Coastguard Worker        for state,N in trans:
2222*635a8641SAndroid Build Coastguard Worker            lookb = []
2223*635a8641SAndroid Build Coastguard Worker            includes = []
2224*635a8641SAndroid Build Coastguard Worker            for p in C[state]:
2225*635a8641SAndroid Build Coastguard Worker                if p.name != N: continue
2226*635a8641SAndroid Build Coastguard Worker
2227*635a8641SAndroid Build Coastguard Worker                # Okay, we have a name match.  We now follow the production all the way
2228*635a8641SAndroid Build Coastguard Worker                # through the state machine until we get the . on the right hand side
2229*635a8641SAndroid Build Coastguard Worker
2230*635a8641SAndroid Build Coastguard Worker                lr_index = p.lr_index
2231*635a8641SAndroid Build Coastguard Worker                j = state
2232*635a8641SAndroid Build Coastguard Worker                while lr_index < p.len - 1:
2233*635a8641SAndroid Build Coastguard Worker                     lr_index = lr_index + 1
2234*635a8641SAndroid Build Coastguard Worker                     t = p.prod[lr_index]
2235*635a8641SAndroid Build Coastguard Worker
2236*635a8641SAndroid Build Coastguard Worker                     # Check to see if this symbol and state are a non-terminal transition
2237*635a8641SAndroid Build Coastguard Worker                     if (j,t) in dtrans:
2238*635a8641SAndroid Build Coastguard Worker                           # Yes.  Okay, there is some chance that this is an includes relation
2239*635a8641SAndroid Build Coastguard Worker                           # the only way to know for certain is whether the rest of the
2240*635a8641SAndroid Build Coastguard Worker                           # production derives empty
2241*635a8641SAndroid Build Coastguard Worker
2242*635a8641SAndroid Build Coastguard Worker                           li = lr_index + 1
2243*635a8641SAndroid Build Coastguard Worker                           while li < p.len:
2244*635a8641SAndroid Build Coastguard Worker                                if p.prod[li] in self.grammar.Terminals: break      # No forget it
2245*635a8641SAndroid Build Coastguard Worker                                if not p.prod[li] in nullable: break
2246*635a8641SAndroid Build Coastguard Worker                                li = li + 1
2247*635a8641SAndroid Build Coastguard Worker                           else:
2248*635a8641SAndroid Build Coastguard Worker                                # Appears to be a relation between (j,t) and (state,N)
2249*635a8641SAndroid Build Coastguard Worker                                includes.append((j,t))
2250*635a8641SAndroid Build Coastguard Worker
2251*635a8641SAndroid Build Coastguard Worker                     g = self.lr0_goto(C[j],t)               # Go to next set
2252*635a8641SAndroid Build Coastguard Worker                     j = self.lr0_cidhash.get(id(g),-1)     # Go to next state
2253*635a8641SAndroid Build Coastguard Worker
2254*635a8641SAndroid Build Coastguard Worker                # When we get here, j is the final state, now we have to locate the production
2255*635a8641SAndroid Build Coastguard Worker                for r in C[j]:
2256*635a8641SAndroid Build Coastguard Worker                     if r.name != p.name: continue
2257*635a8641SAndroid Build Coastguard Worker                     if r.len != p.len:   continue
2258*635a8641SAndroid Build Coastguard Worker                     i = 0
2259*635a8641SAndroid Build Coastguard Worker                     # This look is comparing a production ". A B C" with "A B C ."
2260*635a8641SAndroid Build Coastguard Worker                     while i < r.lr_index:
2261*635a8641SAndroid Build Coastguard Worker                          if r.prod[i] != p.prod[i+1]: break
2262*635a8641SAndroid Build Coastguard Worker                          i = i + 1
2263*635a8641SAndroid Build Coastguard Worker                     else:
2264*635a8641SAndroid Build Coastguard Worker                          lookb.append((j,r))
2265*635a8641SAndroid Build Coastguard Worker            for i in includes:
2266*635a8641SAndroid Build Coastguard Worker                 if not i in includedict: includedict[i] = []
2267*635a8641SAndroid Build Coastguard Worker                 includedict[i].append((state,N))
2268*635a8641SAndroid Build Coastguard Worker            lookdict[(state,N)] = lookb
2269*635a8641SAndroid Build Coastguard Worker
2270*635a8641SAndroid Build Coastguard Worker        return lookdict,includedict
2271*635a8641SAndroid Build Coastguard Worker
2272*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2273*635a8641SAndroid Build Coastguard Worker    # compute_read_sets()
2274*635a8641SAndroid Build Coastguard Worker    #
2275*635a8641SAndroid Build Coastguard Worker    # Given a set of LR(0) items, this function computes the read sets.
2276*635a8641SAndroid Build Coastguard Worker    #
2277*635a8641SAndroid Build Coastguard Worker    # Inputs:  C        =  Set of LR(0) items
2278*635a8641SAndroid Build Coastguard Worker    #          ntrans   = Set of nonterminal transitions
2279*635a8641SAndroid Build Coastguard Worker    #          nullable = Set of empty transitions
2280*635a8641SAndroid Build Coastguard Worker    #
2281*635a8641SAndroid Build Coastguard Worker    # Returns a set containing the read sets
2282*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2283*635a8641SAndroid Build Coastguard Worker
2284*635a8641SAndroid Build Coastguard Worker    def compute_read_sets(self,C, ntrans, nullable):
2285*635a8641SAndroid Build Coastguard Worker        FP = lambda x: self.dr_relation(C,x,nullable)
2286*635a8641SAndroid Build Coastguard Worker        R =  lambda x: self.reads_relation(C,x,nullable)
2287*635a8641SAndroid Build Coastguard Worker        F = digraph(ntrans,R,FP)
2288*635a8641SAndroid Build Coastguard Worker        return F
2289*635a8641SAndroid Build Coastguard Worker
2290*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2291*635a8641SAndroid Build Coastguard Worker    # compute_follow_sets()
2292*635a8641SAndroid Build Coastguard Worker    #
2293*635a8641SAndroid Build Coastguard Worker    # Given a set of LR(0) items, a set of non-terminal transitions, a readset,
2294*635a8641SAndroid Build Coastguard Worker    # and an include set, this function computes the follow sets
2295*635a8641SAndroid Build Coastguard Worker    #
2296*635a8641SAndroid Build Coastguard Worker    # Follow(p,A) = Read(p,A) U U {Follow(p',B) | (p,A) INCLUDES (p',B)}
2297*635a8641SAndroid Build Coastguard Worker    #
2298*635a8641SAndroid Build Coastguard Worker    # Inputs:
2299*635a8641SAndroid Build Coastguard Worker    #            ntrans     = Set of nonterminal transitions
2300*635a8641SAndroid Build Coastguard Worker    #            readsets   = Readset (previously computed)
2301*635a8641SAndroid Build Coastguard Worker    #            inclsets   = Include sets (previously computed)
2302*635a8641SAndroid Build Coastguard Worker    #
2303*635a8641SAndroid Build Coastguard Worker    # Returns a set containing the follow sets
2304*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2305*635a8641SAndroid Build Coastguard Worker
2306*635a8641SAndroid Build Coastguard Worker    def compute_follow_sets(self,ntrans,readsets,inclsets):
2307*635a8641SAndroid Build Coastguard Worker         FP = lambda x: readsets[x]
2308*635a8641SAndroid Build Coastguard Worker         R  = lambda x: inclsets.get(x,[])
2309*635a8641SAndroid Build Coastguard Worker         F = digraph(ntrans,R,FP)
2310*635a8641SAndroid Build Coastguard Worker         return F
2311*635a8641SAndroid Build Coastguard Worker
2312*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2313*635a8641SAndroid Build Coastguard Worker    # add_lookaheads()
2314*635a8641SAndroid Build Coastguard Worker    #
2315*635a8641SAndroid Build Coastguard Worker    # Attaches the lookahead symbols to grammar rules.
2316*635a8641SAndroid Build Coastguard Worker    #
2317*635a8641SAndroid Build Coastguard Worker    # Inputs:    lookbacks         -  Set of lookback relations
2318*635a8641SAndroid Build Coastguard Worker    #            followset         -  Computed follow set
2319*635a8641SAndroid Build Coastguard Worker    #
2320*635a8641SAndroid Build Coastguard Worker    # This function directly attaches the lookaheads to productions contained
2321*635a8641SAndroid Build Coastguard Worker    # in the lookbacks set
2322*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2323*635a8641SAndroid Build Coastguard Worker
2324*635a8641SAndroid Build Coastguard Worker    def add_lookaheads(self,lookbacks,followset):
2325*635a8641SAndroid Build Coastguard Worker        for trans,lb in lookbacks.items():
2326*635a8641SAndroid Build Coastguard Worker            # Loop over productions in lookback
2327*635a8641SAndroid Build Coastguard Worker            for state,p in lb:
2328*635a8641SAndroid Build Coastguard Worker                 if not state in p.lookaheads:
2329*635a8641SAndroid Build Coastguard Worker                      p.lookaheads[state] = []
2330*635a8641SAndroid Build Coastguard Worker                 f = followset.get(trans,[])
2331*635a8641SAndroid Build Coastguard Worker                 for a in f:
2332*635a8641SAndroid Build Coastguard Worker                      if a not in p.lookaheads[state]: p.lookaheads[state].append(a)
2333*635a8641SAndroid Build Coastguard Worker
2334*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2335*635a8641SAndroid Build Coastguard Worker    # add_lalr_lookaheads()
2336*635a8641SAndroid Build Coastguard Worker    #
2337*635a8641SAndroid Build Coastguard Worker    # This function does all of the work of adding lookahead information for use
2338*635a8641SAndroid Build Coastguard Worker    # with LALR parsing
2339*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2340*635a8641SAndroid Build Coastguard Worker
2341*635a8641SAndroid Build Coastguard Worker    def add_lalr_lookaheads(self,C):
2342*635a8641SAndroid Build Coastguard Worker        # Determine all of the nullable nonterminals
2343*635a8641SAndroid Build Coastguard Worker        nullable = self.compute_nullable_nonterminals()
2344*635a8641SAndroid Build Coastguard Worker
2345*635a8641SAndroid Build Coastguard Worker        # Find all non-terminal transitions
2346*635a8641SAndroid Build Coastguard Worker        trans = self.find_nonterminal_transitions(C)
2347*635a8641SAndroid Build Coastguard Worker
2348*635a8641SAndroid Build Coastguard Worker        # Compute read sets
2349*635a8641SAndroid Build Coastguard Worker        readsets = self.compute_read_sets(C,trans,nullable)
2350*635a8641SAndroid Build Coastguard Worker
2351*635a8641SAndroid Build Coastguard Worker        # Compute lookback/includes relations
2352*635a8641SAndroid Build Coastguard Worker        lookd, included = self.compute_lookback_includes(C,trans,nullable)
2353*635a8641SAndroid Build Coastguard Worker
2354*635a8641SAndroid Build Coastguard Worker        # Compute LALR FOLLOW sets
2355*635a8641SAndroid Build Coastguard Worker        followsets = self.compute_follow_sets(trans,readsets,included)
2356*635a8641SAndroid Build Coastguard Worker
2357*635a8641SAndroid Build Coastguard Worker        # Add all of the lookaheads
2358*635a8641SAndroid Build Coastguard Worker        self.add_lookaheads(lookd,followsets)
2359*635a8641SAndroid Build Coastguard Worker
2360*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2361*635a8641SAndroid Build Coastguard Worker    # lr_parse_table()
2362*635a8641SAndroid Build Coastguard Worker    #
2363*635a8641SAndroid Build Coastguard Worker    # This function constructs the parse tables for SLR or LALR
2364*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2365*635a8641SAndroid Build Coastguard Worker    def lr_parse_table(self):
2366*635a8641SAndroid Build Coastguard Worker        Productions = self.grammar.Productions
2367*635a8641SAndroid Build Coastguard Worker        Precedence  = self.grammar.Precedence
2368*635a8641SAndroid Build Coastguard Worker        goto   = self.lr_goto         # Goto array
2369*635a8641SAndroid Build Coastguard Worker        action = self.lr_action       # Action array
2370*635a8641SAndroid Build Coastguard Worker        log    = self.log             # Logger for output
2371*635a8641SAndroid Build Coastguard Worker
2372*635a8641SAndroid Build Coastguard Worker        actionp = { }                 # Action production array (temporary)
2373*635a8641SAndroid Build Coastguard Worker
2374*635a8641SAndroid Build Coastguard Worker        log.info("Parsing method: %s", self.lr_method)
2375*635a8641SAndroid Build Coastguard Worker
2376*635a8641SAndroid Build Coastguard Worker        # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items
2377*635a8641SAndroid Build Coastguard Worker        # This determines the number of states
2378*635a8641SAndroid Build Coastguard Worker
2379*635a8641SAndroid Build Coastguard Worker        C = self.lr0_items()
2380*635a8641SAndroid Build Coastguard Worker
2381*635a8641SAndroid Build Coastguard Worker        if self.lr_method == 'LALR':
2382*635a8641SAndroid Build Coastguard Worker            self.add_lalr_lookaheads(C)
2383*635a8641SAndroid Build Coastguard Worker
2384*635a8641SAndroid Build Coastguard Worker        # Build the parser table, state by state
2385*635a8641SAndroid Build Coastguard Worker        st = 0
2386*635a8641SAndroid Build Coastguard Worker        for I in C:
2387*635a8641SAndroid Build Coastguard Worker            # Loop over each production in I
2388*635a8641SAndroid Build Coastguard Worker            actlist = [ ]              # List of actions
2389*635a8641SAndroid Build Coastguard Worker            st_action  = { }
2390*635a8641SAndroid Build Coastguard Worker            st_actionp = { }
2391*635a8641SAndroid Build Coastguard Worker            st_goto    = { }
2392*635a8641SAndroid Build Coastguard Worker            log.info("")
2393*635a8641SAndroid Build Coastguard Worker            log.info("state %d", st)
2394*635a8641SAndroid Build Coastguard Worker            log.info("")
2395*635a8641SAndroid Build Coastguard Worker            for p in I:
2396*635a8641SAndroid Build Coastguard Worker                log.info("    (%d) %s", p.number, str(p))
2397*635a8641SAndroid Build Coastguard Worker            log.info("")
2398*635a8641SAndroid Build Coastguard Worker
2399*635a8641SAndroid Build Coastguard Worker            for p in I:
2400*635a8641SAndroid Build Coastguard Worker                    if p.len == p.lr_index + 1:
2401*635a8641SAndroid Build Coastguard Worker                        if p.name == "S'":
2402*635a8641SAndroid Build Coastguard Worker                            # Start symbol. Accept!
2403*635a8641SAndroid Build Coastguard Worker                            st_action["$end"] = 0
2404*635a8641SAndroid Build Coastguard Worker                            st_actionp["$end"] = p
2405*635a8641SAndroid Build Coastguard Worker                        else:
2406*635a8641SAndroid Build Coastguard Worker                            # We are at the end of a production.  Reduce!
2407*635a8641SAndroid Build Coastguard Worker                            if self.lr_method == 'LALR':
2408*635a8641SAndroid Build Coastguard Worker                                laheads = p.lookaheads[st]
2409*635a8641SAndroid Build Coastguard Worker                            else:
2410*635a8641SAndroid Build Coastguard Worker                                laheads = self.grammar.Follow[p.name]
2411*635a8641SAndroid Build Coastguard Worker                            for a in laheads:
2412*635a8641SAndroid Build Coastguard Worker                                actlist.append((a,p,"reduce using rule %d (%s)" % (p.number,p)))
2413*635a8641SAndroid Build Coastguard Worker                                r = st_action.get(a,None)
2414*635a8641SAndroid Build Coastguard Worker                                if r is not None:
2415*635a8641SAndroid Build Coastguard Worker                                    # Whoa. Have a shift/reduce or reduce/reduce conflict
2416*635a8641SAndroid Build Coastguard Worker                                    if r > 0:
2417*635a8641SAndroid Build Coastguard Worker                                        # Need to decide on shift or reduce here
2418*635a8641SAndroid Build Coastguard Worker                                        # By default we favor shifting. Need to add
2419*635a8641SAndroid Build Coastguard Worker                                        # some precedence rules here.
2420*635a8641SAndroid Build Coastguard Worker                                        sprec,slevel = Productions[st_actionp[a].number].prec
2421*635a8641SAndroid Build Coastguard Worker                                        rprec,rlevel = Precedence.get(a,('right',0))
2422*635a8641SAndroid Build Coastguard Worker                                        if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')):
2423*635a8641SAndroid Build Coastguard Worker                                            # We really need to reduce here.
2424*635a8641SAndroid Build Coastguard Worker                                            st_action[a] = -p.number
2425*635a8641SAndroid Build Coastguard Worker                                            st_actionp[a] = p
2426*635a8641SAndroid Build Coastguard Worker                                            if not slevel and not rlevel:
2427*635a8641SAndroid Build Coastguard Worker                                                log.info("  ! shift/reduce conflict for %s resolved as reduce",a)
2428*635a8641SAndroid Build Coastguard Worker                                                self.sr_conflicts.append((st,a,'reduce'))
2429*635a8641SAndroid Build Coastguard Worker                                            Productions[p.number].reduced += 1
2430*635a8641SAndroid Build Coastguard Worker                                        elif (slevel == rlevel) and (rprec == 'nonassoc'):
2431*635a8641SAndroid Build Coastguard Worker                                            st_action[a] = None
2432*635a8641SAndroid Build Coastguard Worker                                        else:
2433*635a8641SAndroid Build Coastguard Worker                                            # Hmmm. Guess we'll keep the shift
2434*635a8641SAndroid Build Coastguard Worker                                            if not rlevel:
2435*635a8641SAndroid Build Coastguard Worker                                                log.info("  ! shift/reduce conflict for %s resolved as shift",a)
2436*635a8641SAndroid Build Coastguard Worker                                                self.sr_conflicts.append((st,a,'shift'))
2437*635a8641SAndroid Build Coastguard Worker                                    elif r < 0:
2438*635a8641SAndroid Build Coastguard Worker                                        # Reduce/reduce conflict.   In this case, we favor the rule
2439*635a8641SAndroid Build Coastguard Worker                                        # that was defined first in the grammar file
2440*635a8641SAndroid Build Coastguard Worker                                        oldp = Productions[-r]
2441*635a8641SAndroid Build Coastguard Worker                                        pp = Productions[p.number]
2442*635a8641SAndroid Build Coastguard Worker                                        if oldp.line > pp.line:
2443*635a8641SAndroid Build Coastguard Worker                                            st_action[a] = -p.number
2444*635a8641SAndroid Build Coastguard Worker                                            st_actionp[a] = p
2445*635a8641SAndroid Build Coastguard Worker                                            chosenp,rejectp = pp,oldp
2446*635a8641SAndroid Build Coastguard Worker                                            Productions[p.number].reduced += 1
2447*635a8641SAndroid Build Coastguard Worker                                            Productions[oldp.number].reduced -= 1
2448*635a8641SAndroid Build Coastguard Worker                                        else:
2449*635a8641SAndroid Build Coastguard Worker                                            chosenp,rejectp = oldp,pp
2450*635a8641SAndroid Build Coastguard Worker                                        self.rr_conflicts.append((st,chosenp,rejectp))
2451*635a8641SAndroid Build Coastguard Worker                                        log.info("  ! reduce/reduce conflict for %s resolved using rule %d (%s)", a,st_actionp[a].number, st_actionp[a])
2452*635a8641SAndroid Build Coastguard Worker                                    else:
2453*635a8641SAndroid Build Coastguard Worker                                        raise LALRError("Unknown conflict in state %d" % st)
2454*635a8641SAndroid Build Coastguard Worker                                else:
2455*635a8641SAndroid Build Coastguard Worker                                    st_action[a] = -p.number
2456*635a8641SAndroid Build Coastguard Worker                                    st_actionp[a] = p
2457*635a8641SAndroid Build Coastguard Worker                                    Productions[p.number].reduced += 1
2458*635a8641SAndroid Build Coastguard Worker                    else:
2459*635a8641SAndroid Build Coastguard Worker                        i = p.lr_index
2460*635a8641SAndroid Build Coastguard Worker                        a = p.prod[i+1]       # Get symbol right after the "."
2461*635a8641SAndroid Build Coastguard Worker                        if a in self.grammar.Terminals:
2462*635a8641SAndroid Build Coastguard Worker                            g = self.lr0_goto(I,a)
2463*635a8641SAndroid Build Coastguard Worker                            j = self.lr0_cidhash.get(id(g),-1)
2464*635a8641SAndroid Build Coastguard Worker                            if j >= 0:
2465*635a8641SAndroid Build Coastguard Worker                                # We are in a shift state
2466*635a8641SAndroid Build Coastguard Worker                                actlist.append((a,p,"shift and go to state %d" % j))
2467*635a8641SAndroid Build Coastguard Worker                                r = st_action.get(a,None)
2468*635a8641SAndroid Build Coastguard Worker                                if r is not None:
2469*635a8641SAndroid Build Coastguard Worker                                    # Whoa have a shift/reduce or shift/shift conflict
2470*635a8641SAndroid Build Coastguard Worker                                    if r > 0:
2471*635a8641SAndroid Build Coastguard Worker                                        if r != j:
2472*635a8641SAndroid Build Coastguard Worker                                            raise LALRError("Shift/shift conflict in state %d" % st)
2473*635a8641SAndroid Build Coastguard Worker                                    elif r < 0:
2474*635a8641SAndroid Build Coastguard Worker                                        # Do a precedence check.
2475*635a8641SAndroid Build Coastguard Worker                                        #   -  if precedence of reduce rule is higher, we reduce.
2476*635a8641SAndroid Build Coastguard Worker                                        #   -  if precedence of reduce is same and left assoc, we reduce.
2477*635a8641SAndroid Build Coastguard Worker                                        #   -  otherwise we shift
2478*635a8641SAndroid Build Coastguard Worker                                        rprec,rlevel = Productions[st_actionp[a].number].prec
2479*635a8641SAndroid Build Coastguard Worker                                        sprec,slevel = Precedence.get(a,('right',0))
2480*635a8641SAndroid Build Coastguard Worker                                        if (slevel > rlevel) or ((slevel == rlevel) and (rprec == 'right')):
2481*635a8641SAndroid Build Coastguard Worker                                            # We decide to shift here... highest precedence to shift
2482*635a8641SAndroid Build Coastguard Worker                                            Productions[st_actionp[a].number].reduced -= 1
2483*635a8641SAndroid Build Coastguard Worker                                            st_action[a] = j
2484*635a8641SAndroid Build Coastguard Worker                                            st_actionp[a] = p
2485*635a8641SAndroid Build Coastguard Worker                                            if not rlevel:
2486*635a8641SAndroid Build Coastguard Worker                                                log.info("  ! shift/reduce conflict for %s resolved as shift",a)
2487*635a8641SAndroid Build Coastguard Worker                                                self.sr_conflicts.append((st,a,'shift'))
2488*635a8641SAndroid Build Coastguard Worker                                        elif (slevel == rlevel) and (rprec == 'nonassoc'):
2489*635a8641SAndroid Build Coastguard Worker                                            st_action[a] = None
2490*635a8641SAndroid Build Coastguard Worker                                        else:
2491*635a8641SAndroid Build Coastguard Worker                                            # Hmmm. Guess we'll keep the reduce
2492*635a8641SAndroid Build Coastguard Worker                                            if not slevel and not rlevel:
2493*635a8641SAndroid Build Coastguard Worker                                                log.info("  ! shift/reduce conflict for %s resolved as reduce",a)
2494*635a8641SAndroid Build Coastguard Worker                                                self.sr_conflicts.append((st,a,'reduce'))
2495*635a8641SAndroid Build Coastguard Worker
2496*635a8641SAndroid Build Coastguard Worker                                    else:
2497*635a8641SAndroid Build Coastguard Worker                                        raise LALRError("Unknown conflict in state %d" % st)
2498*635a8641SAndroid Build Coastguard Worker                                else:
2499*635a8641SAndroid Build Coastguard Worker                                    st_action[a] = j
2500*635a8641SAndroid Build Coastguard Worker                                    st_actionp[a] = p
2501*635a8641SAndroid Build Coastguard Worker
2502*635a8641SAndroid Build Coastguard Worker            # Print the actions associated with each terminal
2503*635a8641SAndroid Build Coastguard Worker            _actprint = { }
2504*635a8641SAndroid Build Coastguard Worker            for a,p,m in actlist:
2505*635a8641SAndroid Build Coastguard Worker                if a in st_action:
2506*635a8641SAndroid Build Coastguard Worker                    if p is st_actionp[a]:
2507*635a8641SAndroid Build Coastguard Worker                        log.info("    %-15s %s",a,m)
2508*635a8641SAndroid Build Coastguard Worker                        _actprint[(a,m)] = 1
2509*635a8641SAndroid Build Coastguard Worker            log.info("")
2510*635a8641SAndroid Build Coastguard Worker            # Print the actions that were not used. (debugging)
2511*635a8641SAndroid Build Coastguard Worker            not_used = 0
2512*635a8641SAndroid Build Coastguard Worker            for a,p,m in actlist:
2513*635a8641SAndroid Build Coastguard Worker                if a in st_action:
2514*635a8641SAndroid Build Coastguard Worker                    if p is not st_actionp[a]:
2515*635a8641SAndroid Build Coastguard Worker                        if not (a,m) in _actprint:
2516*635a8641SAndroid Build Coastguard Worker                            log.debug("  ! %-15s [ %s ]",a,m)
2517*635a8641SAndroid Build Coastguard Worker                            not_used = 1
2518*635a8641SAndroid Build Coastguard Worker                            _actprint[(a,m)] = 1
2519*635a8641SAndroid Build Coastguard Worker            if not_used:
2520*635a8641SAndroid Build Coastguard Worker                log.debug("")
2521*635a8641SAndroid Build Coastguard Worker
2522*635a8641SAndroid Build Coastguard Worker            # Construct the goto table for this state
2523*635a8641SAndroid Build Coastguard Worker
2524*635a8641SAndroid Build Coastguard Worker            nkeys = { }
2525*635a8641SAndroid Build Coastguard Worker            for ii in I:
2526*635a8641SAndroid Build Coastguard Worker                for s in ii.usyms:
2527*635a8641SAndroid Build Coastguard Worker                    if s in self.grammar.Nonterminals:
2528*635a8641SAndroid Build Coastguard Worker                        nkeys[s] = None
2529*635a8641SAndroid Build Coastguard Worker            for n in nkeys:
2530*635a8641SAndroid Build Coastguard Worker                g = self.lr0_goto(I,n)
2531*635a8641SAndroid Build Coastguard Worker                j = self.lr0_cidhash.get(id(g),-1)
2532*635a8641SAndroid Build Coastguard Worker                if j >= 0:
2533*635a8641SAndroid Build Coastguard Worker                    st_goto[n] = j
2534*635a8641SAndroid Build Coastguard Worker                    log.info("    %-30s shift and go to state %d",n,j)
2535*635a8641SAndroid Build Coastguard Worker
2536*635a8641SAndroid Build Coastguard Worker            action[st] = st_action
2537*635a8641SAndroid Build Coastguard Worker            actionp[st] = st_actionp
2538*635a8641SAndroid Build Coastguard Worker            goto[st] = st_goto
2539*635a8641SAndroid Build Coastguard Worker            st += 1
2540*635a8641SAndroid Build Coastguard Worker
2541*635a8641SAndroid Build Coastguard Worker
2542*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2543*635a8641SAndroid Build Coastguard Worker    # write()
2544*635a8641SAndroid Build Coastguard Worker    #
2545*635a8641SAndroid Build Coastguard Worker    # This function writes the LR parsing tables to a file
2546*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2547*635a8641SAndroid Build Coastguard Worker
2548*635a8641SAndroid Build Coastguard Worker    def write_table(self,modulename,outputdir='',signature=""):
2549*635a8641SAndroid Build Coastguard Worker        basemodulename = modulename.split(".")[-1]
2550*635a8641SAndroid Build Coastguard Worker        filename = os.path.join(outputdir,basemodulename) + ".py"
2551*635a8641SAndroid Build Coastguard Worker        try:
2552*635a8641SAndroid Build Coastguard Worker            f = open(filename,"w")
2553*635a8641SAndroid Build Coastguard Worker
2554*635a8641SAndroid Build Coastguard Worker            f.write("""
2555*635a8641SAndroid Build Coastguard Worker# %s
2556*635a8641SAndroid Build Coastguard Worker# This file is automatically generated. Do not edit.
2557*635a8641SAndroid Build Coastguard Worker_tabversion = %r
2558*635a8641SAndroid Build Coastguard Worker
2559*635a8641SAndroid Build Coastguard Worker_lr_method = %r
2560*635a8641SAndroid Build Coastguard Worker
2561*635a8641SAndroid Build Coastguard Worker_lr_signature = %r
2562*635a8641SAndroid Build Coastguard Worker    """ % (filename, __tabversion__, self.lr_method, signature))
2563*635a8641SAndroid Build Coastguard Worker
2564*635a8641SAndroid Build Coastguard Worker            # Change smaller to 0 to go back to original tables
2565*635a8641SAndroid Build Coastguard Worker            smaller = 1
2566*635a8641SAndroid Build Coastguard Worker
2567*635a8641SAndroid Build Coastguard Worker            # Factor out names to try and make smaller
2568*635a8641SAndroid Build Coastguard Worker            if smaller:
2569*635a8641SAndroid Build Coastguard Worker                items = { }
2570*635a8641SAndroid Build Coastguard Worker
2571*635a8641SAndroid Build Coastguard Worker                for s,nd in self.lr_action.items():
2572*635a8641SAndroid Build Coastguard Worker                   for name,v in nd.items():
2573*635a8641SAndroid Build Coastguard Worker                      i = items.get(name)
2574*635a8641SAndroid Build Coastguard Worker                      if not i:
2575*635a8641SAndroid Build Coastguard Worker                         i = ([],[])
2576*635a8641SAndroid Build Coastguard Worker                         items[name] = i
2577*635a8641SAndroid Build Coastguard Worker                      i[0].append(s)
2578*635a8641SAndroid Build Coastguard Worker                      i[1].append(v)
2579*635a8641SAndroid Build Coastguard Worker
2580*635a8641SAndroid Build Coastguard Worker                f.write("\n_lr_action_items = {")
2581*635a8641SAndroid Build Coastguard Worker                for k,v in items.items():
2582*635a8641SAndroid Build Coastguard Worker                    f.write("%r:([" % k)
2583*635a8641SAndroid Build Coastguard Worker                    for i in v[0]:
2584*635a8641SAndroid Build Coastguard Worker                        f.write("%r," % i)
2585*635a8641SAndroid Build Coastguard Worker                    f.write("],[")
2586*635a8641SAndroid Build Coastguard Worker                    for i in v[1]:
2587*635a8641SAndroid Build Coastguard Worker                        f.write("%r," % i)
2588*635a8641SAndroid Build Coastguard Worker
2589*635a8641SAndroid Build Coastguard Worker                    f.write("]),")
2590*635a8641SAndroid Build Coastguard Worker                f.write("}\n")
2591*635a8641SAndroid Build Coastguard Worker
2592*635a8641SAndroid Build Coastguard Worker                f.write("""
2593*635a8641SAndroid Build Coastguard Worker_lr_action = { }
2594*635a8641SAndroid Build Coastguard Workerfor _k, _v in _lr_action_items.items():
2595*635a8641SAndroid Build Coastguard Worker   for _x,_y in zip(_v[0],_v[1]):
2596*635a8641SAndroid Build Coastguard Worker      if not _x in _lr_action:  _lr_action[_x] = { }
2597*635a8641SAndroid Build Coastguard Worker      _lr_action[_x][_k] = _y
2598*635a8641SAndroid Build Coastguard Workerdel _lr_action_items
2599*635a8641SAndroid Build Coastguard Worker""")
2600*635a8641SAndroid Build Coastguard Worker
2601*635a8641SAndroid Build Coastguard Worker            else:
2602*635a8641SAndroid Build Coastguard Worker                f.write("\n_lr_action = { ");
2603*635a8641SAndroid Build Coastguard Worker                for k,v in self.lr_action.items():
2604*635a8641SAndroid Build Coastguard Worker                    f.write("(%r,%r):%r," % (k[0],k[1],v))
2605*635a8641SAndroid Build Coastguard Worker                f.write("}\n");
2606*635a8641SAndroid Build Coastguard Worker
2607*635a8641SAndroid Build Coastguard Worker            if smaller:
2608*635a8641SAndroid Build Coastguard Worker                # Factor out names to try and make smaller
2609*635a8641SAndroid Build Coastguard Worker                items = { }
2610*635a8641SAndroid Build Coastguard Worker
2611*635a8641SAndroid Build Coastguard Worker                for s,nd in self.lr_goto.items():
2612*635a8641SAndroid Build Coastguard Worker                   for name,v in nd.items():
2613*635a8641SAndroid Build Coastguard Worker                      i = items.get(name)
2614*635a8641SAndroid Build Coastguard Worker                      if not i:
2615*635a8641SAndroid Build Coastguard Worker                         i = ([],[])
2616*635a8641SAndroid Build Coastguard Worker                         items[name] = i
2617*635a8641SAndroid Build Coastguard Worker                      i[0].append(s)
2618*635a8641SAndroid Build Coastguard Worker                      i[1].append(v)
2619*635a8641SAndroid Build Coastguard Worker
2620*635a8641SAndroid Build Coastguard Worker                f.write("\n_lr_goto_items = {")
2621*635a8641SAndroid Build Coastguard Worker                for k,v in items.items():
2622*635a8641SAndroid Build Coastguard Worker                    f.write("%r:([" % k)
2623*635a8641SAndroid Build Coastguard Worker                    for i in v[0]:
2624*635a8641SAndroid Build Coastguard Worker                        f.write("%r," % i)
2625*635a8641SAndroid Build Coastguard Worker                    f.write("],[")
2626*635a8641SAndroid Build Coastguard Worker                    for i in v[1]:
2627*635a8641SAndroid Build Coastguard Worker                        f.write("%r," % i)
2628*635a8641SAndroid Build Coastguard Worker
2629*635a8641SAndroid Build Coastguard Worker                    f.write("]),")
2630*635a8641SAndroid Build Coastguard Worker                f.write("}\n")
2631*635a8641SAndroid Build Coastguard Worker
2632*635a8641SAndroid Build Coastguard Worker                f.write("""
2633*635a8641SAndroid Build Coastguard Worker_lr_goto = { }
2634*635a8641SAndroid Build Coastguard Workerfor _k, _v in _lr_goto_items.items():
2635*635a8641SAndroid Build Coastguard Worker   for _x,_y in zip(_v[0],_v[1]):
2636*635a8641SAndroid Build Coastguard Worker       if not _x in _lr_goto: _lr_goto[_x] = { }
2637*635a8641SAndroid Build Coastguard Worker       _lr_goto[_x][_k] = _y
2638*635a8641SAndroid Build Coastguard Workerdel _lr_goto_items
2639*635a8641SAndroid Build Coastguard Worker""")
2640*635a8641SAndroid Build Coastguard Worker            else:
2641*635a8641SAndroid Build Coastguard Worker                f.write("\n_lr_goto = { ");
2642*635a8641SAndroid Build Coastguard Worker                for k,v in self.lr_goto.items():
2643*635a8641SAndroid Build Coastguard Worker                    f.write("(%r,%r):%r," % (k[0],k[1],v))
2644*635a8641SAndroid Build Coastguard Worker                f.write("}\n");
2645*635a8641SAndroid Build Coastguard Worker
2646*635a8641SAndroid Build Coastguard Worker            # Write production table
2647*635a8641SAndroid Build Coastguard Worker            f.write("_lr_productions = [\n")
2648*635a8641SAndroid Build Coastguard Worker            for p in self.lr_productions:
2649*635a8641SAndroid Build Coastguard Worker                if p.func:
2650*635a8641SAndroid Build Coastguard Worker                    f.write("  (%r,%r,%d,%r,%r,%d),\n" % (p.str,p.name, p.len, p.func,p.file,p.line))
2651*635a8641SAndroid Build Coastguard Worker                else:
2652*635a8641SAndroid Build Coastguard Worker                    f.write("  (%r,%r,%d,None,None,None),\n" % (str(p),p.name, p.len))
2653*635a8641SAndroid Build Coastguard Worker            f.write("]\n")
2654*635a8641SAndroid Build Coastguard Worker            f.close()
2655*635a8641SAndroid Build Coastguard Worker
2656*635a8641SAndroid Build Coastguard Worker        except IOError:
2657*635a8641SAndroid Build Coastguard Worker            e = sys.exc_info()[1]
2658*635a8641SAndroid Build Coastguard Worker            sys.stderr.write("Unable to create '%s'\n" % filename)
2659*635a8641SAndroid Build Coastguard Worker            sys.stderr.write(str(e)+"\n")
2660*635a8641SAndroid Build Coastguard Worker            return
2661*635a8641SAndroid Build Coastguard Worker
2662*635a8641SAndroid Build Coastguard Worker
2663*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2664*635a8641SAndroid Build Coastguard Worker    # pickle_table()
2665*635a8641SAndroid Build Coastguard Worker    #
2666*635a8641SAndroid Build Coastguard Worker    # This function pickles the LR parsing tables to a supplied file object
2667*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2668*635a8641SAndroid Build Coastguard Worker
2669*635a8641SAndroid Build Coastguard Worker    def pickle_table(self,filename,signature=""):
2670*635a8641SAndroid Build Coastguard Worker        try:
2671*635a8641SAndroid Build Coastguard Worker            import cPickle as pickle
2672*635a8641SAndroid Build Coastguard Worker        except ImportError:
2673*635a8641SAndroid Build Coastguard Worker            import pickle
2674*635a8641SAndroid Build Coastguard Worker        outf = open(filename,"wb")
2675*635a8641SAndroid Build Coastguard Worker        pickle.dump(__tabversion__,outf,pickle_protocol)
2676*635a8641SAndroid Build Coastguard Worker        pickle.dump(self.lr_method,outf,pickle_protocol)
2677*635a8641SAndroid Build Coastguard Worker        pickle.dump(signature,outf,pickle_protocol)
2678*635a8641SAndroid Build Coastguard Worker        pickle.dump(self.lr_action,outf,pickle_protocol)
2679*635a8641SAndroid Build Coastguard Worker        pickle.dump(self.lr_goto,outf,pickle_protocol)
2680*635a8641SAndroid Build Coastguard Worker
2681*635a8641SAndroid Build Coastguard Worker        outp = []
2682*635a8641SAndroid Build Coastguard Worker        for p in self.lr_productions:
2683*635a8641SAndroid Build Coastguard Worker            if p.func:
2684*635a8641SAndroid Build Coastguard Worker                outp.append((p.str,p.name, p.len, p.func,p.file,p.line))
2685*635a8641SAndroid Build Coastguard Worker            else:
2686*635a8641SAndroid Build Coastguard Worker                outp.append((str(p),p.name,p.len,None,None,None))
2687*635a8641SAndroid Build Coastguard Worker        pickle.dump(outp,outf,pickle_protocol)
2688*635a8641SAndroid Build Coastguard Worker        outf.close()
2689*635a8641SAndroid Build Coastguard Worker
2690*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2691*635a8641SAndroid Build Coastguard Worker#                            === INTROSPECTION ===
2692*635a8641SAndroid Build Coastguard Worker#
2693*635a8641SAndroid Build Coastguard Worker# The following functions and classes are used to implement the PLY
2694*635a8641SAndroid Build Coastguard Worker# introspection features followed by the yacc() function itself.
2695*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2696*635a8641SAndroid Build Coastguard Worker
2697*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2698*635a8641SAndroid Build Coastguard Worker# get_caller_module_dict()
2699*635a8641SAndroid Build Coastguard Worker#
2700*635a8641SAndroid Build Coastguard Worker# This function returns a dictionary containing all of the symbols defined within
2701*635a8641SAndroid Build Coastguard Worker# a caller further down the call stack.  This is used to get the environment
2702*635a8641SAndroid Build Coastguard Worker# associated with the yacc() call if none was provided.
2703*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2704*635a8641SAndroid Build Coastguard Worker
2705*635a8641SAndroid Build Coastguard Workerdef get_caller_module_dict(levels):
2706*635a8641SAndroid Build Coastguard Worker    try:
2707*635a8641SAndroid Build Coastguard Worker        raise RuntimeError
2708*635a8641SAndroid Build Coastguard Worker    except RuntimeError:
2709*635a8641SAndroid Build Coastguard Worker        e,b,t = sys.exc_info()
2710*635a8641SAndroid Build Coastguard Worker        f = t.tb_frame
2711*635a8641SAndroid Build Coastguard Worker        while levels > 0:
2712*635a8641SAndroid Build Coastguard Worker            f = f.f_back
2713*635a8641SAndroid Build Coastguard Worker            levels -= 1
2714*635a8641SAndroid Build Coastguard Worker        ldict = f.f_globals.copy()
2715*635a8641SAndroid Build Coastguard Worker        if f.f_globals != f.f_locals:
2716*635a8641SAndroid Build Coastguard Worker            ldict.update(f.f_locals)
2717*635a8641SAndroid Build Coastguard Worker
2718*635a8641SAndroid Build Coastguard Worker        return ldict
2719*635a8641SAndroid Build Coastguard Worker
2720*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2721*635a8641SAndroid Build Coastguard Worker# parse_grammar()
2722*635a8641SAndroid Build Coastguard Worker#
2723*635a8641SAndroid Build Coastguard Worker# This takes a raw grammar rule string and parses it into production data
2724*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2725*635a8641SAndroid Build Coastguard Workerdef parse_grammar(doc,file,line):
2726*635a8641SAndroid Build Coastguard Worker    grammar = []
2727*635a8641SAndroid Build Coastguard Worker    # Split the doc string into lines
2728*635a8641SAndroid Build Coastguard Worker    pstrings = doc.splitlines()
2729*635a8641SAndroid Build Coastguard Worker    lastp = None
2730*635a8641SAndroid Build Coastguard Worker    dline = line
2731*635a8641SAndroid Build Coastguard Worker    for ps in pstrings:
2732*635a8641SAndroid Build Coastguard Worker        dline += 1
2733*635a8641SAndroid Build Coastguard Worker        p = ps.split()
2734*635a8641SAndroid Build Coastguard Worker        if not p: continue
2735*635a8641SAndroid Build Coastguard Worker        try:
2736*635a8641SAndroid Build Coastguard Worker            if p[0] == '|':
2737*635a8641SAndroid Build Coastguard Worker                # This is a continuation of a previous rule
2738*635a8641SAndroid Build Coastguard Worker                if not lastp:
2739*635a8641SAndroid Build Coastguard Worker                    raise SyntaxError("%s:%d: Misplaced '|'" % (file,dline))
2740*635a8641SAndroid Build Coastguard Worker                prodname = lastp
2741*635a8641SAndroid Build Coastguard Worker                syms = p[1:]
2742*635a8641SAndroid Build Coastguard Worker            else:
2743*635a8641SAndroid Build Coastguard Worker                prodname = p[0]
2744*635a8641SAndroid Build Coastguard Worker                lastp = prodname
2745*635a8641SAndroid Build Coastguard Worker                syms   = p[2:]
2746*635a8641SAndroid Build Coastguard Worker                assign = p[1]
2747*635a8641SAndroid Build Coastguard Worker                if assign != ':' and assign != '::=':
2748*635a8641SAndroid Build Coastguard Worker                    raise SyntaxError("%s:%d: Syntax error. Expected ':'" % (file,dline))
2749*635a8641SAndroid Build Coastguard Worker
2750*635a8641SAndroid Build Coastguard Worker            grammar.append((file,dline,prodname,syms))
2751*635a8641SAndroid Build Coastguard Worker        except SyntaxError:
2752*635a8641SAndroid Build Coastguard Worker            raise
2753*635a8641SAndroid Build Coastguard Worker        except Exception:
2754*635a8641SAndroid Build Coastguard Worker            raise SyntaxError("%s:%d: Syntax error in rule '%s'" % (file,dline,ps.strip()))
2755*635a8641SAndroid Build Coastguard Worker
2756*635a8641SAndroid Build Coastguard Worker    return grammar
2757*635a8641SAndroid Build Coastguard Worker
2758*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2759*635a8641SAndroid Build Coastguard Worker# ParserReflect()
2760*635a8641SAndroid Build Coastguard Worker#
2761*635a8641SAndroid Build Coastguard Worker# This class represents information extracted for building a parser including
2762*635a8641SAndroid Build Coastguard Worker# start symbol, error function, tokens, precedence list, action functions,
2763*635a8641SAndroid Build Coastguard Worker# etc.
2764*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
2765*635a8641SAndroid Build Coastguard Workerclass ParserReflect(object):
2766*635a8641SAndroid Build Coastguard Worker    def __init__(self,pdict,log=None):
2767*635a8641SAndroid Build Coastguard Worker        self.pdict      = pdict
2768*635a8641SAndroid Build Coastguard Worker        self.start      = None
2769*635a8641SAndroid Build Coastguard Worker        self.error_func = None
2770*635a8641SAndroid Build Coastguard Worker        self.tokens     = None
2771*635a8641SAndroid Build Coastguard Worker        self.files      = {}
2772*635a8641SAndroid Build Coastguard Worker        self.grammar    = []
2773*635a8641SAndroid Build Coastguard Worker        self.error      = 0
2774*635a8641SAndroid Build Coastguard Worker
2775*635a8641SAndroid Build Coastguard Worker        if log is None:
2776*635a8641SAndroid Build Coastguard Worker            self.log = PlyLogger(sys.stderr)
2777*635a8641SAndroid Build Coastguard Worker        else:
2778*635a8641SAndroid Build Coastguard Worker            self.log = log
2779*635a8641SAndroid Build Coastguard Worker
2780*635a8641SAndroid Build Coastguard Worker    # Get all of the basic information
2781*635a8641SAndroid Build Coastguard Worker    def get_all(self):
2782*635a8641SAndroid Build Coastguard Worker        self.get_start()
2783*635a8641SAndroid Build Coastguard Worker        self.get_error_func()
2784*635a8641SAndroid Build Coastguard Worker        self.get_tokens()
2785*635a8641SAndroid Build Coastguard Worker        self.get_precedence()
2786*635a8641SAndroid Build Coastguard Worker        self.get_pfunctions()
2787*635a8641SAndroid Build Coastguard Worker
2788*635a8641SAndroid Build Coastguard Worker    # Validate all of the information
2789*635a8641SAndroid Build Coastguard Worker    def validate_all(self):
2790*635a8641SAndroid Build Coastguard Worker        self.validate_start()
2791*635a8641SAndroid Build Coastguard Worker        self.validate_error_func()
2792*635a8641SAndroid Build Coastguard Worker        self.validate_tokens()
2793*635a8641SAndroid Build Coastguard Worker        self.validate_precedence()
2794*635a8641SAndroid Build Coastguard Worker        self.validate_pfunctions()
2795*635a8641SAndroid Build Coastguard Worker        self.validate_files()
2796*635a8641SAndroid Build Coastguard Worker        return self.error
2797*635a8641SAndroid Build Coastguard Worker
2798*635a8641SAndroid Build Coastguard Worker    # Compute a signature over the grammar
2799*635a8641SAndroid Build Coastguard Worker    def signature(self):
2800*635a8641SAndroid Build Coastguard Worker        try:
2801*635a8641SAndroid Build Coastguard Worker            from hashlib import md5
2802*635a8641SAndroid Build Coastguard Worker        except ImportError:
2803*635a8641SAndroid Build Coastguard Worker            from md5 import md5
2804*635a8641SAndroid Build Coastguard Worker        try:
2805*635a8641SAndroid Build Coastguard Worker            sig = md5()
2806*635a8641SAndroid Build Coastguard Worker            if self.start:
2807*635a8641SAndroid Build Coastguard Worker                sig.update(self.start.encode('latin-1'))
2808*635a8641SAndroid Build Coastguard Worker            if self.prec:
2809*635a8641SAndroid Build Coastguard Worker                sig.update("".join(["".join(p) for p in self.prec]).encode('latin-1'))
2810*635a8641SAndroid Build Coastguard Worker            if self.tokens:
2811*635a8641SAndroid Build Coastguard Worker                sig.update(" ".join(self.tokens).encode('latin-1'))
2812*635a8641SAndroid Build Coastguard Worker            for f in self.pfuncs:
2813*635a8641SAndroid Build Coastguard Worker                if f[3]:
2814*635a8641SAndroid Build Coastguard Worker                    sig.update(f[3].encode('latin-1'))
2815*635a8641SAndroid Build Coastguard Worker        except (TypeError,ValueError):
2816*635a8641SAndroid Build Coastguard Worker            pass
2817*635a8641SAndroid Build Coastguard Worker        return sig.digest()
2818*635a8641SAndroid Build Coastguard Worker
2819*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2820*635a8641SAndroid Build Coastguard Worker    # validate_file()
2821*635a8641SAndroid Build Coastguard Worker    #
2822*635a8641SAndroid Build Coastguard Worker    # This method checks to see if there are duplicated p_rulename() functions
2823*635a8641SAndroid Build Coastguard Worker    # in the parser module file.  Without this function, it is really easy for
2824*635a8641SAndroid Build Coastguard Worker    # users to make mistakes by cutting and pasting code fragments (and it's a real
2825*635a8641SAndroid Build Coastguard Worker    # bugger to try and figure out why the resulting parser doesn't work).  Therefore,
2826*635a8641SAndroid Build Coastguard Worker    # we just do a little regular expression pattern matching of def statements
2827*635a8641SAndroid Build Coastguard Worker    # to try and detect duplicates.
2828*635a8641SAndroid Build Coastguard Worker    # -----------------------------------------------------------------------------
2829*635a8641SAndroid Build Coastguard Worker
2830*635a8641SAndroid Build Coastguard Worker    def validate_files(self):
2831*635a8641SAndroid Build Coastguard Worker        # Match def p_funcname(
2832*635a8641SAndroid Build Coastguard Worker        fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(')
2833*635a8641SAndroid Build Coastguard Worker
2834*635a8641SAndroid Build Coastguard Worker        for filename in self.files.keys():
2835*635a8641SAndroid Build Coastguard Worker            base,ext = os.path.splitext(filename)
2836*635a8641SAndroid Build Coastguard Worker            if ext != '.py': return 1          # No idea. Assume it's okay.
2837*635a8641SAndroid Build Coastguard Worker
2838*635a8641SAndroid Build Coastguard Worker            try:
2839*635a8641SAndroid Build Coastguard Worker                f = open(filename)
2840*635a8641SAndroid Build Coastguard Worker                lines = f.readlines()
2841*635a8641SAndroid Build Coastguard Worker                f.close()
2842*635a8641SAndroid Build Coastguard Worker            except IOError:
2843*635a8641SAndroid Build Coastguard Worker                continue
2844*635a8641SAndroid Build Coastguard Worker
2845*635a8641SAndroid Build Coastguard Worker            counthash = { }
2846*635a8641SAndroid Build Coastguard Worker            for linen,l in enumerate(lines):
2847*635a8641SAndroid Build Coastguard Worker                linen += 1
2848*635a8641SAndroid Build Coastguard Worker                m = fre.match(l)
2849*635a8641SAndroid Build Coastguard Worker                if m:
2850*635a8641SAndroid Build Coastguard Worker                    name = m.group(1)
2851*635a8641SAndroid Build Coastguard Worker                    prev = counthash.get(name)
2852*635a8641SAndroid Build Coastguard Worker                    if not prev:
2853*635a8641SAndroid Build Coastguard Worker                        counthash[name] = linen
2854*635a8641SAndroid Build Coastguard Worker                    else:
2855*635a8641SAndroid Build Coastguard Worker                        self.log.warning("%s:%d: Function %s redefined. Previously defined on line %d", filename,linen,name,prev)
2856*635a8641SAndroid Build Coastguard Worker
2857*635a8641SAndroid Build Coastguard Worker    # Get the start symbol
2858*635a8641SAndroid Build Coastguard Worker    def get_start(self):
2859*635a8641SAndroid Build Coastguard Worker        self.start = self.pdict.get('start')
2860*635a8641SAndroid Build Coastguard Worker
2861*635a8641SAndroid Build Coastguard Worker    # Validate the start symbol
2862*635a8641SAndroid Build Coastguard Worker    def validate_start(self):
2863*635a8641SAndroid Build Coastguard Worker        if self.start is not None:
2864*635a8641SAndroid Build Coastguard Worker            if not isinstance(self.start,str):
2865*635a8641SAndroid Build Coastguard Worker                self.log.error("'start' must be a string")
2866*635a8641SAndroid Build Coastguard Worker
2867*635a8641SAndroid Build Coastguard Worker    # Look for error handler
2868*635a8641SAndroid Build Coastguard Worker    def get_error_func(self):
2869*635a8641SAndroid Build Coastguard Worker        self.error_func = self.pdict.get('p_error')
2870*635a8641SAndroid Build Coastguard Worker
2871*635a8641SAndroid Build Coastguard Worker    # Validate the error function
2872*635a8641SAndroid Build Coastguard Worker    def validate_error_func(self):
2873*635a8641SAndroid Build Coastguard Worker        if self.error_func:
2874*635a8641SAndroid Build Coastguard Worker            if isinstance(self.error_func,types.FunctionType):
2875*635a8641SAndroid Build Coastguard Worker                ismethod = 0
2876*635a8641SAndroid Build Coastguard Worker            elif isinstance(self.error_func, types.MethodType):
2877*635a8641SAndroid Build Coastguard Worker                ismethod = 1
2878*635a8641SAndroid Build Coastguard Worker            else:
2879*635a8641SAndroid Build Coastguard Worker                self.log.error("'p_error' defined, but is not a function or method")
2880*635a8641SAndroid Build Coastguard Worker                self.error = 1
2881*635a8641SAndroid Build Coastguard Worker                return
2882*635a8641SAndroid Build Coastguard Worker
2883*635a8641SAndroid Build Coastguard Worker            eline = func_code(self.error_func).co_firstlineno
2884*635a8641SAndroid Build Coastguard Worker            efile = func_code(self.error_func).co_filename
2885*635a8641SAndroid Build Coastguard Worker            self.files[efile] = 1
2886*635a8641SAndroid Build Coastguard Worker
2887*635a8641SAndroid Build Coastguard Worker            if (func_code(self.error_func).co_argcount != 1+ismethod):
2888*635a8641SAndroid Build Coastguard Worker                self.log.error("%s:%d: p_error() requires 1 argument",efile,eline)
2889*635a8641SAndroid Build Coastguard Worker                self.error = 1
2890*635a8641SAndroid Build Coastguard Worker
2891*635a8641SAndroid Build Coastguard Worker    # Get the tokens map
2892*635a8641SAndroid Build Coastguard Worker    def get_tokens(self):
2893*635a8641SAndroid Build Coastguard Worker        tokens = self.pdict.get("tokens",None)
2894*635a8641SAndroid Build Coastguard Worker        if not tokens:
2895*635a8641SAndroid Build Coastguard Worker            self.log.error("No token list is defined")
2896*635a8641SAndroid Build Coastguard Worker            self.error = 1
2897*635a8641SAndroid Build Coastguard Worker            return
2898*635a8641SAndroid Build Coastguard Worker
2899*635a8641SAndroid Build Coastguard Worker        if not isinstance(tokens,(list, tuple)):
2900*635a8641SAndroid Build Coastguard Worker            self.log.error("tokens must be a list or tuple")
2901*635a8641SAndroid Build Coastguard Worker            self.error = 1
2902*635a8641SAndroid Build Coastguard Worker            return
2903*635a8641SAndroid Build Coastguard Worker
2904*635a8641SAndroid Build Coastguard Worker        if not tokens:
2905*635a8641SAndroid Build Coastguard Worker            self.log.error("tokens is empty")
2906*635a8641SAndroid Build Coastguard Worker            self.error = 1
2907*635a8641SAndroid Build Coastguard Worker            return
2908*635a8641SAndroid Build Coastguard Worker
2909*635a8641SAndroid Build Coastguard Worker        self.tokens = tokens
2910*635a8641SAndroid Build Coastguard Worker
2911*635a8641SAndroid Build Coastguard Worker    # Validate the tokens
2912*635a8641SAndroid Build Coastguard Worker    def validate_tokens(self):
2913*635a8641SAndroid Build Coastguard Worker        # Validate the tokens.
2914*635a8641SAndroid Build Coastguard Worker        if 'error' in self.tokens:
2915*635a8641SAndroid Build Coastguard Worker            self.log.error("Illegal token name 'error'. Is a reserved word")
2916*635a8641SAndroid Build Coastguard Worker            self.error = 1
2917*635a8641SAndroid Build Coastguard Worker            return
2918*635a8641SAndroid Build Coastguard Worker
2919*635a8641SAndroid Build Coastguard Worker        terminals = {}
2920*635a8641SAndroid Build Coastguard Worker        for n in self.tokens:
2921*635a8641SAndroid Build Coastguard Worker            if n in terminals:
2922*635a8641SAndroid Build Coastguard Worker                self.log.warning("Token '%s' multiply defined", n)
2923*635a8641SAndroid Build Coastguard Worker            terminals[n] = 1
2924*635a8641SAndroid Build Coastguard Worker
2925*635a8641SAndroid Build Coastguard Worker    # Get the precedence map (if any)
2926*635a8641SAndroid Build Coastguard Worker    def get_precedence(self):
2927*635a8641SAndroid Build Coastguard Worker        self.prec = self.pdict.get("precedence",None)
2928*635a8641SAndroid Build Coastguard Worker
2929*635a8641SAndroid Build Coastguard Worker    # Validate and parse the precedence map
2930*635a8641SAndroid Build Coastguard Worker    def validate_precedence(self):
2931*635a8641SAndroid Build Coastguard Worker        preclist = []
2932*635a8641SAndroid Build Coastguard Worker        if self.prec:
2933*635a8641SAndroid Build Coastguard Worker            if not isinstance(self.prec,(list,tuple)):
2934*635a8641SAndroid Build Coastguard Worker                self.log.error("precedence must be a list or tuple")
2935*635a8641SAndroid Build Coastguard Worker                self.error = 1
2936*635a8641SAndroid Build Coastguard Worker                return
2937*635a8641SAndroid Build Coastguard Worker            for level,p in enumerate(self.prec):
2938*635a8641SAndroid Build Coastguard Worker                if not isinstance(p,(list,tuple)):
2939*635a8641SAndroid Build Coastguard Worker                    self.log.error("Bad precedence table")
2940*635a8641SAndroid Build Coastguard Worker                    self.error = 1
2941*635a8641SAndroid Build Coastguard Worker                    return
2942*635a8641SAndroid Build Coastguard Worker
2943*635a8641SAndroid Build Coastguard Worker                if len(p) < 2:
2944*635a8641SAndroid Build Coastguard Worker                    self.log.error("Malformed precedence entry %s. Must be (assoc, term, ..., term)",p)
2945*635a8641SAndroid Build Coastguard Worker                    self.error = 1
2946*635a8641SAndroid Build Coastguard Worker                    return
2947*635a8641SAndroid Build Coastguard Worker                assoc = p[0]
2948*635a8641SAndroid Build Coastguard Worker                if not isinstance(assoc,str):
2949*635a8641SAndroid Build Coastguard Worker                    self.log.error("precedence associativity must be a string")
2950*635a8641SAndroid Build Coastguard Worker                    self.error = 1
2951*635a8641SAndroid Build Coastguard Worker                    return
2952*635a8641SAndroid Build Coastguard Worker                for term in p[1:]:
2953*635a8641SAndroid Build Coastguard Worker                    if not isinstance(term,str):
2954*635a8641SAndroid Build Coastguard Worker                        self.log.error("precedence items must be strings")
2955*635a8641SAndroid Build Coastguard Worker                        self.error = 1
2956*635a8641SAndroid Build Coastguard Worker                        return
2957*635a8641SAndroid Build Coastguard Worker                    preclist.append((term,assoc,level+1))
2958*635a8641SAndroid Build Coastguard Worker        self.preclist = preclist
2959*635a8641SAndroid Build Coastguard Worker
2960*635a8641SAndroid Build Coastguard Worker    # Get all p_functions from the grammar
2961*635a8641SAndroid Build Coastguard Worker    def get_pfunctions(self):
2962*635a8641SAndroid Build Coastguard Worker        p_functions = []
2963*635a8641SAndroid Build Coastguard Worker        for name, item in self.pdict.items():
2964*635a8641SAndroid Build Coastguard Worker            if name[:2] != 'p_': continue
2965*635a8641SAndroid Build Coastguard Worker            if name == 'p_error': continue
2966*635a8641SAndroid Build Coastguard Worker            if isinstance(item,(types.FunctionType,types.MethodType)):
2967*635a8641SAndroid Build Coastguard Worker                line = func_code(item).co_firstlineno
2968*635a8641SAndroid Build Coastguard Worker                file = func_code(item).co_filename
2969*635a8641SAndroid Build Coastguard Worker                p_functions.append((line,file,name,item.__doc__))
2970*635a8641SAndroid Build Coastguard Worker
2971*635a8641SAndroid Build Coastguard Worker        # Sort all of the actions by line number
2972*635a8641SAndroid Build Coastguard Worker        p_functions.sort()
2973*635a8641SAndroid Build Coastguard Worker        self.pfuncs = p_functions
2974*635a8641SAndroid Build Coastguard Worker
2975*635a8641SAndroid Build Coastguard Worker
2976*635a8641SAndroid Build Coastguard Worker    # Validate all of the p_functions
2977*635a8641SAndroid Build Coastguard Worker    def validate_pfunctions(self):
2978*635a8641SAndroid Build Coastguard Worker        grammar = []
2979*635a8641SAndroid Build Coastguard Worker        # Check for non-empty symbols
2980*635a8641SAndroid Build Coastguard Worker        if len(self.pfuncs) == 0:
2981*635a8641SAndroid Build Coastguard Worker            self.log.error("no rules of the form p_rulename are defined")
2982*635a8641SAndroid Build Coastguard Worker            self.error = 1
2983*635a8641SAndroid Build Coastguard Worker            return
2984*635a8641SAndroid Build Coastguard Worker
2985*635a8641SAndroid Build Coastguard Worker        for line, file, name, doc in self.pfuncs:
2986*635a8641SAndroid Build Coastguard Worker            func = self.pdict[name]
2987*635a8641SAndroid Build Coastguard Worker            if isinstance(func, types.MethodType):
2988*635a8641SAndroid Build Coastguard Worker                reqargs = 2
2989*635a8641SAndroid Build Coastguard Worker            else:
2990*635a8641SAndroid Build Coastguard Worker                reqargs = 1
2991*635a8641SAndroid Build Coastguard Worker            if func_code(func).co_argcount > reqargs:
2992*635a8641SAndroid Build Coastguard Worker                self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,func.__name__)
2993*635a8641SAndroid Build Coastguard Worker                self.error = 1
2994*635a8641SAndroid Build Coastguard Worker            elif func_code(func).co_argcount < reqargs:
2995*635a8641SAndroid Build Coastguard Worker                self.log.error("%s:%d: Rule '%s' requires an argument",file,line,func.__name__)
2996*635a8641SAndroid Build Coastguard Worker                self.error = 1
2997*635a8641SAndroid Build Coastguard Worker            elif not func.__doc__:
2998*635a8641SAndroid Build Coastguard Worker                self.log.warning("%s:%d: No documentation string specified in function '%s' (ignored)",file,line,func.__name__)
2999*635a8641SAndroid Build Coastguard Worker            else:
3000*635a8641SAndroid Build Coastguard Worker                try:
3001*635a8641SAndroid Build Coastguard Worker                    parsed_g = parse_grammar(doc,file,line)
3002*635a8641SAndroid Build Coastguard Worker                    for g in parsed_g:
3003*635a8641SAndroid Build Coastguard Worker                        grammar.append((name, g))
3004*635a8641SAndroid Build Coastguard Worker                except SyntaxError:
3005*635a8641SAndroid Build Coastguard Worker                    e = sys.exc_info()[1]
3006*635a8641SAndroid Build Coastguard Worker                    self.log.error(str(e))
3007*635a8641SAndroid Build Coastguard Worker                    self.error = 1
3008*635a8641SAndroid Build Coastguard Worker
3009*635a8641SAndroid Build Coastguard Worker                # Looks like a valid grammar rule
3010*635a8641SAndroid Build Coastguard Worker                # Mark the file in which defined.
3011*635a8641SAndroid Build Coastguard Worker                self.files[file] = 1
3012*635a8641SAndroid Build Coastguard Worker
3013*635a8641SAndroid Build Coastguard Worker        # Secondary validation step that looks for p_ definitions that are not functions
3014*635a8641SAndroid Build Coastguard Worker        # or functions that look like they might be grammar rules.
3015*635a8641SAndroid Build Coastguard Worker
3016*635a8641SAndroid Build Coastguard Worker        for n,v in self.pdict.items():
3017*635a8641SAndroid Build Coastguard Worker            if n[0:2] == 'p_' and isinstance(v, (types.FunctionType, types.MethodType)): continue
3018*635a8641SAndroid Build Coastguard Worker            if n[0:2] == 't_': continue
3019*635a8641SAndroid Build Coastguard Worker            if n[0:2] == 'p_' and n != 'p_error':
3020*635a8641SAndroid Build Coastguard Worker                self.log.warning("'%s' not defined as a function", n)
3021*635a8641SAndroid Build Coastguard Worker            if ((isinstance(v,types.FunctionType) and func_code(v).co_argcount == 1) or
3022*635a8641SAndroid Build Coastguard Worker                (isinstance(v,types.MethodType) and func_code(v).co_argcount == 2)):
3023*635a8641SAndroid Build Coastguard Worker                try:
3024*635a8641SAndroid Build Coastguard Worker                    doc = v.__doc__.split(" ")
3025*635a8641SAndroid Build Coastguard Worker                    if doc[1] == ':':
3026*635a8641SAndroid Build Coastguard Worker                        self.log.warning("%s:%d: Possible grammar rule '%s' defined without p_ prefix",
3027*635a8641SAndroid Build Coastguard Worker                                         func_code(v).co_filename, func_code(v).co_firstlineno,n)
3028*635a8641SAndroid Build Coastguard Worker                except Exception:
3029*635a8641SAndroid Build Coastguard Worker                    pass
3030*635a8641SAndroid Build Coastguard Worker
3031*635a8641SAndroid Build Coastguard Worker        self.grammar = grammar
3032*635a8641SAndroid Build Coastguard Worker
3033*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
3034*635a8641SAndroid Build Coastguard Worker# yacc(module)
3035*635a8641SAndroid Build Coastguard Worker#
3036*635a8641SAndroid Build Coastguard Worker# Build a parser
3037*635a8641SAndroid Build Coastguard Worker# -----------------------------------------------------------------------------
3038*635a8641SAndroid Build Coastguard Worker
3039*635a8641SAndroid Build Coastguard Workerdef yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, start=None,
3040*635a8641SAndroid Build Coastguard Worker         check_recursion=1, optimize=0, write_tables=1, debugfile=debug_file,outputdir='',
3041*635a8641SAndroid Build Coastguard Worker         debuglog=None, errorlog = None, picklefile=None):
3042*635a8641SAndroid Build Coastguard Worker
3043*635a8641SAndroid Build Coastguard Worker    global parse                 # Reference to the parsing method of the last built parser
3044*635a8641SAndroid Build Coastguard Worker
3045*635a8641SAndroid Build Coastguard Worker    # If pickling is enabled, table files are not created
3046*635a8641SAndroid Build Coastguard Worker
3047*635a8641SAndroid Build Coastguard Worker    if picklefile:
3048*635a8641SAndroid Build Coastguard Worker        write_tables = 0
3049*635a8641SAndroid Build Coastguard Worker
3050*635a8641SAndroid Build Coastguard Worker    if errorlog is None:
3051*635a8641SAndroid Build Coastguard Worker        errorlog = PlyLogger(sys.stderr)
3052*635a8641SAndroid Build Coastguard Worker
3053*635a8641SAndroid Build Coastguard Worker    # Get the module dictionary used for the parser
3054*635a8641SAndroid Build Coastguard Worker    if module:
3055*635a8641SAndroid Build Coastguard Worker        _items = [(k,getattr(module,k)) for k in dir(module)]
3056*635a8641SAndroid Build Coastguard Worker        pdict = dict(_items)
3057*635a8641SAndroid Build Coastguard Worker    else:
3058*635a8641SAndroid Build Coastguard Worker        pdict = get_caller_module_dict(2)
3059*635a8641SAndroid Build Coastguard Worker
3060*635a8641SAndroid Build Coastguard Worker    # Collect parser information from the dictionary
3061*635a8641SAndroid Build Coastguard Worker    pinfo = ParserReflect(pdict,log=errorlog)
3062*635a8641SAndroid Build Coastguard Worker    pinfo.get_all()
3063*635a8641SAndroid Build Coastguard Worker
3064*635a8641SAndroid Build Coastguard Worker    if pinfo.error:
3065*635a8641SAndroid Build Coastguard Worker        raise YaccError("Unable to build parser")
3066*635a8641SAndroid Build Coastguard Worker
3067*635a8641SAndroid Build Coastguard Worker    # Check signature against table files (if any)
3068*635a8641SAndroid Build Coastguard Worker    signature = pinfo.signature()
3069*635a8641SAndroid Build Coastguard Worker
3070*635a8641SAndroid Build Coastguard Worker    # Read the tables
3071*635a8641SAndroid Build Coastguard Worker    try:
3072*635a8641SAndroid Build Coastguard Worker        lr = LRTable()
3073*635a8641SAndroid Build Coastguard Worker        if picklefile:
3074*635a8641SAndroid Build Coastguard Worker            read_signature = lr.read_pickle(picklefile)
3075*635a8641SAndroid Build Coastguard Worker        else:
3076*635a8641SAndroid Build Coastguard Worker            read_signature = lr.read_table(tabmodule)
3077*635a8641SAndroid Build Coastguard Worker        if optimize or (read_signature == signature):
3078*635a8641SAndroid Build Coastguard Worker            try:
3079*635a8641SAndroid Build Coastguard Worker                lr.bind_callables(pinfo.pdict)
3080*635a8641SAndroid Build Coastguard Worker                parser = LRParser(lr,pinfo.error_func)
3081*635a8641SAndroid Build Coastguard Worker                parse = parser.parse
3082*635a8641SAndroid Build Coastguard Worker                return parser
3083*635a8641SAndroid Build Coastguard Worker            except Exception:
3084*635a8641SAndroid Build Coastguard Worker                e = sys.exc_info()[1]
3085*635a8641SAndroid Build Coastguard Worker                errorlog.warning("There was a problem loading the table file: %s", repr(e))
3086*635a8641SAndroid Build Coastguard Worker    except VersionError:
3087*635a8641SAndroid Build Coastguard Worker        e = sys.exc_info()
3088*635a8641SAndroid Build Coastguard Worker        errorlog.warning(str(e))
3089*635a8641SAndroid Build Coastguard Worker    except Exception:
3090*635a8641SAndroid Build Coastguard Worker        pass
3091*635a8641SAndroid Build Coastguard Worker
3092*635a8641SAndroid Build Coastguard Worker    if debuglog is None:
3093*635a8641SAndroid Build Coastguard Worker        if debug:
3094*635a8641SAndroid Build Coastguard Worker            debuglog = PlyLogger(open(debugfile,"w"))
3095*635a8641SAndroid Build Coastguard Worker        else:
3096*635a8641SAndroid Build Coastguard Worker            debuglog = NullLogger()
3097*635a8641SAndroid Build Coastguard Worker
3098*635a8641SAndroid Build Coastguard Worker    debuglog.info("Created by PLY version %s (http://www.dabeaz.com/ply)", __version__)
3099*635a8641SAndroid Build Coastguard Worker
3100*635a8641SAndroid Build Coastguard Worker
3101*635a8641SAndroid Build Coastguard Worker    errors = 0
3102*635a8641SAndroid Build Coastguard Worker
3103*635a8641SAndroid Build Coastguard Worker    # Validate the parser information
3104*635a8641SAndroid Build Coastguard Worker    if pinfo.validate_all():
3105*635a8641SAndroid Build Coastguard Worker        raise YaccError("Unable to build parser")
3106*635a8641SAndroid Build Coastguard Worker
3107*635a8641SAndroid Build Coastguard Worker    if not pinfo.error_func:
3108*635a8641SAndroid Build Coastguard Worker        errorlog.warning("no p_error() function is defined")
3109*635a8641SAndroid Build Coastguard Worker
3110*635a8641SAndroid Build Coastguard Worker    # Create a grammar object
3111*635a8641SAndroid Build Coastguard Worker    grammar = Grammar(pinfo.tokens)
3112*635a8641SAndroid Build Coastguard Worker
3113*635a8641SAndroid Build Coastguard Worker    # Set precedence level for terminals
3114*635a8641SAndroid Build Coastguard Worker    for term, assoc, level in pinfo.preclist:
3115*635a8641SAndroid Build Coastguard Worker        try:
3116*635a8641SAndroid Build Coastguard Worker            grammar.set_precedence(term,assoc,level)
3117*635a8641SAndroid Build Coastguard Worker        except GrammarError:
3118*635a8641SAndroid Build Coastguard Worker            e = sys.exc_info()[1]
3119*635a8641SAndroid Build Coastguard Worker            errorlog.warning("%s",str(e))
3120*635a8641SAndroid Build Coastguard Worker
3121*635a8641SAndroid Build Coastguard Worker    # Add productions to the grammar
3122*635a8641SAndroid Build Coastguard Worker    for funcname, gram in pinfo.grammar:
3123*635a8641SAndroid Build Coastguard Worker        file, line, prodname, syms = gram
3124*635a8641SAndroid Build Coastguard Worker        try:
3125*635a8641SAndroid Build Coastguard Worker            grammar.add_production(prodname,syms,funcname,file,line)
3126*635a8641SAndroid Build Coastguard Worker        except GrammarError:
3127*635a8641SAndroid Build Coastguard Worker            e = sys.exc_info()[1]
3128*635a8641SAndroid Build Coastguard Worker            errorlog.error("%s",str(e))
3129*635a8641SAndroid Build Coastguard Worker            errors = 1
3130*635a8641SAndroid Build Coastguard Worker
3131*635a8641SAndroid Build Coastguard Worker    # Set the grammar start symbols
3132*635a8641SAndroid Build Coastguard Worker    try:
3133*635a8641SAndroid Build Coastguard Worker        if start is None:
3134*635a8641SAndroid Build Coastguard Worker            grammar.set_start(pinfo.start)
3135*635a8641SAndroid Build Coastguard Worker        else:
3136*635a8641SAndroid Build Coastguard Worker            grammar.set_start(start)
3137*635a8641SAndroid Build Coastguard Worker    except GrammarError:
3138*635a8641SAndroid Build Coastguard Worker        e = sys.exc_info()[1]
3139*635a8641SAndroid Build Coastguard Worker        errorlog.error(str(e))
3140*635a8641SAndroid Build Coastguard Worker        errors = 1
3141*635a8641SAndroid Build Coastguard Worker
3142*635a8641SAndroid Build Coastguard Worker    if errors:
3143*635a8641SAndroid Build Coastguard Worker        raise YaccError("Unable to build parser")
3144*635a8641SAndroid Build Coastguard Worker
3145*635a8641SAndroid Build Coastguard Worker    # Verify the grammar structure
3146*635a8641SAndroid Build Coastguard Worker    undefined_symbols = grammar.undefined_symbols()
3147*635a8641SAndroid Build Coastguard Worker    for sym, prod in undefined_symbols:
3148*635a8641SAndroid Build Coastguard Worker        errorlog.error("%s:%d: Symbol '%s' used, but not defined as a token or a rule",prod.file,prod.line,sym)
3149*635a8641SAndroid Build Coastguard Worker        errors = 1
3150*635a8641SAndroid Build Coastguard Worker
3151*635a8641SAndroid Build Coastguard Worker    unused_terminals = grammar.unused_terminals()
3152*635a8641SAndroid Build Coastguard Worker    if unused_terminals:
3153*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3154*635a8641SAndroid Build Coastguard Worker        debuglog.info("Unused terminals:")
3155*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3156*635a8641SAndroid Build Coastguard Worker        for term in unused_terminals:
3157*635a8641SAndroid Build Coastguard Worker            errorlog.warning("Token '%s' defined, but not used", term)
3158*635a8641SAndroid Build Coastguard Worker            debuglog.info("    %s", term)
3159*635a8641SAndroid Build Coastguard Worker
3160*635a8641SAndroid Build Coastguard Worker    # Print out all productions to the debug log
3161*635a8641SAndroid Build Coastguard Worker    if debug:
3162*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3163*635a8641SAndroid Build Coastguard Worker        debuglog.info("Grammar")
3164*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3165*635a8641SAndroid Build Coastguard Worker        for n,p in enumerate(grammar.Productions):
3166*635a8641SAndroid Build Coastguard Worker            debuglog.info("Rule %-5d %s", n, p)
3167*635a8641SAndroid Build Coastguard Worker
3168*635a8641SAndroid Build Coastguard Worker    # Find unused non-terminals
3169*635a8641SAndroid Build Coastguard Worker    unused_rules = grammar.unused_rules()
3170*635a8641SAndroid Build Coastguard Worker    for prod in unused_rules:
3171*635a8641SAndroid Build Coastguard Worker        errorlog.warning("%s:%d: Rule '%s' defined, but not used", prod.file, prod.line, prod.name)
3172*635a8641SAndroid Build Coastguard Worker
3173*635a8641SAndroid Build Coastguard Worker    if len(unused_terminals) == 1:
3174*635a8641SAndroid Build Coastguard Worker        errorlog.warning("There is 1 unused token")
3175*635a8641SAndroid Build Coastguard Worker    if len(unused_terminals) > 1:
3176*635a8641SAndroid Build Coastguard Worker        errorlog.warning("There are %d unused tokens", len(unused_terminals))
3177*635a8641SAndroid Build Coastguard Worker
3178*635a8641SAndroid Build Coastguard Worker    if len(unused_rules) == 1:
3179*635a8641SAndroid Build Coastguard Worker        errorlog.warning("There is 1 unused rule")
3180*635a8641SAndroid Build Coastguard Worker    if len(unused_rules) > 1:
3181*635a8641SAndroid Build Coastguard Worker        errorlog.warning("There are %d unused rules", len(unused_rules))
3182*635a8641SAndroid Build Coastguard Worker
3183*635a8641SAndroid Build Coastguard Worker    if debug:
3184*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3185*635a8641SAndroid Build Coastguard Worker        debuglog.info("Terminals, with rules where they appear")
3186*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3187*635a8641SAndroid Build Coastguard Worker        terms = list(grammar.Terminals)
3188*635a8641SAndroid Build Coastguard Worker        terms.sort()
3189*635a8641SAndroid Build Coastguard Worker        for term in terms:
3190*635a8641SAndroid Build Coastguard Worker            debuglog.info("%-20s : %s", term, " ".join([str(s) for s in grammar.Terminals[term]]))
3191*635a8641SAndroid Build Coastguard Worker
3192*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3193*635a8641SAndroid Build Coastguard Worker        debuglog.info("Nonterminals, with rules where they appear")
3194*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3195*635a8641SAndroid Build Coastguard Worker        nonterms = list(grammar.Nonterminals)
3196*635a8641SAndroid Build Coastguard Worker        nonterms.sort()
3197*635a8641SAndroid Build Coastguard Worker        for nonterm in nonterms:
3198*635a8641SAndroid Build Coastguard Worker            debuglog.info("%-20s : %s", nonterm, " ".join([str(s) for s in grammar.Nonterminals[nonterm]]))
3199*635a8641SAndroid Build Coastguard Worker        debuglog.info("")
3200*635a8641SAndroid Build Coastguard Worker
3201*635a8641SAndroid Build Coastguard Worker    if check_recursion:
3202*635a8641SAndroid Build Coastguard Worker        unreachable = grammar.find_unreachable()
3203*635a8641SAndroid Build Coastguard Worker        for u in unreachable:
3204*635a8641SAndroid Build Coastguard Worker            errorlog.warning("Symbol '%s' is unreachable",u)
3205*635a8641SAndroid Build Coastguard Worker
3206*635a8641SAndroid Build Coastguard Worker        infinite = grammar.infinite_cycles()
3207*635a8641SAndroid Build Coastguard Worker        for inf in infinite:
3208*635a8641SAndroid Build Coastguard Worker            errorlog.error("Infinite recursion detected for symbol '%s'", inf)
3209*635a8641SAndroid Build Coastguard Worker            errors = 1
3210*635a8641SAndroid Build Coastguard Worker
3211*635a8641SAndroid Build Coastguard Worker    unused_prec = grammar.unused_precedence()
3212*635a8641SAndroid Build Coastguard Worker    for term, assoc in unused_prec:
3213*635a8641SAndroid Build Coastguard Worker        errorlog.error("Precedence rule '%s' defined for unknown symbol '%s'", assoc, term)
3214*635a8641SAndroid Build Coastguard Worker        errors = 1
3215*635a8641SAndroid Build Coastguard Worker
3216*635a8641SAndroid Build Coastguard Worker    if errors:
3217*635a8641SAndroid Build Coastguard Worker        raise YaccError("Unable to build parser")
3218*635a8641SAndroid Build Coastguard Worker
3219*635a8641SAndroid Build Coastguard Worker    # Run the LRGeneratedTable on the grammar
3220*635a8641SAndroid Build Coastguard Worker    if debug:
3221*635a8641SAndroid Build Coastguard Worker        errorlog.debug("Generating %s tables", method)
3222*635a8641SAndroid Build Coastguard Worker
3223*635a8641SAndroid Build Coastguard Worker    lr = LRGeneratedTable(grammar,method,debuglog)
3224*635a8641SAndroid Build Coastguard Worker
3225*635a8641SAndroid Build Coastguard Worker    if debug:
3226*635a8641SAndroid Build Coastguard Worker        num_sr = len(lr.sr_conflicts)
3227*635a8641SAndroid Build Coastguard Worker
3228*635a8641SAndroid Build Coastguard Worker        # Report shift/reduce and reduce/reduce conflicts
3229*635a8641SAndroid Build Coastguard Worker        if num_sr == 1:
3230*635a8641SAndroid Build Coastguard Worker            errorlog.warning("1 shift/reduce conflict")
3231*635a8641SAndroid Build Coastguard Worker        elif num_sr > 1:
3232*635a8641SAndroid Build Coastguard Worker            errorlog.warning("%d shift/reduce conflicts", num_sr)
3233*635a8641SAndroid Build Coastguard Worker
3234*635a8641SAndroid Build Coastguard Worker        num_rr = len(lr.rr_conflicts)
3235*635a8641SAndroid Build Coastguard Worker        if num_rr == 1:
3236*635a8641SAndroid Build Coastguard Worker            errorlog.warning("1 reduce/reduce conflict")
3237*635a8641SAndroid Build Coastguard Worker        elif num_rr > 1:
3238*635a8641SAndroid Build Coastguard Worker            errorlog.warning("%d reduce/reduce conflicts", num_rr)
3239*635a8641SAndroid Build Coastguard Worker
3240*635a8641SAndroid Build Coastguard Worker    # Write out conflicts to the output file
3241*635a8641SAndroid Build Coastguard Worker    if debug and (lr.sr_conflicts or lr.rr_conflicts):
3242*635a8641SAndroid Build Coastguard Worker        debuglog.warning("")
3243*635a8641SAndroid Build Coastguard Worker        debuglog.warning("Conflicts:")
3244*635a8641SAndroid Build Coastguard Worker        debuglog.warning("")
3245*635a8641SAndroid Build Coastguard Worker
3246*635a8641SAndroid Build Coastguard Worker        for state, tok, resolution in lr.sr_conflicts:
3247*635a8641SAndroid Build Coastguard Worker            debuglog.warning("shift/reduce conflict for %s in state %d resolved as %s",  tok, state, resolution)
3248*635a8641SAndroid Build Coastguard Worker
3249*635a8641SAndroid Build Coastguard Worker        already_reported = {}
3250*635a8641SAndroid Build Coastguard Worker        for state, rule, rejected in lr.rr_conflicts:
3251*635a8641SAndroid Build Coastguard Worker            if (state,id(rule),id(rejected)) in already_reported:
3252*635a8641SAndroid Build Coastguard Worker                continue
3253*635a8641SAndroid Build Coastguard Worker            debuglog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule)
3254*635a8641SAndroid Build Coastguard Worker            debuglog.warning("rejected rule (%s) in state %d", rejected,state)
3255*635a8641SAndroid Build Coastguard Worker            errorlog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule)
3256*635a8641SAndroid Build Coastguard Worker            errorlog.warning("rejected rule (%s) in state %d", rejected, state)
3257*635a8641SAndroid Build Coastguard Worker            already_reported[state,id(rule),id(rejected)] = 1
3258*635a8641SAndroid Build Coastguard Worker
3259*635a8641SAndroid Build Coastguard Worker        warned_never = []
3260*635a8641SAndroid Build Coastguard Worker        for state, rule, rejected in lr.rr_conflicts:
3261*635a8641SAndroid Build Coastguard Worker            if not rejected.reduced and (rejected not in warned_never):
3262*635a8641SAndroid Build Coastguard Worker                debuglog.warning("Rule (%s) is never reduced", rejected)
3263*635a8641SAndroid Build Coastguard Worker                errorlog.warning("Rule (%s) is never reduced", rejected)
3264*635a8641SAndroid Build Coastguard Worker                warned_never.append(rejected)
3265*635a8641SAndroid Build Coastguard Worker
3266*635a8641SAndroid Build Coastguard Worker    # Write the table file if requested
3267*635a8641SAndroid Build Coastguard Worker    if write_tables:
3268*635a8641SAndroid Build Coastguard Worker        lr.write_table(tabmodule,outputdir,signature)
3269*635a8641SAndroid Build Coastguard Worker
3270*635a8641SAndroid Build Coastguard Worker    # Write a pickled version of the tables
3271*635a8641SAndroid Build Coastguard Worker    if picklefile:
3272*635a8641SAndroid Build Coastguard Worker        lr.pickle_table(picklefile,signature)
3273*635a8641SAndroid Build Coastguard Worker
3274*635a8641SAndroid Build Coastguard Worker    # Build the parser
3275*635a8641SAndroid Build Coastguard Worker    lr.bind_callables(pinfo.pdict)
3276*635a8641SAndroid Build Coastguard Worker    parser = LRParser(lr,pinfo.error_func)
3277*635a8641SAndroid Build Coastguard Worker
3278*635a8641SAndroid Build Coastguard Worker    parse = parser.parse
3279*635a8641SAndroid Build Coastguard Worker    return parser
3280