В вычислениях - компилятор - это компьютерная программа, которая переводит компьютерный код, написанный на одном языке программирования (исходный язык), на другой язык (целевой язык). Имя "компилятор" в основном используется для программ, которые переводят исходный код с языка программирования высокого уровня на язык нижнего уровня (например, язык ассемблера, объектный код или машинный код ) для создания исполняемой программы.
Существует много разных типов компиляторов. Если скомпилированная программа может работать на компьютере, на котором ЦП или операционная система отличается от той, на которой работает компилятор, компилятор кросс-компилятором. Компилятор начальной загрузки написан на языке, который он собирается компилировать. Программа, которая переводит с языка низкого уровня на язык более высокого уровня, - это декомпилятор . Программа, которая переводит между языками высокого уровня, обычно называется компилятором кода или транскомпилятором. Переписчик языка обычно представляет собой программу, которая переводит форму выражений без изменений языка. Термин компилятор-компилятор относится к инструментам, используемым для создания синтаксических анализаторов, выполняющих синтаксический анализ.
Компилятор, скорее всего, выполнит многие или все из следующих операций: предварительная обработка, лексический анализ, синтаксический анализ, семантический анализ (синтаксически-управляемый перевод ), преобразование входных программ в промежуточное представление, оптимизация кода и генерация кода. Компиляторы реализуют эти операции поэтапно, что способствует эффективному проектированию и исправляет преобразование исходного ввода в целевой вывод. Ошибки программы, вызванные неправильным поведением компилятора, очень трудно отследить и обойти; поэтому разработчики компилятора прилагают значительные усилия для правильности компилятора..
Компиляторы - не единственный языковой процессор, используемый для преобразования исходных программ. Интерпретатор - это компьютерная программа, которая преобразует, а затем выполняет функцию операции. Процесс перевода влияет на дизайн компьютерных языков, что приводит к предпочтению компиляции или интерпретации. На практике интерпретатор может быть реализован для компилируемых языков, компиляторы могут быть реализованы для интерпретируемых языков.
Концепции теоретических вычислений, разработанные учеными, математиками и инженерами, легли в основе современных цифровых вычислений во время мировой войны II. Примитивные двоичные языки эволюционировали, потому что цифровые устройства понимают только единицу и нули, а также шаблоны в схемах системы генерации машины. В конце 1940-х годов были созданы языки ассемблера, чтобы предложить более работоспособную абстракцию компьютерных архитектур. Ограниченная память первых компьютеров привела к существенным техническим проблемам при разработке первых компиляторов. Поэтому процесс компиляции нужно было разбить на несколько небольших программ. Внешние программы анализа продуктов, используемые внутренними программами для генерации целевого кода. Компьютерные технологии предоставляют больше ресурсов, конструкции компиляторов.
Обычно для программиста более продуктивно использовать язык высокого уровня, поэтому разработка языков высокого уровня естественным образом вытекала из возможностей, предлагаемых цифровыми компьютерами. Языки которые высокого уровня - это формальные языки, устойчивые своим синтаксисом и семантикой, образуют городуру языка высокого уровня. Элементы этих формальных языков включают:
Предложения в языке могут быть использованы набором правил, называемых грамматикой.
Форма Бэкуса - Наура (BNF) используется синтаксис «предложения» язык и использовалась для синтаксиса Algol 60 Автор Джон Бэкус. Идеи вытекают из концепции контекстно-свободной грамматики, разработанной лингвистом Ноамом Хомски. «BNF и его расширения стали стандартных инструментов для описания синтаксиса программных обозначений, и многих других частей генерируют автоматически из описания BNF».
В 1940-х годах Конрад Цузе разработал язык алгоритмического программирования под названием Plankalkül («Расчет плана»). Хотя фактической не реализации было до 1970-х годов, в нем были концепции, которые были замечены в APL, созданном Кеном Айверсоном в конце 1950-х годов. APL - это язык математических вычислений.
Проектирование языков высокого уровня в годы становления вычислений предоставило полезные инструменты программирования для множества приложений:
Технология компиляторов возникла из строго определенного преобразования исходной программы высокого уровня в целевую программу низкого уровня для цифрового компьютера. Компилятор можно рассматривать как интерфейсную часть, которая занимается анализом исходного кода, и серверную часть, чтобы синтезировать анализ в целевой код. Оптимизация между интерфейсом и сервером может дать более эффективный код.
Некоторые ранние вехи в развитии технологий компилятора:
Ранние операционные системы и программное обеспечение были написаны на языке ассемблера. В 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. В этом случае на первом проходе необходимо собрать информацию об объявлениях, появляющихся после операторов, на которые они влияют,с фактическим переводом. во время последующего прохода.
Недостатком компиляции за один проход является невозможным выполнить многие из сложных оптимизаций, необходимых для генерации высококачественного кода. Может быть сложно точно подсчитать, сколько проходов делает оптимизирующий компилятор. Например, разные фазы оптимизации могут проанализировать одно выражение много раз, но проанализировать другое выражение только один раз.
Разделение компилятора на небольшие программы - метод, используемыми исследователями, заинтересованными в создании доказуемо корректных компиляторов. Доказательство правильности набора небольших программ часто требует меньше усилий, чем доказательство правильности более крупной, единственной эквивалентной программы.
Независимо от точного количества фаз в дизайне компилятора, фазы можно отнести к одному из трех этапов. Этапы включают в себя переднюю, среднюю и заднюю части.
Этот подход к интерфейсу / среднему / внутреннему интерфейсу позволяет комбинировать внешние интерфейсы для разных языков с внутренними интерфейсами для разных процессоров при совместном использовании оптимизаций среднего уровня. Практическими примерами этого подхода являются Коллекция компиляторов GNU, Clang (компилятор C / C ++ на основе LLVM ) и Amsterdam Compiler Kit, которые имеют несколько интерфейсов, общую оптимизацию и несколько внутренних интерфейсов.
if (net>0.0) total + = net * (1.0 + tax / 100.0);
», сканер последовательности из токенов и классифицирует каждый из них, например как идентификатор, зарезервированное слово, числовой литерал или оператор. Последняя последовательность преобразуется синтаксическим анализатором в синтаксическое дерево , которое обрабатывается оставшимися фазами компилятора. Сканер и синтаксический анализатор обрабатывают обычные и должным образом контекстно-свободные части матики для C соответственно. Внешний интерфейс анализирует исходный код для построения внутреннее представление программы, называемое промежуточным представлением (IR). Он также управляет таблицами символов , структурой данных, отображающей символ в исходном коде на связанную информацию, как каждое местоположение, тип и область действия.
Интерфейс может быть отдельной монолитной программой, как в анализаторе без сканирования, он чаще реализуется и анализируется как несколько этапов, которые могут работать вместе или одновременно. Этому методу отдают предпочтение из-за его модульности и разделения задач. Чаще всего сегодня интерфейс разбивается на три этапа: лексический анализ (также известный как лексирование), синтаксический анализ (также известный как сканирование или синтаксический анализ) и семантический анализ.. Лексирование и синтаксический анализ включает синтаксический анализ (синтаксис слов и синтаксис соответственно), и в простых случаях эти модули (лекс анализатор и синтаксический анализатор) могут быть автоматически сгенерированы из грамматического языка, хотя в более сложных случаях они требуют ручной модификации. Лексическая грамматика и фразовая грамматика обычно предоставляет собой контекстно-свободные грамматики, что упрощает анализ, контекстную чувствительность обрабатывается на этапе семантического анализа. Фаза семантического анализа, как правило, более сложная и написана от руки, но может быть частично или полностью автоматизирована с использованием грамматик атрибутов. Сами эти этапы могут быть далее разбиты: лексирование как сканирование и оценка и анализ как построение конкретного синтаксического дерева (CST, дерево синтаксического анализа) с последующим преобразованием его в абстрактное синтаксическое дерево (AST, синтаксическое дерево). В некоторых случаях используются дополнительные фазы, реконструкция и предварительная обработка, но это бывает редко.
Основные этапы внешнего интерфейса включают следующее:
Средний конец, также известный как оптимизатор, выполняет оптимизацию представления для повышения производительности и качества производимого машинного кода. Средняя часть содержит те оптимизации, которые не зависят от архитектуры ЦП.
Основные этапы среднего уровня включают следующее:
компилятор. Анализирует инструменты для любого оптимизатора, и они работают вместе. Например, анализ зависимости имеет решающее значение для преобразования цикла.
Объем анализа и оптимизации компилятора различается; их объем может рассматриваться от работы в пределах базового блока до целых процедур или даже всей программы. Существует компромисс между степенью детализации оптимизации и стоимостью компиляции. Например, оптимизация глазка выполняется быстро во время компиляции, но влияет только на небольшой локальный фрагмент кода независимо от контекста, в котором появляется фрагмент кода независимо от контекста. Напротив, межпроцедурная оптимизация требует большего времени компиляции и объема памяти, но обеспечивает, которая возможна только при одновременном рассмотрении поведения нескольких функций.
Межпроцедурный анализ и оптимизация распространены в современных коммерческих компиляторах от 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.
В то время как общий тип компилятора, вывод машинный код, существует много других типов:
DOALL
Фортрана).Найдите компилятор в Wiktionary, бесплатном формате. |
Викиучебники есть книга по теме: Конструирование компиляторов |
На Викискладе есть материалы, связанные с Компиляторами. |