Analizador Léxico

Un analizador léxico es el componente encargado de identificar los tokens válidos en un código de entrada y emitir errores de ser necesario, crearemos un analizador léxico basado en expresiones regulares capaz de detectar números, cadenas, comentarios, operadores, identificadores y palabras reservadas.

El analizador léxico deberá informar de cada token encontrado, en que linea y columna exactamente fue extraído el token, ademas del indice del token, el tipo y el lexema que lo representa, toda esta información la mostraremos en un ListView de WPF.

Uso de Expresiones regulares


Para construir el analizador léxico utilizaremos la clase Regex que implementa el motor de expresiones regulares de .Net Framework, este nos permitirá buscar modelos de caracteres o patrones que representan nuestros tokens admitidos por el analizador léxico, regex creara el AFN (Autómata Finito No Determinista) correspondiente a la expresión regular que creemos.

Para especificar los modelos de caracteres admitidos necesitamos conocer el lenguaje de expresiones regulares, si no estamos familiarizados con las expresiones regulares mira: Introducción a Expresiones Regulares.

Analizador Léxico Basado en Expresiones Regulares


Nuestro analizador léxico identificara la sintaxis básica de el lenguaje C#, para ello definiremos las siguientes expresiones regulares:

csLexer.AddTokenRule(@"\s+", "ESPACIO", true);           
csLexer.AddTokenRule(@"\b[_a-zA-Z][\w]*\b", "IDENTIFICADOR");
csLexer.AddTokenRule("\".*?\"", "CADENA");
csLexer.AddTokenRule(@"'\\.'|'[^\\]'", "CARACTER");
csLexer.AddTokenRule("//[^\r\n]*", "COMENTARIO1");
csLexer.AddTokenRule("/[*].*?[*]/", "COMENTARIO2");
csLexer.AddTokenRule(@"\d*\.?\d+", "NUMERO");             
csLexer.AddTokenRule(@"[\(\)\{\}\[\];,]", "DELIMITADOR");
csLexer.AddTokenRule(@"[\.=\+\-/*%]","OPERADOR");
csLexer.AddTokenRule(@">|<|==|>=|<=|!", "COMPARADOR");

El método AddTokenRule agrega un patrón a reconocer, debemos indicar el primer lugar la expresión regular, seguido de un nombre para el token y por ultimo un valor tipo bool opcional que indica si se debe ignorar el correspondiente token.

Para detectar la palabras reservadas del lenguaje solo agregaremos una lista de estas palabras, si el token IDENTIFICADOR pertenece a la lista de palabras reservadas cambiamos el nombre de token a RESERVADO.

La clase RegexLexer es la encargada de compilar la expresión regular, crear el AFN y detectar los correspondientes tokens, una vez inicializada la clase llamamos al método GetTokens(string).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public IEnumerable GetTokens(string text)
 {
     if (requiereCompilar) throw new Exception("Compilación Requerida, llame al método Compile(options).");

     Match match = rex.Match(text);

     if (!match.Success) yield break;

     int line = 1, start = 0, index = 0;

     while (match.Success)
     {
         if (match.Index &gt; index)
         {
             string token = text.Substring(index, match.Index - index);

             yield return new Token("ERROR", token, index, line, (index - start) + 1);

             line += CountNewLines(token, index, ref start);
         }

         for (int i = 0; i &lt; GNumbers.Length; i++)
         {
             if (match.Groups[GNumbers[i]].Success)
             {
                 string name = rex.GroupNameFromNumber(GNumbers[i]);

                 yield return new Token(name, match.Value, match.Index, line, (match.Index - start) + 1);

                 break;
             }
         }

         line += CountNewLines(match.Value, match.Index, ref start);
         index = match.Index + match.Length;
         match = match.NextMatch();
     }

     if (text.Length &gt; index)
     {
         yield return new Token("ERROR", text.Substring(index), index, line, (index - start) + 1);
     }
 }

Utilizaremos un ListView para crear una vista de nuestros tokens encontrados, aquellos tokens no admitidos serán marcados en rojo y contados como error, la GUI se vera de este modo.


Este es un ejemplo sencillo y muy básico de como crear un analizador léxico usando expresiones regulares en .net, no se admiten todas las características del lenguaje C# pero podemos agregar las expresiones regulares correspondientes si lo deseamos.

Descargar Analizador Léxico.

Comentarios

  1. Como haria si quisiera que analizara un codigo que se encuentra en un archivo .txt?

    ResponderEliminar
    Respuestas
    1. Enves de recibir un codigo den la caja seria una importancion de texto, tendrias que poner el codigo para importar un txt.

      Eliminar
  2. Donde se meten las listas para agregar mas palabras reservadas? Saludos

    ResponderEliminar
    Respuestas
    1. en la variable palabrasReservas, la misma es una lista de string

      Eliminar
  3. ¿Cómo puedo clasificar los tipos de operadores en aritméticos, lógicos, etc?

    ResponderEliminar
    Respuestas
    1. Solo debes crear la expresión regular correspondiente, por ejemplo, la expresión: "[\.=\+\-/*%]" los operadores matemáticos básicos, puedes añadir más operadores o crear otra para los operadores lógicos que desees reconocer.

      Eliminar
    2. Hola, gracias por responder, lo he creado de la siguiente manera:

      csLexer.AddTokenRule(@"[\&\!\|]", "OPERADOR LOGICO");

      Pero me da el siguiente error:

      "Nombre de grupo no válido: los nombres de grupos deben empezar con un carácter de palabra."

      Eliminar
    3. El nombre que le das al grupo no es válido, usa OPERADOR_LOGICO sin espacios y todo funcionará correctamente.

      Eliminar
    4. Muchas gracias, quedó de maravilla, saludos. ¿Cualquier duda puedo preguntarte?

      Eliminar
  4. Disculpa, ¿Cómo puedo hacer que los identificadores sólo sean de 10 caracteres?

    ResponderEliminar
    Respuestas
    1. Lo que debes comprender para realizar tu proyecto es como funcionan las expresiones regulares, para este caso necesitas usar los cuantificadores, por ejemplo, la expresión: \d{2, 8} buscará una coincidencia de 2 a 8 números decimales, otro ejemplo: [a-z]{10} identificará 10 caracteres en minúscula.

      Más información: https://msdn.microsoft.com/es-es/library/3206d374(v=vs.110).aspx

      Eliminar
    2. Gracias, lo revisaré, saludos...

      Eliminar
  5. Disculpa como puedo agregar una palabra reservada ?

    ResponderEliminar
  6. Hola, ¿Cómo se puede hacer el análisis sintáctico con este programa? Te agradecería mucho la ayuda.

    ResponderEliminar
    Respuestas
    1. Lo pudiste resolver? Estoy buscando esto tambien

      Eliminar
    2. Si, logré terminarlo hace un par de años, en base a este proyecto publicado.

      Eliminar
  7. Gracias por tu aporte amigo, voy a darle buen uso.

    ResponderEliminar
  8. muchas gracias
    tratare de mejorarlo ¿si tengo alguna duda puedo preguntar?
    espero y sigas aquí

    ResponderEliminar
  9. hola, disculpa de casualidad no realizaste algún pseudocodigo o diagrama de flujo? agradecería una respuesta, gracias

    ResponderEliminar
  10. Hola, buenas noches.
    ¿Cómo podría hacer que la linea sea de 100 en 100 y la columna sea basada en la linea por lo cual sea 101,102,201,202...etc?

    ResponderEliminar

Publicar un comentario

Temas relacionados

Entradas populares de este blog

tkinter Grid

Histogramas OpenCV Python

Modelo de Iluminación Phong - Tutorial OpenGL

tkinter Canvas