2016-12-04 8 views
0

私はlexical analysis of pythonについてのドキュメントを読んでいます。これは、どのようにインデントとデートントトークンが生成されるかを説明しています。ここにその説明を掲載します。DEDENTトークンはどのように正確に生成されますか?

次のように、スタックを使用して、インデントおよびDEDENTトークンを生成するために連続する行のインデントレベルが使用されます。

ファイルの最初の行が読み取られる前に、1つのゼロがスタックにプッシュされます。これは決して再び現れないでしょう。スタックにプッシュされる数値は、常に下から上へと厳密に増加します。各論理行の先頭で、行のインデントレベルがスタックの先頭と比較されます。等しい場合、何も起こりません。大きい場合はスタックにプッシュされ、1つのインデントトークンが生成されます。小さい場合は、スタック上にある数字の1つでなければなりません。より大きいスタック上のすべての数字がポップオフされ、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つのスペースを使用し、現在インデントの3番目のレベルにあるソースファイルがあるとします。インデントスタックの内容は、最初のゼロと最初に遭遇したときのそれぞれのインデントレベルに加えて、[0, 4, 8, 12]になります。今度は、次のコード行の先頭のスペース数を考えてみましょう。

  • 12(現在のスタックの最上部に一致)の場合、インデントの変更はありません。何も特別なことはありません。
  • 12より大きい値の場合、INDENTトークンが生成され、新しい値がスタックに追加されます。
  • 8の場合、1つのDEDENTトークンが生成され、12がスタックからポップされます。
  • 4の場合、2つのDEDENTが得られ、12と8の両方がポップされます。
  • 0の場合、またはこの時点でソースファイルが終了すると、3つのDEDENTが取得され、12,8,4がポップされます。
  • 12より小さい場合は、前回のレベルのコードを書き留めておくことは不可能なため、「一貫性のないインデント」エラーが生成されます。

実際のコードの行のみが考慮されることに注意してください。行に空白またはコメントのみが含まれている場合、先頭のスペースの量は関係ありません。

このプロセスのポイントは、インデントレベルが対応するインデントの前に存在する量に戻る(または下回る)ポイントで発生する、各インデントに対応するDEDENTが正確に生成されることです。

関連する問題