Ejemplo 530

Enunciado

Dada la siguiente especificación sintáctica en ANTLR y la gramática abstracta que define los nodos del AST, añadir a la especificación de ANTLR el código que cree en AST de las entradas.

programa ⟶ definicion print;

definicion ⟶ tipo nombre:string;

tipoInt:tipo ⟶  ;
tipoReal:tipo ⟶ ;

print ⟶ expr:expresion;

variable:expresion ⟶ nombre:string;
literalEntero:expresion ⟶ valor:string;
start
	: definicion print EOF
	;

definicion
	: tipo IDENT ';'
	;

tipo
	: 'int'
	| 'float'
	;

print
	: 'print' expr ';'
	;

expr
	: IDENT
	| LITENT
	;

Solución

La solución sería la siguiente.

@parser::header {
    import ast.*;
}

start returns[Programa ast]
	: definicion print EOF { $ast = new Programa($definicion.ast, $print.ast); }
	;

definicion returns[Definicion ast]
	: tipo IDENT ';' { $ast = new Definicion($tipo.ast, $IDENT.text); }
	;

tipo returns[Tipo ast]
	: 'int'		{ $ast = new TipoInt(); }
	| 'float'	{ $ast = new TipoReal();}
	;

print returns[Print ast]
	: 'print' expr ';' { $ast = new Print($expr.ast); }
	;

expr returns[Expresion ast]
	: IDENT		{ $ast = new Variable($IDENT.text); }
	| LITENT	{ $ast = new LiteralEntero($LITENT.text); }
	;

La sección @parser::header sirve para indicar qué código se quiere aportar a la clase que va a generar ANTLR. Se suele utilizar para meter los import de Java que el código de las acciones va a requerir.

El main de esta solución seria la siguiente.






 








public static void main(String[] args) throws Exception {

    GrammarLexer lexer = new GrammarLexer(CharStreams.fromFileName("source.txt"));
    GrammarParser parser = new GrammarParser(new CommonTokenStream(lexer));

    AST ast = parser.start().ast;

    if (parser.getNumberOfSyntaxErrors() > 0) {
        System.out.println("Errores sintácticos");
    } else {
        System.out.println("El programa se ha compilado correctamente.");
    }
}

Nótese cómo se obtiene el árbol completo en la llamada a start(). Este método devolverá un objeto en el que habrá un atributo con el mismo nombre que la variable definida con returns en dicha regla start. Ahí es donde dicha regla dejó el AST. Si se quiere saber más sobre los objetos que devuelven los métodos de ANTLR, puede verse el apéndice que trata del contexto de las reglas.

Código

💿 Se puede bajar el proyecto Java con todo lo necesario para poder ejecutar la solución de este ejemplo y así poder ver su resultado y probar otras alternativas.