1

I would really appreciate if someone could give me advice,or point me to tutorial, or sample implementation, anything that could help me implement basic goto statement in ANTLR?

Thanks for any help

edit. ver2 of question:

Say I have this tree structure:

(BLOCK (PRINT 1) (PRINT 2) (PRINT 3) (PRINT 4) )

Now, I'm interested to know is there a way to select, say, node (PRINT 2) and all nodes that follow that node ((PRINT 2) (PRINT 3) (PRINT 4)) ?

I'm asking this because I'm trying to implement basic goto mechanism. I have print statement like this:

i=LABEL print 
{interpreter.store($i.text, $print.tree);} //stores in hash table
-> print

However $print.tree just ignores later nodes, so in input:

label: print 1
print 2
goto label

would print 121! (What I would like is infinite loop 1212...)

I've also tried taking token address of print statement with getTokenStartIndex() and setting roots node with setTokenStartIndex but that just looped whatever was first node over and over.

My question is, how does one implement goto statement in antlr ? Maybe my approach is wrong, as I have overlooked something?

I would really appreciate any help.

ps. even more detail, it is related to pattern 25 - Language Implementation patterns, I'm trying to add on to examples from that pattern. Also, I've searched quite a bit on the web, looks like it is very hard to find goto example

Te33Xaz
  • 23
  • 5
  • Is this homework, or some other type of assignment? If not, what is the bigger problem you're trying to solve? – Bart Kiers Jul 21 '11 at 18:23
  • Practice, I was going through pattern 25 from Language Implementation Pattern by Mr. Parr.I though to add on that pattern for practice to implement goto statement but I'm stuck. I tried this: i=LABEL print {interpreter.store($i.text, $print.tree);} //stores in hash table -> print but $print.tree takes just one node and not any other nodes after it.I've also tried taking token address of print statement with getTokenStartIndex() and setting roots node with setTokenStartIndex but that just looped whatever was first node over and over. – Te33Xaz Jul 21 '11 at 18:42
  • Say I have this tree structure: (BLOCK (PRINT 1) (PRINT 2) (PRINT 3) (PRINT 4) ) Now, I'm interested to know is there a way to select, say, node (PRINT 2) and all that follow that node,that is ((PRINT 2) (PRINT 3) (PRINT 4)) ? So, basically I'm stuck, so any advice at this point I would welcome! – Te33Xaz Jul 21 '11 at 18:44
  • Te33Xaz, I recommend you to add all this information in your original post. You're on the right track! I'll see if I can post a small demo of I think this could be done. – Bart Kiers Jul 21 '11 at 18:49

1 Answers1

3

... anything that could help me implement basic goto statement in ANTLR?

Note that it isn't ANTLR that implements this. With ANTLR you merely describe the language you want to parse to get a lexer, parser and possibly a tree-walker. After that, it's up to you to manipulate the tree and evaluate it.

Here's a possible way. Please don't look too closely at the code. It's a quick hack: there's a bit of code-duplication and I'm am passing package protected variables around which isn't as it should be done. The grammar also dictates you to start your input source with a label, but this is just a small demo of how you could solve it.

You need the following files:

  • Goto.g - the combined grammar file
  • GotoWalker.g - the tree walker grammar file
  • Main.java - the main class including the Node-model classes of the language
  • test.goto - the test input source file
  • antlr-3.3.jar - the ANTLR JAR (could also be another 3.x version)

Goto.g

grammar Goto;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

tokens {
  FILE;
  BLOCK;
}

@members {
  java.util.Map<String, CommonTree[]> labels = new java.util.HashMap<String, CommonTree[]>();
}

parse
  :  block EOF -> block
  ;

block
  :  ID ':' stats b=block? {labels.put($ID.text, new CommonTree[]{$stats.tree, $b.tree});} -> ^(BLOCK stats $b?)
  ;

stats
  :  stat*
  ;

stat
  :  Print Number -> ^(Print Number)
  |  Goto ID      -> ^(Goto ID)
  ;

Goto   : 'goto';
Print  : 'print';
Number : '0'..'9'+; 
ID     : ('a'..'z' | 'A'..'Z')+;
Space  : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};

GotoWalker.g

tree grammar GotoWalker;

options {
  tokenVocab=Goto;
  ASTLabelType=CommonTree;
}

tokens {
  FILE;
  BLOCK;
}

@members {
  java.util.Map<String, CommonTree[]> labels = new java.util.HashMap<String, CommonTree[]>();
}

walk returns [Node n]
  :  block {$n = $block.n;}
  ;

block returns [Node n]
  :  ^(BLOCK stats b=block?) {$n = new BlockNode($stats.n, $b.n);}
  ;

stats returns [Node n]
@init{List<Node> nodes = new ArrayList<Node>();}
  :  (stat {nodes.add($stat.n);})* {$n = new StatsNode(nodes);}
  ;

stat returns [Node n]
  :  ^(Print Number) {$n = new PrintNode($Number.text);}
  |  ^(Goto ID)      {$n = new GotoNode($ID.text, labels);}
  ;

Main.java

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
import java.util.*;

public class Main {
  public static void main(String[] args) throws Exception {
    GotoLexer lexer = new GotoLexer(new ANTLRFileStream("test.goto"));
    GotoParser parser = new GotoParser(new CommonTokenStream(lexer));
    CommonTree tree = (CommonTree)parser.parse().getTree();
    GotoWalker walker = new GotoWalker(new CommonTreeNodeStream(tree));
    walker.labels = parser.labels;
    Node root = walker.walk();
    root.eval();
  }
}

interface Node {
  public static final Node VOID = new Node(){public Object eval(){throw new RuntimeException("VOID.eval()");}};
  public static final Node BREAK = new Node(){public Object eval(){throw new RuntimeException("VOID.eval()");}};
  Object eval();
}

class BlockNode implements Node {

  Node stats;
  Node child;

  BlockNode(Node ns, Node ch) {
    stats = ns;
    child = ch;
  }

  public Object eval() {
    Object o = stats.eval();
    if(o != VOID) {
      return o;
    }
    if(child != null) {
      o = child.eval();
      if(o != VOID) {
        return o;
      }
    }
    return VOID;
  }
}

class StatsNode implements Node {

  List<Node> nodes;

  StatsNode(List<Node> ns) {
    nodes = ns;
  }

  public Object eval() {
    for(Node n : nodes) {
      Object o = n.eval();
      if(o != VOID) {
        return o;
      }
    }
    return VOID;
  }
}

class PrintNode implements Node {

  String text;

  PrintNode(String txt) {
    text = txt;
  }

  public Object eval() {
    System.out.println(text);
    return VOID;
  }
}

class GotoNode implements Node {

  String label;
  Map<String, CommonTree[]> labels;

  GotoNode(String lbl, Map<String, CommonTree[]> lbls) {
    label = lbl;
    labels = lbls;
  }

  public Object eval() {
    CommonTree[] toExecute = labels.get(label);
    try {
      Thread.sleep(1000L);
      GotoWalker walker = new GotoWalker(new CommonTreeNodeStream(toExecute[0]));
      walker.labels = this.labels;
      Node root = walker.stats();
      Object o = root.eval();
      if(o != VOID) {
        return o;
      }
      walker = new GotoWalker(new CommonTreeNodeStream(toExecute[1]));
      walker.labels = this.labels;
      root = walker.block();
      o = root.eval();
      if(o != VOID) {
        return o;
      }
    } catch(Exception e) {
      e.printStackTrace();
    }
    return BREAK;
  }
}

test.goto

root:
print 1
A:
print 2
B:
print 3
goto A
C:
print 4

To run the demo, do the following:

*nix/MacOS

java -cp antlr-3.3.jar org.antlr.Tool Goto.g
java -cp antlr-3.3.jar org.antlr.Tool GotoWalker.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main

or:

Windows

java -cp antlr-3.3.jar org.antlr.Tool Goto.g
java -cp antlr-3.3.jar org.antlr.Tool GotoWalker.g
javac -cp antlr-3.3.jar *.java
java -cp .;antlr-3.3.jar Main

which will print:

1
2
3
2
3
2
3
2
3
...

Note that the 2 and 3 are repeated until you terminate the app manually.

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288