Objetivo de aprendizaje
Al concluir el proyecto, el estudiante será capaz de:
- Ampliar un lenguaje recorriendo sus capas (léxico, sintaxis, semántica y ejecución) y explicar cómo una misma característica las afecta a todas.
- Escribir una gramática que incorpore un operador nuevo con la precedencia y la asociatividad correctas, y comprobarla con casos de prueba.
- Decidir y justificar las reglas de tipado de operaciones nuevas, reconociendo que existen decisiones de diseño defendibles distintas.
- Traducir a mano expresiones y programas a código de pila y comprobarlos en una máquina virtual.
- Documentar su trabajo en un informe con pruebas, decisiones y reflexión.
El producto que se entrega
Un informe (de dos a cuatro páginas) acompañado de la evidencia registrada en esta página: las gramáticas que superaron sus casos, su tabla de reglas de tipado y su código de pila. Todo se exporta en un solo archivo desde el espacio de trabajo de la sección 7.
Rutas de trabajo
El proyecto consta de tres capas. En cada una hay tareas de dificultad creciente. Elija la ruta que corresponda a su meta; su docente puede ajustarla.
| Ruta | Sintaxis | Semántica | Ejecución | Informe |
|---|---|---|---|---|
| Básica | A1 | Tabla de < |
C1 | Completo |
| Intermedia | A2 | Tablas de < y ==, con una diferencia justificada |
C2 y C3 | Completo y con decisiones de diseño argumentadas |
| Avanzada | A2 y A3 | Ambas tablas | C2, C3 y C4 (con el reto de 5 instrucciones) | Todo lo anterior y una propuesta propia de extensión adicional |
1. Planteamiento inicial
A lo largo de la unidad se estudió Mini como un lenguaje cerrado: sus operadores, sus tipos y su máquina de pila estaban dados. Pero un lenguaje es un objeto de diseño, y diseñar consiste en decidir qué se añade y qué costo tiene.
Este laboratorio interactivo requiere JavaScript habilitado en el navegador.
Esta hipótesis se retomará al final del proyecto.
2. Una extensión recorre todas las capas
Cada característica nueva exige decisiones en las cuatro capas estudiadas, en este orden: primero se reconoce (léxico), después se estructura (sintaxis), luego se le da significado (semántica) y por último se ejecuta (generación de código y máquina virtual).
Definición — Extensión de un lenguaje: incorporación de una característica nueva (operador, tipo o sentencia) que requiere modificar de manera coordinada todas las capas del lenguaje en que interviene.
Ejemplo resuelto: el operador de división entera //. Se muestra el recorrido completo de una extensión distinta de las tareas del proyecto, para que pueda reproducir el método con la suya. Se define a // b como el cociente entero de la división de a entre b.
| Capa | Pregunta | Decisión para // |
|---|---|---|
| Léxico | ¿Qué unidad nueva aparece? | Un token de dos caracteres, //, categoría operador aritmético. El escáner debe aplicar la coincidencia más larga: ante / seguido de / emite un solo token y no dos |
| Sintaxis | ¿Dónde se ubica? | En el nivel del producto y la división, asociado a la izquierda: <termino> ::= … | <termino> "//" <factor> |
| Semántica | ¿Qué tipos admite y qué devuelve? | Entero con entero produce entero. Con decimales se rechaza como error de tipos, porque el cociente «entero» de un decimal no está bien definido en Mini. La división entre cero es, como siempre, un error de ejecución |
| Ejecución | ¿Qué instrucción necesita? | Una instrucción nueva IDIV que retira dos valores enteros y coloca su cociente entero. El generador de código la emite para el nodo // |
Observe que la decisión de semántica (rechazar decimales) es de diseño: otra persona podría haber elegido truncar. Lo importante es que esté explícita y justificada.
3. Capa de sintaxis: ampliar la gramática
Parta de la gramática de Mini (la solución del nivel 5 de la práctica B del tema 1.2.1) y modifíquela para incorporar cada operador. Las tareas son:
- A1 · Residuo (
%): misma precedencia que el producto, asociado a la izquierda. - A2 · Potencia (
^): mayor precedencia que el producto, asociada a la derecha. - A3 · Menos unario: el signo menos aplicado a un factor.
Aplique el método de cinco pasos: entienda lo que se pide, redacte ejemplos propios (válidos e inválidos), identifique en qué nivel de la gramática vive la característica, escriba las reglas y verifique. Cada gramática que supera todos sus casos se registra automáticamente en su libreta como evidencia.
Este laboratorio interactivo requiere JavaScript habilitado en el navegador.
Nota: si el verificador indica que una cadena admite más de un árbol, la gramática es ambigua: revise si la precedencia o la asociatividad están codificadas en la estructura de las reglas.
4. Capa de semántica: reglas de tipado
Suponga que Mini incorpora un tipo nuevo, lógico (verdadero o falso), y dos operadores de comparación: < (menor que) y == (igual que). Para cada combinación de tipos de los operandos hay que decidir de qué tipo es el resultado o si la combinación debe rechazarse.
Piense en los principios que guiaron el diseño de Mini hasta ahora: no convertir tipos de manera implícita, detectar los errores antes de ejecutar y no aceptar operaciones que carecen de un significado claro. Compare después su tabla con la decisión de referencia.
Este laboratorio interactivo requiere JavaScript habilitado en el navegador.
Importante: una diferencia con la referencia no es necesariamente un error. Algunos lenguajes aceptan comparar texto con número o convertir valores lógicos a enteros. Lo que se evalúa es que su decisión sea coherente con las demás y esté justificada en el informe, con el criterio de diseño (fiabilidad, facilidad de escritura u otro) y su costo.
5. Capa de ejecución: código de pila a mano
Un compilador genera el código de pila de manera automática. Para comprender de verdad lo que hace, escriba usted el código de cuatro casos. El juez ensambla su código, lo ejecuta en la máquina virtual con varios valores de entrada y comprueba que la pila termine con el resultado correcto (o, en el programa completo, con la salida y el entorno correctos y la pila vacía).
Recuerde el método de la generación de código: operandos primero y operador después (orden posterior). La instrucción nueva NEG cambia el signo del tope y DUP lo duplica.
Este laboratorio interactivo requiere JavaScript habilitado en el navegador.
Nota: use el botón «Ver la ejecución» para observar cómo evoluciona la pila con su código. Es la mejor herramienta de depuración: compare el estado real de la pila con el que usted esperaba en cada instrucción.
6. Planeación del informe
El informe no es un resumen de lo que se hizo, sino un argumento: explica qué decidió, por qué y cómo comprobó que funciona. Algunas pautas:
- Escriba para alguien que no vio su trabajo. Debe poder reproducirlo con su informe.
- Presente evidencia, no afirmaciones. En lugar de «mi gramática es correcta», indique qué casos superó y qué casos inválidos rechazó.
- Nombre los compromisos. Toda decisión favorece algo y cuesta algo; indique qué.
- Compare con la referencia. Donde su decisión difiere, explique por qué la mantiene.
Ejemplo de una justificación pobre: «Puse que comparar texto con número es error porque sí». Ejemplo de una justificación sólida: «Rechacé la comparación entre texto y número porque Mini no convierte tipos de manera implícita y aceptarla obligaría a decidir arbitrariamente si "10" es menor que 9; esto favorece la fiabilidad y cuesta al programador una conversión explícita».
7. Espacio de trabajo del informe
Redacte cada sección. El contenido se guarda automáticamente en este navegador. Al terminar, regístrelo en la libreta y expórtelo.
Este laboratorio interactivo requiere JavaScript habilitado en el navegador.
Importante: lo que registra en esta página solo vive en su navegador. Si cambia de equipo o borra los datos de navegación, lo perderá. Exporte el archivo con frecuencia y conserve una copia.
8. Autoevaluación
Antes de entregar, valore su proyecto con la rúbrica. Está diseñada para que detecte qué mejorar mientras todavía está a tiempo.
Este laboratorio interactivo requiere JavaScript habilitado en el navegador.
Contraste con el planteamiento inicial
Este laboratorio interactivo requiere JavaScript habilitado en el navegador.
9. Libreta y lista de verificación para la entrega
Este laboratorio interactivo requiere JavaScript habilitado en el navegador.
Antes de entregar, compruebe que:
- Eligió una ruta y completó al menos una tarea por capa.
- Cada gramática superó todos sus casos (aparece registrada en la libreta).
- Decidió su tabla de tipado y justificó las diferencias con la referencia.
- Su código de pila supera las pruebas y respeta el presupuesto de instrucciones.
- Las ocho secciones del informe tienen contenido y evidencias.
- Hizo la autoevaluación y atendió los criterios más bajos.
- Exportó el informe y conservó una copia del archivo.
- Puede explicar con sus propias palabras cada decisión de su trabajo.
10. Preguntas de reflexión
- ¿Por qué una sola característica nueva obliga a modificar varias capas del lenguaje? ¿Qué ocurriría si se olvidara una?
- ¿Qué capa le resultó más difícil de extender y por qué?
- Describa una decisión de diseño que tomó y su compromiso: ¿qué favorece y qué cuesta?
- Si el lenguaje se extendiera con una sentencia
if, ¿cómo cambiaría cada una de las cuatro capas? - ¿Qué aprendió sobre la relación entre un lenguaje y las herramientas que lo procesan?
11. Lecturas recomendadas
- Nystrom, R. (2021). Crafting Interpreters: la construcción incremental de un lenguaje, capa por capa, ilustra el método de este proyecto. Acceso libre en craftinginterpreters.com.
- Thain, D. (2020). Introduction to Compilers and Language Design (2nd ed.). Acceso libre en www3.nd.edu/~dthain/compilerbook.
- Sebesta, R. (2015). Concepts of programming languages (11th ed.), capítulo introductorio, sección sobre criterios de evaluación y compromisos de diseño. Pearson.