domingo, 2 de mayo de 2010

Java Analizador Léxico y Sintáctico


Este ejemplo muestra como realizar un analizador léxico a mano en java, el analizador léxico reconoce los elementos básicos para una calculadora : "+", "-", "*", "/" ademas de números enteros, también se incluye un analizador sintáctico implementado por descenso recursivo para la siguiente gramática

E -> num EP

EP -> "+" num EP
         | "-" num EP
         | epsilon

el diagrama de estados del analizador léxico es el siguiente, acompañado de su tabla de transiciones.







public class Lexer {

    private CharReader mLector = null;

    private int mNumeroDeLinea = 1;
    private int mNumeroDeCaracter = 1;
    private String mLexema = ""; //texto del token

    private boolean hayError =
        false; //para saber desde afuera, si hay algun error

    public static int TOKEN_PALABRA = 1001;
    public static int TOKEN_COMA = 1002;
    public static int TOKEN_ESPACIO = 1003;
    public static int TOKEN_INT = 1004;
    public static int TOKEN_SUMA = 1005;
    public static int TOKEN_RESTA = 1006;
    public static int TOKEN_MUL = 1007;
    public static int TOKEN_DIV = 1008;
    public static int TOKEN_FLOAT = 1009;

    public String getUltimoLexema() {
        return mLexema;
    }
    
    public Lexer() {
    }

    public int getNextToken() {

        if (mLector == null) {
            return -1;
        }

        char caracterActual;

        int estadoActual = 0;

        hayError = false;

        mLexema = "";

        while (mLector.listo()) {

            caracterActual = peekChar();

            if (estadoActual == 0) {

                //transicion con S
                if (Character.isWhitespace(caracterActual)) {
                    estadoActual = 1;
                    readChar(); //consumir el caracter
                } else if (Character.isLetter(caracterActual)) { //
                    estadoActual = 2;
                    readChar(); //consumir el caracter
                } else if (Character.isDigit(caracterActual)) { // D
                    estadoActual = 3; // este es el estado de numero, el 3 
                    readChar(); //consumir el caracter
                } else if (caracterActual == '+') {
                    estadoActual = 4;
                    readChar(); //consumir el caracter
                } else if (caracterActual == '-') {
                    estadoActual = 5;
                    readChar(); //consumir el caracter
                } else if (caracterActual == '*') {
                    estadoActual = 6;
                    readChar(); //consumir el caracter
                } else if (caracterActual == '/') {
                    estadoActual = 7;
                    readChar(); //consumir el caracter
                } else {
                    //llega un caracter que no es valido en este estado
                    hayError = true;
                    readChar(); //quitar el error ( un caracter )
                    return -1;
                }

            } //fin del estado 0
            else if (estadoActual == 1) {

                if (Character.isWhitespace(caracterActual)) {
                    estadoActual = 1; //inncesario pero mas claro si
                    readChar(); //consumir el caracter
                } else {
                    
                    mLexema = ""; //
                    estadoActual = 0;
                    //return TOKEN_ESPACIO;
                }

            } else if (estadoActual == 2) {

                if (Character.isLetter(caracterActual)) {
                    estadoActual = 2;
                    readChar(); //consumir el caracter
                } else {
                    return TOKEN_PALABRA;
                }

            } else if (estadoActual == 3) {

                if (Character.isDigit(caracterActual)) {
                    estadoActual = 3;//
                    readChar(); //consumir el caracter
                } else if (caracterActual == '.') {
                    estadoActual = 8;
                    readChar(); //consumir el caracter
                } else {
                    return TOKEN_INT;
                }

            } else if (estadoActual == 4) {
                return TOKEN_SUMA;
            } else if (estadoActual == 5) {
                return TOKEN_RESTA;
            } else if (estadoActual == 6) {
                return TOKEN_MUL;
            } else if (estadoActual == 7) {
                return TOKEN_DIV;
            } else if (estadoActual == 8) {


                if (Character.isDigit(caracterActual)) {
                    estadoActual = 9;
                    readChar(); //consumir el caracter
                } else {
                    //error lexico, este no es de aceptacion
                    hayError = true;
                    readChar(); //quitar el error ( un caracter )
                    return -1;
                }

            } else if (estadoActual == 9) {
                if( Character.isDigit( caracterActual ) ) {
                    estadoActual = 9; // eso falto 
                    readChar();
                }
                return TOKEN_FLOAT;
            }

        }

        //caso que llegue hasta aqui , es que no encontro token
        return -1;
    }

    private char peekChar() {

        if (mLector == null) {
            //no hay archivo abierto
            return Character.MIN_VALUE;
        }

        if (!mLector.listo()) {
            //no esta listo
            return Character.MIN_VALUE;
        }

        return mLector.peekNextChar();

    }

    private char readChar() {

        if (mLector == null) {
            //no hay archivo abierto
            return Character.MIN_VALUE;
        }

        if (!mLector.listo()) {
            //no esta listo
            return Character.MIN_VALUE;
        }

        char temp = mLector.ReadNextChar();

        //si el caracter actual es ENTER "" == cadenas , '' == caracter
        if (temp == '\n') {

            mNumeroDeLinea++; // incrementar en 1
            mNumeroDeCaracter = 1; //regresar a 1

        } else {

            mNumeroDeCaracter++;

        }

        //concatenar este caracter, a la cadena mLexema
        mLexema += temp;

        return temp;

    }

    public void inicializar(String pFilePath) {

        //solo preparar el charReader con el archivo que nos indican
        mLector = new CharReader();

        mLector.inicializar(pFilePath);

        mNumeroDeLinea = 1;
        mNumeroDeCaracter = 1;

    }

}


Descargar Codigo Fuente