¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Encontrar lo que el parser no ve (semántica)

Después de esta lección: Puedo encontrar los errores que un analizador sintáctico no ve.

Lección de 50 min13 comandosLaboratorio de compiladores y arquitectura: gcc, flex, bison y RISC-V en una VM

Una nómina que cumple la gramática

Un script de nóminas termina con show salary + bonus. La gramática lo acepta. Todos los tokens son correctos.

Pero bonus solo existía dentro de un bloque que ya se cerró. El analizador sintáctico comprueba la forma de una frase, no si tiene sentido. De eso se ocupa la parte siguiente del compilador.

Al final de esta lección

Nota

Puedo encontrar los errores que un analizador sintáctico no ve.

Palabras clave

PalabraQué significaEjemplo
Análisis semánticocomprobar que un programa tiene sentido
Declaraciónla línea que crea un nombreint step
Ámbitola parte del programa donde existe un nombre
Tabla de símbolosla lista que guarda el compilador de los nombres vivos
Tipola clase de valor que guarda algoint
Avisoun mensaje que no detiene la compilaciónwarning

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

El compilador lleva una lista de nombres

Mientras recorre el árbol, el compilador lleva una tabla de símbolos. Cada { abre un ámbito nuevo encima. Cada declaración añade un nombre al ámbito de arriba. Cada } tira el ámbito de arriba.

Para comprobar un nombre, busca en el ámbito de arriba, luego en el de debajo, y así hasta el final. Si no lo encuentra, el nombre no está declarado.

Entra en la carpeta del compilador

Comando
cd ~/compiler

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Las líneas que declaran un int

Comando
grep -n "int " scope.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejemplo: la tabla de símbolos de scope.c

LíneaQué pasaNombres vivos
4 y 5main declara unused y totalunused, total
6El bucle abre un ámbito y declara iunused, total | i
7El cuerpo del bucle declara stepunused, total | i | step
9El bucle termina y sus ámbitos se tiranunused, total
10printf usa step: no estáunused, total

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Compila sin comprobaciones extra

Comando
gcc -c scope.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ahora pide los avisos habituales

Comando
gcc -Wall -c scope.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Cada llamada tiene que encajar

El compilador comprueba también que cada llamada encaje con su declaración. square recibe un int y devuelve un int.

Los Runs hacen dos copias de hello.c con sed. En args.c, la llamada pasa dos argumentos. En noret.c, square acaba con un return sin valor. Las dos copias tienen la forma correcta para la gramática.

Una copia con un argumento de más

Comando
sed 's/square(7)/square(7, 2)/' hello.c > args.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Compila la primera copia

Comando
gcc -c args.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Una copia que no devuelve nada

Comando
sed 's/return n \* n/return/' hello.c > noret.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Compila la segunda copia

Comando
gcc -c noret.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un error para la compilación, un aviso no

La última copia, fmt.c, pide a printf un texto con %s y le da un número. gcc sabe cómo lee printf su formato, así que lo nota.

Esta vez da un aviso. La compilación sigue, y ls muestra que fmt.o existe. Tras un error, en cambio, no se escribe ningún archivo objeto.

Una copia con el formato equivocado

Comando
sed 's/is %d/is %s/' hello.c > fmt.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Compila la tercera copia

Comando
gcc -c fmt.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

¿Qué archivos objeto existen?

Comando
ls fmt.o noret.o

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un error frecuente

Advertencia

Mucha gente cree que un aviso se puede ignorar porque el programa se compila igual. Un aviso es el compilador diciendo que algo es legal pero casi seguro está mal. Si ejecutas fmt.c, printf trata el 49 como la dirección de un texto. Lee cada aviso como un fallo hasta saber por qué es seguro.

Python comprueba mientras ejecuta

C comprueba nombres y tipos antes de ejecutar: eso es comprobación estática. Python los comprueba cuando llega a la línea, así que el fallo aparece en ese momento.

Los dos Runs arrancan un programa. Ninguno de los dos fallos se descubre hasta que Python llega a él.

Un nombre que Python no conoce

Comando
python3 -c "print(price)"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un valor del tipo equivocado

Comando
python3 -c "print(len(5))"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Para ir más lejos

Añade a tu comprobador un tercer problema, "sombra". Sale cuando un var interior usa el nombre de un ámbito exterior, como a en una de las pruebas.

No es un error: el programa sigue teniendo sentido. Explica por qué conviene avisar de todos modos, con un ejemplo de nómina donde la sombra confunde.

Sobre este laboratorio y su código: Laboratorio de compiladores y arquitectura: gcc, flex, bison y RISC-V en una VM

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.