linkchecker/PyLR/Parser.py
2000-02-28 13:44:24 +00:00

75 lines
2.5 KiB
Python

__version__ = "$Id$"
import PyLRengine
class Parser:
def __init__(self, lexer, actiontable, gototable, prodinfo):
self.lexer = lexer
self.actions = actiontable
self.gotos = gototable
# get the function from the function name
# if we forgot to supply a function we get an AttributeError here
try: self.prodinfo = map(lambda x,s=self: (x[0], getattr(s, x[1]), x[2]),
prodinfo)
except AttributeError:
sys.stderr.write("Parser: error: forgot to supply a parser function\n")
raise
def unspecified(*args):
"""the unspecified function (the default for all productions)"""
if len(args)>1:
return args[1]
return None
def parse(self, text, verbose=0):
self.lexer.settext(text)
self.engine = PyLRengine.NewEngine(self.prodinfo, self.actions,
self.gotos)
while 1:
tok, val = self.lexer.scan(verbose)
if not self.engine.parse(tok, val):
break
# return final value
return None
def pyparse(self, text, verbose=0):
"""The parse algorithm for an LR-parser.
Written in Python for ease of debugging the parser.
Reference: [Aho,Seti,Ullmann: Compilerbau Teil 1, p. 266]
"""
self.lexer.settext(text)
# push the start state on the stack
stack = [0]
tok, val = self.lexer.scan(verbose)
while 1:
if verbose:
print "\nstack=",stack
state = stack[-1]
if verbose:
print "state=",state
action = self.actions[state][tok]
if verbose:
print "action=",action
if action[0]=='s':
# push the symbol and the new state
stack = stack + [tok, action[1]]
tok, val = self.lexer.scan(verbose)
elif action[0]=='r':
# action[1]-1: compensate previous augmentation
P = self.prodinfo[action[1]-1]
print "P=",P
# reduce P=A->b by popping 2*|b| from the stack
if P[0]:
stack = stack[:-2*P[0]]
goto = self.gotos[stack[-1]][P[2]]
# push A and the goto symbol
stack = stack + [P[2], goto]
if verbose:
print "reduce",P
elif action[0]=='a':
return
else:
print "error"
return