Actuellement, je suis en train de programmer un compilateur pour un très petit sous-ensemble de Python en Python. J'ai déjà réussi à construire un arbre de syntaxe mais j'ai eu quelques problèmes avec le codage de la traversée de l'arbre (qui est essentiel pour générer du code). Je vais d'abord aller de pair avec vous montrer mes structures de données:première traversée d'un arbre en utilisant des générateurs en 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
C'est ma définition de noeud:
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
Mon analyseur est un analyseur de descente récursive, où chaque symbole de grammaire est un appel de fonction autres symboles de grammaire. program
est mon symbole de début.
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)
Il est maintenant était curieux, si après analyse je serais succesful capable d'imprimer tous mes noeuds dans l'arbre de syntaxe par itérer de la profondeur en utilisant d'abord mon générateur __iter__
défini dans Node
et AbstractSyntaxTree
. Mais
def test_tree_traversal():
for node in miniPyGrammar.synTree:
print(node)
n'imprime pas tous les nœuds! Quand j'ai débogué mon code, j'ai réalisé que mon noeud racine n'avait pas d'enfants dans sa liste d'enfants, bien que j'appelle addNode
avec l'ID des noeuds racine. Est-ce que quelqu'un a une idée de ce qui se passe ici?
Si vous avez besoin de plus d'informations ou de plus d'extraits de code, n'hésitez pas à demander.
edit: je viens de trouver la solution (bien que je trouve toujours bizarre ce qui se passe ici.) Ce code se comporte maintenant comme prévu:
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)
Avant d'avoir un objet global grammaire et execute_tests appellerais analyser le cette grammaire, après quoi j'ai exécuté test_tree_traversal, qui accède à l'objet grammar-synTree. Bizarrement, entre les appels, la collecte des ordures supprimait certains nœuds de l'AST. Pourquoi je suppose que c'est la collecte des ordures? Parce que le comportement était non déterministe.
edit: c'était le code sujette aux erreurs: notez que la seule différence est que j'instancie un nouvel objet de grammaire avant d'exécuter un test. La grammaire a une méthode'parse 'qui renvoie true si le programme est syntaxiquement correct et construit un AST qui est accessible via Grammar.synTree.
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()
Je ne pense pas que vous obtiendrez une réponse à propos de la version non fonctionnelle de votre code, parce que vous ne l'avez pas décrit correctement. Nous ne pouvons pas résoudre le code que nous ne pouvons pas voir! Dans 'pour node in miniPyGrammar.synTree:', qu'est ce que 'miniPyGrammar' et pourquoi attendez-vous qu'il contienne votre arbre de syntaxe? Êtes-vous sûr qu'il n'y a pas de bogues dans les méthodes de votre analyseur qui brisent l'arbre? Vous nous avez seulement montré une méthode, et je ne comprends pas la moitié de ce qu'elle fait puisqu'elle appelle des méthodes que vous n'avez pas montrées. Essayez de faire un [mcve] qui démontre votre problème. – Blckknght
Oui, c'est un peu vrai, mais parce que je ne savais pas d'où venait l'erreur, je ne savais pas quelles parties de mon code montrer. Je pensais que le problème venait probablement du mauvais code de l'itérateur. Je vais créer une autre édition pour indiquer où était le problème avant. – drssdinblck