AFAIK使Python源代码词汇化的技术是:


当当前行的缩进级别小于前一行的缩进级别时,生成DEDENT。如果要关闭多个INDENT,则产生多个DEDENT。
当输入结束时,如果未关闭INDENT,则产生DEDENT。


现在,使用PLY:


如何从t_definition返回多个令牌?
到达EOF时如何调用t_definition?简单的\Z不起作用-PLY抱怨它匹配空字符串。

最佳答案

据我所知,PLY没有实现推送解析器接口,这是您最容易用bison解决此问题的方法。但是,注入自己的词法分析器包装器很容易,它可以处理dedent令牌队列。

最少的词法分析器实现需要实现一个token()方法,该方法返回具有typevalue属性的对象。 (如果您的解析器使用它,则也需要它,但是我在这里不必担心。)

现在,让我们假设基础的(PLY生成的)词法分析器生成NEWLINE标记,其值是换行符后的前导空格的长度。如果某些行不参与INDENT / DEDENT算法,则应针对这些行取消NEWLINE;我们在这里不考虑这种情况。 lexer函数的一个简单示例(仅适用于空格,不适用于制表符)可能是:

# This function doesn't handle tabs. Beware!
def t_NEWLINE(self, t):
  r'\n(?:\s*(?:[#].*)?\n)*\s*'
  t.value = len(t.value) - 1 - t.value.rfind('\n')
  return t


现在,我们用处理缩进的包装器包装PLY生成的词法分析器:

# WARNING:
# This code hasn't been tested much and it also may be inefficient
# and/or inexact. It doesn't do python-style tab handling. Etc. etc.

from collections import namedtuple, deque

# These are the tokens. We only generate one of each here. If
# we used lineno or didn't trust the parser to not mess with the
# token, we could generate a new one each time.
IndentToken = namedtuple('Token', 'type value')
dedent = IndentToken('DEDENT', None)
indent = IndentToken('INDENT', None)
newline= IndentToken('NEWLINE', None)

class IndentWrapper(object):

  def __init__(self, lexer):
    """Create a new wrapper given the lexer which is being wrapped"""
    self.lexer = lexer
    self.indent_stack = [0]
    # A queue is overkill for this case, but it's simple.
    self.token_queue = deque()
    # This is just in case the ply-generated lexer cannot be called again
    # after it returns None.
    self.eof_reached = False

  def token(self):
    """Return the next token, or None if end of input has been reached"""
    # Do we have any queued tokens?
    if self.token_queue:
      return self.token_queue.popleft()
    # Are we done?
    if self.eof_reached:
      return None
    # Get a token
    t = self.lexer.token()
    if t is None:
      # At end of input, we might need to send some dedents
      self.eof_reached = True
      if len(self.indent_stack) > 1:
        t = dedent
        for i in range(len(self.indent_stack) - 1):
          self.token_queue.append(dedent)
        self.indent_stack = [0]
    elif t.type == "NEWLINE":
      # The NEWLINE token includes the amount of leading whitespace.
      # Fabricate indent or dedents as/if necessary and queue them.
      if t.value > self.indent_stack[-1]:
        self.indent_stack.append(t.value)
        self.token_queue.append(indent)
      else:
        while t.value < self.indent_stack[-1]:
          self.indent_stack.pop()
          self.token_queue.append(dedent)
        if t.value != self.indent_stack[-1]:
          raise IndentError # Or however you indicate errors
    return t

关于python - PLY-返回多个 token ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28259366/

10-12 16:54