Especificación Léxica y Gramatical¶
Especificación Léxica¶
La especificación léxica le indica al frontend (analizador frontal) cuáles son las unidades significativas del lenguaje (tokens) y qué hacer con ellas. Se define como una lista de reglas.
Formato general:
'(
(nombre-token (expresion-regular) accion)
)
;; expresion-regular: letter, whitespace, digit, arbno, or, etc.
;; accion: skip | symbol | number | string
Ejemplo¶
(define especificacion-lexica
'(
(espacio-blanco (whitespace) skip) ; Ignora espacios, tabs, saltos de línea
(comentario ("%" (arbno (not #\newline))) skip) ; Ignora comentarios que empiezan con '%'
(identificador (letter (arbno (or letter digit "?" "$"))) symbol) ; Identificadores: letra seguida de letras, dígitos, ? o $
(numero (digit (arbno digit)) number) ; Números enteros positivos
(numero ("-" digit (arbno digit)) number) ; Números enteros negativos
(numero (digit (arbno digit) "." digit (arbno digit)) number) ; Números decimales positivos
(numero ("-" digit (arbno digit) "." digit (arbno digit)) number) ; Números decimales negativos
)
)
Salidas del escáner con esta especificación:
> (escaner " ")
() ; Se ignoran todos los espacios en blanco
> (escaner "% soy un comentario")
() ; Se ignora el comentario completo
> (escaner "x + y")
((identificador x 1) (literal-string "+" 1) (identificador y 1)) ; Identifica tokens con sus clases
> (escaner "x -28.3")
((identificador x 1) (numero -28.3 1)) ; Identifica identificador y número decimal negativo
Especificación Gramatical¶
La especificación gramatical define la sintaxis del lenguaje: cómo se combinan los tokens para formar construcciones válidas del programa. Además, permite generar automáticamente los tipos de datos algebraicos (datatypes) que representarán el Árbol de Sintaxis Abstracta (AST).
Formato general:
'(
(no-terminal (produccion) nombre-variante)
)
;; nombre-variante debe ser único para cada variante del datatype
Ejemplo¶
(define especificacion-gramatical
'(
(declaracion ("{" declaracion ";" declaracion "}") decl-1) ; Bloque: { decl1 ; decl2 }
(declaracion ("while" expresion "do" declaracion) decl-2) ; Bucle while
(declaracion (identificador ":=" expresion) decl-3) ; Asignación
(expresion (identificador) exp-1) ; Expresión variable
(expresion (numero) exp-2) ; Expresión literal numérica
(expresion ("(" expresion "+" expresion ")") exp-3) ; Expresión de suma
)
)
Salida del parser con esta gramática:
(parser "while 4 do x := y")
#(struct:decl-2 #(struct:exp-2 4) #(struct:decl-3 x #(struct:exp-1 y)))
;; Estructura: (decl-2 (exp-2 4) (decl-3 x (exp-1 y)))
;; Representa: while 4 do x := y
Funciones del Intérprete/Compilador¶
1. Construcción de los Datatypes¶
Genera automáticamente las definiciones de tipos de datos (structs) para representar el AST según las especificaciones léxica y gramatical.
(sllgen:make-define-datatypes especificacion-lexica especificacion-gramatical)
2. Construcción del Escáner y Parser¶
Crea funciones específicas para analizar cadenas de texto.
;; Construir escáner
(define escaner
(sllgen:make-string-scanner especificacion-lexica especificacion-gramatical))
;; Construir parser
(define parser
(sllgen:make-string-parser especificacion-lexica especificacion-gramatical))
3. Creación del Intérprete Interactivo¶
Crea un bucle de lectura-evaluación-impresión (REPL) para el lenguaje.
(define interpretador
(sllgen:make-rep-loop "--primer lenguaje-->" evaluar-programa
(sllgen:make-stream-parser
especificacion-lexica especificacion-gramatical)))
Evaluación de Programas¶
El intérprete toma como punto de entrada (start symbol) el primer no-terminal definido en la especificación gramatical. En nuestro ejemplo, espera una declaracion.
Función de evaluación de ejemplo:
(define evaluar-programa
(lambda (prog)
(cases declaracion prog ; 'cases' espera una estructura del tipo 'declaracion'
(decl-1 (d1 d2) (list d1 d2)) ; Para bloques: retorna lista de las dos declaraciones
(decl-2 (exp d1) (list exp d1)) ; Para while: retorna expresión y declaración
(decl-3 (id exp) (list id exp))) ; Para asignación: retorna identificador y expresión
))
Importante: Si el parser produce una expresion en lugar de una declaracion, esta función evaluar-programa fallará, ya que cases está configurado para manejar solo variantes del tipo declaracion.