Зачем выполняется преобразование текста программы в машинный язык

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

Компилировать — проводить трансляцию машинной программы с проблемно-ориентированного языка на машинно-ориентированный язык.

Виды компиляторов

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

Виды компиляции

  • Пакетная. Компиляция нескольких исходных модулей в одном пункте задания.
  • Построчная. То же, что и интерпретация.
  • Условная. Компиляция, при которой транслируемый текст зависит от условий, заданных в исходной программе директивами компилятора. Так, в зависимости от значения некоторой константы, можно включать или выключать трансляцию части текста программы.

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

Процесс компиляции состоит из следующих этапов:

Пишу программу в машинных кодах

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

В конкретных реализациях компиляторов эти этапы могут быть разделены или, наоборот, совмещены в том или ином виде.

Надо ли знать программисту: историю ЭВМ, машинный код, уметь работать с низкоуровневыми языками?

Генерация кода

Генерация машинного кода

Большинство компиляторов переводит программу с некоторого высокоуровневого языка программирования в машинный код, который может быть непосредственно выполнен процессором. Как правило, этот код также ориентирован на исполнение в среде конкретной операционной системы, поскольку использует предоставляемые ею возможности (системные вызовы, библиотеки функций). Архитектура (набор программно-аппаратных средств), для которой производится компиляция, называется целевой машиной.

Результат компиляции — исполнимый модуль — обладает максимальной возможной производительностью, однако привязан к определённой операционной системе и процессору (и не будет работать на других).

Для каждой целевой машины (IBM, Apple, Sun и т. д.) и каждой операционной системы или семейства операционных систем, работающих на целевой машине, требуется написание своего компилятора. Существуют также так называемые кросс-компиляторы, позволяющие на одной машине и в среде одной ОС генерировать код, предназначенный для выполнения на другой целевой машине и/или в среде другой ОС. Кроме того, компиляторы могут оптимизировать код под разные модели из одного семейства процессоров (путём поддержки специфичных для этих моделей особенностей или расширений наборов инструкций). Например, код, скомпилированный под процессоры семейства Pentium, может учитывать особенности распараллеливания инструкций и использовать их специфичные расширения — MMX, SSE и т. п.

Некоторые компиляторы переводят программу с языка высокого уровня не прямо в машинный код, а на язык ассемблера (примером может служить PureBasic, транслирующий бейсик-код в ассемблер FASM). Это делается для упрощения части компилятора, отвечающей за кодогенерацию, и повышения его переносимости (задача окончательной генерации кода и привязки его к требуемой целевой платформе перекладывается на ассемблер), либо для возможности контроля и исправления результата компиляции программистом.

Генерация байт-кода

Результатом работы компилятора может быть программа на специально созданном низкоуровневом языке, подлежащем интерпретации виртуальной машиной. Такой язык называется псевдокодом или байт-кодом. Как правило, он не является машинным кодом какого-либо компьютера и программы на нём могут исполняться на различных архитектурах, где имеется соответствующая виртуальная машина, но в некоторых случаях создаются аппаратные платформы, напрямую поддерживающие псевдокод какого-либо языка. Например, псевдокод языка Java называется байт-кодом Java и выполняется в Java Virtual Machine, для его прямого исполнения была создана спецификация процессора picoJava. Для платформы .NET Framework псевдокод называется Common Intermediate Language (CIL), а среда исполнения — Common Language Runtime (CLR).

Читайте также:
Программа геодезического мониторинга пример

Некоторые реализации интерпретируемых языков высокого уровня (например, Perl) используют байт-код для оптимизации исполнения: затратные этапы синтаксического анализа и преобразование текста программы в байт-код выполняются один раз при загрузке, затем соответствующий код может многократно использоваться без промежуточных этапов.

Динамическая компиляция

Из-за необходимости интерпретации байт-код выполняется значительно медленнее машинного кода сравнимой функциональности, однако он более переносим (не зависит от операционной системы и модели процессора). Чтобы ускорить выполнение байт-кода, используется динамическая компиляция, когда виртуальная машина транслирует псевдокод в машинный код непосредственно перед его первым исполнением (и при повторных обращениях к коду исполняется уже скомпилированный вариант).

CIL-код также компилируется в код целевой машины JIT-компилятором, а библиотеки .NET Framework компилируются заранее.

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

Существуют программы, которые решают обратную задачу — перевод программы с низкоуровневого языка на высокоуровневый. Этот процесс называют декомпиляцией, а такие программы — декомпиляторами. Но поскольку компиляция — это процесс с потерями, точно восстановить исходный код, скажем, на C++, в общем случае невозможно.

Более эффективно декомпилируются программы в байт-кодах — например, существует довольно надёжный декомпилятор для Flash. Разновидностью декомпилирования является дизассемблирование машинного кода в код на языке ассемблера, который почти всегда выполняется успешно (при этом сложность может представлять самомодифицирующийся кодили код, в котором собственно код и данные не разделены). Связано это с тем, что между кодами машинных команд и командами ассемблера имеется практически взаимно-однозначное соответствие.

Раздельная компиляция

Раздельная компиляция (англ. separate compilation ) — трансляция частей программы по отдельности с последующим объединением их компоновщиком в единый загрузочный модуль.

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

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

Источник: informatica9class.blogspot.com

Транслятор

Транслятор обычно выполняет также диагностику ошибок, форирует словари идентификаторов, выдаёт для печати тексты программы и т. д.

Трансляция программы — преобразование программы, представленной на одном из языков программирования, в программу на другом языке и, в определённом смысле, равносильную первой.

Язык, на котором представлена входная программа, называется исходным языком, а сама программа — исходным кодом. Выходной язык называется целевым языком или объектным кодом.

Понятие трансляции относится не только к языкам программирования, но и к другим компьютерным языкам, вроде языков разметки, аналогичных HTML, и к естественным языкам, вроде английского или русского. Однако данная статья только о языках программирования, о естественных языках см.: Перевод.

Виды трансляторов

  • Адресный. Функциональное устройство, преобразующее виртуальный адрес (Virtual address) в реальный адрес памяти (Memory address).
  • Диалоговый. Обеспечивает использование языка программирования в режиме разделения времени.
  • Многопроходной. Формирует объектный модуль за несколько просмотров исходной программы.
  • Обратный. То же, что детранслятор. См. также: декомпилятор, дизассемблер.
  • Однопроходной. Формирует объектный модуль за один последовательный просмотр исходной программы.
  • Оптимизирующий. Выполняет оптимизацию кода в создаваемом объектном модуле.
  • Синтаксически-ориентированный (синтаксически-управляемый). Получает на вход описание синтаксиса и семантики языка и текст на описанном языке, который и транслируется в соответствии с заданным описанием.
  • Тестовый. Набор макрокомандязыка ассемблера, позволяющих задавать различные отладочныепроцедуры в программах, составленных на языке ассемблера.

Реализации

Цель трансляции — преобразовать текст с одного языка на другой, который понятен адресату текста. В случае программ-трансляторов, адресатом является техническое устройство (процессор) или программа-интерпретатор.

Основная статья: Компилятор

Язык процессоров (машинный код) обычно является низкоуровневым. Существуют платформы, использующие в качестве машинного язык высокого уровня (например, iAPX-432

Шаблон:Начало цитаты Можно привести ряд других примеров, в которых архитектура разработанных серий вычислительных машин базировалась или сильно зависела от некоторой модели структуры программы. Так, серия GE/Honeywell Multics основывалась на семантической модели выполнения программ, написанных на языке ПЛ/1. В Шаблон:Не переведено B5500, B6700 … B7800 прототипом послужила модель программы этапа выполнения, написанной на расширенном языке Алгол. …

Процессор i432, подобно этим ранним архитектурам, также базируется на семантической модели структуры программы. Однако, в отличие от своих предшественников, i432 не основывается на модели некоторого конкретного языка программирования. Вместо этого, основной целью разработчиков было обеспечение непосредственной поддержки на этапе выполнения как для абстрактных данных (то есть программирование с абстрактными типами данных), так и для доменно-ориентированных операционных систем. …

Язык Ада поддерживает объектно-базированное программирование, что и послужило причиной выбора его в качестве основного языка программирования для i432. Шаблон:Конец цитаты), но они являются исключением из правила в силу сложности и дороговизны. Транслятор, который преобразует программы в машинный язык, принимаемый и исполняемый непосредственно процессором, называется компилятором.

Читайте также:
Реферальная программа для сотрудников это

Процесс компиляции как правило состоит из нескольких этапов: лексического, синтаксического и Шаблон:Не переведено, генерации промежуточного кода, оптимизации и генерации результирующего машинного кода. Помимо этого, программа как правило зависит от сервисов, предоставляемых операционной системой и сторонними библиотеками (например, файловый ввод-вывод или графический интерфейс), и машинный код программы необходимо связать с этими сервисами. Связывание со статическими библиотеками выполняется редактором связей или компоновщиком (который может представлять из себя отдельную программу или быть частью компилятора), а с операционной системой и динамическими библиотеками связывание выполняется при начале исполнения программы загрузчиком.

Достоинство компилятора: программа компилируется один раз и при каждом выполнении не требуется дополнительных преобразований. Соответственно, не требуется наличие компилятора на целевой машине, для которой компилируется программа. Недостаток: отдельный этап компиляции замедляет написание и отладку и затрудняет исполнение небольших, несложных или разовых программ.

Основная статья: Ассемблер

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

Основная статья: Интерпретатор

Противоположный метод реализации — когда программа исполняется с помощью интерпретатора вообще без трансляции. Интерпретатор программно моделирует машину, цикл выборки-исполнения которой работает с командами на языках высокого уровня, а не с машинными командами. Такое программное моделирование создаёт виртуальную машину, реализующую язык.

Этот подход называется чистой интерпретацией. Чистая интерпретация применяется как правило для языков с простой структурой (например, АПЛ или Лисп). Интерпретаторы командной строки обрабатывают команды в скриптах в UNIX или в пакетных файлах (.bat) в MS-DOS также как правило в режиме чистой интерпретации.

Достоинство чистого интерпретатора: отсутствие промежуточных действий для трансляции упрощает реализацию интерпретатора и делает его удобнее в использовании, в том числе в диалоговом режиме. Недостаток — интерпретатор должен быть в наличии на целевой машине, где должна исполняться программа. А свойство чистого интерпретатора, что ошибки в интерпретируемой программе обнаруживаются только при попытке выполнения команды (или строки) с ошибкой, можно признать как недостатком, так и достоинством.

Существуют компромиссные между компиляцией и чистой интерпретацией варианты реализации языков программирования, когда интерпретатор перед исполнением программы транслирует её на промежуточный язык (например, в байт-код или p-код), более удобный для интерпретации (то есть речь идёт об интерпретаторе со встроенным транслятором). Такой метод называется смешанной реализацией. Примером смешанной реализации языка может служить Perl. Этот подход сочетает как достоинства компилятора и интерпретатора (бо́льшая скорость исполнения и удобство использования), так и недостатки (для трансляции и хранения программы на промежуточном языке требуются дополнительные ресурсы; для исполнения программы на целевой машине должен быть представлен интерпретатор). Также, как и в случае компилятора, смешанная реализация требует, чтобы перед исполнением исходный код не содержал ошибок (лексических, синтаксических и семантических).

Основная статья: Динамическая компиляция

По мере увеличения ресурсов компьютеров и расширения гетерогенных сетей (в том числе интернета), связывающих компьютеры разных типов и архитектур, выделился новый вид интерпретации, при котором исходный (или промежуточный) код компилируется в машинный код непосредственно во время исполнения, «на лету». Уже скомпилированные участки кода кешируются, чтобы при повторном обращении к ним они сразу получали управление, без перекомпиляции. Этот подход получил название динамической компиляции.

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

Этот метод хорошо подходит для веб-приложений. Соответственно, динамическая компиляция появилась и поддерживается в той или иной мере в реализациях Java, Microsoft .NET, Perl, Python.

Смешение понятий трансляции и интерпретации

Трансляция и интерпретация — разные процессы: трансляция занимается переводом программ с одного языка на другой, а интерпретация отвечает за исполнение программ. Однако, поскольку целью трансляции как правило является подготовка программы к интерпретации, то эти процессы обычно рассматриваются вместе. Например, языки программирования часто характеризуются как «компилируемые» или «интерпретируемые», в зависимости от того, преобладает при использовании языка компиляция или интерпретация. Причём практически все языки программирования низкого уровня и третьего поколения, вроде ассемблера, Си или Модулы-2, являются компилируемыми, а более высокоуровневые языки, вроде Python или SQL, — интерпретируемыми.

С другой стороны, существует взаимопроникновение процессов трансляции и интерпретации: интерпретаторы могут быть компилирующими (в том числе с динамической компиляцией), а в трансляторах может требоваться интерпретация для конструкций метапрограммирования (например, для макросов в языке ассемблера, условной компиляции в Си или для шаблонов в C++).

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

Читайте также:
Загадки из программы что где когда

Источник: www.tadviser.ru

3.1. Машинный язык и ассемблер

На своем рабочем уровне микропроцессор реагирует на список операций, называемый машинной программой. На рис. 3.1, а приведено содержимое памяти, являющееся программой на машинном языке. Эта программа начинается с адреса 2000Н с содержимым КОП ОО11 11102 и оканчивается адресом 2006Н с содержимым 0111 01102. Человеку практически невозможно понять программу, представленную в такой форме.

Программа на машинном языке на рис. 3.1, а становится несколько проще для восприятия, когда она представлена в шестнадцатеричном коде (Н-коде), как показано на рис. 3.1, б. Однако, хотя двоичные данные приведены в шестнадцатеричном коде, эта часть программы всегда рассматривается как заданная на машинном языке и оказывается трудной для понимания.

В более приемлемой форме записанная на машинном языке она могла бы выглядеть так:

1. Загрузить двоичное число (1011 0100) в аккумулятор.

Инвертировать каждый двоичный бит содержимого аккумулятора.

Поместить результаты инверсии в ячейку памяти данных 2100Н.

В этой части осуществляется перевод двоичного 8-разрядного числа в его эквивалент в инверсной форме.

Возникает вопрос: как перейти от этой формы человеческого языка, иногда длинной и сложной, к машинному языку? Ответ состоит в использовании языка простого программирования – от самого высокого уровня до машинного, представленного на рис. 3.1. Ассемблер использует слова и фразы, преобразуя их в машинный код микропроцессора.

Обычно фраза или заданная величина на ассемблере будет соответствовать выражению длиной от одного до трех байт машинного языка. Суть и процедура ассемблирования показаны на рис. 3.2, где, например, вторая команда программы представлена единственной мнемоникой из трех букв СМА (инвертировать содержимое аккумулятора).

Сначала три буквы переведены в их эквивалент в коде ASCI , затем три кода AS СI преобразованы в оп­ределенный порядок специальной программой ассемблера, которая выдает код инверсии содержимого аккумулятора на машинном языке, т.е. 0010 11112 в данном случае или 2FH. Мнемоника преобразована в один единственный байт машинного языка.

Программа на языке ассемблер, записанная человеком, могла бы быть представлена в виде табл. 3.1.

Число различных команд микропроцессора равно 78 и для них предложено 78 имен команд. Многие базовые команды порождают несколько различных кодов операций, поэтому общее число кодов команд равно 244.

Запомнить 244 восьмиразрядных двоичных кода очень трудно, и поэтому каждому коду ставится в соответствие мнемоническое название (мнемоника) команды, которое является сокращением от английских слов, описывающих ее действие. Например, IN 25 – input data at accumulator from port 25. На русский язык переводится так – ввести данные в аккумулятор из порта с адресом 25.

Мнемонический код команд позволяет легче запомнить их функции и значительно упрощает написание программ.

Такой язык написания программ называется языком ассемблера.

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

Перевод может происходить автоматически с помощью специальных программ-трансляторов (кросс-ассемблеров или ассемблеров) или вручную с помощью таблицы кодов команд.

При работе микропроцессор реагирует на список команд, называемый машинной программой. На рис. 3.1 показаны программы: а) в двоичном машинном коде; б) в шестнадцатеричном машинном коде.

Программа на рис. 3.1, а начинается с адреса 2000Н с содержимым КОП 001111100 и оканчивается адресом 2006 с содержимым 01110110. Человеку практически невозможно понять программу, представленную в таком виде. Хотя любая микропроцессорная система будет работать только с такой программой.

Программа, представленная на рис. 3.1, б, несколько проще для восприятия, так как она представлена в шестнадцатеричном коде, но все равно она трудна для понимания. Обе эти программы написаны на машинном языке.

А как программа, записанная на машинном языке, могла быть описана человеком?

1 – загрузить двоичное число 10110100 в аккумулятор;

2 – инвертировать каждый дв
оичный бит содержимого аккумулятора;

3 – поместить результат инверсии в ячейку памяти данных 2100Н;

4 – остановить микропроцессор.

Здесь осуществляется инвертирование двоичного восьмиразрядного числа.

Возникает вопрос: как перейти от этой формы человеческого языка, иногда длинной и сложной, к машинному языку.

Язык ассемблер использует слова и фразы, преобразуя их в машинный код микропроцессора.

Суть и процедура ассемблирования показаны на рис. 3.2, где вторая команда программы представлена единственной мнемоникой из трех букв CMA – complement accumulator – инвертировать содержимое аккумулятора.

Ход ассемблирования. Сначала три буквы переведены в их эквивалент в коде АСКИ, затем эти три кода АСКИ преобразованы в определенный порядок специальной программой ассемблера, которая выдает код инверсии содержимого аккумулятора на машинном языке – 2FH.

Программа, записанная человеком на языке ассемблера, выглядит следующим образом:

Программа разделена на 4 поля:

1 – поле метки; используется не всегда;

2 – поле мнемоники, содержит точную мнемонику, установленную разработчиком. Указывает программе ассемблера операцию для выполнения;

3 – поле операнда, содержит информацию о регистрах, данных и адресах, объединенных соответствующей операцией;

4 – поле комментариев, не учитывается ассемблером и ограничивается его перепечаткой. Очень важно, так как позволяет понять события в программе.

Таблица 3.1 Программа на языке ассемблер

Источник: electrono.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru