現在、私はPythonのPythonの非常に小さなサブセットのコンパイラをプログラミングしています。私はすでにシンタックスツリーを構築していましたが、(コードを生成するためには不可欠な)ツリートラバーサルのコーディングに関するいくつかの問題がありました。だから私は、最初にあなたに私のデータ構造を示すと一緒に行くよ:深さ最初にPythonでジェネレータを使用するツリーのトラバーサル
class AbstractSyntaxTree(object):
def __init__(self, startSymbol):
self.root = Node(startSymbol, val=None)
self.nodes = [self.root]
def addNode(self, name, val, parentId):
parent = self.nodes[parentId]
self.nodes.append(Node(name=name, val=val, parent=parent))
return len(self.nodes)-1
def getLastId(self):
return len(self.nodes)-1
def __iter__(self):
for node in self.root:
yield node
これは私のノード定義である:
class Node:
def __init__(self, name, val, parent=None):
self.name = name
self.val = val
self.parent = parent
self.children = []
if parent:
parent.children.append(self)
def __iter__(self):
yield self
for child in self.children:
for node in child:
yield node
私のパーサは全ての文法シンボルが関数呼び出しで再帰下降構文解析であり、他の文法記号。 program
は私のスタートシンボルです。成功し解析した後、私はNode
とAbstractSyntaxTree
で定義された私の__iter__
発電機を使用して第1の深さ、それを繰り返すことによって、構文ツリー内のすべての私のノードを印刷することができるかどう
def program(self, indentLvl=0):
parent = self.synTree.getLastId()
if self.smellAndConsume(TOK.EOF, parentId=parent): return
self.smellAndConsume(TOK.NEWL, parentId=parent)
self.synTree.addNode(name=VAR.statement, val=None, parentId=parent)
self.statement()
while self.accept and not self.isConsumable(TOK.EOF):
self.consume(TOK.NEWL, parentId=parent)
self.synTree.addNode(name=VAR.statement, val=None, parentId=parent)
self.statement()
self.consume(TOK.EOF, parentId=parent)
は今、興味がありました。しかし、
def test_tree_traversal():
for node in miniPyGrammar.synTree:
print(node)
すべてのノードが印刷されません。コードをデバッグすると、私のルートノードに子ノードがありませんでしたが、私はaddNode
とルートノードidを呼び出しました。誰かがここで何が起こっているかの手がかりを持っていますか?
さらに詳しい情報やコードスニペットが必要な場合は、お気軽にお問い合わせください。
編集:(私はまだここで何が起こっている奇妙なことを見つけるが。)私は解決策を見つけたこのコードは、今期待通りに動作します。
def test_tree_traversal(code):
grammar = Grammar()
grammar.parse(code)
for node in grammar.synTree:
print(node)
def execute_tests():
for name, code in programs.items():
parse_test(name, code)
test_tree_traversal(code)
私はグローバル文法オブジェクトとexecute_testsが上の解析呼んでいた前に、その文法、その後、私は文法オブジェクトsynTreeにアクセスするtest_tree_traversalを実行しました。不思議なことに、呼び出しのあいだで、ガベージコレクションはASTのいくつかのノードを削除しました。なぜ私はそれがガベージコレクションだと思いますか?その行動は非決定的であったからです。
編集:これはエラーが発生しやすいコードです: 唯一の違いは、テストを実行する前に新しい文法オブジェクトをインスタンス化することです。文法には'parse 'メソッドがあります。このメソッドは、プログラムが構文的に正しい場合にtrueを返し、Grammar.synTree経由でアクセス可能なASTを作成します。
miniPyGrammar = Grammar()
def parse_test(
programName: str,
programCode: str):
success = miniPyGrammar.parse(programCode)
if success:
print('{} is a valid miniPyProgram :)'.format(programName))
else:
print('{} is not a valid miniPyProgram'.format(programName))
print(miniPyGrammar.synTree)
def tree_traversal(code):
for node in miniPyGrammar.synTree:
print(node)
def execute_tests():
for name, code in programs.items():
parse_test(name, code)
tree_traversal(code)
if __name__ == '__main__':
execute_tests()
私はあなたのコードが適切に記述されていないため、コードの非動作バージョンに関する回答を得るつもりはないと思います。私たちは見ることができないコードのトラブルシューティングはできません! 'for node in miniPyGrammar.synTree:'では、 'miniPyGrammar'とは何ですか、なぜあなたの構文木を保持すると思いますか?あなたのパーサのツリーを壊しているメソッドにバグがないことは確かですか?私たちには1つの方法しか示されていませんでした。私はあなたが示していないメソッドを呼び出しているので、何をしているのか分かりません。あなたの問題を示す[mcve]を作りましょう。 – Blckknght
これは事実ですが、エラーの原因がわからないため、コードのどの部分を表示するのか分かりませんでした。問題はおそらく間違ったイテレータコードから来たと思いました。問題がどこにあったかを指摘する別の編集を作成します。 – drssdinblck