2016-12-04 70 views
0

我正在阅读关于lexical analysis of python的文档,其中描述了如何生成INDENT和DEDENT标记。我在此处发布说明。Python中如何生成DEDENT标记?

连续行的缩进级别用于使用堆栈生成INDENT和DEDENT标记,如下所示。

在读取文件的第一行之前,单个零被压入堆栈;这将永远不会再弹出。推入堆栈的数字总是从下到上严格递增。在每条逻辑行的开始处,将行的缩进级别与堆栈的顶部进行比较。如果相等,则没有任何反应。如果它较大,则将其压入堆栈,并生成一个INDENT标记。如果它更小,它必须是堆栈中出现的数字之一;堆栈中所有较大的数字都会弹出,并为每个弹出的DEDENT令牌生成一个数字。在文件结尾处,为堆栈上剩余的大于零的每个数字生成一个DEDENT令牌。

我试图了解DEDENT语言部分,但未能,也有人给比引用一个更好的解释?

回答

1

由于Python有时比英语更容易,下面是对Python描述的粗略翻译。您可以看到真实世界的解析器(由我自己编写),其工作方式如下here

import re 
code = """ 
for i in range(10): 
    if i % 2 == 0: 
    print(i) 
    print("Next number") 
print("That's all") 

for i in range(10): 
    if i % 2 == 0: 
     print(i) 
print("That's all again) 

for i in range(10): 
    if i % 2 == 0: 
     print(i) 
    print("That's all") 
""" 
def get_indent(s) -> int: 
    m = re.match(r' *', s) 
    return len(m.group(0)) 
def add_token(token): 
    print(token) 
INDENT="indent" 
DEDENT="dedent" 
indent_stack = [0] 
# Before the first line of the file is read, a single zero is pushed on the stack 
for line in code.splitlines(): 
    print("processing line:", line) 
    indent = get_indent(line) 
    # At the beginning of each logical line, the line’s 
    # indentation level is compared to the top of the stack. 
    if indent > indent_stack[-1]: 
     # If it is larger, it is pushed on the stack, 
     # and one INDENT token is generated. 
     add_token(INDENT) 
     indent_stack.append(indent) 
    elif indent < indent_stack[-1]: 
     while indent < indent_stack[-1]: 
      # If it is smaller, ... 
      # all numbers on the stack that are larger are popped off, 
      # and for each number popped off a DEDENT token is generated. 
      add_token(DEDENT) 
      indent_stack.pop() 
     if indent != indent_stack[-1]: 
      # it must be one of the numbers occurring on the stack; 
      raise IndentationError 
while indent_stack[-1]>0: 
    # At the end of the file, a DEDENT token is generated for each number 
    # remaining on the stack that is larger than zero. 
    add_token(DEDENT) 
    indent_stack.pop() 

这里是输出:

processing line: 
processing line: for i in range(10): 
processing line: if i % 2 == 0: 
indent 
processing line:  print(i) 
indent 
processing line: print("Next number") 
dedent 
processing line: print("That's all") 
dedent 
processing line: 
processing line: for i in range(10): 
processing line: if i % 2 == 0: 
indent 
processing line:  print(i) 
indent 
processing line: print("That's all again) 
dedent 
dedent 
processing line: 
processing line: for i in range(10): 
processing line: if i % 2 == 0: 
indent 
processing line:  print(i) 
indent 
processing line: print("That's all") 
dedent 
dedent 
    File "<string>", line unknown 
IndentationError 
2

假设我们有一个源文件,每个缩进级别使用4个空格,而且我们当前处于缩进的第三个级别。缩进堆栈的内容将是[0, 4, 8, 12]--初始零,加上每次新遇到的缩进级别。现在,考虑前导空格的数量上的下一行代码...

  • 如果是12(匹配堆栈目前上方),没有缩进改变,什么都不会发生。
  • 如果它大于12,则会生成INDENT标记,并将新值添加到堆栈。
  • 如果它是8,则会生成一个DEDENT令牌,并且12个弹出堆栈。
  • 如果它是4,你会得到两个DEDENT,并且12和8都会弹出。
  • 如果它是0,或源文件在这一点结束,你会得到三个DEDENT,并且弹出12,8,4。
  • 如果是小于12的其他值,则会生成“不一致的缩进”错误,因为无法确定您之前缩进的代码级别。

请注意,只有具有实际代码的行才会被考虑 - 如果一行只包含空格或注释,则其前导空间量无关紧要。

此过程的重点在于,只有一个DEDENT被生成以对应于每个INDENT,发生在缩进级别返回(或低于)相应INDENT之前存在的数量的位置。