Leí que necesitas usar '^' y '!' operadores para construir un árbol de análisis similar a los que se muestran en ANTLR Works (aunque no es necesario usarlos para obtener un árbol agradable en ANTLR Works). Entonces, mi pregunta es ¿cómo puedo construir un árbol así? He visto algunas páginas sobre la construcción de árboles usando los dos operadores y reescrituras, y aún digo que tengo una cadena de entrada abc abc123 y una gramática:

grammar test;

program : idList;
idList : id* ;
id : ID ;

ID : LETTER (LETTER | NUMBER)* ;
LETTER : 'a' .. 'z' | 'A' .. 'Z' ;
NUMBER : '0' .. '9' ;

ANTLR Works generará:

Salida del intérprete de ANTLR Works

Lo que no entiendo es cómo se puede colocar el nodo 'idList' en la parte superior de este árbol (así como el de gramática de hecho). ¿Cómo puedo reproducir este árbol usando reescrituras y esos operadores?

2
Chris Covert 12 abr. 2012 a las 06:20

1 respuesta

La mejor respuesta

Lo que no entiendo es cómo se puede colocar el nodo 'idList' en la parte superior de este árbol (así como el de gramática de hecho). ¿Cómo puedo reproducir este árbol usando reescrituras y esos operadores?

No puede usar ^ y ! solos. Estos operadores solo operan en tokens existentes, mientras que usted desea crear tokens adicionales (y convertirlos en la raíz de sus subárboles). puede hacer eso usando reescribir reglas y definir algunos tokens imaginarios.

Una demostración rápida:

grammar test;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

tokens {
  IdList;
  Id;
}

@parser::members {

  private static void walk(CommonTree tree, int indent) {
    if(tree == null) return;
    for(int i = 0; i < indent; i++, System.out.print("    "));
    System.out.println(tree.getText());
    for(int i = 0; i < tree.getChildCount(); i++) {
      walk((CommonTree)tree.getChild(i), indent + 1);
    }
  }

  public static void main(String[] args) throws Exception {
    testLexer lexer = new testLexer(new ANTLRStringStream("abc abc123"));
    testParser parser = new testParser(new CommonTokenStream(lexer));
    walk((CommonTree)parser.program().getTree(), 0);
  }
}

program : idList EOF -> idList;
idList  : id*        -> ^(IdList id*);
id      : ID         -> ^(Id ID);

ID    : LETTER (LETTER | DIGIT)*;
SPACE : ' ' {skip();};

fragment LETTER : 'a' .. 'z' | 'A' .. 'Z';
fragment DIGIT  : '0' .. '9';

Si ejecuta la demostración anterior, verá lo siguiente que se imprime en la consola:

IdList
    Id
        abc
    Id
        abc123

Como puede ver, los tokens imaginarios también deben comenzar con una letra mayúscula, al igual que las reglas de lexer. Si desea dar a los tokens imaginarios el mismo text que la regla del analizador que representan, haga algo como esto en su lugar:

idList  : id*        -> ^(IdList["idList"] id*);
id      : ID         -> ^(Id["id"] ID);

Que imprimirá:

idList
    id
        abc
    id
        abc123
2
Community 23 may. 2017 a las 15:19
Gracias por una respuesta tan detallada. Por alguna razón, nunca pude obtener eso de la documentación.
 – 
Chris Covert
12 abr. 2012 a las 11:21