sadScript 💔
SadScript es un lenguaje de programación temático donde cada palabra clave duele. Está diseñado para sentirse triste, cansado y existencial por fuera, pero seguir siendo formalmente compilable por dentro.
dolor edad = 20;
vacio promedio = 3.14;
esperanza seguir_vivo = vivo;
recuerdo mensaje = "nadie me entiende";
si_duele (edad > 18) {
confesar("ya soy adulto... qué triste");
} Filosofía
Section titled “Filosofía”“SadScript debe sentirse triste, cansado y existencial por fuera, pero seguir siendo formalmente compilable por dentro.”
El lenguaje une dos mundos:
- El tema: vocabulario emo en primera persona — toda palabra reservada evoca angustia, melancolía o drama existencial.
- La técnica: un analizador léxico (Flex) + parser (Bison) con precedencia de operadores, tipos explícitos, colecciones reales y reporte de errores preciso.
Es un proyecto ideal para:
- Aprender cómo funcionan lexers y parsers en compiladores
- Explorar diseño de lenguajes con un toque de humor negro
- Usar como base para un lenguaje completo con intérprete o transpilador
Estado actual
Section titled “Estado actual”SadScript es actualmente un validador de sintaxis. El analizador léxico y el parser están completos y funcionales. No hay todavía un intérprete, generación de código, ni análisis semántico (type checking, AST, etc.).
| Fase | Estado |
|---|---|
| Léxico (Flex) | ✅ Completo |
| Sintáctico (Bison) | ✅ Completo |
| Semántico | ❌ Pendiente |
| Intérprete / VM | ❌ Pendiente |
| Generación de código | ❌ Pendiente |
Guía de inicio rápido
Section titled “Guía de inicio rápido”Requisitos
Section titled “Requisitos”- Flex (analizador léxico)
- Bison (generador de parser)
- GCC o Clang (compilador C)
Instalación en Linux (Debian/Ubuntu):
sudo apt install flex bison build-essentialInstalación en macOS:
brew install flex bisonCompilar
Section titled “Compilar”git clone https://github.com/Aserturik/sadScript.gitcd sadScript./build.shEsto genera:
a_sintactico.tab.c/.h— parser generado por Bisonlex.yy.c— lexer generado por FlexsadScript— binario ejecutable
Ejecutar un programa
Section titled “Ejecutar un programa”./sadScript tests/01_happy.sadSalida exitosa:
Análisis léxico y sintáctico completado sin errores.Ejecutar todos los tests
Section titled “Ejecutar todos los tests”./run_tests.shGuía del lenguaje
Section titled “Guía del lenguaje”Tipos de datos
Section titled “Tipos de datos”| SadScript | Significado | Ejemplo |
|---|---|---|
dolor | Entero (int) | dolor edad = 20; |
vacio | Flotante (float) | vacio promedio = 3.14; |
esperanza | Booleano (bool) | esperanza ok = vivo; |
recuerdo | Cadena (string) | recuerdo msg = "hola"; |
cicatriz | Vector / arreglo 1D | cicatriz nums = [1,2,3]; |
trauma | Matriz / arreglo 2D | trauma mat = [[1,2],[3,4]]; |
Literales y valores
Section titled “Literales y valores”| Tipo de literal | Ejemplo | Token interno |
|---|---|---|
| Booleano true | esperanza x = vivo | TRUE |
| Booleano false | esperanza x = muerto | FALSE |
| Nulo | nulo | NULO |
| Cadena | recuerdo x = "texto" | LITERAL_CADENA |
| Caracter | 'a' | LITERAL_CARACTER |
| Entero | dolor x = 42 | LITERAL_ENTERO |
| Flotante | vacio x = 3.14 | LITERAL_DECIMAL |
| Notación científica | vacio x = 1.5e10 (también 42e10) | LITERAL_DECIMAL |
Declaración de variables
Section titled “Declaración de variables”dolor edad = 20;vacio promedio = 3.14;esperanza seguir_vivo = vivo;recuerdo msg = "hola mundo";cicatriz nums = [1, 2, 3, 4];trauma mat = [[1.2, 3.4], [5.6, 7.8]];Las variables se pueden declarar sin inicializar:
dolor edad;recuerdo nombre;Asignación
Section titled “Asignación”edad = 21;edad += 1;edad -= 1;edad *= 2;edad /= 2;edad %= 3;Operadores
Section titled “Operadores”Aritméticos
Section titled “Aritméticos”| Operador | Operación |
|---|---|
+ | Suma |
- | Resta |
* | Multiplicación |
/ | División |
% | Módulo |
** | Potencia |
++ | Incremento |
-- | Decremento |
Relacionales
Section titled “Relacionales”| Operador | Significado |
|---|---|
== | Igual a |
!= | Diferente de |
<> | Diferente de (alternativo) |
< | Menor que |
<= | Menor o igual que |
> | Mayor que |
>= | Mayor o igual que |
Lógicos
Section titled “Lógicos”| Símbolo | Palabra | Significado |
|---|---|---|
&& | y | AND |
|| | o | OR |
! | no | NOT |
Puedes usar ambas formas:
si_duele (edad > 18 && vivo) { ... }si_duele (edad > 18 y vivo) { ... }Operadores especiales
Section titled “Operadores especiales”| Operador | Token interno | Uso típico |
|---|---|---|
-> | FLECHA | Punteros / acceso |
=> | FLECHA_DOBLE | Lambdas / mapeo |
# | NUMERAL | Directivas / metadatos |
@ | ARROBA | Decoradores / anotaciones |
Operadores de reducción
Section titled “Operadores de reducción”SadScript incluye operadores de agregación sobre colecciones:
sum([1, 2, 3]) // → 6prod([2, 3, 4]) // → 24max([1, 5, 2]) // → 5min([1, 5, 2]) // → 1prom([1, 2, 3]) // → 2.0Precedencia de operadores
Section titled “Precedencia de operadores”De menor a mayor precedencia:
| Precedencia | Operadores | Asociatividad |
|---|---|---|
| 1 (más baja) | = += -= *= /= %= | Derecha |
| 2 | || o | Izquierda |
| 3 | && y | Izquierda |
| 4 | == != <> | Izquierda |
| 5 | > < >= <= | Izquierda |
| 6 | + - | Izquierda |
| 7 | * / % | Izquierda |
| 8 | ** | Derecha |
| 9 (más alta) | ! no - (unario) | Derecha |
Control de flujo
Section titled “Control de flujo”If / Else if / Else
Section titled “If / Else if / Else”si_duele (edad > 18) { confesar("adulto");} si_no_duele_pero (edad > 12) { confesar("adolescente");} si_no_duele { confesar("niño");}mientras_duela (vivo) { confesar("todavía respiro"); cortarme; // break}para_que_duela (dolor i = 0; i < 10; i = i + 1) { confesar("duele");}Do-While
Section titled “Do-While”aunque_no_quiera { confesar("una vez");} mientras_duela (condicion);Switch
Section titled “Switch”segun_mi_animo (edad)
caso 18:
confesar("ya casi");
cortarme;
caso 21:
confesar("legalmente adulto");
cortarme;
por_defecto_mio:
confesar("sin rumbo");
Break y Continue
Section titled “Break y Continue”cortarme; // breakseguir_fingiendo; // continueFunciones
Section titled “Funciones”Definición con tipo de retorno
Section titled “Definición con tipo de retorno”ritual llorar() : vacio { confesar("hola mundo"); regresar_a_llorar 0.0;}Definición sin tipo de retorno
Section titled “Definición sin tipo de retorno”ritual gritar(dolor intensidad) { confesar("AHH");}Con múltiples parámetros
Section titled “Con múltiples parámetros”ritual sumar(dolor a, dolor b) : dolor { regresar_a_llorar a + b;}Llamada a función
Section titled “Llamada a función”llorar();gritar(intensidad: 10); // argumento nombradosumar(a: 5, b: 3); // múltiples argumentos nombradosColecciones
Section titled “Colecciones”Vectores (arreglos 1D)
Section titled “Vectores (arreglos 1D)”cicatriz numeros = [1, 2, 3, 4];numeros[0] = 10;confesar(numeros[2]); // imprime 3Matrices (arreglos 2D)
Section titled “Matrices (arreglos 2D)”trauma sombras = [[1.2, 3.4], [5.6, 7.8]];confesar(sombras[0][1]); // imprime 3.4Manejo de excepciones
Section titled “Manejo de excepciones”Try / Catch
Section titled “Try / Catch”intentar_sentir { confesar("intentando...");} romperse(error) { confesar(error);}colapsar("algo salió mal");Assert
Section titled “Assert”afirmar(edad > 0);Print (salida por consola)
Section titled “Print (salida por consola)”confesar("mensaje");confesar(edad);confesar(3.14);Comentarios
Section titled “Comentarios”// Comentario de línea
/* Comentario multilínea */Ejemplos completos
Section titled “Ejemplos completos”Programa feliz (válido)
Section titled “Programa feliz (válido)”// Declaraciones base con tipos emodolor edad = 20;vacio promedio = 3.14;esperanza seguir_vivo = vivo;recuerdo mensaje = "nadie me entiende";
// Coleccionescicatriz numeros = [1, 2, 3, 4];trauma sombras = [[1.2, 3.4], [5.6, 7.8]];
// Condicionalsi_duele (edad > 18) { confesar("ya soy adulto");}
// Ciclo while con breakmientras_duela (seguir_vivo) { confesar("todavia respiro"); cortarme;}
// Función con retornoritual llorar() : vacio { confesar("hola mundo"); regresar_a_llorar 0.0;}Switch con caso y default
Section titled “Switch con caso y default”dolor edad = 15+3-0;
segun_mi_animo (edad) { caso 18: confesar("ya casi"); por_defecto_mio: confesar("sin rumbo");}Con errores
Section titled “Con errores”Error léxico (carácter inválido)
Section titled “Error léxico (carácter inválido)”dolor edad = 20;confesar("léxico roto"); ~ // ← error: '~' no está en el alfabeto del lenguajeSalida:
Error léxico en línea 4, columna 3: token no reconocido '~'Error sintáctico (keyword mal escrita)
Section titled “Error sintáctico (keyword mal escrita)”dolor edad = 20;si_duel (edad > 18) { // ← error: debería ser "si_duele" confesar("typo en keyword");}Salida:
Error sintáctico en línea 4, columna 18: syntax error, unexpected LLAVE_IZQ, expecting PUNTO_COMA cerca de '{'Error sintáctico (bloque sin cerrar)
Section titled “Error sintáctico (bloque sin cerrar)”dolor edad = 21;si_duele (edad > 18) { confesar("parser roto"); // falta la llave de cierreSalida:
Error sintáctico en línea 4, columna 4: syntax error, unexpected end of fileError sintáctico (punto y coma faltante)
Section titled “Error sintáctico (punto y coma faltante)”dolor edad = 20confesar("falta punto y coma"); // ← error: falta ; en línea anteriorArquitectura
Section titled “Arquitectura”SadScript sigue el modelo clásico de frontend de compilador en dos fases:
Código fuente (.sad) │ ▼┌─────────────────┐│ Flex Lexer │ a_lexico.l│ (análisis │ → produce tokens│ léxico) │└────────┬─────────┘ │ tokens ▼┌─────────────────┐│ Bison Parser │ a_sintactico.y│ (análisis │ → valida gramática│ sintáctico) │ → llama yyerror() si falla└────────┬─────────┘ │ ▼ ✅ Éxito (exit 0) ❌ Error (exit 1 + mensaje)Lexer (a_lexico.l)
Section titled “Lexer (a_lexico.l)”- ~195 líneas de definiciones Flex
- Reconoce ~78 tokens: palabras reservadas, operadores, literales, identificadores, delimitadores
- Soporta caracteres con acentos del español (
áéíóúüñÁÉÍÓÚÜÑ) - Comentarios multilínea mediante estados Flex (
COMENTARIO_MULTI) - Reporte de errores léxicos con línea y columna exacta
- Los identificadores soportan caracteres Unicode del español
Parser (a_sintactico.y)
Section titled “Parser (a_sintactico.y)”- 356 líneas de gramática Bison
- Precedencia de operadores declarativa con
%left,%right,%nonassoc %define parse.error verbosepara mensajes de error descriptivosyyerror()imprime:Error sintáctico en línea X, columna Y: <mensaje> cerca de '<token>'
Reporte de errores
Section titled “Reporte de errores”- Errores léxicos → se reportan a stdout
- Errores sintácticos → se reportan a stderr
- Ambos incluyen número de línea y columna
main()devuelveexit 0en éxito,exit 1en cualquier error
Build system (build.sh)
Section titled “Build system (build.sh)”bison -d a_sintactico.y # genera parser + headerflex a_lexico.l # genera lexercc lex.yy.c a_sintactico.tab.c -o sadScript -lfl -lm # compilaTesting
Section titled “Testing”Suite de tests
Section titled “Suite de tests”| Archivo | Esperado | Descripción |
|---|---|---|
tests/01_happy.sad | ✅ exit 0 | Programa válido completo |
tests/02_typo_keyword_fail.sad | ❌ exit 1 | Keyword mal escrita |
tests/03_missing_semicolon_fail.sad | ❌ exit 1 | Punto y coma faltante |
tests/04_default_switch.sad | ✅ exit 0 | Switch con default |
tests/05_lexer_fail.sad | ❌ exit 1 | Caracter inválido ~ |
tests/06_parser_fail.sad | ❌ exit 1 | Bloque sin cerrar |
Ejecutar tests
Section titled “Ejecutar tests”./run_tests.shEl script:
- Compila el proyecto con
build.sh - Ejecuta cada
.sadverificando código de salida - Verifica mensajes de salida esperados (stdout/stderr)
- Reporta PASS/FAIL con resumen
Glosario de keywords
Section titled “Glosario de keywords”La tabla completa de mapeo entre el vocabulario emo visible y los tokens internos del parser:
| SadScript | Token interno | Significado |
|---|---|---|
dolor | ENTERO | Tipo entero |
vacio | FLOTANTE | Tipo flotante |
esperanza | BOOLEANO | Tipo booleano |
recuerdo | CADENA | Tipo cadena |
cicatriz | VECTOR | Tipo vector |
trauma | MATRIZ | Tipo matriz |
si_duele | IF | Condicional if |
si_no_duele | ELSE | Condicional else |
si_no_duele_pero | ELSEIF | Condicional else if |
segun_mi_animo | SWITCH | Switch |
caso | CASE | Case |
por_defecto_mio | DEFAULT | Default |
mientras_duela | WHILE | Bucle while |
para_que_duela | FOR | Bucle for |
aunque_no_quiera | DO | Bucle do-while |
cortarme | BREAK | Break |
seguir_fingiendo | CONTINUE | Continue |
ritual | FUNCTION | Definición de función |
regresar_a_llorar | RETURN | Return |
confesar | PRINT | Salida por consola |
intentar_sentir | TRY | Try |
romperse | CATCH | Catch |
colapsar | THROW | Throw |
afirmar | ASSERT | Assert |
vivo | TRUE | Booleano verdadero |
muerto | FALSE | Booleano falso |
nulo | NULO | Null |
sum | OP_SUMA_REDUCCION | Suma de colección |
prod | OP_PROD_REDUCCION | Producto de colección |
max | OP_MAX_REDUCCION | Máximo de colección |
min | OP_MIN_REDUCCION | Mínimo de colección |
prom | OP_PROM_REDUCCION | Promedio de colección |
Próximos pasos (ideas para contribuir)
Section titled “Próximos pasos (ideas para contribuir)”Estas son las áreas donde SadScript puede crecer:
- Árbol de sintaxis abstracta (AST) — construir un AST en las acciones semánticas del parser
- Intérprete — evaluar el AST y ejecutar programas
- Type checker — validar tipos en tiempo de compilación
- Transpilador — generar código JavaScript, Python o C
- Standard library — funciones incorporadas (IO, matemáticas, strings)
- Sistema de módulos — imports y exports entre archivos
.sad - Editor support — resaltado de sintaxis para VS Code, Vim, etc.
- Playground web — intérprete en el navegador
Estructura del proyecto
Section titled “Estructura del proyecto”sadScript/├── a_lexico.l # Lexer (Flex)├── a_sintactico.y # Parser (Bison)├── a_sintactico.tab.c # Parser generado (no editar)├── a_sintactico.tab.h # Tokens generados (no editar)├── lex.yy.c # Lexer generado (no editar)├── sadScript # Binario compilado├── build.sh # Script de compilación├── run_tests.sh # Suite de tests automatizada├── requirements.md # Especificación del lenguaje└── tests/ ├── 01_happy.sad ├── 02_typo_keyword_fail.sad ├── 03_missing_semicolon_fail.sad ├── 04_default_switch.sad ├── 05_lexer_fail.sad └── 06_parser_fail.sadLicencia
Section titled “Licencia”MIT — haz con esto lo que quieras, pero si duele, ya sabes por qué.
Contribuciones
Section titled “Contribuciones”¿Te duele algo y querés contribuir? Bienvenido. Este proyecto acepta:
- Pull requests con mejoras al lexer/parser
- Nuevos tests (especialmente casos negativos)
- Ideas para la semántica del lenguaje
- Implementación de intérprete o transpilador
- Temática: mientras más depresión existencial, mejor
“Duele, pero al menos compila.”