[antlr-interest] AST - Ordering of sibling nodes

Søren Boisen sboisen at mail.dk
Tue Feb 28 05:35:06 PST 2012


For reference, here is my solution, that seems to be working.

I created a simple base class for sorting (just to have as much Java
code in .java files as possible as opposed to having it floating
around in the grammar file):



public abstract class BaseSqlSorter extends TreeRewriter {

    private Map<Integer, Integer> sortValues = new HashMap<Integer,
Integer>(10);

    public BaseSqlSorter (TreeNodeStream input) {
        super(input);
        insertSortValues(sortValues);
    }

    public BaseSqlSorter (TreeNodeStream input, RecognizerSharedState state) {
        super(input, state);
        insertSortValues(sortValues);
    }

    protected abstract void insertSortValues (Map<Integer, Integer> map);

    public final class NodeComparator implements Comparator<ODataNode> {
        @Override
        public int compare (ODataNode n1, ODataNode n2) {
            Integer s1 = sortValues.get(n1.getType());
            Integer s2 = sortValues.get(n2.getType());

            assert s1 != null && s2 != null : "unrecognized token type(s): "
                    + n1.getType() + ", " + n2.getType();

            return s1.compareTo(s2);
        }
    }

    public void sortChildren (ODataNode uriNode) {
        List<ODataNode> children = new
ArrayList<ODataNode>(uriNode.getChildren());
        Collections.sort(children, new NodeComparator());

        ODataNode root = new ODataNode((Token) null);
        root.addChildren(children);

        input.replaceChildren(uriNode, 0, children.size()-1, root);
    }

}




And then I can create a very primitive rewrite tree grammar:

tree grammar SqlSorter;
options {
    tokenVocab = QueryParser;
    ASTLabelType = ODataNode;
    filter = true;
    output = AST;
    superClass = BaseSqlSorter;
}

@header {
<------- SNIP --------->
}

@members {
    protected void insertSortValues (Map<Integer, Integer> map) {
        map.put(SELECT, 25);
        map.put(RESOURCE, 50);
        map.put(FILTER, 75);
        map.put(ORDERBY, 100);
    }
}

topdown:    sortUriChildren ;

sortUriChildren
       :    ^(URI .*) {
           sortChildren($URI);
       } ;



This way I emulate what happens during normal tree rewrite operations,
so I should hopefully be pretty safe :)


/Søren


27. feb. 2012 11.10 skrev Søren Boisen <sboisen at mail.dk>:
> Hi there, I'm transforming a URL query language (OData) to SQL. In the
> query language the query operators can be specified in arbitrary
> sequence:
>
> uri     :   resource ('?' query)? EOF
>        ->  ^(URI resource query?) ;
>
> query   :   queryOp ('&' queryOp)*
>        ->  ^(QUERY queryOp+) ;
>
> queryOp :         expandQueryOp
>        |         orderByQueryOp
>        |         selectQueryOp
>        |         filterQueryOp ;
>
> <--------snip--------->
>
>
> However, in SQL I of course have to abide by a very specific ordering:
>
> selectClause
> fromClause
> whereClause
> orderByClause
>
> The question is, what's the best/easiest/simplest way of reordering
> the AST nodes, so they align with the SQL requirements?
> Currently I'm generating the SQL via string templates like so:
>
> uri     :   ^(URI clauses+=resource clauses+=queryOp*)
>        ->  query(clauses={$clauses}) ;
>
> resource:   ^(RESOURCE ID s=subResource*)
>             -> fromClause(entity={entity($ID)}, joins={$s.st}) ;
>
> queryOp :   ^(SELECT items=selectItem+)        ->
> selectClause(items={$items.st})
>                |   ^(FILTER expr)                               ->
> whereClause(condition={$expr.st})
>                |   ^(ORDERBY items=orderByItem+)   ->
> orderByClause(items={$items.st}) ;
>
> <--------snip--------->
>
> But this requires that the nodes are already sorted in the right order.
>
> /Søren


More information about the antlr-interest mailing list