ASTNodeCreator Sample?

Aug 23, 2013 at 7:00 PM
I've just finished a compiler for the Shakespeare programming language (http://shakespearelang.sourceforge.net/). I'm now working on separating the scanner/parser from the code generator. The best way to handle this appears to be by replacing all the typeof(MyAstNode) references in my grammar with AstNodeCreator reference. But that brings up the question::

What exactly is a AstNodeCreator method supposed to do?

Currently, I'm using essentially:
MyAstNodeCreator(AstContext context, ParseTreeNode parseNode)
{
    parseNode.AstNode = new MyAstNode()
    //Initialize node
    var iInit = parseNode.AstNode as IAstNodeInit;
     if (iInit != null)
        iInit.Init(context, parseNode);
};
(to be strictly accurate, I'M using:)
    static private AstNodeCreator MakeCreator(Type type)
    {
        return (context, parseNode) =>
            {
                parseNode.AstNode = Activator.CreateInstance(type);
                //Initialize node
                var iInit = parseNode.AstNode as IAstNodeInit;
                if (iInit != null)
                    iInit.Init(context, parseNode);

            };
    }
Coordinator
Aug 23, 2013 at 11:05 PM
there's nothing special about this method, it is just alternative, supposedly more flexible way to create AST nodes. You can provide custom code that creates the node object, depending on the context (parseNode in particular), maybe different node types for different cases.
Coordinator
Aug 24, 2013 at 6:48 AM
Edited Aug 24, 2013 at 6:50 AM
one more comment. The initial 'reason' to introduce this creator method is to accommodate similar language constructs from different languages which have the same AST node. AST node is an 'implementation' of operation, while representation may differ. For example, the BinaryOp AST node from interpreter expects that it's operands are in the following order: left, op, right - this in normal, infix operator notation. However, in languages like Scheme which have prefix op order, like ' (+ a b)' the order of operands would be different in the parse tree. In order to use the standard AST node in Scheme, you need to intercept and reorder the operands - that's what you can do with node creator custom method. Essentially you can remap child nodes (in children of ParseTreeNode) into arguments of Ast node.
Aug 26, 2013 at 5:31 AM
there's nothing special about this method
I'm not interested in a special one. I'd like to know what an ordinary one is supposed to do. It returns void, so we are to assume it's supposed to DO something, but that "something" isn't documented anywhere. I based the one I use on what the framework does when NodeCreator is null.


What I am doing, is, at first I had two assemblies, Shakespeare, which implemented the grammar, and Shakespeare2C, which defined the ASTNodes for a backend which output C code. In the grammar, non-terminals were defined in the form var Title = new NonTerminal("Title", typeof(TitleNode)); with Shakespeare.dll having a reference to Shakespeare2C.dll.

However, I wish to create a number of different backends (C# source code, and eventually, direct IL generation). This means the grammar can't reference the backend dll. I handled this by changing the grammar to define non-terminals as var Title = new NonTerminal("Title", compiler.TitleNode); where compiler.TitleNode returns a AstNodeCreator built using the MakeCreator method given above and a Type objected read from a dynamically loaded backend assembly.
Coordinator
Aug 26, 2013 at 7:15 PM
Sorry, misunderstood, I thought you know what it supposed to do - your fragment does this - it must set the parseNode.AstNode property.
As for your strategy, to use different set of AST nodes for different outputs. IMHO, that seems a little off-base. AST nodes purpose is to represent 'universal' structure or 'semantics' of the language construct, independent of syntactic representation. Like For-I loop in VB.NET and c# look different in source, and therefore have different concrete trees (parse nodes); but as every .NET programmer knows, they represent the same thing, so AST node (abstract, abstracted from representation) should be the same, and this same node would be in intermediate representation for code analysis and eventual compilation to IL or whatever final output is. It is the Code generator that would differ, not the nodes themselves. So that's my suggestion - to use the same set of AST nodes in all output generators, but put the differentiating logic into output generators
Roman
Aug 27, 2013 at 7:07 AM
Well, that bring up a whole 'nother issue as the concept of attaching a separate code generator object to node is a complete mystery.