Empieza aquí

Introducción

Todo programa que has ejecutado empezó siendo texto. Algo tuvo que convertir ese texto en las conmutaciones eléctricas de un procesador: un compilador, un intérprete o, más a menudo de lo que parece, una cadena de ambos. Esta web sigue ese viaje paso a paso con Wahoo, un pequeño lenguaje del Reino Champiñón cuyo compilador de verdad se ejecuta en tu navegador.

Capítulo 00: ¿Compilado, interpretado o las dos cosas? →Abrir el playgroundAprende Wahoo en cinco minutos

Un programa en Wahoo. world 1-1 es donde empieza, coin declara una variable, run es un bucle que cuenta, power_up suma a un contador, question es un if y wahoo(...) imprime. Pulsa Ejecutar: el texto pasa por el análisis léxico y sintáctico, la comprobación de tipos y el optimizador, y se convierte en WebAssembly gracias a un compilador escrito en Rust que, a su vez, se está ejecutando aquí como WebAssembly.

El viaje en una imagen

Un compilador es una cadena de montaje. Cada etapa recibe el programa con una forma y se lo pasa a la siguiente con otra un poco más cercana a la máquina: los caracteres se convierten en tokens, los tokens en un árbol, el árbol adquiere significado (nombres resueltos, tipos comprobados), el significado se convierte en instrucciones, las instrucciones se hacen más rápidas y, por último, algo las ejecuta. Los capítulos siguen ese orden:

  1. 00 Modelos 1949 – hoy ¿Compilado, interpretado o las dos cosas? Un procesador solo entiende código máquina. Hay dos maneras de hacerle llegar un programa escrito como texto: traducirlo entero de antemano, o leerlo y representarlo sobre la marcha. Casi todos los lenguajes reales usan una mezcla de las dos.
    • Compilador frente a intérprete
    • Bytecode y máquinas virtuales
    • Compilación «justo a tiempo»
    • Transpiladores
    • Autocompilación
  2. 01 Léxico 1956 – 1975 De los caracteres a las palabras Para un compilador, un programa llega como una larga ristra de caracteres. La primera fase, el analizador léxico, los lee uno a uno y los agrupa en tokens: palabras clave, nombres, números, símbolos. Es la fase más sencilla, y descansa sobre uno de los resultados más limpios de la informática.
    • Tokens y lexemas
    • Expresiones regulares
    • Autómatas finitos
    • La coincidencia más larga
    • Recuperación de errores
  3. 02 Sintaxis 1956 – 1975 De las palabras a los árboles Los tokens llegan en fila, pero los programas están anidados: expresiones dentro de expresiones, bloques dentro de bucles dentro de funciones. El parser recupera esa estructura en forma de árbol, guiado por una gramática, una idea tomada de la lingüística en los años cincuenta.
    • Gramáticas independientes del contexto
    • BNF
    • Árboles de sintaxis abstracta
    • Descenso recursivo
    • Parsing de Pratt
    • LL y LR
  4. 03 Semántica 1958 – hoy ¿Tiene sentido? Un programa puede ser perfectamente gramatical y no significar nada: un nombre que nadie declaró, un número usado como condición, una función que olvida devolver. El comprobador resuelve cada nombre y da un tipo a cada expresión, para que estos fallos se detecten antes de ejecutar el programa.
    • Ámbitos y tablas de símbolos
    • Comprobación de tipos
    • Inferencia de tipos
    • Desazucarado
    • Análisis conservador
  5. 04 Código 1957 – hoy Del significado a las instrucciones El programa comprobado dice qué debe ocurrir; el generador de código decide cómo, con el vocabulario de la máquina destino. En WebAssembly esa máquina es una máquina de pila: las expresiones se convierten en secuencias de apilar y operar, y los bucles en bloques de los que solo se puede salir o volver al principio.
    • Representaciones intermedias
    • Máquinas de pila
    • Traducir el control de flujo
    • Disposición en memoria
    • Asignación de registros
  6. 05 Optimizar 1957 – hoy Hacer menos, más deprisa Un optimizador reescribe un programa en otro más barato que se comporta exactamente igual. Algunas reescrituras son obvias, como calcular 2 × 60 al compilar; otras exigen analizar con cuidado cómo fluyen los valores por el programa. Todas obedecen una única regla: nadie debe poder notar la diferencia.
    • La regla del «como si»
    • Plegado de constantes
    • Eliminación de código muerto
    • Análisis de flujo de datos
    • Comportamiento indefinido
  7. 06 Ejecutar 1945 – hoy ¿Quién lo ejecuta de verdad? El último acto del compilador es escribir un fichero de bytes. Convertir esos bytes en un programa en marcha es trabajo de otra pieza de software: un cargador, una máquina virtual o, en el caso de Wahoo, el motor de WebAssembly de tu navegador, que comprueba el módulo, lo compila una vez más y lo ejecuta dentro de un entorno aislado.
    • Programa almacenado
    • Enlazado y carga
    • WebAssembly
    • Validación y aislamiento
    • Compilación por niveles

¿Compilado, interpretado… o las dos cosas?

«Python es interpretado y C es compilado» es una de esas frases que son verdad a medias. Python se compila a bytecode antes de ejecutarse; Java se compila dos veces; JavaScript empieza interpretado y se recompila a código máquina mientras se ejecuta; TypeScript se compila a otro lenguaje de programación. El capítulo 00 desmonta una docena de lenguajes reales y muestra en qué punto de cada uno el texto deja de ser texto. El resto de la web construye un compilador completo, fase a fase, para que cada palabra de esos diagramas tenga un significado concreto que puedas inspeccionar.

FasePregunta que respondeEn el compilador de WahooDónde
Análisis léxico¿Qué palabras hay en este texto?lexer.rs: caracteres → tokens01
Análisis sintáctico¿Cómo encajan las palabras?parser.rs: tokens → árbol sintáctico02
Análisis semántico¿Tiene sentido?checker.rs: ámbitos y tipos03
Generación de código¿Qué debe hacer la máquina?codegen.rs, wasm.rs: WebAssembly04
Optimización¿Puede hacer menos?optimizer.rs: plegado, código muerto05
Ejecución¿Quién lo ejecuta, y cómo?el motor Wasm de tu navegador06

¿Por qué Mario?

Porque un lenguaje que nunca has visto te obliga a mirarlo como lo mira un compilador: como texto con reglas. En Wahoo los programas se juegan como mundos (1-1, luego 1-2…), las funciones son tuberías (pipes) por las que bajas y de las que vuelves con un valor al llegar a la bandera (flag), los números enteros son monedas (coins), los booleanos son star y goomba, y una división entre cero te hace caer a un foso. Bajo el disfraz hay un lenguaje de verdad, con tipos estáticos, recursión, bucles, ámbitos y un compilador con buenos mensajes de error. La página del lenguaje lo cuenta entero en una pantalla.

Cómo leer esta web

En orden, como un libro corto, o saltando directamente a la fase que te despierte curiosidad: cada capítulo se sostiene solo. Todas las figuras interactivas usan el mismo compilador que el playground, así que lo que escribas se procesa de verdad, no se simula. El código de todo (compilador, herramienta de línea de órdenes y esta web) está en GitHub, y es lo bastante pequeño para leerlo en una tarde.

Capítulo 00: ¿Compilado, interpretado o las dos cosas? →