Введение

Программа, обрабатывающая входные данные для другой программы.

В информатике препроцессор (или прекомпилятор) — это программа, которая обрабатывает свои входные данные для создания вывода, используемого в качестве входных данных для другой программы. Вывод считается предварительно обработанной формой входных данных, которая часто используется последующими программами, такими как компиляторы. Объем и тип выполняемой обработки зависят от препроцессора: некоторые препроцессоры способны выполнять лишь относительно простые текстовые подстановки и расширение макросов, в то время как другие обладают возможностями полноценных языков программирования. Распространенным примером в программировании является обработка исходного кода перед компиляцией. В некоторых языках программирования (например, C и PL/I) существует этап преобразования, известный как предварительная обработка. Он может включать обработку макросов, включение файлов и расширения языка.

Лексические препроцессоры

Лексические препроцессоры — это самый нижний уровень препроцессоров, поскольку они требуют лишь лексического анализа, то есть они оперируют с исходным текстом до какого-либо синтаксического анализа, выполняя простую замену токенизированных последовательностей символов на другие токенизированные последовательности символов в соответствии с правилами, заданными пользователем. Обычно они выполняют подстановку макросов, текстовое включение других файлов и условную компиляцию или включение.

C преобразователь

Наиболее распространенным примером этого является препроцессор C, который воспринимает строки, начинающиеся с "#", как директивы. Препроцессор C не предполагает, что его входные данные будут использовать синтаксис языка C. Некоторые языки используют иной подход и применяют встроенные языковые средства для достижения аналогичных результатов. Например:
Вместо макросов некоторые языки используют агрессивную инлайнинг и шаблоны. Вместо включений (includes) некоторые языки используют импорт времени компиляции, опирающийся на информацию о типах в объектном коде. Некоторые языки используют конструкции if-then-else и удаление мертвого кода для реализации условной компиляции.

Другие лексические препроцессоры

Другие лексические препроцессоры включают в себя m4 общего назначения, который наиболее часто используется в кроссплатформенных системах сборки, таких как autoconf, и GEMA — макропроцессор с открытым исходным кодом, работающий с образцами контекста.

Синтаксические препроцессоры

Синтаксические препроцессоры появились в семействе языков Lisp. Их задача — преобразовывать синтаксические деревья в соответствии с набором правил, заданных пользователем. Для некоторых языков программирования эти правила записываются на том же языке, что и сама программа (рефлексия во время компиляции). Это справедливо для Lisp и OCaml. В других языках для определения преобразований используется полностью внешний язык, например, XSLT-препроцессор для XML или его статически типизированный аналог CDuce. Синтаксические препроцессоры обычно применяются для изменения синтаксиса языка, расширения языка за счет добавления новых примитивов или для внедрения предметно-ориентированного языка программирования (DSL) в язык общего назначения.

Настройка синтаксиса

Хорошим примером настройки синтаксиса является наличие двух различных синтаксисов в языке программирования Objective Caml. Программы могут быть написаны как в "обычном синтаксисе", так и в "пересмотренном синтаксисе", и могут быть отформатированы для вывода с использованием любого из этих синтаксисов по запросу. Аналогично, многие программы, написанные на OCaml, расширяют синтаксис языка, добавляя новые операторы.

Расширение языка

Лучшие примеры расширения языка с помощью макросов можно найти в семействе языков Lisp. Хотя сами языки представляют собой простые динамически типизированные функциональные ядра, стандартные реализации Scheme или Common Lisp допускают императивное или объектно-ориентированное программирование, а также статическую типизацию. Практически все эти возможности реализованы посредством синтаксической предобработки, хотя стоит отметить, что фаза "расширения макросов" компиляции обрабатывается компилятором в Lisp. Это всё равно можно рассматривать как форму предобработки, поскольку она происходит перед другими фазами компиляции.

Специализация языка

Одной из необычных особенностей семейства языков Lisp является возможность использования макросов для создания внутренней DSL. Как правило, в крупном проекте на основе Lisp модуль может быть написан на различных таких мини-языках, один, например, с использованием диалекта Lisp, основанного на SQL, другой – на диалекте, специализированном для графических интерфейсов или форматированного вывода и т.д. Стандартная библиотека Common Lisp содержит пример такого уровня синтаксической абстракции в виде макроса LOOP, который реализует мини-язык, подобный Algol, для описания сложных итераций, при этом позволяя использовать стандартные операторы Lisp. Препроцессор/язык MetaOCaml предоставляет аналогичные возможности для внешних DSL. Этот препроцессор принимает описание семантики языка (то есть интерпретатора) и, сочетая интерпретацию во время компиляции и генерацию кода, преобразует это определение в компилятор для языка программирования OCaml, а из этого языка – либо в байт-код, либо в машинный код.

Преобразователь общего назначения

Большинство препроцессоров предназначены для конкретной задачи обработки данных (например, компиляции языка C). Препроцессор может позиционироваться как универсальный, что означает, что он не ориентирован на конкретное применение или язык программирования и предназначен для широкого спектра задач обработки текста. M4, вероятно, самый известный пример такого универсального препроцессора, хотя препроцессор C иногда используется не по прямому назначению. Примеры:
использование препроцессора C для предварительной обработки JavaScript; использование препроцессора C для обработки дерева устройств в ядре Linux; использование M4 (см. пример в статье) или препроцессора C в качестве шаблонизатора для генерации HTML; imake – интерфейс к make, использующий препроцессор C, разработанный для X Window System, но теперь устаревший в пользу automake; grompp – препроцессор для входных файлов симуляций GROMACS (быстрого, бесплатного и открытого программного обеспечения для решения некоторых задач вычислительной химии), который вызывает системный препроцессор C (или другой препроцессор, определяемый входным файлом симуляции) для разбора топологии, в основном используя механизмы #define и #include для определения эффективной топологии во время выполнения grompp.