Перейти заявление в antlr? - PullRequest
1 голос
/ 21 июля 2011

Я был бы очень признателен, если бы кто-то мог дать мне совет, или указать мне учебник или пример реализации, что-нибудь, что могло бы помочь мне реализовать базовое утверждение goto в ANTLR?

Спасибо за любую помощь

редактировать. ver2 вопроса:

Скажите, у меня есть эта древовидная структура:

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

Теперь мне интересно знать, есть ли способ выберите, скажем, узел (PRINT 2) и все последующие узлы этот узел ((ПЕЧАТЬ 2) (ПЕЧАТЬ 3) (ПЕЧАТЬ 4))?

Я спрашиваю это, потому что я пытаюсь реализовать Основной механизм Гото. У меня есть заявление для печати, как это:

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

Однако $ print.tree просто игнорирует более поздние узлы, Итак, на входе:

label: print 1
print 2
goto label

напечатает 121! (То, что я хотел бы, это бесконечный цикл 1212 ...)

Я также пытался взять токен адрес распечатки выписки с getTokenStartIndex () и установка корень узел с setTokenStartIndex но это просто зацикливало то, что было первым узлом снова и снова.

Мой вопрос: как реализовать оператор goto в antlr? Может быть, мой подход неверен, так как я что-то упустил?

Буду очень признателен за любую помощь.

пс. еще более подробно, это связано с шаблоном 25 - Шаблоны языковой реализации, я пытаюсь добавить примеры из этого шаблона. Кроме того, я довольно много искал в Интернете, похоже, очень сложно найти пример goto

1 Ответ

3 голосов
/ 22 июля 2011

... что-нибудь, что могло бы помочь мне реализовать базовый оператор goto в ANTLR?

Обратите внимание, что это не ANTLR, который реализует это.С ANTLR вы просто описываете язык, который вы хотите проанализировать, чтобы получить лексер, парсер и, возможно, обходчик деревьев.После этого вам остается управлять деревом и оценивать его.

Вот возможный способ.Пожалуйста, не смотрите внимательно на код.Это быстрый взлом: есть небольшое дублирование кода, и я передаю переменные, защищенные пакетами, а это не так, как должно быть.Грамматика также требует, чтобы ваш источник ввода начинался с label, но это всего лишь небольшая демонстрация того, как вы могли бы решить ее.

Вам нужны следующие файлы:

  • Goto.g - объединенный файл грамматики
  • GotoWalker.g - файл грамматики обхода дерева
  • Main.java - основной класс, включающий классы Node-моделиязык
  • test.goto - исходный файл теста
  • antlr-3.3.jar - JAR-файл ANTLR (также может быть другой версии 3.x)

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

Чтобы запустить демонстрацию, выполните следующие действия:

* 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

или:

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

, который будет печатать:

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

Обратите внимание, что 2 и 3 повторяются, пока вы не завершите приложение вручную.

...