En el ámbito de la informática, un preprocesador (o precompilador) es un programa diseñado para procesar datos de entrada y generar una salida que servirá como entrada para otro programa posterior. Generalmente, esta salida es una forma preprocesada de los datos originales, la cual es frecuentemente utilizada por programas subsiguientes, como los compiladores.
La complejidad y el tipo de procesamiento varían según la naturaleza del preprocesador; algunos se limitan a realizar sustituciones textuales simples y expansiones de macros, mientras que otros poseen la potencia de lenguajes de programación completos.
Tipos de Preprocesadores
Preprocesadores Léxicos
Los preprocesadores léxicos representan el nivel más básico de procesamiento. Operan sobre el texto fuente antes de cualquier análisis sintáctico (parsing), realizando sustituciones simples de secuencias de caracteres tokenizadas basándose en reglas definidas por el usuario.
- Funciones principales: Sustitución de macros, inclusión textual de otros archivos y compilación condicional.
- Ejemplo clásico: El C preprocessor, que utiliza directivas que comienzan con el símbolo
#. Es importante notar que el preprocesador de C no requiere que su entrada siga la sintaxis del lenguaje C.
Algunos lenguajes modernos evitan el uso de preprocesadores léxicos mediante funciones integradas como el inlining agresivo, plantillas (templates) o la eliminación de código muerto para lograr la compilación condicional.
Preprocesadores Sintácticos
Introducidos principalmente con la familia de lenguajes Lisp, los preprocesadores sintácticos transforman árboles de sintaxis según reglas definidas por el usuario. En algunos casos, estas reglas se escriben en el mismo lenguaje que el programa (reflexión en tiempo de compilación), como ocurre en Lisp y OCaml.
Estos preprocesadores se utilizan comúnmente para:
- Personalizar la sintaxis: Permitir diferentes formas de escribir el código (por ejemplo, las dos sintaxis disponibles en Objective Caml).
- Extender el lenguaje: Añadir nuevas primitivas o funcionalidades, permitiendo que lenguajes funcionales simples como Scheme o Common Lisp soporten programación imperativa u orientada a objetos.
- Especializar el lenguaje: Crear lenguajes de dominio específico (DSL) internos. Un ejemplo notable es la macro
LOOPde Common Lisp, que implementa un minilenguaje similar a Algol para iteraciones complejas.
Preprocesadores de Propósito General
A diferencia de los preprocesadores específicos para una tarea (como el de C), existen herramientas de propósito general que no están ligadas a un lenguaje de programación concreto y pueden usarse para diversas tareas de procesamiento de texto.
El ejemplo más conocido es M4, ampliamente utilizado en sistemas de construcción multiplataforma como autoconf. No obstante, ocasiones existen casos donde el preprocesador de C se utiliza para tareas ajenas a C, como el preprocesamiento de JavaScript o el procesamiento de árboles de dispositivos en el núcleo de Linux.

