Введение
Компьютерная программа, которая переводит код с одного языка программирования на другой – программное обеспечение для перевода компьютерных языков. В информатике компилятор — это компьютерная программа, которая переводит компьютерный код, написанный на одном языке программирования (исходный язык), на другой язык (целевой язык). Термин "компилятор" в основном используется для программ, которые переводят исходный код с языка программирования высокого уровня на язык программирования низкого уровня (например, ассемблер, объектный код или машинный код) для создания исполняемой программы. Существует множество различных типов компиляторов, которые генерируют вывод в различных полезных форматах. Кросс-компилятор генерирует код для другого процессора или операционной системы, чем та, на которой работает сам кросс-компилятор. Bootstrap-компилятор часто является временным компилятором, используемым для компиляции более постоянного или лучше оптимизированного компилятора для языка. Связанное программное обеспечение включает декомпиляторы, программы, которые переводят с языков низкого уровня на языки более высокого уровня; программы, которые переводят между языками высокого уровня, обычно называемые компиляторами или транспиляторами из источника в источник; переписыватели языка, обычно программы, которые переводят форму выражений без изменения языка; и компиляторы компиляторов, компиляторы, которые генерируют компиляторы (или их части), часто в общем и повторно используемом виде, чтобы иметь возможность генерировать множество различных компиляторов. Компилятор, вероятно, выполняет некоторые или все из следующих операций, часто называемых фазами: предварительная обработка, лексический анализ, парсинг, семантический анализ (синтаксически-ориентированный перевод), преобразование входных программ в промежуточное представление, оптимизация кода и генерация машинного кода. Компиляторы обычно реализуют эти фазы как модульные компоненты, способствуя эффективному проектированию и корректности преобразований исходного ввода в целевой вывод. Ошибки программы, вызванные некорректным поведением компилятора, могут быть очень сложными для отладки и обхода; поэтому разработчики компиляторов прилагают значительные усилия для обеспечения корректности компилятора. Компиляторы — не единственный языковой процессор, используемый для преобразования исходных программ. Интерпретатор — это компьютерное программное обеспечение, которое преобразует и затем выполняет указанные операции. Форма Бэкуса — Наура (BNF) описывает синтаксис "предложений" языка. Она была разработана Джоном Бэкусом и использовалась для синтаксиса Algol 60. Идеи происходят из концепций контекстно-свободной грамматики лингвиста Ноама Хомского. "BNF и его расширения стали стандартными инструментами для описания синтаксиса языков программирования. Во многих случаях части компиляторов генерируются автоматически из описания BNF". Между 1942 и 1945 годами Конрад Цузе разработал первый (алгоритмический) язык программирования для компьютеров под названием Plankalkül ("плановый исчисление"). Цузе также представил Planfertigungsgerät ("устройство сборки планов") для автоматического перевода математической формулировки программы в машиночитаемую перфорированную плёнку. APL — это язык для математических вычислений. В период с 1949 по 1951 год Хайнц Рутисхаузер предложил Superplan, язык высокого уровня и автоматический переводчик. COBOL (Common Business Oriented Language) развился из A0 и FLOW-MATIC, чтобы стать доминирующим языком высокого уровня для бизнес-приложений. LISP (List Processor) для символьных вычислений. Технология компиляции развилась из необходимости строго определенного преобразования исходной программы высокого уровня в целевую программу низкого уровня для цифрового компьютера. Компилятор можно рассматривать как front-end для анализа исходного кода и back-end для синтеза анализа в целевой код. Оптимизация между front-end и back-end может создать более эффективный целевой код. Некоторые ранние вехи в развитии технологии компиляции: май 1952 года: команда Грейс Хоппер в Remington Rand написала компилятор для языка программирования A0 (и ввела термин "компилятор" для его описания), хотя компилятор A0 функционировал скорее как загрузчик или линковщик, чем как современное представление полного компилятора. 1952 год, до сентября: Autocode-компилятор, разработанный Аликом Гленни для компьютера Manchester Mark I в Манчестерском университете, некоторыми считается первым компилируемым языком программирования. 1954–1957: команда под руководством Джона Бэкуса в IBM разработала FORTRAN, который обычно считается первым языком программирования высокого уровня. В 1957 году они завершили FORTRAN-компилятор, который обычно считается первым однозначно полным компилятором. 1959 год: Конференция по языкам систем данных (CODASYL) инициировала разработку COBOL. Дизайн COBOL опирался на A0 и FLOW-MATIC. К началу 1960-х годов COBOL компилировался на множестве архитектур. 1958–1960: Algol 58 был предшественником ALGOL 60. Он представил блоки кода, важный шаг в развитии структурированного программирования. ALGOL 60 был первым языком, реализовавшим вложенные определения функций с лексической областью видимости. Он включал рекурсию. Его синтаксис был определен с использованием BNF. ALGOL 60 вдохновил многие языки, которые последовали за ним. Тони Хоар заметил: "это было не только улучшением по сравнению с его предшественниками, но и почти со всеми его последователями". 1958–1962: Джон Маккарти из MIT разработал LISP. Возможности обработки символов обеспечили полезные функции для исследований в области искусственного интеллекта. В 1962 году в выпуске LISP 1.5 были отмечены некоторые инструменты: интерпретатор, написанный Стивеном Расселом и Даниэлем Дж. Эдвардсом, компилятор и ассемблер, написанные Тимом Хартом и Майком Левином. Ранние операционные системы и программное обеспечение были написаны на ассемблере. В 1960-х и начале 1970-х годов использование языков высокого уровня для системного программирования все еще было спорным из-за ограничений ресурсов. Однако несколько исследовательских и промышленных усилий начали переход к языкам системного программирования высокого уровня, например, BCPL, BLISS, B и C.
software to translate computer languages
In computing, a compiler is a computer program that translates computer code written in one programming language (the source language) into another language (the target language). The name "compiler" is primarily used for programs that translate source code from a high level programming language to a low level programming language (e. g. assembly language, object code, or machine code) to create an executable program. There are many different types of compilers which produce output in different useful forms. A cross compiler produces code for a different CPU or operating system than the one on which the cross compiler itself runs. A bootstrap compiler is often a temporary compiler, used for compiling a more permanent or better optimised compiler for a language. Related software include decompilers, programs that translate from low level languages to higher level ones; programs that translate between high level languages, usually called source to source compilers or transpilers; language rewriters, usually programs that translate the form of expressions without a change of language; and compiler compilers, compilers that produce compilers (or parts of them), often in a generic and reusable way so as to be able to produce many differing compilers. A compiler is likely to perform some or all of the following operations, often called phases: preprocessing, lexical analysis, parsing, semantic analysis (syntax directed translation), conversion of input programs to an intermediate representation, code optimization and machine specific code generation. Compilers generally implement these phases as modular components, promoting efficient design and correctness of transformations of source input to target output. Program faults caused by incorrect compiler behavior can be very difficult to track down and work around; therefore, compiler implementers invest significant effort to ensure compiler correctness. Compilers are not the only language processor used to transform source programs. An interpreter is computer software that transforms and then executes the indicated operations. Backus–Naur form (BNF) describes the syntax of "sentences" of a language. It was developed by John Backus and used for the syntax of Algol 60. The ideas derive from the context free grammar concepts by linguist Noam Chomsky. "BNF and its extensions have become standard tools for describing the syntax of programming notations. In many cases, parts of compilers are generated automatically from a BNF description." Between 1942 and 1945, Konrad Zuse designed the first (algorithmic) programming language for computers called Plankalkül ("Plan Calculus"). Zuse also envisioned a Planfertigungsgerät ("Plan assembly device") to automatically translate the mathematical formulation of a program into machine readable punched film stock. APL is a language for mathematical computations. Between 1949 and 1951, Heinz Rutishauser proposed Superplan, a high level language and automatic translator. COBOL (Common Business Oriented Language) evolved from A 0 and FLOW MATIC to become the dominant high level language for business applications. LISP (List Processor) for symbolic computation. Compiler technology evolved from the need for a strictly defined transformation of the high level source program into a low level target program for the digital computer. The compiler could be viewed as a front end to deal with the analysis of the source code and a back end to synthesize the analysis into the target code. Optimization between the front end and back end could produce more efficient target code. Some early milestones in the development of compiler technology:
May 1952: Grace Hopper's team at Remington Rand wrote the compiler for the A 0 programming language (and coined the term compiler to describe it), although the A 0 compiler functioned more as a loader or linker than the modern notion of a full compiler. 1952, before September: An Autocode compiler developed by Alick Glennie for the Manchester Mark I computer at the University of Manchester is considered by some to be the first compiled programming language. 1954–1957: A team led by John Backus at IBM developed FORTRAN which is usually considered the first high level language. In 1957, they completed a FORTRAN compiler that is generally credited as having introduced the first unambiguously complete compiler. 1959: The Conference on Data Systems Language (CODASYL) initiated development of COBOL. The COBOL design drew on A 0 and FLOW MATIC. By the early 1960s COBOL was compiled on multiple architectures. 1958–1960: Algol 58 was the precursor to ALGOL 60. It introduced code blocks, a key advance in the rise of structured programming. ALGOL 60 was the first language to implement nested function definitions with lexical scope. It included recursion. Its syntax was defined using BNF. ALGOL 60 inspired many languages that followed it. Tony Hoare remarked: " it was not only an improvement on its predecessors but also on nearly all its successors." 1958–1962: John McCarthy at MIT designed LISP. The symbol processing capabilities provided useful features for artificial intelligence research. In 1962, LISP 1.5 release noted some tools: an interpreter written by Stephen Russell and Daniel J. Edwards, a compiler and assembler written by Tim Hart and Mike Levin. Early operating systems and software were written in assembly language. In the 1960s and early 1970s, the use of high level languages for system programming was still controversial due to resource limitations. However, several research and industry efforts began the shift toward high level systems programming languages, for example, BCPL, BLISS, B, and C.
BCPL (Basic Combined Programming Language) designed in 1966 by Martin Richards at the University of Cambridge was originally developed as a compiler writing tool. Several compilers have been implemented, Richards' book provides insights to the language and its compiler. BCPL was not only an influential systems programming language that is still used in research but also provided a basis for the design of B and C languages. BLISS (Basic Language for Implementation of System Software) was developed for a Digital Equipment Corporation (DEC) PDP 10 computer by W. A. Wulf's Carnegie Mellon University (CMU) research team. The CMU team went on to develop BLISS 11 compiler one year later in 1970. Multics (Multiplexed Information and Computing Service), a time sharing operating system project, involved MIT, Bell Labs, General Electric (later Honeywell) and was led by Fernando Corbató from MIT. Multics was written in the PL/I language developed by IBM and IBM User Group. IBM's goal was to satisfy business, scientific, and systems programming requirements. There were other languages that could have been considered but PL/I offered the most complete solution even though it had not been implemented. For the first few years of the Multics project, a subset of the language could be compiled to assembly language with the Early PL/I (EPL) compiler by Doug McIlory and Bob Morris from Bell Labs. EPL supported the project until a boot strapping compiler for the full PL/I could be developed. Bell Labs left the Multics project in 1969, and developed a system programming language B based on BCPL concepts, written by Dennis Ritchie and Ken Thompson. Ritchie created a boot strapping compiler for B and wrote Unics (Uniplexed Information and Computing Service) operating system for a PDP 7 in B. Unics eventually became spelled Unix. Bell Labs started the development and expansion of C based on B and BCPL. The BCPL compiler had been transported to Multics by Bell Labs and BCPL was a preferred language at Bell Labs. Initially, a front end program to Bell Labs' B compiler was used while a C compiler was developed. In 1971, a new PDP 11 provided the resource to define extensions to B and rewrite the compiler. By 1973 the design of C language was essentially complete and the Unix kernel for a PDP 11 was rewritten in C. Steve Johnson started development of Portable C Compiler (PCC) to support retargeting of C compilers to new machines. Object oriented programming (OOP) offered some interesting possibilities for application development and maintenance. OOP concepts go further back but were part of LISP and Simula language science. Bell Labs became interested in OOP with the development of C++. C++ was first used in 1980 for systems programming. The initial design leveraged C language systems programming capabilities with Simula concepts. Object oriented facilities were added in 1983. The Cfront program implemented a C++ front end for C84 language compiler. In subsequent years several C++ compilers were developed as C++ popularity grew. In many application domains, the idea of using a higher level language quickly caught on. Because of the expanding functionality supported by newer programming languages and the increasing complexity of computer architectures, compilers became more complex. DARPA (Defense Advanced Research Projects Agency) sponsored a compiler project with Wulf's CMU research team in 1970. The Production Quality Compiler Compiler PQCC design would produce a Production Quality Compiler (PQC) from formal definitions of source language and the target. PQCC tried to extend the term compiler compiler beyond the traditional meaning as a parser generator (e. g., Yacc) without much success. PQCC might more properly be referred to as a compiler generator. PQCC research into code generation process sought to build a truly automatic compiler writing system. The effort discovered and designed the phase structure of the PQC. The BLISS 11 compiler provided the initial structure. The phases included analyses (front end), intermediate translation to virtual machine (middle end), and translation to the target (back end). TCOL was developed for the PQCC research to handle language specific constructs in the intermediate representation. Variations of TCOL supported various languages. The PQCC project investigated techniques of automated compiler construction. The design concepts proved useful in optimizing compilers and compilers for the (since 1995, object oriented) programming language Ada. The Ada STONEMAN document formalized the program support environment (APSE) along with the kernel (KAPSE) and minimal (MAPSE). An Ada interpreter NYU/ED supported development and standardization efforts with the American National Standards Institute (ANSI) and the International Standards Organization (ISO). Initial Ada compiler development by the U. S. Military Services included the compilers in a complete integrated design environment along the lines of the STONEMAN document. Army and Navy worked on the Ada Language System (ALS) project targeted to DEC/VAX architecture while the Air Force started on the Ada Integrated Environment (AIE) targeted to IBM 370 series. While the projects did not provide the desired results, they did contribute to the overall effort on Ada development. Other Ada compiler efforts got underway in Britain at the University of York and in Germany at the University of Karlsruhe. In the U. S., Verdix (later acquired by Rational) delivered the Verdix Ada Development System (VADS) to the Army. VADS provided a set of development tools including a compiler. Unix/VADS could be hosted on a variety of Unix platforms such as DEC Ultrix and the Sun 3/60 Solaris targeted to Motorola 68020 in an Army CECOM evaluation. There were soon many Ada compilers available that passed the Ada Validation tests. The Free Software Foundation GNU project developed the GNU Compiler Collection (GCC) which provides a core capability to support multiple languages and targets. The Ada version GNAT is one of the most widely used Ada compilers. GNAT is free but there is also commercial support, for example, AdaCore, was founded in 1994 to provide commercial software solutions for Ada. GNAT Pro includes the GNU GCC based GNAT with a tool suite to provide an integrated development environment. High level languages continued to drive compiler research and development. Focus areas included optimization and automatic code generation. Trends in programming languages and development environments influenced compiler technology. More compilers became included in language distributions (PERL, Java Development Kit) and as a component of an IDE (VADS, Eclipse, Ada Pro). The interrelationship and interdependence of technologies grew. The advent of web services promoted growth of web languages and scripting languages. Scripts trace back to the early days of Command Line Interfaces (CLI) where the user could enter commands to be executed by the system. User Shell concepts developed with languages to write shell programs. Early Windows designs offered a simple batch programming capability. The conventional transformation of these language used an interpreter. While not widely used, Bash and Batch compilers have been written. More recently sophisticated interpreted languages became part of the developers tool kit. Modern scripting languages include PHP, Python, Ruby and Lua. (Lua is widely used in game development.) All of these have interpreter and compiler support. "When the field of compiling began in the late 50s, its focus was limited to the translation of high level language programs into machine code The compiler field is increasingly intertwined with other disciplines including computer architecture, programming languages, formal methods, software engineering, and computer security." The "Compiler Research: The Next 50 Years" article noted the importance of object oriented languages and Java. Security and parallel computing were cited among the future research targets.
BCPL (Basic Combined Programming Language), разработанный в 1966 году Мартином Ричардсом в Кембриджском университете, изначально был разработан как инструмент для написания компиляторов. Было реализовано несколько компиляторов, книга Ричардса дает представление о языке и его компиляторе. BCPL был не только влиятельным языком системного программирования, который до сих пор используется в исследованиях, но и послужил основой для разработки языков B и C. BLISS (Basic Language for Implementation of System Software) был разработан для компьютера Digital Equipment Corporation (DEC) PDP 10 исследовательской группой В. А. Вульфа из Carnegie Mellon University (CMU). Команда CMU разработала компилятор BLISS 11 годом позже, в 1970 году. Multics (Multiplexed Information and Computing Service), проект операционной системы с разделением времени, включал MIT, Bell Labs, General Electric (позже Honeywell) и возглавлялся Фернандо Корбато из MIT. Multics был написан на языке PL/I, разработанном IBM и IBM User Group. Целью IBM было удовлетворить требования бизнес-, научных и системных программ. Существовали и другие языки, которые можно было бы рассмотреть, но PL/I предлагал наиболее полное решение, хотя он еще не был реализован. В первые несколько лет проекта Multics подмножество языка можно было компилировать в ассемблерный код с помощью Early PL/I (EPL) компилятора Дуга МакИлори и Боба Морриса из Bell Labs. EPL поддерживал проект до тех пор, пока не был разработан bootstrap-компилятор для полного PL/I. Bell Labs покинула проект Multics в 1969 году и разработала язык системного программирования B, основанный на концепциях BCPL, написанный Деннисом Ритчи и Кеном Томпсоном. Ритчи создал bootstrap-компилятор для B и написал операционную систему Unics (Uniplexed Information and Computing Service) для PDP 7 на B. Unics в конечном итоге стал называться Unix. Bell Labs начала разработку и расширение C на основе B и BCPL. Компилятор BCPL был перенесен в Multics компанией Bell Labs, и BCPL был предпочтительным языком в Bell Labs. Первоначально использовалась front-end программа для B-компилятора Bell Labs, пока разрабатывался C-компилятор. В 1971 году новый PDP 11 предоставил рес...
software to translate computer languages
In computing, a compiler is a computer program that translates computer code written in one programming language (the source language) into another language (the target language). The name "compiler" is primarily used for programs that translate source code from a high level programming language to a low level programming language (e. g. assembly language, object code, or machine code) to create an executable program. There are many different types of compilers which produce output in different useful forms. A cross compiler produces code for a different CPU or operating system than the one on which the cross compiler itself runs. A bootstrap compiler is often a temporary compiler, used for compiling a more permanent or better optimised compiler for a language. Related software include decompilers, programs that translate from low level languages to higher level ones; programs that translate between high level languages, usually called source to source compilers or transpilers; language rewriters, usually programs that translate the form of expressions without a change of language; and compiler compilers, compilers that produce compilers (or parts of them), often in a generic and reusable way so as to be able to produce many differing compilers. A compiler is likely to perform some or all of the following operations, often called phases: preprocessing, lexical analysis, parsing, semantic analysis (syntax directed translation), conversion of input programs to an intermediate representation, code optimization and machine specific code generation. Compilers generally implement these phases as modular components, promoting efficient design and correctness of transformations of source input to target output. Program faults caused by incorrect compiler behavior can be very difficult to track down and work around; therefore, compiler implementers invest significant effort to ensure compiler correctness. Compilers are not the only language processor used to transform source programs. An interpreter is computer software that transforms and then executes the indicated operations. Backus–Naur form (BNF) describes the syntax of "sentences" of a language. It was developed by John Backus and used for the syntax of Algol 60. The ideas derive from the context free grammar concepts by linguist Noam Chomsky. "BNF and its extensions have become standard tools for describing the syntax of programming notations. In many cases, parts of compilers are generated automatically from a BNF description." Between 1942 and 1945, Konrad Zuse designed the first (algorithmic) programming language for computers called Plankalkül ("Plan Calculus"). Zuse also envisioned a Planfertigungsgerät ("Plan assembly device") to automatically translate the mathematical formulation of a program into machine readable punched film stock. APL is a language for mathematical computations. Between 1949 and 1951, Heinz Rutishauser proposed Superplan, a high level language and automatic translator. COBOL (Common Business Oriented Language) evolved from A 0 and FLOW MATIC to become the dominant high level language for business applications. LISP (List Processor) for symbolic computation. Compiler technology evolved from the need for a strictly defined transformation of the high level source program into a low level target program for the digital computer. The compiler could be viewed as a front end to deal with the analysis of the source code and a back end to synthesize the analysis into the target code. Optimization between the front end and back end could produce more efficient target code. Some early milestones in the development of compiler technology:
May 1952: Grace Hopper's team at Remington Rand wrote the compiler for the A 0 programming language (and coined the term compiler to describe it), although the A 0 compiler functioned more as a loader or linker than the modern notion of a full compiler. 1952, before September: An Autocode compiler developed by Alick Glennie for the Manchester Mark I computer at the University of Manchester is considered by some to be the first compiled programming language. 1954–1957: A team led by John Backus at IBM developed FORTRAN which is usually considered the first high level language. In 1957, they completed a FORTRAN compiler that is generally credited as having introduced the first unambiguously complete compiler. 1959: The Conference on Data Systems Language (CODASYL) initiated development of COBOL. The COBOL design drew on A 0 and FLOW MATIC. By the early 1960s COBOL was compiled on multiple architectures. 1958–1960: Algol 58 was the precursor to ALGOL 60. It introduced code blocks, a key advance in the rise of structured programming. ALGOL 60 was the first language to implement nested function definitions with lexical scope. It included recursion. Its syntax was defined using BNF. ALGOL 60 inspired many languages that followed it. Tony Hoare remarked: " it was not only an improvement on its predecessors but also on nearly all its successors." 1958–1962: John McCarthy at MIT designed LISP. The symbol processing capabilities provided useful features for artificial intelligence research. In 1962, LISP 1.5 release noted some tools: an interpreter written by Stephen Russell and Daniel J. Edwards, a compiler and assembler written by Tim Hart and Mike Levin. Early operating systems and software were written in assembly language. In the 1960s and early 1970s, the use of high level languages for system programming was still controversial due to resource limitations. However, several research and industry efforts began the shift toward high level systems programming languages, for example, BCPL, BLISS, B, and C.
BCPL (Basic Combined Programming Language) designed in 1966 by Martin Richards at the University of Cambridge was originally developed as a compiler writing tool. Several compilers have been implemented, Richards' book provides insights to the language and its compiler. BCPL was not only an influential systems programming language that is still used in research but also provided a basis for the design of B and C languages. BLISS (Basic Language for Implementation of System Software) was developed for a Digital Equipment Corporation (DEC) PDP 10 computer by W. A. Wulf's Carnegie Mellon University (CMU) research team. The CMU team went on to develop BLISS 11 compiler one year later in 1970. Multics (Multiplexed Information and Computing Service), a time sharing operating system project, involved MIT, Bell Labs, General Electric (later Honeywell) and was led by Fernando Corbató from MIT. Multics was written in the PL/I language developed by IBM and IBM User Group. IBM's goal was to satisfy business, scientific, and systems programming requirements. There were other languages that could have been considered but PL/I offered the most complete solution even though it had not been implemented. For the first few years of the Multics project, a subset of the language could be compiled to assembly language with the Early PL/I (EPL) compiler by Doug McIlory and Bob Morris from Bell Labs. EPL supported the project until a boot strapping compiler for the full PL/I could be developed. Bell Labs left the Multics project in 1969, and developed a system programming language B based on BCPL concepts, written by Dennis Ritchie and Ken Thompson. Ritchie created a boot strapping compiler for B and wrote Unics (Uniplexed Information and Computing Service) operating system for a PDP 7 in B. Unics eventually became spelled Unix. Bell Labs started the development and expansion of C based on B and BCPL. The BCPL compiler had been transported to Multics by Bell Labs and BCPL was a preferred language at Bell Labs. Initially, a front end program to Bell Labs' B compiler was used while a C compiler was developed. In 1971, a new PDP 11 provided the resource to define extensions to B and rewrite the compiler. By 1973 the design of C language was essentially complete and the Unix kernel for a PDP 11 was rewritten in C. Steve Johnson started development of Portable C Compiler (PCC) to support retargeting of C compilers to new machines. Object oriented programming (OOP) offered some interesting possibilities for application development and maintenance. OOP concepts go further back but were part of LISP and Simula language science. Bell Labs became interested in OOP with the development of C++. C++ was first used in 1980 for systems programming. The initial design leveraged C language systems programming capabilities with Simula concepts. Object oriented facilities were added in 1983. The Cfront program implemented a C++ front end for C84 language compiler. In subsequent years several C++ compilers were developed as C++ popularity grew. In many application domains, the idea of using a higher level language quickly caught on. Because of the expanding functionality supported by newer programming languages and the increasing complexity of computer architectures, compilers became more complex. DARPA (Defense Advanced Research Projects Agency) sponsored a compiler project with Wulf's CMU research team in 1970. The Production Quality Compiler Compiler PQCC design would produce a Production Quality Compiler (PQC) from formal definitions of source language and the target. PQCC tried to extend the term compiler compiler beyond the traditional meaning as a parser generator (e. g., Yacc) without much success. PQCC might more properly be referred to as a compiler generator. PQCC research into code generation process sought to build a truly automatic compiler writing system. The effort discovered and designed the phase structure of the PQC. The BLISS 11 compiler provided the initial structure. The phases included analyses (front end), intermediate translation to virtual machine (middle end), and translation to the target (back end). TCOL was developed for the PQCC research to handle language specific constructs in the intermediate representation. Variations of TCOL supported various languages. The PQCC project investigated techniques of automated compiler construction. The design concepts proved useful in optimizing compilers and compilers for the (since 1995, object oriented) programming language Ada. The Ada STONEMAN document formalized the program support environment (APSE) along with the kernel (KAPSE) and minimal (MAPSE). An Ada interpreter NYU/ED supported development and standardization efforts with the American National Standards Institute (ANSI) and the International Standards Organization (ISO). Initial Ada compiler development by the U. S. Military Services included the compilers in a complete integrated design environment along the lines of the STONEMAN document. Army and Navy worked on the Ada Language System (ALS) project targeted to DEC/VAX architecture while the Air Force started on the Ada Integrated Environment (AIE) targeted to IBM 370 series. While the projects did not provide the desired results, they did contribute to the overall effort on Ada development. Other Ada compiler efforts got underway in Britain at the University of York and in Germany at the University of Karlsruhe. In the U. S., Verdix (later acquired by Rational) delivered the Verdix Ada Development System (VADS) to the Army. VADS provided a set of development tools including a compiler. Unix/VADS could be hosted on a variety of Unix platforms such as DEC Ultrix and the Sun 3/60 Solaris targeted to Motorola 68020 in an Army CECOM evaluation. There were soon many Ada compilers available that passed the Ada Validation tests. The Free Software Foundation GNU project developed the GNU Compiler Collection (GCC) which provides a core capability to support multiple languages and targets. The Ada version GNAT is one of the most widely used Ada compilers. GNAT is free but there is also commercial support, for example, AdaCore, was founded in 1994 to provide commercial software solutions for Ada. GNAT Pro includes the GNU GCC based GNAT with a tool suite to provide an integrated development environment. High level languages continued to drive compiler research and development. Focus areas included optimization and automatic code generation. Trends in programming languages and development environments influenced compiler technology. More compilers became included in language distributions (PERL, Java Development Kit) and as a component of an IDE (VADS, Eclipse, Ada Pro). The interrelationship and interdependence of technologies grew. The advent of web services promoted growth of web languages and scripting languages. Scripts trace back to the early days of Command Line Interfaces (CLI) where the user could enter commands to be executed by the system. User Shell concepts developed with languages to write shell programs. Early Windows designs offered a simple batch programming capability. The conventional transformation of these language used an interpreter. While not widely used, Bash and Batch compilers have been written. More recently sophisticated interpreted languages became part of the developers tool kit. Modern scripting languages include PHP, Python, Ruby and Lua. (Lua is widely used in game development.) All of these have interpreter and compiler support. "When the field of compiling began in the late 50s, its focus was limited to the translation of high level language programs into machine code The compiler field is increasingly intertwined with other disciplines including computer architecture, programming languages, formal methods, software engineering, and computer security." The "Compiler Research: The Next 50 Years" article noted the importance of object oriented languages and Java. Security and parallel computing were cited among the future research targets.
Конструкция компилятора
Компилятор реализует формальное преобразование из программы на языке высокого уровня в программу на языке низкого уровня. Проектирование компилятора может представлять собой комплексное решение или сосредоточиться на определенной подзадаче, взаимодействующей с другими инструментами компиляции, например, с препроцессорами, ассемблерами и компоновщиками. Требования к проектированию включают в себя строго определенные интерфейсы как внутри самого компилятора между его компонентами, так и снаружи – между вспомогательными инструментами. На заре развития компиляторов подход к их проектированию напрямую зависел от сложности обрабатываемого языка программирования, опыта разработчика (или разработчиков) и доступных ресурсов. Ограниченность ресурсов обусловила необходимость многократного прохода по исходному коду. Компилятор для относительно простого языка, разработанный одним человеком, мог представлять собой единое монолитное программное обеспечение. Однако с ростом сложности исходного языка проектирование может быть разделено на несколько взаимосвязанных этапов. Разделение на этапы позволяет улучшить структуру компилятора и сосредоточить разработку на отдельных функциях процесса компиляции.
Однопроходные компиляторы против многопроходных
Классификация компиляторов по количеству проходов обусловлена ограничениями аппаратных ресурсов компьютеров. Компиляция требует значительных вычислительных затрат, и ранние компьютеры не имели достаточного объема памяти для размещения одной программы, выполняющей весь этот объем работы. В результате компиляторы были разделены на более мелкие программы, каждая из которых выполняла проход по исходному коду (или его представлению), осуществляя часть необходимого анализа и преобразований. Возможность компиляции за один проход традиционно считалась преимуществом, поскольку она упрощает разработку компилятора, а компиляторы с одним проходом обычно выполняют компиляцию быстрее, чем многопроходные компиляторы. Таким образом, отчасти из-за ограниченности ресурсов ранних систем, многие ранние языки программирования были специально разработаны для компиляции за один проход (например, Паскаль). В некоторых случаях, конструкция определенной языковой конструкции может потребовать от компилятора выполнения более одного прохода по исходному коду. Например, рассмотрим объявление, расположенное в строке 20 исходного кода, которое влияет на преобразование оператора, расположенного в строке 10. В этом случае первый проход должен собрать информацию об объявлениях, следующих за операторами, на которые они влияют, а фактическое преобразование происходит на последующем проходе. Недостатком компиляции за один проход является невозможность выполнения многих сложных оптимизаций, необходимых для генерации высококачественного кода. Точно определить количество проходов, выполняемых оптимизирующим компилятором, может быть затруднительно. Например, различные этапы оптимизации могут многократно анализировать одно выражение, но анализировать другое выражение только один раз. Разделение компилятора на небольшие программы – это метод, используемый исследователями, заинтересованными в создании компиляторов, корректность которых можно доказать. Доказательство корректности набора небольших программ часто требует меньше усилий, чем доказательство корректности одной большой эквивалентной программы.
Трехступенчатая структура компилятора
Независимо от точного количества фаз в разработке компилятора, эти фазы можно отнести к одной из трех стадий: фронтенду, миддленду и бэкенду. Фронтенд сканирует входные данные и проверяет синтаксис и семантику в соответствии с конкретным исходным языком. Для языков со статической типизацией он выполняет проверку типов, собирая информацию о типах. Если входная программа содержит синтаксические ошибки или ошибки типов, он генерирует сообщения об ошибках и/или предупреждения, обычно указывая местоположение в исходном коде, где проблема была обнаружена; в некоторых случаях фактическая ошибка может находиться (значительно) раньше в программе. К аспектам фронтенда относятся лексический, синтаксический и семантический анализ. Фронтенд преобразует входную программу в промежуточное представление (IR) для дальнейшей обработки миддлендом. Это IR обычно представляет собой представление программы более низкого уровня по сравнению с исходным кодом. Миддленд выполняет оптимизации IR, не зависящие от целевой архитектуры процессора. Эта независимость от исходного кода и машинного кода позволяет совместно использовать общие оптимизации между версиями компилятора, поддерживающими разные языки и целевые процессоры. Примерами оптимизаций миддленда являются удаление бесполезного кода (устранение мертвого кода) или недостижимого кода (анализ достижимости), обнаружение и распространение констант (распространение констант), перемещение вычислений в менее часто выполняемое место (например, за пределы цикла) или специализация вычислений на основе контекста, в конечном итоге создавая "оптимизированный" IR, который используется бэкендом. Бэкенд принимает оптимизированный IR от миддленда. Он может выполнять дополнительный анализ, преобразования и оптимизации, специфичные для целевой архитектуры процессора. Бэкенд генерирует целевой машинный код, выполняя распределение регистров в процессе. Бэкенд выполняет планирование инструкций, переупорядочивая их для поддержания занятости параллельных исполнительных устройств за счет заполнения интервалов задержки. Хотя большинство задач оптимизации являются NP-трудными, эвристические методы их решения хорошо разработаны и реализованы в компиляторах промышленного качества. Обычно выходные данные бэкенда – это машинный код, специализированный для конкретного процессора и операционной системы. Такой подход с использованием фронтенда, миддленда и бэкенда позволяет объединять фронтенды для разных языков с бэкендами для разных процессоров, при этом совместно используя оптимизации миддленда. Практическими примерами этого подхода являются GNU Compiler Collection, Clang (компилятор C/C++ на основе LLVM) и Amsterdam Compiler Kit, которые имеют несколько фронтендов, общие оптимизации и несколько бэкендов.
Задняя часть
Задний конец отвечает за оптимизации, специфичные для архитектуры процессора, и за генерацию кода. Ярким примером является оптимизация "подсматриванием", которая переписывает короткие последовательности инструкций ассемблера в более эффективные инструкции. Генерация кода: преобразованный промежуточный язык транслируется в целевой язык, обычно в машинный язык системы. Это включает в себя принятие решений об использовании ресурсов и памяти, таких как определение того, какие переменные поместить в регистры, а какие – в память, а также выбор и планирование соответствующих машинных инструкций с использованием подходящих режимов адресации (см. также алгоритм Сети-Уллмана). Для упрощения отладки также может потребоваться генерация данных отладки.
Правильность компилятора
Корректность компилятора — это область программной инженерии, занимающаяся доказательством соответствия поведения компилятора спецификации языка. Методы включают разработку компилятора с применением формальных методов и проведение тщательного тестирования (часто называемого валидацией компилятора) для уже существующего компилятора.
Сборник и интерпретированный языки
Языки программирования высокого уровня обычно создаются с учетом определенного типа трансляции: либо как компилируемые, либо как интерпретируемые. Однако на практике редко можно найти что-то в языке, что однозначно требовало бы исключительно компиляции или исключительно интерпретации, хотя можно спроектировать языки, полагающиеся на повторную интерпретацию во время выполнения. Категоризация обычно отражает наиболее популярные или распространенные реализации языка – например, BASIC часто называют интерпретируемым языком, а C – компилируемым, несмотря на существование компиляторов BASIC и интерпретаторов C. Интерпретация не отменяет компиляцию полностью, она лишь скрывает ее от пользователя и делает поэтапной. Даже если сам интерпретатор может быть интерпретирован, где-то внизу стека выполнения все равно необходим набор непосредственно исполняемых машинных инструкций (см. машинный язык). Более того, для оптимизации компиляторы могут включать функциональность интерпретатора, а интерпретаторы – методы компиляции во время выполнения. Например, если выражение можно вычислить во время компиляции и вставить результат в выходную программу, то это предотвращает его пересчет при каждом запуске программы, что может значительно ускорить работу. Современные тенденции к компиляции "точно в срок" (just-in-time) и интерпретации байт-кода еще больше размывают традиционные границы между компиляторами и интерпретаторами. Некоторые спецификации языков предписывают, чтобы реализации включали средства компиляции, например, Common Lisp. Однако в определении Common Lisp нет ничего, что препятствовало бы его интерпретации. Другие языки имеют функции, которые легко реализовать в интерпретаторе, но значительно усложняют написание компилятора; например, APL, SNOBOL4 и многие скриптовые языки позволяют программам создавать произвольный исходный код во время выполнения с помощью стандартных строковых операций, а затем выполнять этот код, передавая его специальной функции вычисления. Для реализации этих функций в компилируемом языке программы обычно должны поставляться с библиотекой времени выполнения, включающей версию самого компилятора.