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