Custom AstNode's

Jan 27, 2009 at 8:04 PM
Hi, I did exactly in few examples (Atleast I think so). While creating NonTerminal I used type as second parameter, but it didn't work and Parse(string) method returns standard AstNode. Can you help me? In other words following code fails even though I use NodeType to specify custom AstNode class for each node

// Parsing
 var grammar = new LanguageGramar();
 var compiler = new LanguageCompiler(grammar);
AstNode tree = compiler.Parse (@"a = 150 + 28");

// Grammar
namespace ConsoleApplication1
{
    public class LanguageGramar : Grammar
    {
        public LanguageGramar ()
        {
            // ...

            var Program = new NonTerminal ("Program", typeof(ProgramNode));

            // ...
        }
    }
}

// ProgramNode
namespace ConsoleApplication1.Nodes
{
    public class ProgramNode : AstNode
    {
        public ProgramNode(NodeArgs args) : base(args)
        {
        }
    }
}

Coordinator
Jan 27, 2009 at 9:11 PM
Please try to stop in ProgramNode constructor in debugger, to see if it's actually called. Anyway, hard to say, can you  please list the entire grammar class (cs file)?
Jan 28, 2009 at 7:33 AM
Yes, it visits constructor two times

Grammar
=========================
using Irony.Compiler;
using Irony.Compiler.AST;
using ConsoleApplication1.Nodes;
using AssigmentNode=ConsoleApplication1.Nodes.AssigmentNode;

namespace ConsoleApplication1
{
    // This grammar describes programs that consist of simple expressions and assignments,
    // for ex:
    // x = 3 + 4
    // y = x * 2 + 1
    //  the result of calculation is the result of last expression or assignment (value of "y" in this case).
    //  Irony's default  runtime provides expression evaluation. 

    [Language ("ExpressionEvaluator", "1.0", "Multi-line expression evaluator")]
    public class LanguageGramar : Grammar
    {
        public LanguageGramar ()
        {
            // 1. Terminals
            var number = new NumberLiteral ("number");
            var identifier = new IdentifierTerminal ("identifier");
            var comment = new CommentTerminal ("comment", "#", "\n", "\r");
            NonGrammarTerminals.Add (comment);

            // 2. Non-terminals
            var Variable = new NonTerminal ("Variable", typeof (VariableNode));
            var Expr = new NonTerminal ("Expr", typeof(ExpressionNode));
            var Term = new NonTerminal ("Term", typeof(TermNode));
            var BinExpr = new NonTerminal ("BinExpr", typeof (BinaryExpressionNode));
            var ParExpr = new NonTerminal ("ParExpr", typeof(ParenthesedExpressionNode));
            var UnExpr = new NonTerminal ("UnExpr", typeof (UnparenthesedExpressionNode));
            var UnOp = new NonTerminal ("UnOp", typeof(UnaryOperatorNode));
            var BinOp = new NonTerminal ("BinOp", typeof(BinaryOperatorNode));
            var AssignmentStmt = new NonTerminal ("AssignmentStmt", typeof (AssigmentNode));
            var Statement = new NonTerminal ("Statement", typeof(StatementNode));
            var ProgramLine = new NonTerminal ("ProgramLine", typeof (LineNode));
            var Program = new NonTerminal ("Program", typeof(ProgramNode));

            Statement.NodeType = typeof (ProgramNode);

            // 3. BNF rules
            Variable.Rule = identifier;
            Expr.Rule = Term | UnExpr | BinExpr;
            Term.Rule = number | ParExpr | Variable;
            ParExpr.Rule = "(" + Expr + ")";
            UnExpr.Rule = UnOp + Term;
            UnOp.Rule = Symbol ("+") | "-";
            BinExpr.Rule = Expr + BinOp + Expr;
            BinOp.Rule = Symbol ("+") | "-" | "*" | "/" | "**";
            AssignmentStmt.Rule = Variable + "=" + Expr;
            Statement.Rule = AssignmentStmt | Expr | Empty;
            ProgramLine.Rule = Statement + NewLine;
            Program.Rule = MakeStarRule (Program, ProgramLine);
            Root = Program;       // Set grammar root

            // 4. Operators precedence
            RegisterOperators (1, "+", "-");
            RegisterOperators (2, "*", "/");
            RegisterOperators (3, Associativity.Right, "**");

            RegisterPunctuation ("(", ")");

            // automatically add NewLine before EOF so that our BNF rules work correctly 
            // when there's no final line break in source
            LanguageFlags = LanguageFlags.NewLineBeforeEOF | LanguageFlags.SupportsInterpreter;

        }
    }
}//namespace


ProgramNode
===================================
using System.Collections.Generic;
using System.Linq;
using Irony.Compiler;

namespace ConsoleApplication1.Nodes
{
    public class ProgramNode : AstNode
    {
        public ProgramNode(NodeArgs args) : base(args)
        {
        }

        public IEnumerable<LineNode> Lines
        {
            get
            {
                return ChildNodes.Cast<LineNode>();
            }
        }
    }
}

Parsing
==========================
using Irony.Compiler;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main (string[] args)
        {
            var grammar = new LanguageGramar();
            var compiler = new LanguageCompiler(grammar);
            AstNode tree = compiler.Parse (@"a = 150 + 28");
        }
    }
}

Coordinator
Jan 28, 2009 at 5:47 PM
What you see as a root node is actually "augmented root" node named Program' (with apostroph). Your expected root is the first child of this node. You should add the "BubbleNodes" flag to Grammar flags like this:

LanguageFlags =

LanguageFlags.NewLineBeforeEOF | LanguageFlags.SupportsInterpreter | LanguageFlags.BubbleNodes;

Then you'll see your node on top. This is confusing a bit, I know, and is more like a workaround. I'm trying to streamline all this "bubble nodes" business and make it more explicit and clear. Expect fixes soon.