2010-01-30 13 views
22

I análisis de fuente agregado recientemente analizado a una herramienta existente que generó archivos de salida a partir de argumentos de línea de comando complejos.¿Existe una herramienta mejor (más moderna) que lex/flex para generar un tokenizer para C++?

Los argumentos de la línea de comandos llegaron a ser tan complejos que comenzamos a permitir que se suministraran como un archivo que se analizó como si fuera una línea de comando muy grande, pero la sintaxis aún era incómoda. Así que agregué la capacidad de analizar un archivo fuente usando una sintaxis más razonable.

Utilicé flex 2.5.4 para Windows para generar el tokenizer para este formato de archivo fuente personalizado, y funcionó. Pero odiaba el código. las variables globales, la convención de nomenclatura extraña y el código de C++ que generó fueron terribles. El backend de generación de código existente estaba pegado a la salida de flex: no uso yacc o bison.

Estoy a punto de sumergirme en ese código y me gustaría utilizar una herramienta mejor/más moderna. ¿Alguien sabe de algo?

  • Se ejecuta en el intérprete de comandos de Windows (integración de Visual Studio está bien, pero yo uso que los archivos para construir)
  • Genera un adecuado tokenizer encapsulado C++. (Sin variables globales)
  • Utiliza expresiones regulares para describir las reglas de tokenización (compatible con sintaxis lex a plus)
  • No me obliga a utilizar el c-runtime (o simularlo) para la lectura de archivos. (Análisis sintáctico de la memoria)
  • me advierte cuando mis reglas obligan al tokenizer que dar marcha atrás (o correcciones de forma automática)
  • me da un control total sobre los nombres de variables y métodos (para que pueda ajustarse a mi convención de nomenclatura existente)
  • me permite enlazar varios programas de análisis en un solo .exe y sin conflictos de nombres
  • se puede generar un analizador Unicode (UCS-2 de 16 bits), si yo quiero que
  • no es una tokenizer + integrado generador de analizadores sintácticos (Quiero un lex reemplazo, no reemplazo de lex + yacc)

Probablemente podría vivir con una herramienta que acaba de generar las tablas de tokenización si eso fuera lo único disponible.

+3

Boost.Spirit, Boost.Proto y Boost.Xpressive no son opciones? –

+0

@Konrad: pueden ser, no estoy familiarizado con ellos. algo que genere plantillas en lugar de una clase de C++ sería aceptable. –

Respuesta

11

Ragel: http://www.complang.org/ragel/ Se ajusta a la mayoría de sus requisitos.

  • Se ejecuta en Windows
  • no declara las variables, por lo que puede ponerlos dentro de una clase o dentro de una función como desee.
  • Tiene buenas herramientas para analizar expresiones regulares para ver cuándo retrocederían. (No sé mucho sobre esto, ya que nunca uso la sintaxis en Ragel que crearía un analizador de retroceso).
  • Los nombres de las variables no se pueden cambiar.
  • Los nombres de las tablas llevan como prefijo el nombre de la máquina, y se declaran "const static", por lo que puede poner más de uno en el mismo archivo y tener más de uno con el mismo nombre en un solo programa (siempre que están en diferentes archivos).
  • Puede declarar las variables como cualquier tipo de entero, incluido UChar (o el tipo de UTF-16 que prefiera). Sin embargo, no maneja automáticamente pares sustitutos. Tampoco tiene clases de caracteres especiales para Unicode (creo).
  • Solo hace expresiones regulares ... no tiene funciones de bison/yacc.

El código que genera interfiere muy poco con un programa. El código también es increíblemente rápido, y la sintaxis de Ragel es más flexible y legible que cualquier cosa que haya visto. Es una pieza de software sólida como una roca. Puede generar un analizador basado en tablas o un analizador controlado por goto.

+0

+1 esto parece prometedor. –

+0

Lo uso yo mismo y estoy totalmente de acuerdo. También hay Kelbt, del mismo autor, para el análisis: no es una versión de lanzamiento y tiene sus peculiaridades (en particular, no asocia asociatividad o desambiguación de precedencia), pero la he estado usando de todos modos y los únicos bloqueos son " había tenido tiempo de compilación y fue el resultado de errores de código (haciendo referencia a un token inexistente en una acción de análisis). – Steve314

+0

También utilicé treecc para la definición de nodo AST con operaciones de despacho múltiple, en combinación con Kelbt y Ragel. En estos días, tengo mi propio reemplazo con algunos trucos adicionales (por ejemplo, clases de iterador de recorrido AST) - Incluso puedo lanzarlo, un día ... – Steve314

5

Hay dos herramientas que te vienen a la mente, aunque deberías averiguar por ti mismo cuál sería adecuado, Antlr y GoldParser. Hay enlaces de lenguaje disponibles en ambas herramientas en los que se puede conectar al entorno de tiempo de ejecución C++.

+0

Hablando de eso cuando fui a buscar en Google, aparentemente hay una versión orientada a objetos de flex/bison utilizando la biblioteca de impulso - compruébalo http://dudka.cz/vyp08 – t0mm13b

+0

Ya sabía sobre asta y lo encontré inadecuado. Soy un generador de analizadores y requiere la instalación del tiempo de ejecución de Java, que en mi experiencia es inestable y molesto en Windows. GoldParser parece prometedor, gracias. –

+0

@ tommeib75: dudka.cz buen hallazgo. tal vez él tiene una mejor manera de arreglar la salida flexible en código limpio. –

5

Flex también tiene una opción de salida C++.
El resultado es un conjunto de clases que hacen ese análisis sintáctico.

Apenas añada lo siguiente a la cabeza de ustedes archivo lex:

%option C++ 
%option yyclass="Lexer" 

Luego, en que es fuente:

std::fstream file("config"); 
Lexer   lexer(&file) 
while(int token = lexer.yylex()) 
{ 
} 
+0

Sí, lo intenté, es incluso peor que el código C IMO, pero resuelve las variables golbal y el problema de varias instancias. –

+1

Como no mantiene el código producido, sus detalles estéticos son irrelavantes. Su archivo de origen es el archivo lex. Mientras el código funcione no contamine el espacio de nombre global, los detalles de implementación son irrelevantes.Nota 1: No construya los archivos fuente solo construya los archivos y encabezados del objeto (es decir, elimine la fuente de inmediato). Haga que la dependencia entre el objeto y el archivo lex no sea el archivo fuente. Nota: Son messey porque lo hacen eficiente. –

6

Boost.Spirit.Qi (parser-tokenizer) o realce. Spirit.Lex (solo tokenizer). Adoro a Qi, y Lex tampoco está mal, pero tiendo a tomar Qi para mis necesidades de análisis ...

El único inconveniente real con Qi tiende a ser un aumento en el tiempo de compilación, y también se ejecuta un poco más lento que el código de análisis escrito a mano. Sin embargo, en general es mucho más rápido que el análisis con expresiones regulares.

http://www.boost.org/doc/libs/1_41_0/libs/spirit/doc/html/index.html

+0

Gracias, echaré un vistazo a Boost.Spirit.Lex –

2

boost.spirit y Yard parser vienen a la mente. Tenga en cuenta que el enfoque de tener generadores lexer es algo sustituido por C++ DSL interno (lenguaje específico del dominio) para especificar tokens. Simplemente porque es parte de su código sin usar una utilidad externa, simplemente siguiendo una serie de reglas para especificar su gramática.

Cuestiones relacionadas