9

// Créer un scanner qui lit le flux d'entrée qui nous a été transmis CSLexer lexer = new CSLexer (new ANTLRFileStream (f)); tokens.TokenSource = lexer;Construire son propre compilateur C# en utilisant ANTLR: Unité de compilation

// Create a parser that reads from the scanner 
CSParser parser = new CSParser(tokens); 

// start parsing at the compilationUnit rule 
CSParser.compilation_unit_return x = parser.compilation_unit(); 
object ast = x.Tree; 

Que puis-je faire avec le x qui est de type compilation_unit_return, pour extraire la racine, ses classes, ses méthodes, etc? Dois-je extraire son adaptateur? Comment je fais ça? Notez que le compilation_unit_return est défini comme tel dans mon CSParser (qui est généré automatiquement par ANTLR):

public class compilation_unit_return : ParserRuleReturnScope 
    { 
     private object tree; 
     override public object Tree 
     { 
      get { return tree; } 
      set { tree = (object) value; } 
     } 
    }; 

Cependant, l'arbre que je reçois est de l'objet de type. Je cours en utilisant le débogueur et a semblé voir qu'il est du type BaseTree. Mais BaseTree est une interface! Je ne sais pas comment cela se rapporte à BaseTree et je ne sais pas comment extraire les détails de cet arbre. Je dois écrire un visiteur qui a visité sa classe, méthode, variables .... La classe ParserRuleReturn s'étend de RuleReturnScope et a un objet start et stop, dont je ne sais pas ce que c'est ... En outre , il y a cette classe TreeVisitor fournie par ANTLR qui semble confuse. Il nécessite un adaptateur pour être passé en paramètre à son constructeur (sinon il utilisera le CommonTreeAdaptor par défaut), c'est pourquoi j'ai demandé à propos de la façon d'obtenir l'adaptateur de l'adaptateur. Et d'autres questions aussi ... Pour l'API, vous pouvez vous référer à http://www.antlr.org/api/CSharp/annotated.html

Maintenant, je suis frappé ici ... Si vous ne savez rien, pls aider. Merci un million.

Répondre

3

Je n'ai jamais travaillé avec ANTLR de C#, mais après votre lien vers API, BaseTree est manifestement pas une interface - c'est un class, et il a des propriétés publiques: Type pour obtenir le type du noeud, Text pour obtenir (Je suppose) le texte source correspondant et Children pour obtenir les nœuds enfants. De quoi d'autre avez-vous besoin pour marcher?

+0

C'est une classe abstraite ... public abstract class BaseTree: ITree – yeeen

+1

Eh bien oui, et pourquoi ça t'arrêterait? Vous avez le nœud racine de l'arbre, dont vous savez qu'il est d'un type qui a toutes les méthodes nécessaires pour récupérer ses enfants (et donc marcher l'arbre à n'importe quelle profondeur). –

-2

Si je devais faire un compilateur C# aujourd'hui, voici ce que je faire essayer comme une première tentative:

  1. Commencez avec la cible ANTLR C# 3 (bien sûr, je suis partial ici - sérieusement, vous pouvez utiliser la cible CSharp2 ou CSharp3).
  2. Obtenez Visual Studio 2010 avec le .NET Framework 4. La clé ici est .NET 4 et c'est doux nouveaux arbres d'expression.
  3. Construire un analyseur syntaxique combiné de base. Mettez aussi peu de logique dans l'analyseur que possible. Il devrait avoir peu d'actions (le cas échéant), et la sortie devrait être une AST non décorée qui peut être parcourue avec LL (1) walker.
  4. Créez une grammaire arborescente pour parcourir l'arborescence et identifier tous les types déclarés. Il devrait également conserver les sous-arbres member_declaration pour une utilisation ultérieure.
  5. Construire un marcheur d'arbre qui marche un seul member_declaration et ajoute le membre au TypeBuilder. Gardez une trace des corps de la méthode, mais ne marchez pas encore profondément.
  6. Construire un marcheur d'arbre qui marche le corps d'une méthode. Génère un Expression<TDelegate> correspondant à la méthode, et utilise la méthode ma propre API (voir Pavel et mes commentaires) pour générer le code IL.

Si vous faites les choses dans cet ordre, lorsque vous êtes enfin l'analyse syntaxique des expressions (corps de méthode, Initialiseur sur le terrain), vous pouvez utiliser les méthodes paramétrées stringlike this one dans la classe Expression pour sauver les membres la résolution de travail.

+0

Malheureusement, 'CompileToMethod' ne peut pas vraiment être utilisé dans ce scénario en raison de ses limitations inhérentes - il n'y a aucun moyen de compiler dans un code une autre méthode que vous générez à côté, et la cible' MethodBuilder' doit être pour une méthode statique seulement. Voir https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=473128 pour plus de détails. –

+0

Nice. Eh bien, alors je commencerais par construire un compilateur 'Expression' qui fonctionnerait dans ces cas, puis j'utiliserais ça à la place. :) Je garderais le compilateur 'Expression' en tant que module indépendant afin qu'il puisse être utilisé avec d'autres projets (et peut-être que je le ferai pour m'amuser de toute façon). –

+0

Peut-être juste pour dévier un peu de mon qn ci-dessus: Je hv le code source pour antlr-3.1.3. N sous le dossier d'exécution, il y a 2 dossiers - CSharp n CSharp3. Depuis que vous avez parlé de CSharp3, vous savez pourquoi il y a 2 dossiers? Cependant l'API fournie en ligne semblait être pour CSharp seulement pas CSharp3, aussi la DLL compilée aussi. Si quelqu'un veut utiliser CSharp3, il doit compiler lui-même les codes? Pour moi, il semble que CSharp3 possède des fonctionnalités plus avancées, mais pas vraiment pertinentes dans mon contexte. – yeeen

6

Vous pouvez définir le type d'arbre AST dans les options de grammaire en haut du fichier comme ceci:

tree grammar CSharpTree; 
options { 
    ASTLabelType = CommonTree 
} 

Je construirait une 3ème grammaire ou de travailler dans votre grammaire de l'analyseur existant qui transforme l'arbre en les classes que vous créez. Supposons par exemple que vous ayez une règle qui correspond à l'opérateur plus et que ce soit 2 arguments. Vous pouvez définir une règle correspondant à cet arbre qui crée une classe que vous avez écrit, nous allons l'appeler PlusExpression comme ceci:

plusExpr returns [PlusExpression value] 
    : ^(PLUS left=expr right=expr) { $value = new PlusExpression($left.value, $right.value); } 

expr serait une autre règle dans vos expressions de correspondance de grammaire. gauche et droite ne sont que des alias donnés aux valeurs de l'arbre. La partie entre les {} est pratiquement transformée en code C# verbatim à l'exception du remplacement des références de variable. La propriété .value off de $ left et $ right provient du retour spécifié hors des règles à partir desquelles ils ont été créés.