This project has moved and is read-only. For the latest updates, please go here.

From AST to source code

Jul 13, 2015 at 2:22 PM

I am wondering if it is possible to generate source code from AST for a particular grammar.

Most tutorials I googled parse code to AST but I would like to go from AST to code.

A use case would be to build/modify the AST and have Irony generate the resulting code.

I am also wondering if validation will be possible based on the grammar provided.

Thank you.
Jul 13, 2015 at 6:06 PM
This is possible and is called (pretty-)printing an AST.
Of course you will lose the original formatting and can only pront a "standard" form, hence pretty-printing.

In Irony you could make a print method with a large switch inside that handles all types of nodes. For child nodes you (recursively) call this method inside the case's.
Jul 14, 2015 at 7:13 AM

What is the method to call and could you provide some sample code to do this please?

Thank you.
Jul 14, 2015 at 8:21 AM
It's something you'll have to write yourself. You could make it something like this:
public string Print(AstNode node) {
    switch(node.GetType().Name) {
        case "BinaryOperationNode":
            var binopnode = (BinaryOperationNode)node;
            return String.Format("{0} {1} {2}", Print(binopnode.Left), binopnode.OpSymbol, binopnode.Right);
        // all your AST node types here
            throw new ArgumentException("Could not print node of type {0}", node.GetType().Name);
Switching on types is... subpar in C# (until we get pattern matching in a future version) so there's other/"better" ways you can do it. I also like defining multiple methods with concrete subtypes and using the runtime method resolution of C#'s dynamic.

If you want to print ParseTreeNode's it gets simpler. You can first check if it's a nonterminal or terminal (terminals are usually just outputted), and switch on Term.Name for nonterminals with the proper logic.
public string Print(ParseTree tree) { return Print(tree.Root); }

public string Print(ParseTreeNode node) {
    if(node.Term is Terminal) return node.Token.Text;
    var childs = node.ChildNodes.Select(Print);
    List<string> childsC; // concrete
    switch(node.Term.Name) {
        case "BinOp":
            childsC = childs.toList();
            return String.Format("{0} {1} {2}", childsC[0], childsC[1], childsC[2]);
        // all your nonterminals here
            throw new ArgumentException("Could not print node of type {0}", node.GetType().Name);