Se implementaría un analizador léxico simple como un “envoltorio” alrededor de una secuencia de entrada (que representa el texto fuente del programa) que le permite “retroceder” los caracteres en la secuencia. (java.io.PushbackReader es un ejemplo de esto). Tal lexer sería responsable de omitir el espacio en blanco en la entrada, reconocer los comentarios y omitirlos, y reconocer varios tokens. Las palabras clave pueden reconocerse junto con los identificadores, y luego se utilizaría un paso de búsqueda por separado para detectar una palabra clave y devolver el token de palabra clave apropiado, o insertar un identificador en la tabla de símbolos y devolver un token “identificador”. Los tokens de caracteres numéricos y especiales se pueden devolver directamente, con cierta anticipación necesaria para distinguir entre tokens como “>”, “> =” y “>>”.
En cuanto al análisis, una de las formas más comunes de escribir analizadores sin un generador de analizadores es escribir un analizador de descenso recursivo , que a menudo es adecuado para analizar construcciones de lenguaje de programación. Considere este fragmento de una gramática del lenguaje de programación (en algo similar a Backus-Naur Form, o BNF):
declaración :: = expresión
El | Sentencia IF ‘(‘ expresión ‘)’ [instrucción ELSE]
El | MIENTRAS declaración ‘(‘ expresión ‘)’
El | ‘{‘ declaración-lista ‘}’
;
- ¿Cómo es que los piratas informáticos 'olfatean' los datos personales del tráfico de Internet en una conexión Wi-Fi pública?
- Si el mundo tal como lo observamos fuera realmente una simulación interactiva (como se sugiere en ciertas películas de ciencia ficción), ¿qué tipo de potencia informática se necesitaría para ejecutarlo? ¿Cuánto poder dibujaría?
- ¿Por qué los estudiantes de informática son tan elitistas?
- Cómo obtener UPSEE y obtener CS en HBTI
- ¿Por qué no podría ser reemplazada la HCI por sentido común básico?
Esto podría implementarse mediante un pseudocódigo que se parece a esto:
Sentencia parse_statement ()
{
Token t = peek_next_token ();
si (t == IF)
return parse_if_statement ();
más si (t == MIENTRAS)
return parse_while_statement ();
si no (t == ‘{‘)
return parse_block_statement ();
más
devolver nuevo ExpressionStatement (parse_expression ());
}
Sentencia parse_if_statement ()
{
match_token (IF);
match_token (‘(‘);
Expresión expr = parse_expression ();
match_token (‘)’);
Sentencia thenstmt = parse_statement ();
if (peek_next_token () == ELSE)
{
match_token (ELSE);
Sentencia elsestmt = parse_statement ();
devolver nuevo IfStatement (expr, thenstmt, elsestmt);
}
más
devolver nuevo IfStatement (expr, thenstmt, null);
}
Sentencia parse_while_statement ()
{
match_token (MIENTRAS);
match_token (‘(‘);
Expresión expr = parse_expression ();
match_token (‘)’);
Sentencia stmt = parse_statement ();
return new WhileStatement (expr, stmt);
}
Sentencia parse_block_statement ()
{
match_token (‘{‘);
List list = new ArrayList ();
while (peek_next_token ()! = ‘}’)
{
list.add (parse_statement ());
}
match_token (‘}’);
devolver nueva BlockStatement (lista);
}
En el código anterior, dos operaciones básicas interactúan con el lexer:
- peek_next_token () mira el siguiente token en la entrada, sin consumirlo, y lo devuelve.
- match_token () consume el siguiente token de la entrada y arroja un error si el token no es igual al que se pasó a la función.
Tampoco he definido parse_expression () por brevedad, y porque dejé “expresión” indefinida en el fragmento de gramática original.
Tenga en cuenta que este analizador utiliza la pila de llamadas para ayudar a rastrear lo que se analiza y crea un árbol de sintaxis abstracta (AST) correspondiente al texto del programa analizado.
El tema de la construcción de lexers y analizadores es mucho más complicado de lo que podría esperar en una sola respuesta. Para más información, vea los capítulos 3 y 4 de Compiladores: Principios, Técnicas y Herramientas , por Alfred V. Aho, Ravi Sethi. y Jeffrey D. Ullman (Addison-Wesley, 1986), el famoso “Libro del Dragón”.
Punta de sombrero: Aryeh Friedman para la A2A.