Como quiere aprender cómo funcionan los lexers, supongo que realmente quiere saber cómo funcionan los generadores de lexer.
Un generador de lexer toma una especificación léxica, que es una lista de reglas (pares de símbolos de expresión regular) y genera un lexer. Este lexer resultante puede transformar una cadena de entrada (carácter) en una cadena de token de acuerdo con esta lista de reglas.
El método que se usa más comúnmente consiste principalmente en transformar una expresión regular en un autómata finito determinista (DFA) a través de un autómata no determinista (NFA), más algunos detalles.
Una guía detallada de hacer esta transformación se puede encontrar aquí . Tenga en cuenta que no lo he leído yo mismo, pero se ve bastante bien. Además, casi cualquier libro sobre construcción de compiladores presentará esta transformación en los primeros capítulos.
Si está interesado en diapositivas de cursos sobre el tema, no hay duda de que hay una cantidad infinita de cursos sobre la construcción de compiladores. Desde mi universidad, puedes encontrar tales diapositivas aquí y aquí .
Hay algunas cosas más que no se emplean comúnmente en lexers o que se tratan en textos, pero que son bastante útiles:
En primer lugar, manejar Unicode es algo no trivial. El problema es que la entrada ASCII tiene solo 8 bits de ancho, lo que significa que puede tener fácilmente una tabla de transición para cada estado en el DFA, porque solo tienen 256 entradas. Sin embargo, Unicode, que tiene 16 bits de ancho (si usa UTF-16), requiere tablas de 64k para cada entrada en el DFA. Si tiene gramáticas complejas, esto puede comenzar a ocupar bastante espacio. Llenar estas tablas también comienza a tomar bastante tiempo.
Alternativamente, podría generar árboles de intervalos. Un árbol de rango puede contener las tuplas ('a', 'z'), ('A', 'Z'), por ejemplo, que es mucho más eficiente en la memoria que tener la tabla completa. Si mantiene intervalos no superpuestos, puede usar cualquier árbol binario equilibrado para este propósito. El tiempo de ejecución es lineal en la cantidad de bits que necesita para cada carácter, por lo que O (16) en el caso de Unicode. Sin embargo, en el mejor de los casos, generalmente será un poco menos.
Otro problema es que los lexers, como se generan comúnmente, en realidad tienen un rendimiento cuadrático en el peor de los casos. Aunque este comportamiento en el peor de los casos no se ve comúnmente, puede morderte. Si se encuentra con el problema y quiere resolverlo, aquí puede encontrar un documento que describe cómo lograr el tiempo lineal .
Probablemente querrá poder describir expresiones regulares en forma de cadena, como normalmente aparecen. Sin embargo, analizar estas descripciones de expresiones regulares en NFA (o posiblemente una estructura intermedia recursiva primero) es un problema de huevo de gallina. Para analizar descripciones de expresiones regulares, el algoritmo Shunting Yard es muy adecuado. Wikipedia parece tener una página extensa sobre el algoritmo .