# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.# Licensed to PSF under a Contributor Agreement."""Parser engine for the grammar tables generated by pgen.The grammar table must be loaded first.See Parser/parser.c in the Python distribution for additional info onhow this parsing engine works."""# Local importsfrom . import tokenclass ParseError(Exception):"""Exception to signal the parser is stuck."""def __init__(self, msg, type, value, context):Exception.__init__(self, "%s: type=%r, value=%r, context=%r" %(msg, type, value, context))self.msg = msgself.type = typeself.value = valueself.context = contextclass Parser(object):"""Parser engine.The proper usage sequence is:p = Parser(grammar, [converter]) # create instancep.setup([start]) # prepare for parsing<for each input token>:if p.addtoken(...): # parse a token; may raise ParseErrorbreakroot = p.rootnode # root of abstract syntax treeA Parser instance may be reused by calling setup() repeatedly.A Parser instance contains state pertaining to the current tokensequence, and should not be used concurrently by different threadsto parse separate token sequences.See driver.py for how to get input tokens by tokenizing a file orstring.Parsing is complete when addtoken() returns True; the root of theabstract syntax tree can then be retrieved from the rootnodeinstance variable. When a syntax error occurs, addtoken() raisesthe ParseError exception. There is no error recovery; the parsercannot be used after a syntax error was reported (but it can bereinitialized by calling setup())."""def __init__(self, grammar, convert=None):"""Constructor.The grammar argument is a grammar.Grammar instance; see thegrammar module for more information.The parser is not ready yet for parsing; you must call thesetup() method to get it started.The optional convert argument is a function mapping concretesyntax tree nodes to abstract syntax tree nodes. If notgiven, no conversion is done and the syntax tree produced isthe concrete syntax tree. If given, it must be a function oftwo arguments, the first being the grammar (a grammar.Grammarinstance), and the second being the concrete syntax tree nodeto be converted. The syntax tree is converted from the bottomup.A concrete syntax tree node is a (type, value, context, nodes)tuple, where type is the node type (a token or symbol number),value is None for symbols and a string for tokens, context isNone or an opaque value used for error reporting (typically a(lineno, offset) pair), and nodes is a list of children forsymbols, and None for tokens.An abstract syntax tree node may be anything; this is entirelyup to the converter function."""self.grammar = grammarself.convert = convert or (lambda grammar, node: node)def setup(self, start=None):"""Prepare for parsing.This *must* be called before starting to parse.The optional argument is an alternative start symbol; itdefaults to the grammar's start symbol.You can use a Parser instance to parse any number of programs;each time you call setup() the parser is reset to an initialstate determined by the (implicit or explicit) start symbol."""if start is None:start = self.grammar.start# Each stack entry is a tuple: (dfa, state, node).# A node is a tuple: (type, value, context, children),# where children is a list of nodes or None, and context may be None.newnode = (start, None, None, [])stackentry = (self.grammar.dfas[start], 0, newnode)self.stack = [stackentry]self.rootnode = Noneself.used_names = set() # Aliased to self.rootnode.used_names in pop()def addtoken(self, type, value, context):"""Add a token; return True iff this is the end of the program."""# Map from token to labelilabel = self.classify(type, value, context)# Loop until the token is shifted; may raise exceptionswhile True:dfa, state, node = self.stack[-1]states, first = dfaarcs = states[state]# Look for a state with this labelfor i, newstate in arcs:t, v = self.grammar.labels[i]if ilabel == i:# Look it up in the list of labelsassert t < 256# Shift a token; we're done with itself.shift(type, value, newstate, context)# Pop while we are in an accept-only statestate = newstatewhile states[state] == [(0, state)]:self.pop()if not self.stack:# Done parsing!return Truedfa, state, node = self.stack[-1]states, first = dfa# Done with this tokenreturn Falseelif t >= 256:# See if it's a symbol and if we're in its first setitsdfa = self.grammar.dfas[t]itsstates, itsfirst = itsdfaif ilabel in itsfirst:# Push a symbolself.push(t, self.grammar.dfas[t], newstate, context)break # To continue the outer while loopelse:if (0, state) in arcs:# An accepting state, pop it and try something elseself.pop()if not self.stack:# Done parsing, but another token is inputraise ParseError("too much input",type, value, context)else:# No success finding a transitionraise ParseError("bad input", type, value, context)def classify(self, type, value, context):"""Turn a token into a label. (Internal)"""if type == token.NAME:# Keep a listing of all used namesself.used_names.add(value)# Check for reserved wordsilabel = self.grammar.keywords.get(value)if ilabel is not None:return ilabelilabel = self.grammar.tokens.get(type)if ilabel is None:raise ParseError("bad token", type, value, context)return ilabeldef shift(self, type, value, newstate, context):"""Shift a token. (Internal)"""dfa, state, node = self.stack[-1]newnode = (type, value, context, None)newnode = self.convert(self.grammar, newnode)if newnode is not None:node[-1].append(newnode)self.stack[-1] = (dfa, newstate, node)def push(self, type, newdfa, newstate, context):"""Push a nonterminal. (Internal)"""dfa, state, node = self.stack[-1]newnode = (type, None, context, [])self.stack[-1] = (dfa, newstate, node)self.stack.append((newdfa, 0, newnode))def pop(self):"""Pop a nonterminal. (Internal)"""popdfa, popstate, popnode = self.stack.pop()newnode = self.convert(self.grammar, popnode)if newnode is not None:if self.stack:dfa, state, node = self.stack[-1]node[-1].append(newnode)else:self.rootnode = newnodeself.rootnode.used_names = self.used_names
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。