Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Analex ANTLR2
Analex ANTLR2
Lxico
con ANTLR
(II)
import antr.* ;
public class Prog {
public static void main(String args[ ]) {
try {
FileinputStream f = new FileInputStream(args[0]); //flujo de caracteres de entrada
Analex analex = new Analex(f); //creacin de objeto lexer
CommonToken token = analex.nextToken( ); // produccin del primer token
while (token.getType( ) != Token.EOF_TYPE) {
// mientras no se alcance el ltimo token
...
token = analex.nextToken( );
}
}catch(ANTLRException e) { ... }
catch(FileNotFoundException e) { ... }
}
}
Tokens
Los tokens en Antlr se implementan mediante dos clases predefinidas Antlr.Token y
Antlr.CommonToken. La segunda es una subclase de la primera aadiendo informaciones
sobre la lnea y la columna en el fichero fuente del token y el texto asociado al mismo. Estas
clases definen los mtodos getType( ) y getText( ) para obtener el tipo y el texto de un token.
El atributo esttico EOF_TYPE en la clase Antlr.Token permite representar al ltimo token de
un flujo o secuencia de tokens.
Podemos extender dichas clases para construir tokens ms complejos.
Ejemplo:
public class MiToken extends Token{
String nuevoatributo;
public Mitoken( ){ }
public void setNuevoAtributo(String s){
nuevoAtributo=s;
}
public void getNuevoAtributo(String s){
return nuevoAtributo;
}
}
Los analizadores lxicos disponen de otros mtodos adicionales como makeToken para crear
tokens y setTokenObjectClass para establecer el tipo de tokens que usa el analizador
(parametrizacin de tokens).
Ejemplo:
class Analex extends Lexer;
{
protected Token makeToken(int type){
MiToken token = (MiToken)super.makeToken(type);
token.setNuevoAtributo(...);
return token;
}
}
// Zona de reglas ...
Ejemplo de uso del lexer:
import java.io.* ;
import antr.* ;
public class Prog {
public static void main(String args[ ]) {
try {
FileinputStream f = new FileInputStream(args[0]); //flujo de caracteres de entrada
Analex analex = new Analex(f); // creacin de objeto lexer
analex.setTokenObjectClass(MiToken); // parametrizacin del tipo token
...
}catch(ANTLRException e) { ... }
catch(FileNotFoundException e) { ... }
}
}
Reglas Lxicas
Las reglas lxicas constituyen la parte esencial del analizador lxico y estn destinadas a definir
tokens como secuencias de caracteres desde el flujo de entrada.
Las reglas lxicas presentan la forma Token: Patrn y se implementan en el analizador
resultante como mtodos. Por ejemplo, la regla SEPARADOR: ; ;
se implementa como la funcin:
public final void mSEPARADOR(boolean _createToken) throws
RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = SEPARADOR;
int _saveIndex;
match(';');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()_begin));
}
_returnToken = _token;
}
El identificador usado para Token debe comenzar con una letra en mayscula. La parte Patrn
se especifica en notacin EBNF (operadores * para cierre de Kleene, + para el cierre irreflexivo,
| para alternativas y ? para opcionalidad). Los caracteres se especifican con comillas simples (ej.
0) y las secuencias de caracteres entre doble comillas (ej. \r\n).
Estados lxicos: Antlr dispone de un recurso similar a las macros de Flex. Toda regla con el
atributo protected se considera como algo equivalente una macro en Flex. En la terminologa
Antlr sto se conoce como estado lxico.
Ejemplo:
protected
LETRA : (a..z) ;
protected
NUM : (0..9) ;
IDENT : LETRA (LETRA | NUM)*
Alfabeto
El alfabeto usado en el lexer puede definir de forma implcita o explcita.
La forma implcita consiste en definir como alfabeto slo los caracteres que aparecen en la
especificacin del lexer.
Ejemplo:
Para el analizador lxico,
class Analex extends Lexer;
BLANCO: ( | \t | N_LINEA) {$setType(Token.SKIP) ;}
;
protected N_LINEA: \r\n {newline();}
;
NUMERO: (0 .. 9)+(.(0..9)+)?
;
OPERADOR: + | - | * | /
;
PARENTESIS: ( | )
;
OPERADOR: + | - | * | /
;
SEPARADOR: ;
;
Ejemplo:
BR : <! br >! ; // descarta los smbolos < y > del buffer.
Salto de caracteres: los caracteres reconocidos por una regla son ignorados mediante el token
Token.SKIP.
WS: ( | \t | \n )+ { $setType(Token.SKIP); }
;
Predicados sintcticos: Antlr permite construir lexers LL(k) (con k arbitrario) haciendo uso de
predicados sintcticos. Se trata de construcciones de la forma ( lookahead ) => regla lxica
El siguiente ejemplo implementa un reconocedor LL(2) (ver regla NUMERO ):
class Analex extends Lexer;
tokens {
LIT_REAL;
LIT_ENT;
}
protected DIGITO: '0'.. '9';
NUMERO : ((DIGITO)+ '.') => (DIGITO)+ '.' (DIGITO)* {$setType(LIT_REAL);}
| ((DIGITO)+ ) => (DIGITO)+ {$setType(LIT_ENT);}
;
BLANCO : (' ' | '\t' | "\r\n") {$setType(Token.SKIP);} ;
Es importante destacar que si una alternativa subsume a otra entonces debe colocarse la
alternativa que subsume antes que la subsumida. Esto puede verse en la regla NUMERO
donde (DIGITO)+ '.' subsume a (DIGITO)+
El siguiente ejemplo implementa un reconocedor LL(6) para reconocer asignaciones o bucles
FORTRAN:
DO_OR_VAR
: (DO_HEADER)=> "DO" { $setType(DO); }
| VARIABLE { $setType(VARIABLE); }
;
protected
DO_HEADER
options { ignore=WS; }
VARIABLE
: 'A'..'Z'
('A'..'Z' | ' ' | '0'..'9')*
{ /* strip space from end */ }
;
// just an int or float
protected EXPR
: INT ( '.' (INT)? )?
;
Predicados semnticos: Antlr permite asociar condiciones booleanas a reglas. De esta forma,
una regla slo puede aplicarse si su condicin correspondiente es cierta. Se trata de
construcciones de la forma {condicin}? regla lxica
Ejemplo:
BEGIN_TABLE
: [ {this.inTable = true;} // inicio contexto tabla
;
ROW_SEP
: {this.inTable}?----
;
END_TABLE
: ] {this.inTable = false;} // fin contexto tabla
;
Palabras Reservadas: Antlr permite especificar palabras reservadas en la seccin tokens. La
opcion testLiterals permite habilitar la bsqueda o no de token declarado en la seccin tokens.
Por ejemplo,
options{
testLiterals=false; // por defecto no se consideran los literales definidos en la
// seccin tokens
}
tokens {
INT = int;
CHAR = char;
...
}
protected LETRA : (A.. Z)| (a.. z) ;
IDENT options {testLiterals=true;} : LETRA (DIGITO | LETRA)*;
// localmente a esta regla se consideran los literales declarados en la secc. tokens
Tokens virtuales: Antlr permite declarar tokens en la seccin tokens sin tener literales
asociados. A estos tokens lo denominaremos tokens virtuales.
Ejemplo:
tokens {
LIT_REAL;
LIT_ENT;
}
protected DIGITO: 0.. 9;
NUMERO : ((DIGITO)+ .) => (DIGITO)+ . (DIGITO)*
{$setType(LIT_REAL);}
| ((DIGITO)+ ) => (DIGITO)+ {$setType(LIT_ENT);}
;
Reglas con comportamiento no voraz: Antlr admite el uso de reglas con un comportamiento
no voraz. El siguiente ejemplo muestra una regla con comportamiento voraz :
BLOCK : { (.)* }; // el cierre de Kleene consume todos los caracteres incluido }
No es este el comportamiento deseado con la regla anterior. Para evitarlo existe una opcin
greedy cuyo valor (cierto o falso) fuerza dicho comportamiento.
Por ejemplo:
BLOCK : { (options {greedy = false;}: . )*) }; // el cierre de Kleene consume todos
los caracteres hasta llegar a }
Opciones
Muchos aspectos en el comportamiento de Antlr puede programarse mediante opciones a nivel
global para todo el reconocedor o a nivel local de una regla.
Las opciones principales son:
k: nmero de token lookahead. Alterar su nmero permite decidir alternativas con ms
informacin (ms tokens).
Ejemplo:
class MyLexer extends Lexer;
options { k=3; } //opcin global
...
greedy: Un valor falso para esta opcin permite salir de un ( )*, ( )+ cuando el elemento que
sigue al estos bucles es detectado como lookahead.
Ejemplo:
BLOCK : { (options {greedy = false}: . )*) }; // opcin local donde el cierre de /
//Kleene consume todos los caracteres hasta llegar a }
charVocabulary: permite definir el alfabeto mediante rango de cdigos ascii.
Ejemplo:
class Analex extends Lexer;
options{
charVocabulary ='\3'..'\377'; //rango de cd. ascii representando el alfabeto
}
caseSensitive: indica si el analizador es sensible a maysculas.
Ejemplo:
class Analex extends Lexer;
options{
caseSensitive = false; //(opcin global) el analizador no es sensible a
// maysculas, es decir, HoLa es un literal idntico a
// hola
}
ignore: indica al analizador los patrones de smbolos a ignorar desde el flujo de entrada.
Ejemplo:
options { ignore = BLANCO; } //el lexer ignorar los espacios en blanco.
BLANCO
...
'' ;
Token:
tok = (MiToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType()+" Texto: "+tok.getTexto());
}
}catch
(FileNotFoundException
e){System.out.println("Excepcin
"+e.getMessage());}
catch
(TokenStreamException
e){System.out.println("Excepcin
"+e.getMessage());}
}
}
Flujo de entrada (entrada.txt):
12 * 34;
23;
1.2 / 3;
Resultado ejecucin programa Prog sobre entrada.txt:
Lexema: 12
Token: 5
Lexema:
Token: 4
Texto: token
Lexema: *
Token: 6
Texto: token
Lexema:
Token: 4
Texto: token
Lexema: 34
Token: 5
Texto: token
Lexema: ;
Token: 8
Texto: token
Lexema:
Token: 4
Texto: token
Lexema: 23
Token: 5
Texto: token
Lexema: ;
Token: 8
Texto: token
Lexema:
Token: 4
Texto: token
Lexema: 1.2
Token: 5
Texto: token
Lexema:
Token: 4
Texto: token
Lexema: /
Token: 6
Texto: token
Lexema:
Token: 4
Texto: token
Lexema: 3
Token: 5
Texto: token
Lexema: ;
Token: 8
Texto: token
Lexema: null
Token: 1
Texto: token
while (tok.getType()!=Token.EOF_TYPE){
tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+"
Token:
"+tok.getType());
}
}catch
"+e.getMessage());}
catch
"+e.getMessage());}
}
}
(FileNotFoundException
e){System.out.println("Excepcin
(TokenStreamException
e){System.out.println("Excepcin
12 * 34;
12 ";
123
Resultado ejecucin programa Prog sobre entrada.txt:
Lexema: 12
Token: 4
Excepcin unexpected char: ' '
Token:
Token:
}catch
"+e.getMessage());}
catch
"+e.getMessage());}
}
}
(FileNotFoundException
e){System.out.println("Excepcin
(TokenStreamException
e){System.out.println("Excepcin
Token: 5
Token: 4
Token: 6
Token: 4
Lexema: 34
Token: 5
Lexema: ;
Token: 8
Lexema:
Token: 4
Lexema: 12
Token: 5
Lexema: ;
Token: 8
Lexema:
Token: 4
Lexema: 123
Token: 5
Lexema: null
Token: 1
Todos los smbolos presentes en el flujo de entrada son smbolos definidos en el alfabeto del
analizador lxico (Analex.g).
System.out.println("Lexema: "+tok.getText()+"
Token:
"+tok.getType());
}
}catch
"+e.getMessage());}
catch
"+e.getMessage());}
}
}
(FileNotFoundException
e){System.out.println("Excepcin
(TokenStreamException
e){System.out.println("Excepcin
1.2
Token: 4
/*
Token: 8
*/
Token: 9
9
Token: 5
null
Token: 1
}
Flujo de entrada (entrada.txt):
{
entero x
juan pedro
real y
}
Fichero de texto con la definicin de los tokens:
// $ANTLR : Analex.g -> AnalexTokenTypes.txt$
Analex // output token vocab name
ENT="entero"=4
REAL="real"=5
DIGITO=6
LETRA=7
BLANCO=8
IDENT=9
BLOQUE=10
Resultado ejecucin programa Prog sobre entrada.txt:
Excepcin expecting '}', found '<EOF>' /// IMPORTANTE ///
Para evitar este comportamiento voraz se anula la opcin greedy que Antlr presenta por defecto.
class Analex extends Lexer;
options{
testLiterals=true;
}
tokens {
ENT="entero";
REAL="real";
}
{
boolean comentario = false;
}
protected DIGITO: '0'.. '9';
protected LETRA: 'a' .. 'z' | 'A' .. 'Z';
BLANCO : (' ' | '\t' | "\r\n") {$setType(Token.SKIP);} ;
IDENT: LETRA(LETRA|DIGITO)* ;
Token: 1