Implementación de Operadores de Dos Caracteres en Lexer

Clase 10 de 58Curso de Creación de Lenguajes de Programación: Intérpretes

Contenido del curso

Construcción del lexer o tokenizador

Construcción del parser o analizador sintáctico

Evaluación o análisis semántico

Resumen

Construir un lexer capaz de leer operadores de un solo carácter es apenas el primer paso. Cuando tu lenguaje necesita distinguir entre asignación (=) e igualdad (==), o entre negación (!) y desigualdad (!=), el lexer debe aprender a mirar hacia adelante antes de decidir qué token emitir. Aquí se explica exactamente cómo lograrlo usando dos funciones clave: peek character y make two character token.

¿Por qué el lexer necesita ver el siguiente carácter?

Hasta este punto, el lexer lee carácter por carácter y produce tokens individuales. El problema aparece con los operadores de dos caracteres [0:10]: cuando el lexer encuentra un =, no sabe si se trata de una asignación o del inicio de un == (igualdad). Lo mismo ocurre con !, que puede ser negación o el comienzo de != (desigualdad).

En lenguajes como JavaScript o Python, el doble igual (==) representa el test de igualdad, mientras que el igual simple (=) es asignación. El lexer debe replicar esa distinción.

Para resolverlo, se aprovechan las dos variables que ya existen en el lexer: position y read position [0:40]. La primera indica dónde estamos; la segunda apunta al carácter que viene después. Ahora se entiende por qué eran necesarias ambas variables desde el diseño inicial.

¿Cómo implementar el test para operadores de dos caracteres?

Siguiendo la metodología de desarrollo guiado por pruebas, se crea un test llamado test_two_character_operator [1:16]. El source de entrada es:

10 == 10; 10 != 9;

La lista de tokens esperados contiene ocho elementos:

  • INT(10), EQUALS, INT(10), SEMICOLON.
  • INT(10), NOT_EQUALS, INT(9), SEMICOLON.

Antes de ejecutar el test, es necesario agregar los nuevos token types al archivo de token [2:18]:

  • EQUALS se ubica en orden alfabético.
  • NOT_EQUALS se coloca después de NEGATION.

Al correr el test sin más cambios, el lexer reporta que esperaba un EQUALS pero encontró un ASSIGN [2:38]. Esto confirma que el lexer aún no sabe leer dos caracteres seguidos.

¿Cómo funcionan peek character y make two character token?

Dentro del archivo lexer.py se modifica la lógica para los símbolos = y ! [2:55].

¿Qué hace peek character?

La función peek_character no recibe parámetros y retorna un string [4:02]. Su lógica es directa:

python def peek_character(self) -> str: if self.read_position >= len(self.source): return '' return self.source[self.read_position]

  • Si read_position supera la longitud del source, ya no hay nada que leer y devuelve una cadena vacía.
  • En caso contrario, devuelve el carácter en read_position sin avanzar la posición actual.

¿Qué hace make two character token?

Esta función recibe un token_type como parámetro y retorna un token compuesto [4:36]:

python def make_two_character_token(self, token_type: TokenType) -> Token: prefix = self.character self.read_character() suffix = self.character return Token(token_type, f'{prefix}{suffix}')

  • Guarda el carácter actual como prefijo.
  • Llama a read_character() para avanzar al siguiente carácter.
  • Guarda el nuevo carácter actual como sufijo.
  • Concatena ambos y crea el token con el tipo correspondiente.

La llamada a read_character() en medio es fundamental: permite que el lexer se posicione correctamente para la siguiente iteración [5:00].

¿Cómo se conecta todo en el lexer?

Cuando el lexer encuentra =:

  • Usa peek_character() para ver si el siguiente también es =.
  • Si lo es, genera un token EQUALS con make_two_character_token.
  • Si no, genera un token ASSIGN normal.

La misma lógica aplica para !:

  • Si el siguiente carácter es =, genera NOT_EQUALS.
  • Si no, genera NEGATION.

Tras corregir un pequeño error tipográfico en la línea 114 detectado por los propios tests [5:28], todas las pruebas pasan correctamente.

¿Qué puede hacer ahora el lexer completo?

Con esta implementación, el lexer ya reconoce [5:42]:

  • Operadores de un carácter: asignación, negación, suma, resta.
  • Operadores de dos caracteres: igualdad y desigualdad.
  • Keywords: si, si_no, variable, regresa, verdadero, falso, procedimiento.
  • Delimitadores: paréntesis, llaves, comas, puntos y comas.
  • Literales: enteros e identificadores.

El siguiente paso será construir un REPL (Read-Eval-Print Loop) para interactuar directamente con el intérprete, enviándole statements y expresiones en tiempo real [6:25]. ¿Ya modificaste algo en tu propio lenguaje? Comparte cómo va tu lexer y qué se siente programar en español.