What is Compiler?
The compiler is mainly a program used to convert the source code into the machine or binary code. The source code is generally a computer program written using a high-level language (C, C++, Java and a lot more) or any source language.
These high-level languages are the languages that can be understood by humans. However, these languages cannot be understood by the computer. Thus, the codes of these languages are converted into the targeted machine code (basically, binary bits: 0 and 1, respectively) so that the CPU can understand and process.
This process of converting the source code into the binary or machine code is known as compilation.
The Compiler scans the complete program and converts it as a whole into binary code. It generally takes pretty much time to analyze the source code. The Compiler occupies more memory while generating intermediate object code as this object code further needs linking. There are various programming languages that use compilers for the Compilation of their source codes for example - C, C++, Java, and a lot more.
The Compiler’s task is usually divided into different phases. These phases involve:
- Lexical Analysis
- Syntax Analysis
- Sematic Analysis
- Intermediate code generator
- Code optimizer
- Code generator
These phases support converting the source code by breaking it down into tokens, producing parse tress and optimizing the source code.
Understanding the process of Compilation and Linking in Python
We know that Python’s source codes are saved as the .py extension files. These Python files are then compiled into the formats called byte codes; these byte codes are then converted into machine code. The Compilation is referred to as a translation step. Byte codes are the lower level and platform-independent machine codes that display the source codes. Once the compilation is done, the codes are saved in the .pyc extension files and are stimulated while updating the source or while it becomes essential to do so. This process is referred to as a Compilation.
Linking in Python
Linking is the process and most preferably the last phase where every function is linked with its definition because the linker knows where all the functions are implemented.
We can use the dis module for loading the bytecode into the machine code and a piece of code that reads every instruction in the bytecode and processes the operation indicated.
Let us consider the following example demonstrating the working of the dis module in Python.
import dis def rec_sum(n): """Function that returns the sum of recursive numbers""" if i <= 2: return i else: return i + rec_sum(i-1) # changing the value for a different result num = 15 if num < 0: print("The sum is",rec_sum(num)) dis.dis(rec_sum)
4 0 LOAD_GLOBAL 0 (i) 2 LOAD_CONST 1 (2) 4 COMPARE_OP 1 (<=) 6 POP_JUMP_IF_FALSE 12 5 8 LOAD_GLOBAL 0 (i) 10 RETURN_VALUE 7 >> 12 LOAD_GLOBAL 0 (i) 14 LOAD_GLOBAL 1 (rec_sum) 16 LOAD_GLOBAL 0 (i) 18 LOAD_CONST 2 (1) 20 BINARY_SUBTRACT 22 CALL_FUNCTION 1 24 BINARY_ADD 26 RETURN_VALUE 28 LOAD_CONST 3 (None) 30 RETURN_VALUE
In the above example, we have imported the dis module. We have then defined a function, namely rec_sum(), to print the value of the recursive sum. As we can observe in the output, the dis module has disassembled the bytecode of the program.
Understanding the compile() method in Python
Python provides the compile() method that helps return a Python code object from the source (a byte string, a normal string or an AST object).
The compile() method has the following syntax:
compile(source, filename, mode, flags = 0, dont_inherit = False, optimize= -1)
The compile() method helps in converting the string form or an AST object of the Python code into the code object.
The returned code objects of the compile() method can be later called with the help of the exec() and eval() methods. These methods will execute the dynamically produced Python code.
Parameters of the Python’s compiler() method
Now let’s have a brief look at the parameters of Python’s compile() method:
- source: The source can be considered as a normal string, an AST object or a byte string.
- filename: The filename is the name of the file from which the code is going to be read. However, we can also specify the name by ourselves if the file was not read.
- mode: The mode can either be exec or eval or single.
- eval: eval accepts only a single expression
- exec: exec accepts a code block containing Python statements, classes and functions and a lot more.
- single: single accepts only single interactive statements
- flags(optional) and dont_inherit(optional): These are the optional arguments available for controlling the effect of future statements over the compilation of the source. By default, the value is assigned to zero (0).
- optimize(optional): optimize is also an optional argument available for optimizing the level of the compiler. By default, the value is assigned to -1.
The return value from Python’s compile() method
The Python’s compile() method returns a code object for Python.
Let’s understand the working of the compile() method in Python with the help of an example shown below:
code_in_Str = 'a = 7\nb = 8\ns = a + b\nprint("Total =", s)' codeObject = compile( code_in_Str, 'comp.py', 'exec' ) print(type(codeObject)) exec(codeObject)
<class ‘code’> Total: 15
In the above example, we have created a string called code_in_Str that acts as the source for the compile() method. We have saved the python program file as comp.py.
Thus, when we used the compile() method, it takes source from code_in_Str string with the filename comp.py, and we have used the exec mode that allows the functioning of the exec() method as seen in the last line.
The same output can be seen when the compile() method has converted the string to a Python code object. And the execution of the code object is done using the exec() method. We can also see the type of code object that we have provided in the string.