views:

1269

answers:

3

Hi,

// Create a scanner that reads from the input stream passed to us
 CSLexer lexer = new CSLexer(new ANTLRFileStream(f));
tokens.TokenSource = lexer;

// 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;

What can I do with the x which is of compilation_unit_return type, to extract its root , its classes, its methods etc? Do I have to extract its Adaptor out? How do I do that? Note that the compilation_unit_return is defined as such in my CSParser (which is automatically generated by ANTLR):

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

However the tree I am getting is of the type object. I run using the debugger and seemed to see that it is of the type BaseTree. But BaseTree is an interface! I don't know how it relates to BaseTree and don't know how to extract details out from this tree. I need to write a visitor which has visit to its class, method, variables.... Tthe ParserRuleReturn class extends from RuleReturnScope and has a start and stop object, which I don't know what it is... Furthermore, there is this TreeVisitor class provided by ANTLR which looks confusing. It requires an Adaptor to be pass as a parameter to its constructor (if not it will use the default CommonTreeAdaptor), tt's why I asked abt the how to obtain the Adaptor eariler on. And other issues too... For the API, u can refer to http://www.antlr.org/api/CSharp/annotated.html

Now I am struck here... If u do know anything, pls help out. Thanks a million.

+2  A: 

I haven't ever worked with ANTLR from C#, but following your link to API, BaseTree is clearly not an interface - it's a class, and it has public properties: Type to get type of the node, Text to get (I assume) source text corresponding to it, and Children to get the child nodes. What else do you need to walk it?

Pavel Minaev
It is an abstract class...public abstract class BaseTree : ITree
yeeen
Well yes, and why would it stop you? You have the root node of the tree, which you know to be of a type which has all methods necessary to retrieve its children (and thus walk the tree to any depth).
Pavel Minaev
A: 

If I were going to make a C# compiler today, here's what I would do try as a first attempt:

  1. Start with the ANTLR C# 3 target (of course I'm biased here - seriously you can use either the CSharp2 or CSharp3 target).
  2. Get Visual Studio 2010 with the .NET Framework 4. The key here is .NET 4 and it's sweet new expression trees.
  3. Build a basic combined parser. Put as little logic in the parser as absolutely possible. It should have few (if any) actions, and the output should be an undecorated AST that can be walked with LL(1) walker.
  4. Build a tree grammar to walk the tree and identify all declared types. It should also keep the member_declaration sub-trees for later use.
  5. Build a tree walker that walks a single member_declaration and adds the member to the TypeBuilder. Keep track of the method bodies but don't deep-walk them yet.
  6. Build a tree walker that walks the body of a method. Generate an Expression<TDelegate> matching the method, and use the CompileToMethod method my own API (see Pavel's and my comments) to generate the IL code.

If you do things in this order, then when you are finally parsing the expressions (method bodies, field initializers), you can use the string parameterized methods like this one in the Expression class to save work resolving members.

280Z28
Unfortunately, `CompileToMethod` cannot truly be used in this scenario because of its inherent limitations - there's no way to compile in a code to another method that you're generating alongside, and the target `MethodBuilder` has to be for a static method only. See https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=473128 for more details.
Pavel Minaev
Nice. Well, then I'd start by building an `Expression` compiler that works in those cases, and then use that instead. :) I'd keep the `Expression` compiler as an independent module so it could be used with other projects (and maybe I'll do it for fun anyway).
280Z28
Perhaps just to deviate a bit from my qn above: I hv the source code for antlr-3.1.3. N under the runtime folder, there are 2 folders - CSharp n CSharp3. Since u mentioned abt CSharp3, u know why there are 2 folders? However the API provided online seemed to be for CSharp only not CSharp3, also the compiled dll too. If someone wants to use CSharp3, he has to compile the codes there himself? To me it seems like CSharp3 has more advanced features, but not really relevant in my context.
yeeen
I am actually not too sure what is going on in the discussion btn u and Pavel Minaev. So the conclusion of ur discussion is tt the steps u provided above are not workable?
yeeen
Initally I just want to use an API equivalent to "http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.cdt.doc.isv/reference/api/org/eclipse/cdt/core/dom/ast/ASTVisitor.html" in Java to achieving the transversal of C# AST. Unfortuntably from what I researched, the current API provided by C# compiler is a black box, doesn't hv the feature tt allows one to manipulate its AST. So I had to come out with my own compiler, tt's why I chose to use ANTLR... Hopefully u or someone else do hv ways to solve my doubts. I do welcome ways faster than using ANTLR (i.e. an existing C# compiler tt).
yeeen
This doesn't really answer the question about ANTLR, it's just a set of steps of how you would approach building a compiler, which is an entirely different question.
Michael Donohue
+3  A: 

You can set the AST tree type in your grammar options at the top of the file like so:

tree grammar CSharpTree;
options { 
    ASTLabelType = CommonTree
}

I would build a 3rd grammar or work it into your existing parser grammar that turns the tree into classes that you create. For example assume you've got a rule that matches the plus operator and it's 2 arguments. You can define a rule matching that tree that creates a class that you've written, let's call it PlusExpression like this:

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

expr would be another rule in your grammar matching expressions. left and right are just aliases given to the tree values. The part in between the { }'s is pretty much turned into C# code verbatim with the exception of replacing the variable references. The .value property off of $left and $right comes from the return specified off of the rules that they were created from.

Ted Elliott