9
votes

TRAVERSAL AST dans le visiteur ou dans les nœuds?

mise à jour forte> acceptée la réponse de l'IRA Baxter, car il m'a pointé dans la bonne direction: j'ai d'abord compris ce que j'avais réellement besoin en démarrant la mise en œuvre du stade de la compilation, et il est devenu évident très bientôt que Traversal dans l'intérieur Les nœuds ont fait une approche impossible. Tous les nœuds ne doivent pas être visités, et certains d'entre eux dans l'ordre inverse (par exemple, d'abord le RHS d'une affectation afin que le compilateur puisse vérifier si le type correspond au rhs / opérateur). Mettre la traversée dans le visiteur rend tout cela très facile.

Je joue avec des asts et des goûts avant de décider d'un refacteur majeur de la manipulation d'une mini-langage utilisée dans une requérante. J'ai construit un lexer / analyseur et je peux obtenir l'Ast très bien. Il y a aussi un visiteur et comme une mise en œuvre concrète que j'ai faite un asttoachiginal qui recaisse simplement le fichier source d'origine. Finalement, il y a une sorte de compilateur qui implémente également le vSisiteur et crée le code C ++ réel au moment de l'exécution afin que je souhaite que tout soit dès le début. Bien que tout fonctionne bien maintenant, il existe un code similaire / dupliqué car l'ordre parcouru est mis en œuvre dans le visiteur lui-même. P>

Lorsque vous recherchez plus d'informations, il semble que certaines implémentations préfèrent garder l'ordre de traversée dans les visités. objets eux-mêmes plutôt, afin de ne pas répéter cela dans chaque visiteur concret. Même le GOF ne parle que brièvement à ce sujet, de la même manière. Donc, je voulais donner à cette approche un essai aussi mais j'ai été coincé assez bientôt .. Laissez-moi vous expliquer. P>

Ligne source d'échantillons et nœuds AST correspondants: P>

class BinaryOp {
  void Accept( Conditional* v ) { 
    v->Visit( this );
    op->Accept( v )
    VisitList( ifTrue, v );
    VisitList( ifFalse, v );
};
class Vistor {
  //now all methods are pure virtual
};
class ASTToOriginal {
  void Visit( Conditional* p ) {
    str << "if(";
    //now what??? after returning here, BinaryOp will visit the op automatically so I can't insert the "?"
    //If I make a PostVisit( BinaryOp* ), and call it it BinaryOp::Accept, I get the chance to insert the "?",
    //but now I have to keep a state: my PostVisit method needs to know it's currently being called as part of a Conditional
    //Things are even worse for the ifTrue/ifFalse statement arrays: each element needs a ";" appended, but not the last one,
    //how am I ever going to do that in a clean way?
  }
};


0 commentaires

3 Réponses :


0
votes

imo, j'aurais chaque classe de béton (par exemple Binaryop, variable) étendre la classe des visiteurs. De cette façon, toute la logique nécessaire pour créer un objet BinyOP réside dans la classe Binyop. Cette approche est similaire à celle de modèle Walkabout . Cela peut faciliter votre tâche.


4 commentaires

Cela ne détruirait-il pas totalement tout le concept du modèle de visiteur? En outre, le visiteur n'a rien à voir avec la création d'objets. Je pense que vous avez complètement mal compris la question.


Merci pour le commentaire. En réfléchissant au problème, il semblait plus facile d'utiliser un modèle Walkabout. J'ai mis à jour ma réponse en conséquence.


Il semble que la performance du modèle Walkabout est terrible. Les visiteurs ne sont pas parfaits, mais ils résolvent la "localité des définitions", ce qui aurait beaucoup mieux été résolu en premier lieu en utilisant une langue Langue fonctionnelle et correspondant .


@STIJN: Je pense que cela pourrait être fait en mettant des champs membres dans une liste ou un autre type de structure de données dans la classe. Cependant, cela semble une solution où "quand tout ce que j'ai est un marteau, tout ressemble à un clou". Donc, ce ne serait probablement pas un bon ajustement pour une solution C ++.



1
votes

Pour la traversée générique récursive des arbres, les visiteurs et composites sont généralement utilisés ensemble, comme dans (le premier lien Google pertinent) . J'ai d'abord lu sur cette idée là-bas . Il y a aussi Combinateurs de visiteurs qui sont une bonne idée.

et au fait ...

C'est ici que les langues fonctionnelles brillent, avec leurs types de données algébriques et leur correspondance de motif. Si vous le pouvez, passez à une langue fonctionnelle. Les composites et les visiteurs ne sont que des solutions de contournement laids pour le manque de soutien linguistique pour l'adt et la correspondance des motifs respectivement.


0 commentaires

6
votes

Il y a deux problèmes:

  • Quels nœuds pour enfants sont possibles de visiter?
  • De quel ordre devriez-vous vous rendre visite?

    sans doute les nœuds d'enfants réels doivent être connus par type de noeud; En fait, il devrait être connu de la grammaire et "reflété" de la grammaire dans le visiteur général.

    L'ordre dans lequel les nœuds sont visités dépendent complètement de ce que vous devez faire. Si vous faites attention, une commande d'enfant gauche à droite est logique (si les nœuds pour enfants sont répertoriés dans l'ordre de la grammaire, ce qu'ils pourraient ne pas être). Si vous construisez des tables de symboles, vous voulez sûrement visiter les enfants de la Déclaration avant de visiter l'enfance du corps de la déclaration.

    En outre, vous devez vous inquiéter de quelles informations circule vers le haut ou le bas de l'arborescence. Un accès à la liste de variable déboucherait l'arborescence. Une table de symboles construite évolue l'arbre des déclarations et recule dans l'enfant de la déclaration. Et ce flux d'informations force l'ordre de visite; Pour avoir une table de symboles à transmettre dans le corps de la déclaration, vous devez d'abord avoir une table de symboles construit et transmise de l'enfant déclarations.

    Je pense que ces problèmes sont ceux qui vous donnent à Greif. Vous essayez d'imposer une seule structure sur vos visiteurs, lorsque l'ordre de visite est totalement dépendant de la tâche et qu'il y a beaucoup de tâches différentes que vous pourriez faire avec un arbre, chacun avec son propre flux d'informations et donc de la dépendance des commandes.

    L'une des façons que ceci est résolu est avec la notion d'un attribut (d) grammaire (AG ) , dans lequel on décore les règles de grammaire avec différents types d'attributs et comment ils sont calculés / utilisés. Vous écrivez littéralement un calcul comme une annotation à la règle de la grammaire, par exemple: xxx

    La règle de grammaire vous indique quels types de noeuds que vous devez avoir. Le calcul Atrribute vous indique quelle valeur est transmise à l'arborescence (référence à la méthode.SyMboltable consiste à former le parent), à l'arborescence (référence à déclarations.symbols est à quelque chose de calculé par cet enfant), ou à travers le Arbre (déclarations.SYMBoltable est transmis à l'enfant des déclarations, de la valeur calculée par déclarations.symboltables). Le calcul d'attribut définit le visiteur. Le calcul exécuté est une "évaluation d'attribut" appelée "

    Cette notation pour cette grammaire d'attribut particulière fait partie de notre Toolkit de réengagement logiciel DMS . D'autres outils AG utilisent des notations similaires. Comme tous les schémas (AG), la règle particulière est utilisée pour fabriquer le visiteur spécifique ("résolvols") spécifique à des fins pour le nœud spécifique ("méthode"). Avec un ensemble de telles spécifications pour chaque nœud, vous obtenez un ensemble de visiteurs spécifiques à des fins pouvant être exécutés. La valeur d'un schéma AG est que vous pouvez écrire cela facilement et que tout le gunk de la chaudière est généré.

    Vous pouvez penser à votre problème dans le résumé comme celui-ci, puis générer simplement les visiteurs spécifiques à des fins. la main, comme vous l'avez fait.


2 commentaires

Pour répondre à vos questions: tous les nœuds devraient être visités, mais ce n'est pas encore clair pour moi dans quel ordre, car je ne suis pas sûr que je ne suis pas sûr de ce que je vais faire avec l'AST exactement. Peut-être que pour cette raison seul, je devrais rester avec l'ordre dans le visiteur pour l'instant. Au moins, je peux plus tard, sans avoir à modifier un nœud, change toujours d'ordre.


@Puchacz Oui Voir la mise à jour que j'ai ajoutée à la question elle-même