Зачем нужен компилятор

Разбираемся, какую задачу решает компилятор и почему без трансляции код был бы бесполезным текстом.

Компилятор — программа, которая переводит исходный код с одного языка (обычно высокоуровневого) на другой (обычно машинный или промежуточный), сохраняя смысл.

Процессор умеет выполнять только последовательности числовых команд — машинный код. Строка print("Привет") для него ничего не значит: это просто набор символов. Чтобы такой текст ожил, кто-то должен прочитать его, понять структуру и превратить в инструкции, понятные железу. Именно этим и занимается компилятор.

Почему нельзя писать сразу в машинном коде

Теоретически можно. Но машинный код привязан к конкретной архитектуре, состоит из чисел и адресов, не имеет имён переменных и крайне труден для человека. Высокоуровневые языки появились ради нас: они читаемы, переносимы и выразительны. Цена за это — необходимость трансляции.

Сравните одну и ту же идею «сложить два числа» на двух уровнях абстракции.

a = 2
b = 3
print(a + b)

Вывод:

5

А вот как примерно выглядит та же операция на уровне ассемблера — уже почти то, что понимает процессор.

MOV  AX, 2     ; положить 2 в регистр
ADD  AX, 3     ; прибавить 3
; в AX теперь 5

Что значит «сохранять смысл»

Ключевое требование к компилятору — эквивалентность. Программа после трансляции должна делать ровно то же, что задумал автор. Если исходник печатает 5, машинный код тоже обязан напечатать 5. Компилятор не имеет права «улучшать» логику программы, он лишь переводит её на другой язык, иногда оптимизируя форму, но не результат.

Как работает под капотом

Грубо говоря, компилятор читает текст слева направо, разбивает его на осмысленные кусочки, проверяет, складываются ли они в допустимые конструкции языка, строит внутреннюю модель программы и по этой модели порождает целевой код. Всё это — череда превращений одного представления в другое: текст → токены → дерево → промежуточный код → машинный код. Каждое следующее представление ближе к железу, чем предыдущее.

исходный текст
      |
      v
[ трансляция ]
      |
      v
машинный / промежуточный код

Частые ошибки

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

Другое заблуждение — что компилятор «понимает» программу как человек. Нет: он работает по строгим формальным правилам и не догадывается о ваших намерениях. Если правило нарушено — будет ошибка, даже если «и так понятно».

Итог

  • Процессор понимает только машинный код, а не текст программы.
  • Компилятор переводит высокоуровневый код в код, понятный машине, сохраняя смысл.
  • Высокоуровневые языки нужны людям ради читаемости и переносимости.
  • Компиляция (перевод) и выполнение (запуск) — разные стадии жизни программы.
Проверьте себя
1. Какова основная задача компилятора?
AУскорять работу процессора
BПереводить исходный код в другой язык, сохраняя смысл
CИсправлять логические ошибки в программе
DЗапускать программу в облаке
2. Чем компиляция отличается от выполнения?
AЭто синонимы
BКомпиляция — перевод кода, выполнение — запуск результата
CКомпиляция происходит только на сервере
DВыполнение порождает исполнимый файл