Una forma más sencilla de compilar tus proyectos de Flex y Bison.
¿Qué debo tener instalado en Windows?
-
MinGW y GCC con las variables de entorno incluidas.
-
Los siguientes programas de GnuWin32 (la opción que dice "Complete package, except sources") instalado en una carpeta sin espacios (puede ser, al igual que para MinGW,
C:\GnuWin32
):
La variable de entorno PATH
debe apuntar hacia la subcarpeta bin
(ej:
C:\GnuWin32\bin
).
- Crear una nueva variable de entorno llamada
LIBRARY_PATH
y asignarle como valor la ruta hacia la subcarpetalib
(ej:C:\GnuWin32\lib
)1.
-
Windows Terminal (recomendado).
-
Una consola Bash, que puede ser la que viene con Git.
Para poder abrirla desde Windows Terminal, cuando estemos instalando Git debemos tildar la opción que dice "Add a Git Bash profile to Windows Terminal":
¿Qué debo tener instalado en Ubuntu?
Make y gcc vienen instalados en forma nativa, se puede averiguar con el flag
--version
:
$ gcc --version
$ make --version
En el caso de Flex y Bison, se pueden obtener con el gestor de paquetes
apt-get
:
$ sudo apt-get install libfl-dev libbison-dev
Para descargar los templates deberemos abrir una consola Bash y ejecutar:
- Para Flex:
$ mkdir "nombre-del-proyecto"
$ cd nombre-del-proyecto
$ curl -fsSL https://github.com/RaniAgus/ssl-flex-bison-projects/releases/download/v1.1/flex-v1.1.tar.gz \
| tar xvzf - --strip-components 1
- Para Bison:
$ mkdir "nombre-del-proyecto"
$ cd nombre-del-proyecto
$ curl -fsSL https://github.com/RaniAgus/ssl-flex-bison-projects/releases/download/v1.1/bison-v1.1.tar.gz \
| tar xvzf - --strip-components 1
En el repo se encuentran dos archivos makefile (uno para solo flex y otro para flex y bison), los cuales se rigen bajo la siguiente estructura para funcionar:
.
│
└─── src/
| └─── <nombre_archivo_final>.l # Archivo flex
| └─── <nombre_archivo_final>.y # Archivo bison (si corresponde)
| └─── ... # Código C (archivos *.c y *.h)
└─── makefile # Archivo makefile para compilar el proyecto
Al compilar, se generará lo siguiente:
.
│
└── bin/
| └─── <nombre_archivo_final>.exe/.out # Archivo ejecutable generado por gcc
└── obj/
└─── <nombre_archivo_final>.yy.c # Código C generado por flex
└─── <nombre_archivo_final>.tab.c # Código C generado por bison (si corresponde)
└─── <nombre_archivo_final>.tab.h # Encabezado C generado por bison (si corresponde)
└─── <nombre_archivo_final>.output # Gramática generada por bison (si corresponde)
└─── ... # Código máquina generado por gcc (archivos *.o)
Para que los makefiles funcionen, es fundamental usarlos siempre en una consola Bash. Para configurarla por default en VSCode se deberá hacer lo siguiente:
Para resaltar la sintaxis de Flex y Bison, recomiendo usar el plugin Yash:
Para ejecutar los makefiles, nos moveremos a la ruta donde se encuentra nuestro
archivo makefile
y usaremos el comando make
seguido de alguna de las reglas
existentes de ser necesario. Si querés ver cómo funciona el makefile, podés
hacerlo en la wiki de este repo.
$ make
$ make clean
Esto es útil por si uno quiere compilar todo el proyecto desde cero. Si tu intención es eliminar los objetos generados del repo, te aconsejo usar un archivo gitignore.
$ make debug
En el caso de Bison, para debugear el proyecto hay que tener dentro del
main()
, antes de yyparse()
, las siguientes tres líneas:
#if YYDEBUG
yydebug = 1;
#endif
Para más información sobre cómo funciona esta regla, podés ver la sección sobre make debug en la wiki de este repo.
El ejecutable generado va a imprimir por la salida estándar las reglas por las que va derivando:
Starting parse
Entering state 0
Reducing stack by rule 1 (line 29):
-> $$ = nterm input ()
Stack now 0
Entering state 1
Reading a token: --(end of buffer or a NUL)
Probablemente, a medida que el proyecto vaya escalando, leer eso desde la
consola te resulte poco práctico, así que una forma rápida en Bash de redirigir
stdout
a un archivo de log sin modificar código es la siguiente:
$ ./main.out &> main.log
Esto me genera un archivo main.log
que puede ser abierto por cualquier editor
de texto. En VSCode, incluso se puede abrir durante la ejecución y seguirlo en
tiempo real como si fuera el stdout
.
Al principio del makefile hay un comentario que lo explica muy simple:
# Agregar bibliotecas necesarias acá (por ejemplo, -lm para incluir <math.h>)
LIBS+=-lfl
Entonces, si queremos incluir una biblioteca como math, simplemente concatenamos ahí el flag correspondiente.
make: Nothing to be done for 'all'.
¡No es un error! Significa que los archivos en src/
no fueron modificados
desde la última vez que se compiló el proyecto. Asegurate de haber guardado los
últimos cambios antes de compilar ;)
makefile:35: *** missing separator. Stop.
Esto se debe a que el make es sensible a los tabs. Probablemente habrás copiado
el texto del makefile, y lo habrás pegado en un bloc de notas o en el VSCode, y
el editor incluyó espacios en vez de tabs con \t
.
En VSCode esto se puede resolver de esta forma.
Probablemente, si estás en Windows y al ejecutar make
se crea una subcarpeta
-p
, además de aparecer errores del estilo:
Ya existe el subdirectorio o el archivo -p.
Error mientras se procesaba: -p.
Ya existe el subdirectorio o el archivo obj.
Error mientras se procesaba: obj.
make: *** [Ejemplo.exe] Error 1
y al ejecutar make clean
también puede que te aparezca algo como:
process_begin: CreateProcess(NULL, uname, ...) failed.
rm -f obj/*
process_begin: CreateProcess(NULL, rm -f obj/*, ...) failed.
make (e=2): El sistema no puede encontrar el archivo especificado.
make: *** [clean] Error 2
Es porque estás usando la consola cmd o Powershell. Asegurate de cambiarla a Bash como se explica más arriba.
Footnotes
-
Esto permite que GCC encuentre las bibliotecas de Flex y Bison, más info en: https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html ↩