Backpatching in Compiler Design
Last Updated :
02 Jul, 2024
Backpatching is basically a process of fulfilling unspecified information. This information is of labels. It basically uses the appropriate semantic actions during the process of code generation. It may indicate the address of the Label in goto statements while producing TACs for the given expressions.
Here basically two passes are used because assigning the positions of these label statements in one pass is quite challenging. It can leave these addresses unidentified in the first pass and then populate them in the second round. Backpatching is the process of filling up gaps in incomplete transformations and information.
What is Backpatching?
Backpatching is a method to deal with jumps in the control flow constructs like if statements, loops, etc in the intermediate code generation phase of the compiler. Otherwise, as the target of these jumps may not be known until later in the compilation stages, back patching is a method to fill in these destinations located elsewhere.
Forward jumps are very common in constructs like the if statements, while loops, switch cases. For example, in a language with goto statements, the destination of a goto may not be resolved until and unless its label appears following the goto statement. Forward references i.e; Jumps from lower addresses to higher address it is a mechanism to maintain and solve these.
Need for Backpatching:
Backpatching is mainly used for two purposes:
1. Boolean Expression
Boolean expressions are statements whose results can be either true or false. A boolean expression which is named for mathematician George Boole is an expression that evaluates to either true or false. Let’s look at some common language examples:
- My favorite color is blue. → true
- I am afraid of mathematics. → false
- 2 is greater than 5. → false
2. Flow of control statements:
The flow of control statements needs to be controlled during the execution of statements in a program. For example:
The flow of control statements3. Labels and Gotos
The most elementary programming language construct for changing the flow of control in a program is a label and goto. When a compiler encounters a statement like goto L, it must check that there is exactly one statement with label L in the scope of this goto statement. If the label has already appeared, then the symbol table will have an entry giving the compiler-generated label for the first three-address instruction associated with the source statement labeled L. For the translation, we generate a goto three-address statement with that compiler-generated label as a target.
When a label L is encountered for the first time in the source program, either in a declaration or as the target of the forward goto, we enter L into the symbol table and generate a symbolic table for L.
One-pass code generation using backpatching:
In a single pass, backpatching may be used to create a boolean expressions program as well as the flow of control statements. The synthesized properties truelist and falselist of non-terminal B are used to handle labels in jumping code for Boolean statements. The label to which control should go if B is true should be added to B.truelist, which is a list of a jump or conditional jump instructions. B.falselist is the list of instructions that eventually get the label to which control is assigned when B is false. The jumps to true and false exist, as well as the label field, are left blank when the program is generated for B. The lists B.truelist and B.falselist, respectively, contain these early jumps.
A statement S, for example, has a synthesized attribute S.nextlist, which indicates a list of jumps to the instruction immediately after the code for S. It can generate instructions into an instruction array, with labels serving as indexes. We utilize three functions to modify the list of jumps:
- Makelist (i): Create a new list including only i, an index into the array of instructions and the makelist also returns a pointer to the newly generated list.
- Merge(p1,p2): Concatenates the lists pointed to by p1, and p2 and returns a pointer to the concatenated list.
- Backpatch (p, i): Inserts i as the target label for each of the instructions on the record pointed to by p.
Backpatching for Boolean Expressions
Using a translation technique, it can create code for Boolean expressions during bottom-up parsing. In grammar, a non-terminal marker M creates a semantic action that picks up the index of the next instruction to be created at the proper time.
For Example, Backpatching using boolean expressions production rules table:
Step 1: Generation of the production table
Production Table for BackpatchingStep 2: We have to find the TAC(Three address code) for the given expression using backpatching:
A < B OR C < D AND P < Q
Three address codes for the given exampleStep 3: Now we will make the parse tree for the expression:
Parse tree for the exampleThe flow of Control Statements:
Control statements are those that alter the order in which statements are executed. If, If-else, Switch-Case, and while-do statements are examples. Boolean expressions are often used in computer languages to
- Alter the flow of control: Boolean expressions are conditional expressions that change the flow of control in a statement. The value of such a Boolean statement is implicit in the program's position. For example, if (A) B, the expression A must be true if statement B is reached.
- Compute logical values: During bottom-up parsing, it may generate code for Boolean statements via a translation mechanism. A non-terminal marker M in the grammar establishes a semantic action that takes the index of the following instruction to be formed at the appropriate moment.
Applications of Backpatching
- Backpatching is used to translate flow-of-control statements in one pass itself.
- Backpatching is used for producing quadruples for boolean expressions during bottom-up parsing.
- It is the activity of filling up unspecified information of labels during the code generation process.
- It helps to resolve forward branches that have been planted in the code.
Similar Reads
Bootstrapping in Compiler Design
Bootstrapping is an important technique in compiler design, where a basic compiler is used to create a more advanced version of itself. This process helps in building compilers for new programming languages and improving the ones already in use. By starting with a simple compiler, bootstrapping allo
6 min read
Type Checking in Compiler Design
Type checking is the process of checking and enforcing the constraints of types assigned to values in a program. A compiler has to check that a source program conforms both to the syntactic and semantic rules of the language as well as its type rules. The process also helps in limiting the kinds of
7 min read
Basic Blocks in Compiler Design
Basic Block is a straight line code sequence that has no branches in and out branches except to the entry and at the end respectively. Basic Block is a set of statements that always executes one after other, in a sequence. The first task is to partition a sequence of three-address codes into basic b
3 min read
Input Buffering in Compiler Design
The lexical analyzer scans the input from left to right one character at a time. It uses two pointers begin ptr(bp) and forward ptr(fp) to keep track of the pointer of the input scanned. Input buffering is an important concept in compiler design that refers to the way in which the compiler reads inp
5 min read
Semantic Analysis in Compiler Design
Semantic Analysis is the third phase of Compiler. Semantic Analysis makes sure that declarations and statements of program are semantically correct. It is a collection of procedures which is called by parser as and when required by grammar. Both syntax tree of previous phase and symbol table are use
2 min read
Symbolic Analysis in Compiler Design
Symbolic analysis helps in expressing program expressions as symbolic expressions. During program execution, functional behavior is derived from the algebraic representation of its computations. Generally, during normal program execution, the numeric value of the program is computed but the informat
5 min read
Pass By Name in Compiler Design
Compiler design is a captivating field that plays a role, in transforming high-level programming languages into machine code enabling computers to perform tasks. One concept that often stands out in compiler design is the idea of "pass by the name". We will explore the details of pass-by names, defi
3 min read
Labeling Algorithm in Compiler Design
Labeling algorithm is used by compiler during code generation phase. Basically, this algorithm is used to find out how many registers will be required by a program to complete its execution. Labeling algorithm works in bottom-up fashion. We will start labeling firstly child nodes and then interior n
3 min read
Loader in Compiler Design
Pre-requisites: Introduction To Compilers In compiler design, a loader is a program that is responsible for loading executable programs into memory for execution. The loader reads the object code of a program, which is usually in binary form, and copies it into memory. It also performs other tasks s
7 min read
Liveliness Analysis in Compiler Design
Liveliness Analysis consists of a specified technique that is implemented to optimize register space allocation, for a given piece of code and facilitate the procedure for dead-code elimination. As any machine has a limited number of registers to hold a variable or data which is being used or manipu
9 min read