Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I don't think there's an easy way to do that. You could make your rule like this:</p> <pre><code>function : ID PERIOD function -&gt; ^(function ID) | ID ; </code></pre> <p>but that only makes the last node the root and all other nodes its children. For example, the following source:</p> <pre><code>a.b.c.d.e </code></pre> <p>will result in the following tree:</p> <pre><code> e / / \ \ d c b a </code></pre> <p>I can't see an easy fix since when you first parse <code>a.b.c.d.e</code>, <code>a</code> will be the <code>ID</code> and <code>b.c.d.e</code> the recursive call to <code>function</code>:</p> <pre><code>a.b.c.d.e | +-----+ | | | `-----&gt; function | `----------&gt; ID </code></pre> <p>resulting in the fact that <code>b.c.d.e</code> will have <code>a</code> as its child. When then <code>b</code> becomes the <code>ID</code>, it too is added as a child next to <code>a</code>. In your case, <code>a</code> should be removed as a child and then added to the list of <code>b</code>'s children. But AFAIK, that is not possible in ANLTR (at least, not in a clean way inside the grammar).</p> <hr> <p><strong>EDIT</strong></p> <p>Okay, as a work-around I had something elegant in mind, but that didn't work as I had hoped. So, as a less elegant solution, you could match the <code>last</code> node as the root in your rewrite rule:</p> <pre><code>function : (id '.')* last=id -&gt; ^($last) ; </code></pre> <p>and then collect all possible preceding nodes (<code>children</code>) in a <code>List</code> using the <code>+=</code> operator:</p> <pre><code>function : (children+=id '.')* last=id -&gt; ^($last) ; </code></pre> <p>and use a custom member-method in the parser to "inject" these <code>children</code> into the root of your tree (going from right to left in your <code>List</code>!):</p> <pre><code>function : (children+=id '.')* last=id {reverse($children, (CommonTree)$last.tree);} -&gt; ^($last) ; </code></pre> <p>A little demo:</p> <pre><code>grammar ReverseTree; options { output=AST; } tokens { ROOT; } @members { private void reverse(List nodes, CommonTree root) { if(nodes == null) return; for(int i = nodes.size()-1; i &gt;= 0; i--) { CommonTree temp = (CommonTree)nodes.get(i); root.addChild(temp); root = temp; } } } parse : function+ EOF -&gt; ^(ROOT function+) ; function : (children+=id '.')* last=id {reverse($children, (CommonTree)$last.tree);} -&gt; ^($last) ; id : ID ; ID : ('a'..'z' | 'A'..'Z')+ ; Space : ' ' {skip();} ; </code></pre> <p>And a little test class:</p> <pre><code>import org.antlr.runtime.*; import org.antlr.runtime.tree.*; import org.antlr.stringtemplate.*; public class Main { public static void main(String[] args) throws Exception { ANTLRStringStream in = new ANTLRStringStream("a.b.c.d.e Stack.Overflow.Horse singleNode"); ReverseTreeLexer lexer = new ReverseTreeLexer(in); CommonTokenStream tokens = new CommonTokenStream(lexer); ReverseTreeParser parser = new ReverseTreeParser(tokens); ReverseTreeParser.parse_return returnValue = parser.parse(); CommonTree tree = (CommonTree)returnValue.getTree(); DOTTreeGenerator gen = new DOTTreeGenerator(); StringTemplate st = gen.toDOT(tree); System.out.println(st); } } </code></pre> <p>which will produce an AST that looks like:</p> <p><img src="https://i.stack.imgur.com/ERNwr.png" alt="alt text"></p> <ul> <li>(image generated using <a href="http://graph.gafol.net" rel="nofollow noreferrer">http://graph.gafol.net</a>)</li> </ul> <p>For the input string:</p> <pre><code>"a.b.c.d.e Stack.Overflow.Horse singleNode" </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload