Компилятор

редактировать
Компьютерная программа, которая переводит код с одного языка программирования на другой

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

Существует много разных типов компиляторов. Если скомпилированная программа может работать на компьютере, на котором ЦП или операционная система отличается от той, на которой работает компилятор, компилятор кросс-компилятором. Компилятор начальной загрузки написан на языке, который он собирается компилировать. Программа, которая переводит с языка низкого уровня на язык более высокого уровня, - это декомпилятор . Программа, которая переводит между языками высокого уровня, обычно называется компилятором кода или транскомпилятором. Переписчик языка обычно представляет собой программу, которая переводит форму выражений без изменений языка. Термин компилятор-компилятор относится к инструментам, используемым для создания синтаксических анализаторов, выполняющих синтаксический анализ.

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

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

Содержание
  • 1
  • 2 Конструкция компилятора
    • 2.1 Сравнение однопроходных и многопроходных компиляторов
    • 2.2 Трехэтапная структура компилятора
      • 2.2.1 Внешний интерфейс
      • 2.2.2 Средняя часть
      • 2.2.3 Внутренняя часть
    • 2.3 Корректность компилятора
  • 3 Сравнение скомпилированных и интерпретируемых языков
  • 4 Типы
  • 5 См. Также
  • 6 Ссылки
  • 7 Дополнительная литература
  • 8 Внешние ссылки
История
Схема работы типичного многоязычного многоцелевого компилятора

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

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

  • алфавит, любой конечный набор символов;
  • строка, конечная последовательность символов;
  • язык, любой набор строк в алфавите.

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

Форма Бэкуса - Наура (BNF) используется синтаксис «предложения» язык и использовалась для синтаксиса Algol 60 Автор Джон Бэкус. Идеи вытекают из концепции контекстно-свободной грамматики, разработанной лингвистом Ноамом Хомски. «BNF и его расширения стали стандартных инструментов для описания синтаксиса программных обозначений, и многих других частей генерируют автоматически из описания BNF».

В 1940-х годах Конрад Цузе разработал язык алгоритмического программирования под названием Plankalkül («Расчет плана»). Хотя фактической не реализации было до 1970-х годов, в нем были концепции, которые были замечены в APL, созданном Кеном Айверсоном в конце 1950-х годов. APL - это язык математических вычислений.

Проектирование языков высокого уровня в годы становления вычислений предоставило полезные инструменты программирования для множества приложений:

  • FORTRAN (Перевод формул) для инженерных и научных приложений считается язык высокого уровня.
  • COBOL (Common Business-Oriented Language) эволюционировал из A-0 и FLOW-MATIC и стал доминирующим языком высокого уровня для бизнеса. приложений.
  • LISP (обработчик списков) для символьных вычислений.

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

Некоторые ранние вехи в развитии технологий компилятора:

  • 1952 - компилятор Автокод Алик Гленни для компьютера Manchester Mark I в Манчестерском университете, по мнению некоторых, был первым скомпилированным языком программирования.
  • 1952 - Грейс Хоппер Команда в Remington Rand написала компилятор для языка программирования A-0 (и придумала термин компилятор для его описания), компилятор A-0 работал больше в качестве загрузчика или компоновщика, чем современное понятие полного компилятора.
  • 1954-1957 - Команда под руководством Джона Бэкуса в IBM разработала FORTRAN, обычно считается первым языком высокого уровня. В 1957 году они завершили компилятор FORTRAN, как обычно считается, представил первый однозначно завершенный компилятор.
  • 1959 - Конференция по языку данных (CODASYL) систем инициировала разрешение COBOL. Дизайн COBOL основан на A-0 и FLOW-MATIC. К началу 1960-х COBOL был скомпилирован на нескольких архитектурах.
  • 1958-1962 - Джон Маккарти в MIT разработал LISP. Возможности обработки символов предоставили полезные функции для исследований искусственного интеллекта. В 1962 году в выпуске LISP 1.5 были некоторые инструменты: интерпретатор, написанный Стивеном Расселом и Дэниелом Эдвардсом, компилятор и асслер, написанный Тимомтом и Майком Левином.

Ранние операционные системы и программное обеспечение были написаны на языке ассемблера. В 1960-х и начале 1970-х годов использование языков высокого уровня для системного программирования все еще оставалось спорным из-за ограничений ресурсов. Однако некоторые исследования и отраслевые усилия ведут к переходу на языки системного программирования высокого уровня, например, BCPL, BLISS, B и C.

BCPL (базовый комбинированный язык программирования).), представился в 1966 году Мартином Ричардсом из Кембриджского университета, изначально разрабатывался как инструмент для написания компиляторов. Было реализовано несколько компиляторов, книга Ричардса представляет представление о языке и его компиляторе. BCPL был не только влиятельным языком системного программирования, который до сих пор используется в исследованиях, но и послужил средством для разработки языков B и C.

BLISS (Базовый язык для реализации системного программного обеспечения) был разработан для компьютера PDP- 10 Digital Equipment Corporation (DEC) исследовательской группы Университета Карнеги-Меллона (CMU) WA Wulf. Группа CMU продолжила годом компилятора BLISS-11 позже, в 1970 году.

Multics (Multiplexed Information and Computing Service), проект системы с разделением времени, в котором участвовали MIT, Bell Labs, General Electric (позже Honeywell ) и опаслся Фернандо Корбато из Массачусетского технологического института. Multics был написан на языке PL / I, разработанном IBM и IBM User Group. Целью IBM было удовлетворение требований бизнеса, науки и системного программирования. Могли быть рассмотрены и другие языки, но PL / I предлагает наиболее полное решение, хотя оно и не было реализовано. В течение первых нескольких лет проекта Mulitics подмножество языка могло быть скомпилировано на язык ассемблера с помощью компилятора Early PL / I (EPL) Дугом Макилори и Бобом Моррисом из Bell Labs. EPL поддерживает проект до тех пор, пока не разработан загрузочный компилятор для полной PL / I.

Bell Labs покинула проект Multics в 1969 году: «Со временем надежда сменилась разочарованием, поскольку усилия группы изначально провалились. для производства экономически полезной системы ». Продолжение увеличит расходы на поддержку проекта. Поэтому исследователи обратились к другим разработкам. Язык системного программирования B, основанный на концепциях BCPL, был написан Деннисом Ричи и Кеном Томпсоном. Ричи создал загрузочный компилятор для B и написал операционную Unics (Uniplexed Information and Computing Service) для PDP-7 в B. В итоге Unics стала называться Unix.

Bell Labs начала поиска и расширения C на основе B и BCPL. Компилятор BCPL был перенесен в Multics компанией Bell Labs, и BCPL был предпочтительным языком в Bell Labs. Первоначально использовалась интерфейсная программа для компилятора B Bell Labs, компилятор C был разработан. В 1971 году новый PDP-11 предоставил ресурсы для определения расширений B и переписывания компилятора. К 1973 году разработка языка C была практически завершена, и ядро ​​Unix для PDP-11 было переписано на C. Стив Джонсон начал программу Portable C Compiler (PCC) для поддержки перенацеливания компиляторов C на новые машины.

Объект- ориентированное программирование (ООП) предлагает некоторые возможности для разработки и сопровождения приложений. Концепции ООП восходят к более ранним временам, но были частью LISP и Simula языковой науки. В Bell Labs разработка C ++ заинтересовалась ООП. C ++ впервые был использован в 1980 году для системного программирования. Первоначальный дизайн использовал возможности системного программирования на языке C с концепциями Simula. Объектно-ориентированные средства были добавлены в 1983 году. Программа Cfront реализовала интерфейс C ++ для компилятора языка C84. В последующие годы по мере роста C ++ было разработано несколько компиляторов C ++.

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

DARPA (Агентство перспективных исследовательских проектов Министерства обороны) спонсировало проект компилятора исследовательской группы CMU Вульфа в 1970 году. Проект производственного компилятора-компилятора PQCC должен был создать компилятор производственного качества (PQC) из формальных определения исходного языка и целевого языка. PQCC без особого успеха попытался расширить «компилятор-компилятор» за пределы традиционного значения генератора синтаксического анализатора (например, Yacc ). PQCC правильнее было бы называть генератором компилятора.

Исследование PQCC процесса генерации кода было направлено на создание действительно автоматической системы написания компиляторов. В рамках этой работы была обнаружена и обновлена ​​фазовая структура PQC. Компилятор BLISS-11 предоставил исходную структуру. Этапы включали анализ (внешний интерфейс), промежуточный перевод в виртуальную машину (средний этап) и перевод в объект объект (серверный этап). TCOL был разработан для исследования PQCC для обработки языковых конструкций в промежуточном представлении. Варианты TCOL, используя разные языки. В рамках проекта PQCC исследовались методы построения автоматизированных компиляторов. Концепции дизайна оказались полезными при оптимизации компиляторов и компиляторов для объектно-ориентированного языка программирования Ada.

Документ Ады Стоунман формализовал среду поддержки программ (APSE) вместе с ядром (KAPSE) и минимальным (MAPSE). Переводчик Ada NYU / ED поддерживал стандарты и стандарты стандартов Американского национального института стандартов (ANSI) и международных организаций (ISO). Первоначальная разработка компилятора Ada военными службами США включающая компиляторы в полностью интегрированную среду в соответствии с положениями документа Stoneman Document. Армия и флот работали над проектом Ada Language System (ALS), ориентированная на потребление энергии DEC / VAX, в то время как ВВС начали работу над интегрированной средой Ada (AIE), ориентированной на серию IBM 370. Хотя проекты не принесли желаемых результатов, они внесли свой вклад в общие усилия по разработке Ada.

Другие попытки компилятора Ada были предприняты в Великобритании в Йоркском университете и в Германии в университете Карлсруэ. В США компания Verdix (позже приобретенная Rational) предоставила армии Verdix Ada Development System (VADS). VADS предоставил набор инструментов разработки, включая компилятор. Unix / VADS может быть размещен на различных платформах Unix, таких как DEC Ultrix и Sun 3/60 Solaris, предназначенных для Motorola 68020 в оценке Army CECOM. Вскоре появилось много компиляторов Ada, которые прошли проверку Ada Validation. В рамках проекта Фонда бесплатного программного обеспечения GNU была предоставлена ​​поддержка Коллекция компиляторов GNU (GCC), которая предоставляет базовые возможности для поддержки нескольких языков и целевых объектов. Версия Ada GNAT - один из наиболее широко используемых компиляторов Ada. GNAT бесплатен, но есть также коммерческая поддержка, например, AdaCore была основана в 1994 году для предоставления коммерческих программных решений для Ada. GNAT Pro включает GNU на основе GNU GCC с набором инструментов для обеспечения интегрированной среды разработки.

Языки высокого уровня продолжали стимулировать исследования и разработки компиляторов. Основные включающие оптимизацию и автоматическую генерацию кода. Тенденции в языках программирования и средах разработки повлияли на компиляции. В языковые дистрибутивы (PERL, Java Development Kit) и в качестве компонента IDE (VADS, Eclipse, Ada Pro) вошло больше компиляторов. Взаимосвязь и взаимозависимость технологий росли. Появление веб-сервисов способствовало развитию веб-языков и языков сценариев. Сцена восходят к ранним дням интерфейса командной строки (CLI), когда пользователь мог ввести команду для выполнения системой. Концепции пользовательской языка оболочки, разработанные с использованием для написания программ оболочки. Ранние разработки Windows предлагали простую возможность пакетного программирования. При обычном преобразовании этих языков использовался интерпретатор. Компиляторы Bash и Batch были написаны, хотя и не получили широкого распространения. Совсем недавно сложные интерпретируемые языки стали частью набора инструментов разработчиков. Современные языки сценариев включают PHP, Python, Ruby и Lua. (Lua широко используется в разработке игр.) Все они имеют поддержку интерпретатора и компилятора.

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

Конструкция компилятора

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

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

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

Сравнение однопроходных и многопроходных компиляторов

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

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

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

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

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

Трехэтапная структура компилятора

Дизайн компилятора

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

  • Внешний интерфейс проверяет синтаксис и семантику в соответствии с определенным исходным языком. Для языков со статической типизацией он действует проверка путем сбора информации о типе. Если программа ввода синтаксически типа неверна или имеет ошибку, она генерирует сообщения об ошибках и / или предупреждениях, обычно идентифицируя место в исходном коде, где была обнаружена проблема; в некоторых случаях фактическая ошибка может быть (намного) раньше в программе. Аспекты внешнего интерфейса включают лексический анализ, синтаксический анализ и семантический анализ. Внешний преобразует входную программу в промежуточное представление (IR) для дальнейшей обработки средним концом. Этот IR обычно является представлением программы нижнего уровня по отношению к исходному коду.
  • Средний конец работы оптимизацию, которая не зависит от архитектуры ЦП. Эта независимая программа программного обеспечения предлагает возможности совместной оптимизации между версиями компилятора, поддерживающими разные языки и целевые процессоры. Примеры промежуточных оптимизаций: бесполезного (удаление мертвого кода ) или недоступного кода (анализ достижимости ), обнаружение и распространение постоянных значений (распространение констант, удаление ), перемещение вычислений в менее часто выполняемое место (например, вне цикла) или специализация вычислений на основе контекста. В рамках создается "оптимизированный" IR, который используется серверной частью.
  • Серверная часть берет оптимизированную ИК из средней части. Он может выполнить больше анализа, преобразований и оптимизаций, специфичных для ЦП архитектуры. Серверная часть генерирует зависимый от цели ассемблерный код, выполняя выполнение регистров в процессе. Серверная часть работы планирование команд, которое переупорядочивает команды, чтобы держать параллельные исполнительные блоки занятыми, заполняя интервалы задержки. Хотя большинство проблем оптимизации представляют собой NP-трудными, эвристические методы их решения хорошо разработаны и в настоящее время реализованы в компиляторах производственного качества. Обычно выходные данные серверной части представляют собой машинный код, специализированный для конкретного процессора и операционной системы.

Этот подход к интерфейсу / среднему / внутреннему интерфейсу позволяет комбинировать внешние интерфейсы для разных языков с внутренними интерфейсами для разных процессоров при совместном использовании оптимизаций среднего уровня. Практическими примерами этого подхода являются Коллекция компиляторов GNU, Clang (компилятор C / C ++ на основе LLVM ) и Amsterdam Compiler Kit, которые имеют несколько интерфейсов, общую оптимизацию и несколько внутренних интерфейсов.

Внешний интерфейс

Lexer и синтаксический анализатор, пример для C. Исходя из последовательности символов «if (net>0.0) total + = net * (1.0 + tax / 100.0);», сканер последовательности из токенов и классифицирует каждый из них, например как идентификатор, зарезервированное слово, числовой литерал или оператор. Последняя последовательность преобразуется синтаксическим анализатором в синтаксическое дерево , которое обрабатывается оставшимися фазами компилятора. Сканер и синтаксический анализатор обрабатывают обычные и должным образом контекстно-свободные части матики для C соответственно.

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

Интерфейс может быть отдельной монолитной программой, как в анализаторе без сканирования, он чаще реализуется и анализируется как несколько этапов, которые могут работать вместе или одновременно. Этому методу отдают предпочтение из-за его модульности и разделения задач. Чаще всего сегодня интерфейс разбивается на три этапа: лексический анализ (также известный как лексирование), синтаксический анализ (также известный как сканирование или синтаксический анализ) и семантический анализ.. Лексирование и синтаксический анализ включает синтаксический анализ (синтаксис слов и синтаксис соответственно), и в простых случаях эти модули (лекс анализатор и синтаксический анализатор) могут быть автоматически сгенерированы из грамматического языка, хотя в более сложных случаях они требуют ручной модификации. Лексическая грамматика и фразовая грамматика обычно предоставляет собой контекстно-свободные грамматики, что упрощает анализ, контекстную чувствительность обрабатывается на этапе семантического анализа. Фаза семантического анализа, как правило, более сложная и написана от руки, но может быть частично или полностью автоматизирована с использованием грамматик атрибутов. Сами эти этапы могут быть далее разбиты: лексирование как сканирование и оценка и анализ как построение конкретного синтаксического дерева (CST, дерево синтаксического анализа) с последующим преобразованием его в абстрактное синтаксическое дерево (AST, синтаксическое дерево). В некоторых случаях используются дополнительные фазы, реконструкция и предварительная обработка, но это бывает редко.

Основные этапы внешнего интерфейса включают следующее:

  • Реконструкция строки преобразует входную последовательность символов в каноническую формулу, готовую для синтаксического анализа. Языки, которые ограничивают свои ключевые слова или допускают произвольные пробелы этого слова в этом языке, требуют фазы. нисходящие, рекурсивно-спусковые, управляемые таблицами синтаксические анализаторы, использовавшиеся в 1960-х годах, обычно считывают источник по одному символу за раз и не требуют отдельной фазы токенизации. Atlas Autocode и Imp (и некоторые реализации ALGOL и Coral 66 ) являются примерами стропированных языков, компиляторы которых будут иметь реконструкцию строки
  • Предварительная обработка поддерживает подстановку макроса и условную компиляцию. Обычно этап предварительной обработки происходит перед синтаксическим или семантическим анализом; например в случае C препроцессор управляет лексическими токенами, а не синтаксическими формами. Однако некоторые языки, такие как Схема, база макрозамены на основе синтаксических форм.
  • Лексический анализ (также известный как лексирование или токенизация) фрагментов кода последовательности фрагментов, называемых лексическими жетоны. Этот этап можно разделить на два этапа: сканирование, при вводе текста разбивается на синтаксические единицы, называемые лексемами, и присваивается им категория; и оценка, которая преобразует лексемы в обработанное значение. Токен - это пара, состоящая из имени токена и необязательного значения токена. Общие категории токенов местные инструменты программирования, ключевые слова, разделители, операторы, литералы и комментарии, хотя набор категорий токенов различается в разных языках программирования языков программирования. Синтаксис лексемы обычно является регулярным языком, поэтому для его распознавания можно использовать автомат с конечным числом состояний, созданный из регулярного выражения. Программа, выполняющая лексический анализ, называется лексический анализатор. Это не может быть шагом - его можно объединить с этапом синтаксического анализа в синтаксическом анализе, и в этом синтаксическом анализе выполняется на уровне символов, а не на уровне токена.
  • Анализ синтаксиса (также известный как синтаксический анализ) включает синтаксический анализ придерживаться токенов для идентификации синтаксической структуры программы. На этом этапе обычно строится дерево синтаксического анализа , которое заменяет линейную последовательность токенов древовидной структурой, построенной в соответствии с правилами формальной грамматики, которые определяют синтаксис языка. Дерево синтаксического анализа часто анализируется, дополняется и трансформируется на более поздних этапах работы компилятора.
  • Семантический анализ mater семантическую информацию в дерево синтаксического анализа и строит таблицу символов. На этом этапе выполняются семантические проверки, такие как проверка типа (проверка на наличие ошибок типа) или привязка объекта (связывание ссылок на переменные и функции с их определением) или определенное присвоение (требует инициализации всех локальных чисел перед использованием), отклонение неправильных программ или выдача предупреждений. Для семантического анализа обычно требуется полное дерево синтаксического анализа, что означает, что эта фаза логически следует за фазой синтаксического анализа и логически предшествует фазе генерации кода, хотя часто возможно объединить несколько фаз в одну. передать код в реализации компилятора.

Средний конец

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

Основные этапы среднего уровня включают следующее:

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

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

Межпроцедурный анализ и оптимизация распространены в современных коммерческих компиляторах от HP, IBM, SGI, Intel, Microsoft и Sun Microsystems. Бесплатное программное обеспечение GCC долгое время подвергалось критике за отсутствие мощных межпроцедурных оптимизаций, но в этом отношении оно меняется. Другой компилятор с открытым исходным кодом с полной инфраструктурой анализа и оптимизации - это Open64, который используется многими организациями в исследовательских и коммерческих целях.

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

Бэкэнд

Бэкэнд отвечает за оптимизацию архитектуры ЦП и за генерацию кода.

Основные этапы бэкэнда включают следующее:

  • Машина зависимые оптимизации: оптимизации, которые зависят от деталей архитектуры ЦП, на которую нацелен компилятор. Ярким примером является оптимизация глазка, которая переписывает короткие последовательности инструкций ассемблера в более эффективные инструкции.
  • Генерация кода : преобразованный промежуточный язык переводится на язык вывода, обычно на собственный машинный язык системы. Это включает решения о ресурсах и хранилище, такие как решение, какие переменные вписываются в регистры и память, и выбор и планирование соответствующих машинных инструкций вместе с их связанными режимы адресации (см. Также алгоритм Сетхи-Уллмана ). Также может потребоваться сгенерировать данные отладки для облегчения отладки.

Корректность компилятора

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

Сравнение компилируемых языков и интерпретируемых языков

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

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

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

В некоторых спецификациях языка указаны включенные средства компиляции; например, Common Lisp. Однако в определении Common Lisp нет ничего, что мешало бы его интерпретации. В других языках есть функции, которые очень легко реализовать в интерпретаторе, но значительно усложняют написание компилятора; например, APL, SNOBOL4 и многие сценарии позволяют программам создать произвольный исходный код во время выполнения с обычными строковыми операциями, выполнять этот код, передавая его специальному оценочная функция. Для реализации этих функций на скомпилированном языке программы обычно поставляться с runt Библиотека ime, которая включает версию самого компилятора.

Типы

Одна классификация компиляторов - по платформе, на которой выполняется их сгенерированный код. Это называется целевой платформой.

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

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

Язык нижнего уровня, который является целью компилятора, может сам быть языком программирования высокого уровня. C, рассматриваемый как своего рода переносимый язык ассемблера, часто является целевым языком таких компиляторов. Например, Cfront, исходный компилятор для C ++, использовал C в качестве целевого языка. Код C, сгенерированный компилятор, обычно не предназначенный для чтения и обслуживания людей, поэтому стиль отступа и создание красивого промежуточного кода C игнорируются. Некоторые из функций C делают его хорошим целевым языком, включая директиву #line, который может быть сгенерирован компилятором для поддержки отладки, которые могут быть исходным исходным кодом и широкая поддержка платформы, доступная с помощью компиляторов C.

В то время как общий тип компилятора, вывод машинный код, существует много других типов:

  • компиляторы исходного кода - это тип компилятора, который принимает язык высокого уровня в качестве входных и выходных данных. язык высокого уровня. Например, компилятор с автоматическим распараллеливанием часто принимает программу на языке высокого уровня в качестве входных данных, а затем преобразует код и аннотирует его с помощью аннотаций параллельного кода (например, OpenMP ) или языка конструкции (например, операторы DOALLФортрана).
  • компиляторы байт-кода, которые компилируются на язык ассемблера теоретической машины, как некоторые реализации Prolog
  • Оперативные компиляторы (JIT-компилятор) откладывают компиляцию до времени выполнения. JIT-компиляторы существуют для многих современных языков, включая Python, JavaScript, Smalltalk, Java, Microsoft .NET Общий промежуточный язык (CIL) и другие. Компилятор JIT обычно работает внутри интерпретатора. Используется JIT-компилятор и скомпилировать «горячий» код для повышения производительности.
    • Для некоторых, таких как Java, сначала компилируются с приложениями языков-компиляторов в машинно-независимом промежуточном представлении. Интерпретатор байт-кода выполняет байт-код, но JIT-компилятор преобразует байт-код в машинный код, когда требуется повышенная производительность.
  • Аппаратные компиляторы (также известные как инструменты синтеза) - это компиляторы, выходные данные которых являются описанием конфигурации оборудования. вместо следовать инструкций.
    • Выходные данные этих компиляторов нацелены на компьютерное оборудование на очень низком уровне, например, программируемый вентильный массив (FPGA) или структурированное приложение . специальная интегральная схема (ASIC). Такие компиляторы называются аппаратными компиляторами, потому что исходный код, который они компилируют, эффективно контролирует окончательную конфигурацию оборудования и его работу. Результатом компиляции является только соединение транзисторов или таблиц поиска.
    • . Примером аппаратного компилятора является XST, Xilinx Synthesis Tool, использовать для настройки FPGA. Аналогичные инструменты доступны от Altera, Synplicity, Synopsys и других поставщиков оборудования.
  • Ассемблер - это программа, которая компилирует читаемый человеком язык ассемблера в машинный код, фактические инструкции, выполняемые оборудование. Обратная программа, которая переводит машинный код на язык ассемблера, называется дизассемблером.
  • Программа, которая переводит с низкоуровневого языка на более высокий уровень, является декомпилятором.
  • Программа, которая переводит между высокими языками уровня-обычно называют языковым переводчиком, компилятором кода, языковым преобразователем или языковым преобразователем языком. Последний обычно применяется к переводам, не используется с изменением языка.
  • Программа, которая переводит в формат объектного кода, который не поддерживает компиляцию, кросс-компилятором и обычно используется для подготовки кода для встраиваемых приложений.
  • Программа, которая переписывает объектный код обратно в тот же тип объекта, применяя оптимизацию и преобразование, является двоичным рекомпилятором.
См. также
  • значок Портал компьютерного программирования
Ссылки
Дополнительная литература
Внешние ссылки
Найдите компилятор в Wiktionary, бесплатном формате.
Викиучебники есть книга по теме: Конструирование компиляторов
На Викискладе есть материалы, связанные с Компиляторами.
Последняя правка сделана 2021-05-15 08:11:18
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте