Translate

martes, 5 de mayo de 2026

Crear un mini lenguaje que compile a LLVM IR (paso a paso)


En el post anterior vimos qué es LLVM y por qué cambió la forma de construir compiladores.


Ahora vamos a lo interesante: crear un mini lenguaje propio y compilarlo a LLVM IR

Vamos a construir un lenguaje súper simple que permita esto:

sum(10, 20)


Y lo transforme en LLVM IR listo para compilar.

Nuestro “compilador” va a tener:

  • Parser (muy básico)
  • AST (árbol)
  • Generador de LLVM IR


Paso 1: Definir el lenguaje


Nuestro lenguaje soporta:

Función: sum(a, b)

Números enteros


Ejemplo válido:

sum(4, 5)


Paso 2: Representar el AST

En pseudocódigo:

java id="y0yqg3"

interface Expr {}


class Number implements Expr {

    int value;

}


class Sum implements Expr {

    Expr left;

    Expr right;

}


Paso 3: Parser (ultra simple)


Para simplificar, parseamos a mano:

java id="x7p0a1"

Expr parse(String input) {

    // sum(10,20)

    String inside = input.substring(4, input.length() - 1);

    String[] parts = inside.split(",");


    return new Sum(

        new Number(Integer.parseInt(parts[0])),

        new Number(Integer.parseInt(parts[1]))

    );

}


Sí, es naive, pero suficiente para entender el flujo


Paso 4: Generar LLVM IR

Acá está la magia 💣


java id="l6c0qw"

String generate(Expr expr) {

    if (expr instanceof Sum s) {

        return """

        define i32 @main() {

            %a = add i32 %d, %d

            ret i32 %a

        }

        """.formatted(

            ((Number)s.left).value,

            ((Number)s.right).value

        );

    }

    throw new RuntimeException("Unsupported");

}


Resultado

Entrada:

sum(10, 20)


Salida:

llvm id="0a8v8l"

define i32 @main() {

  %a = add i32 10, 20

  ret i32 %a

}


Ya es LLVM IR válido


Paso 5: Ejecutarlo

Guardás el archivo como main.ll y usás:


bash id="3e7twz"

lli main.ll


o lo compilás con:


bash id="z4c9yb"

llc main.ll


Aunque el ejemplo es simple, reproduce el flujo real:

1. Texto → AST

2. AST → IR

3. IR → código ejecutable


Exactamente lo que hacen lenguajes como Rust o compiladores como Clang

Lo difícil NO es generar código máquina.

Lo difícil es definir bien el lenguaje y su semántica.


LLVM te resuelve:

  • optimización
  • portabilidad
  • generación de código



No hay comentarios.:

Publicar un comentario