2016-12-04 75 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之前存在的數量的位置。