# Компилятор и декомпилятор

**Компилятор - программа, переводящая написанный код на языке программирования высокого уровня в набор машинных кодов.**

**Виды компиляторов:**
- **Векторизующий.** Компилирует исходный код в машинный код для компьютеров, оснащённых векторным процессором.
- **Гибкий.** Сконструирован по модульному принципу, управляется таблицами и запрограммирован на языке высокого уровня или - реализован с помощью компилятора компиляторов.
- **Инкрементальный.** Повторно транслирует/компонует фрагменты программы и дополнения к ней без перекомпиляции всей программы.
- **Интерпретирующий (пошаговый).** Последовательно выполняет независимую компиляцию каждого отдельного оператора (команды) исходной программы.
- **Компилятор компиляторов.** Компилятор, воспринимающий формальное описание языка программирования и генерирующий компилятор для этого языка.
- **Отладочный.** Устраняет отдельные виды синтаксических ошибок.
- **Резидентный.** Постоянно находится в оперативной памяти и доступен для повторного использования многими задачами.
- **Самокомпилируемый.** Написан на том же языке, с которого осуществляется компиляция.
- **Универсальный.** Основан на формальном описании синтаксиса и семантики входного языка. Важными составными частями такого компилятора являются: ядро, синтаксический и семантический загрузчики.


**Компиляция - это процесс преобразования программного кода из одного языка программирования в другой, как правило, с языка программирования высокого уровня в машинный код.**

**Виды компиляции:**
- **Пакетная.** Компиляция нескольких исходных модулей в одном задании.
- **Построчная.** Машинный код порождается и затем исполняется для каждой завершённой грамматической конструкции языка. Внешне воспринимается как интерпретация, но имеет иное устройство.
- **Условная.** На фазе трансляции результат трансляции зависит от условий, прописанных в исходном транслируемом тексте программы директивами компилятора.

**История создания**

Создание первых программ компиляции следует отнести к началу пятидесятых годов прошлого века. Главной задачей реализации первых компиляторов в то время было решение проблемы преобразования алгебраических выражений в машинные коды. А фактическим годом рождения теории компиляции может считаться 1957-ой год, когда была реализована первая программа компиляции языка Фортран, сформированная Джоном Бэкусом и выдававшая довольно эффективные объектные (машинные) коды. Этот компилятор был предназначен для платформ IBM 704, IBM 360 и DEC PDP-11. В восьмидесятом году прошлого века вышел новый вариант компилятора, предназначенный для IBM 360 и IBM РС, который поддерживал стандарт Fortran 77. Годом позже образовалась компания Watcom, представившая в 1988-ом году программу компиляции Си. Она мгновенно стала чрезвычайно популярной среди специалистов по программированию, поскольку могла генерировать наиболее быстрые коды
в сравнении с другими компиляторами тех времён.

**Джон Бэкус**

![Джон Бэкус](1.jpg)


**Принцип работы**

Компилятор – это системная программа, которая воспринимает на входе текст программы на языке высокого уровня (исходный модуль), а на выходе генерирует программу на языке ассемблера или машинном языке (объектный модуль). Объектный модуль состоит из двух основных частей: тела модуля, представляющего собой программу в кодах команд конкретной ЭВМ, и заголовка, содержащего внешние имена (имена переменных, используемых в данном модуле, но определённых в других модулях). Эта информация необходима для построения из набора объектных модулей программы или программной системы,готовой к выполнению. Объектные модули обрабатываются компоновщиком (редактором связей), который строит исполняемую программу (исполняемый файл, exe-модуль, загрузочный модуль) содержащую только команды ЭВМ.

![Компилятор](2.png)

![Принцип работы компилятора](3.png)

Компиляция работает быстрее интерпретации, потому что компилятор запускается только один раз: делает перевод и отдает его процессору. Интерпретатор же запускается на каждой строке кода и нужен при каждом запуске программы. Кроме того, программный код в компиляторе уже переведен в машинный, поэтому требуется намного меньше времени для его исполнения. Поэтому, при разработке объёмных приложений лучше использовать компилятор. В то время как интерпретатор будет превосходить по скорости компилятор при использовании его в разработке небольших приложений.

Отдельные программы компиляции, к примеру, Java, способны переводить программу не в машинные коды, а в программу на определённом специализированном языке низкого уровня. Данный язык, или по-другому байт-код, тоже может считаться языком машинных кодов, так как он должен интерпретироваться виртуальной машиной. К примеру, для языка Java языком виртуальной машины является JVM, или иначе байт-код Java. 

Для всех целевых машин, к примеру, IBM, Apple и так далее, и всех операционных систем или их семейств, используемых на целевой машине, необходимо написать свою программу компиляции. Есть ещё так называемые программы кросс-компиляции, которые позволяют на одной машине и одной операционной системе формировать коды, предназначенные для исполнения на другой целевой машине или другой операционной системе.

Помимо этого, программы компиляции можно оптимизировать для разных типов процессоров из единого семейства. К примеру, коды, сформированные компилятором для процессоров семейства i686, могут применять специфические для данных процессоров инструкции ММХ, SSE, SSE2. Имеются также программы, решающие обратную задачу, а именно, они переводят
программы с языка низкого уровня на язык высокого уровня. Такая процедура именуется декомпиляцией, а выполняющие её программы называются декомпиляторами.


**Структура компилятора**

Любой компилятор состоит из транслятора и компоновщика. Часто в качестве компоновщика компилятор использует внешний компоновщик, реализованный в виде самостоятельной программы, а сам выполняет лишь трансляцию исходного текста (по этой причине многие ошибочно считают компилятором разновидность транслятора). Компилятор может быть реализован и как своеобразная программа-менеджер, для трансляции программы вызывающая сооствествующий транслятор (трансляторы - если разные части программы написаны на разных языках программирования) и затем - для компоновки программы, - вызывающая компоновщик. Ярким примером такого компилятора является имеющаяся во всех UNIX-системах (и Linux-системах в том числе) утилита make (имеются реализации утилиты make и в других системах, в частности в Windows-системах).

Процесс компиляции состоит из следующих фаз:
1. **Лексический анализ.** На этой фазе последовательность символов исходного файла преобразуется в последовательность лексем.
2. **Синтаксический (грамматический) анализ.** Последовательность лексем преобразуется в древо разбора.
3. **Семантический анализ.** Древо разбора обрабатывается с целью установления его семантики (смысла) — например, привязка идентификаторов к их определениям, типам данных, проверка совместимости типов данных, определение результирующих типов данных выражений и т. д. Результат обычно называется «промежуточным представлением/кодом», и может быть дополненным древом разбора, новым древом, абстрактным набором команд или чем-то ещё, удобным для дальнейшей обработки.
4. **Оптимизация.** Удаляются избыточные команды и упрощается (где это возможно) код с сохранением его смысла, т. е. реализуемого им алгоритма (в том числе предвычисляются (т. е. вычисляются на фазе трансляции) выражения, результаты которых практически являются константами). Оптимизация может быть на разных уровнях и этапах — например, над промежуточным кодом или над конечным машинным кодом.
5. **Генерация кода.** Из промежуточного представления порождается код на целевом языке (в том числе выполняется компоновка программы).


**Примеры компиляторов**

Для Windows:
- Borland C++ Compiler
- C++Builder XE7
- Dev-C++
- Microsoft Visual C++

Для Unix:
- g++
- GNU Compiler Collection
- Oracle Solaris Studio


**Достоинства и недостатки**

Достоинства компилятора:
- Программный код уже переведен в машинный, следовательно, требуется меньше времени на его исполнение.
- Файлы .exe выполняются быстрее, чем исходный код. Объектные программы сохраняются и могут быть запущены в любое время.
- Объектные программы пользователю сложнее изменить, чем исходный код.
- Компилятор проверяет исходный код на наличие синтаксических ошибок во время компиляции.

Недостатки компиляторов:
- Использует гораздо больше памяти компьютера.
- При работе с компилятором невозможно изменить программу, не вернувшись к исходному коду.
- Необходимо создавать объектную программу перед окончательным исполняемым файлом. Это может занять много времени.
- Исходный код должен быть на 100% верным для создания исполняемого файла.


**Декомпиляция**

Существуют программы, которые решают обратную задачу - перевод программы с низкоуровневого языка на высокоуровневый. Этот процесс называют **декомпиляцией**, а такие программы - **декомпиляторами**.

**Декомпилятор - это программа, транслирующая исполняемый модуль (полученный на выходе компилятора) в эквивалентный исходный код на языке программирования высокого уровня.**

**Декомпиляция - процесс воссоздания исходного кода декомпилятором.**

Декомпиляция, в частности, используется при обратной разработке программ.

Удачность декомпиляции зависит от объема информации, представленной в декомпилируемом коде. Байт-код, используемый большинством виртуальных машин, часто содержит обширные метаданные, делающие декомпиляцию вполне выполнимой, в то время как машинный код более скуден и сложен в декомпиляции. В частности трудночитаемыми представляются вызовы подпрограмм или функций с косвенной адресацией вызовов.

Если известно на каком языке была написана декомпилируемая программа, то в первую очередь дизассемблируются и анализируются библиотеки времени исполнения (RTL — runtime library) компилятора с этого языка, так как в основном компиляция программы сводится к вызовам с различными параметрами процедур из этих библиотек. Кроме того, многие компиляторы позволяют увидеть, в какой ассемблерный код превращаются операторы программы после компиляции. Эти конструкции становятся шаблонами для декомпилятора, поэтому процесс декомпиляции в некотором смысле похож на распознавание в машинном коде конечного набора подобных шаблонов. Легче всего распознаются вызовы процедур и возвраты из них. Они служат границами для восстановления операторов процедуры.

Примеры декомпиляторов:
- FernFlower
- .NET Reflector, dotPeek — для декомпиляции сборок .NET
- ILSpy
- Delphi Decompiler
- JAD — JAva Decompiler

Для чего нужен декомпилятор:
- взлом коммерческих программ и видеоигр.
- исследование работы программы (реверс-инжиниринг). Например, есть мессенджер Skype. Протокол его взаимодействия с сервером не опубликован. А мы хотим создать свой мессенджер, который может работать в сети Skype. Или хотим сделать чит к игре.
- поиск уязвимостей в программе, исходный код которой недоступен.
- чтобы видеть не только ЧТО программа делает, но и КАК она это делает.

_Таким образом, мы познакомились с такими понятиями, как: компилятор, компиляция, декомпилятор, декомпиляция. Узнали как работает компилятор и для чего нужен декомпилятор._

## Список литературы

[Декомпилятор](https://ru.wikipedia.org/wiki/Декомпилятор)

[Компилятор](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%82%D0%BE%D1%80)

[Компилятор против интерпертатора. Ключевые отличия](https://medium.com/nuances-of-programming/компилятор-vs-интерпретатор-ключевые-отличия-ef14a2aa0ee6)

[Компиляторы: история создания и развития](https://spravochnick.ru/informacionnye_tehnologii/kompilyatory_istoriya_sozdaniya_i_razvitiya/)

[Компиляция и интерпретация кода: что это такое и в чём разница](https://ru.hexlet.io/blog/posts/kompilyatsiya-i-interpretatsiya-koda-chto-eto-takoe-i-v-chem-raznitsa)

[Принципы работы компилятора](https://studfile.net/preview/358641/page:6/)

[Структура компиляторов. Общая схема работы компилятора](https://studfile.net/preview/2910570/)

