This articleneeds additional citations forverification. Please helpimprove this article byadding citations to reliable sources. Unsourced material may be challenged and removed. Find sources: "Programming language design and implementation" – news ·newspapers ·books ·scholar ·JSTOR(March 2023) (Learn how and when to remove this message) |
Programming languages are typically created by designing a form of representation of a computer program, and writing an implementation for the developed concept,[1] usually aninterpreter orcompiler. Interpreters are designed to read programs, usually in some variation of atext format, and perform actions based on what it reads, whereas compilers convert code to a lower level form, such as object code.[2]
In programming language design, there are a wide variety of factors to consider. Some factors may be mutually exclusive (e.g. security versus speed). It may be necessary to consider whether a programming language will perform better interpreted, or compiled, if a language should be dynamically or statically typed, if inheritance will be in, and the general syntax of the language.[3] Many factors involved with the design of a language can be decided on by the goals behind the language. It's important to consider the target audience of a language, its unique features and its purpose.[4] It is good practice to look at what existing languages lack, or make difficult, to make sure a language serves a purpose.[4]
Various experts have suggested useful design principles:
Many programming languages have design features intended to make it easier to implement at least the first initial version of the compiler or interpreter.For example, Pascal, Forth, and many assembly languages are specifically designed to support one-pass compilation.
Often new programming languages are designed to fix (perceived) problems with earlier programming languages, typically by adding features that (while they may make the interpreter or compiler more complicated) make programs written in those languages simpler.For example, languages with built-in automatic memory management and garbage collection; languages with built-inassociative arrays; etc.
On the other hand,a few programming languages were specifically designed to make it relatively easy to write aself-hosting compiler,typically by deliberately leaving out features that make compilation difficult,such asBCPL,Pascal, andRPython.
There are two general approaches to programming language implementation:[8]
In addition to these two extremes, many implementations use hybrid approaches such as just-in-time compilation and bytecode interpreters.
Interpreters have some advantages over JIT compilers and ahead-of-time compilers.[10]Typically interpreters support aread–eval–print loop that makes developing new programs much quicker; compilers force developers to use a much slower edit-compile-run-debug loop.
A typical program, when compiled with an ahead-of-time compiler, will (after the program has been compiled) run faster than the same program processed and run with a JIT compiler; which in turn may run faster than that same program partially compiled into ap-codeintermediate language such as abytecode and interpreted by anapplication virtual machine; which in turn runs much faster than a pure interpreter.[11]
In theory, a programming language can first be specified and then later an interpreter or compiler for it can be implemented (waterfall model).In practice, often things learned while trying to implement a language can effect later versions of the language specification, leading to combined programming language design and implementation.
Both interpreters and compilers usually implement some sort ofsymbol table.
An interpreter is a program that reads another program, typically as text,[4] as seen in languages likePython.[2] Interpreters read code, and produce the result directly.[12] Interpreters typically read code line by line, and parse it to convert and execute the code as operations and actions.[13]
An interpreter is composed of two parts: aparser and anevaluator. After a program is read as input by an interpreter, it is processed by the parser. The parser breaks the program intolanguage components to form aparse tree. The evaluator then uses the parse tree to execute the program.[14]
A virtual machine is a special type of interpreter that interprets bytecode.[9] Bytecode is aportable low-level code similar to machine code, though it is generally executed on a virtual machine instead of a physical machine.[15] To improve their efficiencies, many programming languages such asJava,[15]Python,[16] andC#[17] are compiled to bytecode before being interpreted.
Some virtual machines include a just-in-time (JIT) compiler to improve the efficiency of bytecode execution. While the bytecode is being executed by the virtual machine, if the JIT compiler determines that a portion of the bytecode will be used repeatedly, it compiles that particular portion to machine code. The JIT compiler then stores the machine code inmemory so that it can be used by the virtual machine. JIT compilers try to strike a balance between longer compilation time and faster execution time.[9]
A compiler translates programs written in one language into another language. Most compilers are organized into three stages: afront end, anoptimizer, and aback end. The front end is responsible for understanding the program. It makes sure a program is valid and transforms it into anintermediate representation, a data structure used by the compiler to represent the program. The optimizer improves the intermediate representation to increase the speed or reduce the size of theexecutable which is ultimately produced by the compiler. The back end converts the optimized intermediate representation into the output language of the compiler.[18]
If a compiler of a givenhigh level language produces another high level language, it is called atranspiler. Transpilers can be used to extend existing languages or to simplify compiler development by exploitingportable and well-optimized implementations of other languages (such asC).[9]
Many combinations of interpretation and compilation are possible, and many modern programming language implementations include elements of both. For example, theSmalltalk programming language is conventionally implemented by compilation intobytecode, which is then either interpreted or compiled by avirtual machine. Since Smalltalk bytecode is run on a virtual machine, it is portable across different hardware platforms.[19]
Programming languages can have multiple implementations. Different implementations can be written in different languages and can use different methods to compile or interpret code. For example, implementations ofPython include: [20]
Processes of making a programming language may differ from developer to developer; however, here is a general process of how one might create a programming language, which includes common concepts:
Getting started presents the chicken-and-egg problem familiar from compiler construction: one needs a compiler to bootstrap a compiler, and bootstrapping compiler generators is no exception.