Инструменты: ANTLR и LLVM
Свой компилятор полезно написать руками, но в индустрии используют готовые инструменты — познакомимся с двумя главными.
Генератор парсеров — инструмент, который по описанию грамматики автоматически создаёт код лексера и парсера, избавляя от ручного написания рекурсивного спуска.
Мы написали лексер и парсер вручную — это отлично для понимания. Но для большого языка делать всё руками утомительно и чревато ошибками. Индустрия давно автоматизировала эти этапы. Разберём два знаковых инструмента.
ANTLR: генератор парсеров
ANTLR принимает грамматику в нотации, похожей на EBNF, и генерирует готовый лексер с парсером на Java, Python, C# и других языках. Вы описываете правила — ANTLR пишет код.
// грамматика ANTLR для арифметики (фрагмент)
grammar Expr;
expr : term (('+' | '-') term)* ;
term : factor (('*' | '/') factor)* ;
factor: NUMBER | '(' expr ')' ;
NUMBER: [0-9]+ ;
WS : [ \t\r\n]+ -> skip ;Узнаёте? Это ровно наша грамматика expr → term → factor, только в синтаксисе ANTLR. Строка WS ... -> skip говорит: пробелы пропускать — то, что наш лексер делал вручную. ANTLR сам построит AST и даже сгенерирует заготовки visitor-методов для обхода.
LLVM: инфраструктура back-end
LLVM — набор инструментов и библиотек для построения back-end компилятора: оптимизаций и генерации машинного кода поверх единого промежуточного представления (LLVM IR).
Если ANTLR помогает с front-end (анализом), то LLVM закрывает back-end (кодогенерацию). Вы порождаете LLVM IR — а LLVM сам его оптимизирует и скомпилирует под x86, ARM и десятки других архитектур. На LLVM построены компиляторы Clang (C/C++), Rust, Swift.
; LLVM IR для функции, складывающей два числа (фрагмент)
define i32 @add(i32 %a, i32 %b) {
%sum = add i32 %a, %b
ret i32 %sum
}Как работает под капотом
Эти инструменты опираются на то, что вы уже знаете. ANTLR внутри строит парсер по грамматике (часто разновидность рекурсивного спуска) и формирует дерево. LLVM IR — это то самое промежуточное представление из нашего раздела, только индустриального уровня, с типами и оптимизирующими проходами. Разделение front-end/back-end через общий IR, о котором мы говорили, — буквально архитектура LLVM.
| Инструмент | Зона | Что даёт |
| ANTLR | front-end | лексер + парсер из грамматики |
| LLVM | back-end | оптимизация + машинный код из IR |
Когда писать руками, а когда брать готовое
Ручной рекурсивный спуск оправдан для небольших языков, конфигов, простых калькуляторов и когда важны идеальные сообщения об ошибках (многие промышленные компиляторы, например GCC и Clang, используют рукописные парсеры именно ради качества диагностики). Готовые инструменты выигрывают, когда грамматика большая и часто меняется, а сроки важнее тонкого контроля.
Частые ошибки
Первое заблуждение — что инструмент избавляет от понимания теории. Наоборот: чтобы написать грамматику для ANTLR без конфликтов или отладить LLVM IR, нужно понимать приоритеты, неоднозначность и фазы — всё, что мы прошли. Инструмент ускоряет, но не заменяет знание.
Второе — тащить тяжёлый LLVM туда, где хватило бы интерпретатора на дереве. Для DSL, который считает формулы, наш calc из проекта проще и быстрее в разработке, чем полноценная компиляция в машинный код.
Итог
- ANTLR генерирует лексер и парсер из грамматики — это автоматизированный front-end.
- LLVM даёт back-end: оптимизации и кодогенерацию поверх единого LLVM IR.
- Оба инструмента опираются на пройденные понятия: грамматики, AST, IR, фазы.
- Ручной парсер хорош для малых языков и качественных ошибок; инструменты — для больших грамматик.