Incomputer programming, aprogramming language implementation is a system for executingcomputer programs. There are two general approaches to programming language implementation:[1]
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.[3]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.[4]
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 combinedprogramming language design and implementation.
Aninterpreter 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.[5]
Avirtual machine is a special type of interpreter that interprets bytecode.[2] Bytecode is aportable low-level code similar to machine code, though it is generally executed on a virtual machine instead of a physical machine.[6] To improve their efficiencies, many programming languages such asJava,[6]Python,[7] andC#[8] are compiled to bytecode before being interpreted.
Some virtual machines include ajust-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.[2]
Acompiler 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.[9]
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).[2]
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.[10]
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: [11]