You are on page 1of 30

Anlisis

Lxico
con ANTLR
(II)










- Repasa los conceptos
- Prueba los ejemplos
Anlisis lxico con ANTLR


Antlr (ANother Tool for Language Recognition) genera analizadores lxicos LL(k) con predicados
sintcticos y semnticos.

Estructura de un analizador lxico

Los analizadores lxicos o lexers reconocen tokens (categoras lxicas) desde secuencias de
caracteres. La estructura general de un analizador lxico antlr es:

header { ... } //Cdigo que se situar en la cabecera del lexer (opcional)
// Suele usarse para decidir la ubicacin del analizador tras ser
// compilado (pe. header {package X; })
class Analex extends Lexer;

options { ... } // opciones globales destinadas a particularizar el lexer (opcional)

tokens {...} //definicin de tokens (opcional)

{ //clases internas necesarias para la implementacin del lexer } (opcional)

// definicin de reglas lxicas


Ejemplo:

class Analex extends Lexer;

BLANCO: ( | \T | N_LINEA) {$setType(Token.SKIP) ;}
;
protected N_LINEA: \r\n {newline();}
;
NUMERO: (0 .. 9)+(.(0..9)+)?
;
PARENTESIS: ( | )
;
OPERADOR: + | - | * | /
;
SEPARADOR: ;
;

Uso de un analizador lxico

El procesamiento de un lexer como el anterior produce una clase Analex cuyo mtodo principal
es nextToken ( mtodo para producir tokens desde el flujo de caracteres de entrada ).

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
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: ;
;

el alfabeto definido es: , \t, \r, \n,, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +, -, *, /, (, ), ;

La forma explcita consiste en definir mediante la opcin charVocabulary.

Ejemplo:

Para el analizador lxico siguiente,

// Analizador lxico

class Analex extends Lexer;
options{
charVocabulary ='\3'..'\377'; // rango de cd. ascii representando el alfabeto
}

BLANCO: ( | \t | N_LINEA) {$setType(Token.SKIP) ;}
;
protected N_LINEA: \r\n {newline();}
;
NUMERO: (0 .. 9)+(.(0..9)+)?
;
OPERADOR: + | - | * | /
;
PARENTESIS: ( | )
;
OPERADOR: + | - | * | /
;
SEPARADOR: ;
;
el alfabeto definido es el rango de caracteres con cdigo ascii '\3'..'\377'


Adems, Antlr cuenta con el patrn . para representar cualquier smbolo simple y el operador ~
para hacer referencia a todos los simbolos no presentes en un conjunto dado.

Ejemplo: NODIG: ~(0..9); // todos los caracteres no dgitos.

Acciones predefinidas en Antlr: Antlr permite realizar las siguientes operaciones:

$getText: devuelve la cadena reconocida por una regla.
$getType: devuelve el token reconocido.
$append(x) : aade x al texto reconocido.
$setText(x) : asigna el texto reconocido en la variable x.
$setToken(x) : asigna a la variable (token) _token el valor x.
$setType(x) : asigna a la variable (tipo token) _ttype el valor x.

El operador ! se usa para descartar texto del buffer.

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:

(blucle) DO 100 l = 1,10
(asignacin) DO 100 l = 1.10

DO_OR_VAR
: (DO_HEADER)=> "DO" { $setType(DO); }
| VARIABLE { $setType(VARIABLE); }
;

protected
DO_HEADER
options { ignore=WS; }
: "DO" INT VARIABLE '=' EXPR ','
;

protected INT : ('0'..'9')+;

protected WS : ' ';

protected
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 : ' ' ;
...
Anlisis Lxico en Antlr. Ejemplos

En esta seccin, mostramos en 12 ejemplos los recursos de Antlr para realizar anlisis lxico.

Ejemplo 1: Ejemplo de analizador lxico.

Analizador lxico Antlr (Analex.g) :

class Analex extends Lexer;

BLANCO : (' ' | '\t' | "\r\n");
NUMERO : ('0'..'9')+('.'('0'..'9'))? ;
OPERADOR : '+' | '-' | '*' | '/' ;
PARENTESIS : '(' | ')' ;
SEPARADOR : ';' ;

Programa que utiliza el analizador anterior (Prog.java):

import java.io.*;
import antlr.*;
public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
CommonToken tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
}
}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;



Asignacin de enteros a tokens tras compilar AnalexTokenTypes.txt:

// $ANTLR : Analex.g -> AnalexTokenTypes.txt$
Analex // output token vocab name
BLANCO=4
NUMERO=5
OPERADOR=6
PARENTESIS=7
SEPARADOR=8

Interfaz Java con la definicin de tokens (AnalexTokenTypes.java):

public interface AnalexTokenTypes {
int EOF = 1;
int NULL_TREE_LOOKAHEAD = 3;
int BLANCO = 4;
int NUMERO = 5;
int OPERADOR = 6;
int PARENTESIS = 7;
int SEPARADOR = 8;
}

Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: 12 Token: 5
Lexema: Token: 4
Lexema: * Token: 6
Lexema: Token: 4
Lexema: 34 Token: 5
Lexema: ; Token: 8
Lexema:
Token: 4
Lexema: 23 Token: 5
Lexema: ; Token: 8
Lexema:
Token: 4
Lexema: 1.2 Token: 5
Lexema: Token: 4
Lexema: / Token: 6
Lexema: Token: 4
Lexema: 3 Token: 5
Lexema: ; Token: 8
Lexema: null Token: 1

Ejemplo 2: Redefinicin de Tokens en Antlr

Antlr permite redefinir el tipo de tokens.

Redefinicin de tokens (MiToken.java):

import antlr.*;

public class MiToken extends CommonToken{
private String texto;

public MiToken( ){ }
public void setTexto(String s){texto = s;}
public String getTexto(){return texto;}
}

Fuente del analizador lxico (Analex.g):

class Analex extends Lexer;
{
protected Token makeToken(int type){
MiToken tok = (MiToken)super.makeToken(type);
tok.setTexto("token");
return tok;
}
}
BLANCO : (' ' | '\t' | "\r\n");
NUMERO : ('0'..'9')+('.'('0'..'9'))? ;
OPERADOR : '+' | '-' | '*' | '/' ;
PARENTESIS : '(' | ')' ;
SEPARADOR : ';' ;

Programa que utiliza el analizador anterior (Prog.java):

import java.io.*;
import antlr.*;

public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
analex.setTokenObjectClass("MiToken");
MiToken tok = (MiToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
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

Ejemplo 3: Ejemplo de analizador con estados lxico.

Fuente del analizador lxico (Analex.g) SIN estados lxicos:

class Analex extends Lexer;

FIN_LINEA : "\r\n" ;
BLANCO : (' ' | '\t' | FIN_LINEA);
NUMERO : ('0'..'9')+('.'('0'..'9'))? ;
OPERADOR : '+' | '-' | '*' | '/' ;
PARENTESIS : '(' | ')' ;
SEPARADOR : ';' ;


Programa que utiliza el analizador anterior (Prog.java):


import java.io.*;
import antlr.*;
public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
CommonToken tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
}
}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: 6
Lexema: Token: 5
Lexema: * Token: 7
Lexema: Token: 5
Lexema: 34 Token: 6
Lexema: ; Token: 9
Lexema:
Token: 4 ///////// IMPORTANTE ///////
Lexema: 23 Token: 6
Lexema: ; Token: 9
Lexema:
Token: 4 ///////// IMPORTANTE ///////
Lexema: 1.2 Token: 6
Lexema: Token: 5
Lexema: / Token: 7
Lexema: Token: 5
Lexema: 3 Token: 6
Lexema: ; Token: 9
Lexema: null Token: 1


Fuente del analizador lxico (Analex.g) CON estados lxicos:

class Analex extends Lexer;

protected FIN_LINEA : "\r\n" ;
BLANCO : (' ' | '\t' | FIN_LINEA);
NUMERO : ('0'..'9')+('.'('0'..'9'))? ;
OPERADOR : '+' | '-' | '*' | '/' ;
PARENTESIS : '(' | ')' ;
SEPARADOR : ';' ;



Programa que utiliza el analizador anterior (Prog.java):


import java.io.*;
import antlr.*;
public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
CommonToken tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
}
}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: 6
Lexema: Token: 5
Lexema: * Token: 7
Lexema: Token: 5
Lexema: 34 Token: 6
Lexema: ; Token: 9
Lexema:
Token: 5 ////////// IMPORTANTE ////////////
Lexema: 23 Token: 6
Lexema: ; Token: 9
Lexema:
Token: 5 ////////// IMPORTANTE ////////////
Lexema: 1.2 Token: 6
Lexema: Token: 5
Lexema: / Token: 7
Lexema: Token: 5
Lexema: 3 Token: 6
Lexema: ; Token: 9
Lexema: null Token: 1

Ejemplo 4: Formas de definir el alfabeto en Antlr

Antlr permite definir el alfabeto de forma implcita o explcita. Saber de qu alfabeto se trata es
fundamental para interpretar las reglas definidas por complementariedad (Ejemplo: NODIG :
~(0..9); ).

Alfabeto definido implcitamente: conjunto de smbolos que aparecen en la parte derecha de las
reglas del analizador lxico.

class Analex extends Lexer;

NUMERO : ('0'..'9')+('.'('0'..'9'))? ;
OPERADOR : '+' | '-' | '*' | '/' ;
PARENTESIS : '(' | ')' ;
SEPARADOR : ';' ;
BLANCO : ~('0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'+' | '-' | '*' | '/'| '(' | ')'|';'|'.');

El alfabeto para Analex es: { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + ,- ,* , /, ( , ) , ; , .}


Programa que utiliza el analizador anterior (Prog.java):

import java.io.*;
import antlr.*;

public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
analex.setTokenObjectClass("MiToken");
MiToken tok = (MiToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
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;
12 ";
123


Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: 12 Token: 4
Excepcin unexpected char: ' ' //IMPORTANTE: ' ' no
//pertenece al alfabeto.


Alfabeto definido explcitamente: la opcin charVocabulary define el alfabeto como un rango de
smbolos.

El alfabeto para el siguiente analizador lxico (Analex.g) es el conjunto de smbolos
correspondientes al rango de cdigos ascii 3..377

class Analex extends Lexer;
options{
charVocabulary='\3'..'\377';
}
NUMERO : ('0'..'9')+('.'('0'..'9'))? ;
OPERADOR : '+' | '-' | '*' | '/' ;
PARENTESIS : '(' | ')' ;
SEPARADOR : ';' ;
BLANCO : ~('0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'+' | '-' | '*' | '/'| '(' | ')'|';');


Programa que utiliza el analizador anterior (Prog.java):

import java.io.*;
import antlr.*;

public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
analex.setTokenObjectClass("MiToken");
MiToken tok = (MiToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
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;
12 ";
123


Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: 12 Token: 4
Lexema: Token: 8
Lexema: * Token: 5
Lexema: Token: 8
Lexema: 34 Token: 4
Lexema: ; Token: 7
Lexema:
Token: 8
Lexema:
Token: 8
Lexema: 12 Token: 4
Lexema: Token: 8
Lexema: " Token: 8
Lexema: ; Token: 7
Lexema:
Token: 8
Lexema:
Token: 8
Lexema: 123 Token: 4
Lexema: null Token: 1

Flujo de entrada (entrada.txt):

12 * 34;
12;
123


Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: 12 Token: 5
Lexema: Token: 4
Lexema: * Token: 6
Lexema: 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).
Ejemplo 5: Tokens virtuales, acciones predefinidas y predicados sintcticos.

Analizador lxico Antlr (Analex.g) :

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);} ;

Programa que utiliza el analizador anterior (Prog.java):

import java.io.*;
import antlr.*;
public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
CommonToken tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
}
}catch (FileNotFoundException e){System.out.println("Excepcin
"+e.getMessage());}
catch (TokenStreamException e){System.out.println("Excepcin
"+e.getMessage());}
}
}

Flujo de entrada (entrada.txt):

1.2

23


Fichero de texto con la definicin de los tokens:

// $ANTLR : Analex.g -> AnalexTokenTypes.txt$
Analex // output token vocab name
LIT_REAL=4
LIT_ENT=5
DIGITO=6
NUMERO=7
BLANCO=8

Interfaz Java con la definicin de tokens (AnalexTokenTypes.java):

public interface AnalexTokenTypes {
int EOF = 1;
int NULL_TREE_LOOKAHEAD = 3;
int LIT_REAL = 4;
int LIT_ENT = 5;
int DIGITO = 6;
int NUMERO = 7;
int BLANCO = 8;
}

Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: 1.2 Token: 4
Lexema: 23 Token: 5
Lexema: null Token: 1
Ejemplo 6: Predicados semnticos.

Analizador lxico Antlr (Analex.g) :

class Analex extends Lexer;
tokens {
LIT_REAL;
LIT_ENT;
}
{
boolean comentario = false;
}

protected DIGITO: '0'.. '9';

BLANCO : (' ' | '\t' | "\r\n") {$setType(Token.SKIP);} ;

INICIO_COMENTARIO : {!this.comentario}? "/*" {this.comentario = true;}
;

FIN_COMENTARIO : {this.comentario}? "*/" {this.comentario = false;}
;

NUMERO : {!this.comentario}?((DIGITO)+ '.') => (DIGITO)+ '.' (DIGITO)*
{$setType(LIT_REAL);}
| {!this.comentario}?((DIGITO)+ ) => (DIGITO)+ {$setType(LIT_ENT);}
| {this.comentario}?((DIGITO)+ '.') => (DIGITO)+ '.' (DIGITO)*
{$setType(Token.SKIP);}
| {this.comentario}?((DIGITO)+ ) => (DIGITO)+ {$setType(Token.SKIP);}
;

Programa que utiliza el analizador anterior (Prog.java):


import java.io.*;
import antlr.*;
public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
CommonToken tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
}
}catch (FileNotFoundException e){System.out.println("Excepcin
"+e.getMessage());}
catch (TokenStreamException e){System.out.println("Excepcin
"+e.getMessage());}
}
}


Flujo de entrada (entrada.txt):

1.2
/* 123 */
9

Fichero de texto con la definicin de los tokens:

// $ANTLR : Analex.g -> AnalexTokenTypes.txt$
Analex // output token vocab name
LIT_REAL=4
LIT_ENT=5
DIGITO=6
BLANCO=7
INICIO_COMENTARIO=8
FIN_COMENTARIO=9
NUMERO=10


Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: 1.2 Token: 4
Lexema: /* Token: 8
Lexema: */ Token: 9
Lexema: 9 Token: 5
Lexema: null Token: 1


Otro flujo de entrada (entrada.txt):

1.2
/* /* 123 */
9

Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: 1.2 Token: 4
Lexema: /* Token: 8
Excepcin unexpected char: '/' /// IMPORTANTE ///
Ejemplo 7: Palabras Reservadas.

Analizador lxico Antlr (Analex.g) :

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)* ;

Programa que utiliza el analizador anterior (Prog.java):


import java.io.*;
import antlr.*;
public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
CommonToken tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
}
}catch (FileNotFoundException e){System.out.println("Excepcin
"+e.getMessage());}
catch (TokenStreamException e){System.out.println("Excepcin
"+e.getMessage());}
}
}


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


Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: entero Token: 4
Lexema: x Token: 9
Lexema: juan Token: 9
Lexema: pedro Token: 9
Lexema: real Token: 5
Lexema: y Token: 9
Lexema: null Token: 1

Ejemplo 8: Reglas con Comportamiento Voraz.

Analizador lxico Antlr (Analex.g) :

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)* ;

BLOQUE: '{' (.)* '}';

Programa que utiliza el analizador anterior (Prog.java):


import java.io.*;
import antlr.*;
public class Prog {

public static void main(String[] args) {
try{
FileInputStream f =
new FileInputStream("entrada.txt");
Analex analex = new Analex(f);
CommonToken tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
while (tok.getType()!=Token.EOF_TYPE){
tok = (CommonToken)analex.nextToken();
System.out.println("Lexema: "+tok.getText()+" Token:
"+tok.getType());
}
}catch (FileNotFoundException e){System.out.println("Excepcin
"+e.getMessage());}
catch (TokenStreamException e){System.out.println("Excepcin
"+e.getMessage());}
}
}


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)* ;

BLOQUE: '{' (options{greedy=false;}:.)* '}';

Resultado ejecucin programa Prog sobre entrada.txt:

Lexema: {
entero x
juan pedro
real y
} Token: 10
Lexema: null Token: 1

You might also like