~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to third_party/ply/ply/yacc.py

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

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