Un parser generador LALR(1) hecho en C++ que prioriza el AST
Yantra, publicado por Renji Panicker (@renjipanicker) bajo licencia MIT y mostrado en Show HN, es un parser generator (compilador de compiladores) escrito en C++ que implementa el algoritmo LALR(1) con un giro poco común: en vez de ejecutar las acciones semánticas mientras reduce reglas —el comportamiento clásico de la familia Bison/Yacc— primero construye el AST completo y luego lo recorre top-down en una segunda pasada.
El nombre viene del sánscrito: yantra significa "máquina", en referencia a una state machine. No requiere dependencias más allá de la biblioteca estándar de C++ y se compila con CMake. El ejecutable generado, ycc, produce dos formatos: un .cpp único auto-contenido con su propio main() (modo amalgamated) o un par .hpp/.cpp listo para integrarse a un proyecto existente.
Qué trae de fábrica
El README del repositorio lista un conjunto de características que suelen requerir glue code en otras herramientas:
👥 ¿Quieres ir más allá de la noticia?
En nuestra comunidad discutimos las tendencias, compartimos oportunidades y nos ayudamos entre emprendedores. Sin humo, solo acción.
👥 Unirme a la comunidad- Lexer integrado (no hace falta un generador de lexer separado).
- Soporte UTF-8 de entrada.
- AST builder incorporado.
- Walkers top-down que ejecutan las acciones semánticas después del parseo.
- Multi-mode lexer: permite implementar comentarios multilínea anidados y otros estados de tokenización.
- Parser dirigido por el lexer (push-based): procesa la entrada carácter a carácter, útil cuando los datos llegan por streaming (sockets, pipes).
- Soporte para múltiples walkers sobre el mismo AST: una gramática puede producir código para C++ y para Java sin re-parsear.
Requiere un compilador C++23 (probado con clang++, g++ y cl.exe de MSVC según los comandos de ejemplo del repositorio).
El detalle clave: AST primero, acciones después
La mayoría de generadores de parsers LALR ejecutan las acciones de cada regla en el momento en que la regla se reduce, en orden bottom-up. Yantra lo invierte: parsea todo, construye el árbol, y lo recorre de la raíz hacia las hojas. El ejemplo del repositorio lo muestra con una calculadora: la expresión 1 + 2 + 3 se imprime como un árbol left-associative y la acción del nodo padre (Adding) corre antes que las de sus hijos (Number: 1, Number: 2, Number: 3).
Para una herramienta bottom-up esto no sale gratis: conseguir ese orden con Bison obliga a construir clases de AST a mano y un walker adicional encima. Yantra lo resuelve directamente desde la gramática.
Yantra frente a Bison, ANTLR y tree-sitter
El propio repositorio compara Yantra con tres familias distintas. La síntesis basada en lo que el README declara:
- Bison / Yacc / Lemon. Lemon (de SQLite) es la inspiración declarada del proyecto. Todos corren acciones bottom-up. Yantra se diferencia en que el AST completo existe antes de ejecutar acciones y permite múltiples walkers sobre el mismo parse.
- ANTLR. También recorre un árbol completo, pero porque su algoritmo LL(*) Adaptive ya construye el árbol top-down mientras parsea. Yantra obtiene el mismo efecto partiendo de LALR(1), que es bottom-up y más eficiente en tiempo y espacio. ANTLR genera código para muchos lenguajes y requiere una JVM para correr el generador; Yantra es C++ nativo y solo apunta a C++. El autor reconoce que ANTLR es mucho más maduro y tiene un ecosistema mayor; Yantra es un proyecto más pequeño, nuevo y con un único mantenedor.
- tree-sitter. Resuelve un problema distinto: parsing incremental tolerante a errores, pensado para editores e IDEs (GitHub, Neovim). Yantra no hace reparseo incremental ni intenta competir en ese nicho.
Qué significa esto para tu startup
Si tu equipo está evaluando construir un DSL interno, un lenguaje de plantillas, un validador de configuración complejo o un generador de código dentro de tu producto, la decisión rara vez pasa por qué algoritmo es mejor en abstracto — pasa por qué orden de ejecución necesitas. Tres situaciones concretas:
- Acciones que dependen del árbol completo. Si tu acción semántica necesita ver el AST entero antes de ejecutarse (por ejemplo, para resolver referencias cruzadas, hacer type checking o emitir código que requiere mirar nodos hijos primero), Yantra te lo da sin escribir el walker a mano.
- Múltiples backends desde una sola gramática. Si quieres emitir, desde la misma gramática, código para dos o más destinos (C++ para tu backend, JSON para el inspector, Markdown para documentación), el soporte de varios walkers sobre el mismo parse reduce trabajo duplicado.
- Toolchain C++ puro. Si tu build ya genera ejecutables con CMake y clang, agregar Yantra no agrega nada de runtime, y la dependencia de una JVM (caso de ANTLR) desaparece. Para proyectos que buscan minimizar dependencias en CI, esto importa.
Dos acciones concretas:
- Prototipar antes de comprometerse. Clona el repo, compílalo con CMake, y pasa la gramática
calc.ydel tutorial. En menos de una hora vas a saber si el modelo "parsear primero, caminar después" encaja con tu caso de uso o si necesitas las acciones bottom-up de Bison. - Mirar el proyecto de muestra. El repo
TantrixAuto/lingoes un proyecto independiente que usa Yantra. Estudiar su gramática y su estructura es la forma más rápida de ver cómo se usa la herramienta fuera del tutorial.
Lo que Yantra todavía no hace
El repositorio es explícito en sus limitaciones (sección Known Limitations del README): es un proyecto nuevo con un solo mantenedor, no apunta a ser un reemplazo universal de ANTLR ni de Bison. Si necesitas la robustez de un parser con décadas de producción, soporte multilinguaje o un ecosistema amplio de tooling, las opciones más maduras siguen ganando. Yantra es una opción a evaluar cuando el modelo de "AST primero, walkers después" encaje con tu problema y no necesites pelear con un stack adicional.
Fuentes
👥 ¿Quieres ir más allá de la noticia?
En nuestra comunidad discutimos las tendencias, compartimos oportunidades y nos ayudamos entre emprendedores. Sin humo, solo acción.
👥 Unirme a la comunidad













