A data structure called display is used to access a variable in surrounding blocks. The display contains pointers to the most recent activation records for the current block and for all blocks that surround the current one in the source program. When a block refers to a variable that is declared in some surrounding block, the generated object code uses the display to find the activation record that contains this variable.
Example:
When a procedure calls itself recursively thus an activation record is created on the stack as a result of the call. Assume procedure C calls itself recursively. It is shown in fig. 42(b) the record for C is created on the stack as a result of the call. Any reference to a variable declared by C should use this most recent activation record ; the display pointer for C is changed accordingly. Variables that correspond to the previous invocation of C are not accessible for the movement, so there is no display pointer to this
activation record.
42
Activation
Record for
C
Activation
Record for
B
Activation
Record for
C
Activation
Record for
C
Activatio
C
B
A
C
B
A
Activation
Record for
C
Activation
Record for
B
Stack Display
Fig 42(c)
Now if procedure 'C' call procedure D the resulting stack and display are as illustrated in fig. 42(c) . An activation record for D has been created in the usual way and added to the stack. Note, that the display now contains only two pointers: one each to the activation records for D and A. This is because procedure D cannot refer to variable in B or C, except through parameters that are passed to it, even though it is called from C.
According to the rules for the scope of names in as block-structured language, procedure D can refer only to variable that are declared by D or by some block that contains D in
the source program.
8.4 COMPILER DESIGN OPTIONS
The compiler design is briefly discussed in this section. The compiler is divided into single pass and multi pass compilers.
4.1. COMPILER PASSES
One pass compiler for a subset of the Pascal language was discussed in section 1. In this design the parsing process drove the compiler. The lexical scanner was called when the parser needed another input token and a code-generation routine was invoked as the parser recognized each language construct. The code optimization techniques discussed cannot be applied in total to one-pass compiler without intermediate code-generation. One pass compiler is efficient to generate the object code.
One pass compiler cannot be used for translation for all languages. FORTRAN and PASCAL language programs have declaration of variable at the beginning of the program. Any variable that is not declared is assigned characteristic by default.
One pass compiler may fix the formal reference jump instruction without problem as in one pass assembler. But it is difficult to fix if the declaration of an identifier appears after it has been used in the program as in some programming
languages.
Example: X : = Y * Z
If all the variables x, y and z are of type INTEGER, the object code for this statement might consist of a simple integer multiplication followed by storage of the result. If the variable are a mixture of REAL and INTEGER types, one or more conversion operations will need to be included in the object code, and floating point arithmetic instructions may be used. Obviously the compiler cannot decide what machine instructions to generate for this statement unless instruction about the operands is available. The statement may even be illegal for certain combinations of operand types. Thus a language that allows forward reference to data items cannot be compiled in one pass.
Some programming language requires more than two passes. Example : ALGOL-98 requires at least 3 passes.
D
A
There are a number of factors that should be considered in deciding between one pass and multi pass compiler designs.
(1) One Pass Compiles: Speed of compilation is considered important. Computer
running students jobs tend to spend a large amount of time performing compilations. The resulting object code is usually executed only once or twice for each compilation, these test runs are not normally very short. In such an environment, improvement in the speed of compilation can lead to significant benefit in system performance and job turn around time.
(2)
Multi-Pass Compiles: If programs are executed many times for each compilation orif they process large amount of data, then speed of executive becomes more important than speed of compilation. In a case, we might prefer a multi-pass compiler design that could incorporate sophisticated code-optimization technique.
Multi-pass compilers are also used when the amount of memory, or other systems resources, is severely limited. The requirements of each pass can be kept smaller if the work by compilation is divided into several passes.
Other factors may also influence the design of the compiler. If a compiler is divided into several passes, each pass becomes simpler and therefore, easier to understand, read and test. Different passes can be assigned to different programmers and can be written and tested in parallel, which shortens the overall time require for compiler construction.
INTERPRETERS
An interpreter processes a source program written in a high-level language. The main difference between compiler and interpreter is that interpreters execute a version of the source program directly, instead of translating it into machine code.
An interpreter performs lexical and syntactic analysis functions just like compiler and then translates the source program into an internal form. The internal form may also be a sequence of quadruples.
After translating the source program into an internal form, the interpreter executes the operations specified by the program. During this phase, an interpreter can be viewed as a set of subtractions. The internal form of the program drives the execution of this subtraction.
The major differences b/w interpreter and compiler are:
Most programming languages can be either compiled or interpreted successfully. However, some languages are particularly well suited to the use of interpreter. Compilers usually generate calls to library routines to perform function such as I/O and complex conversion operations. In such cases, an interpreter might be performed because of its speed of translation. Most of the execution time for the standard program would be consumed by the standard library routines. These routines would be the same, regardless of whether a compiler or an interpreter is used.
In some languages the type of a variable can change during the execution of a program. Dynamic scoping is used, in which the variable that are referred to by a function or a subroutines are determined by the sequence of calls made during execution, not by the nesting of blocks in the source program. It is difficult to compile such language efficiently and allow for dynamic changes in the types of variables and the scope of names. These features can be more easily handled by an interpreter that provides
delayed binding of symbolic variable names to data types and locations.
4.3 P-CODE COMPILERS
P-Code compilers also called byte of code compilers are very similar in concept to interpreters. A P-code compiler, intermediate form is the machine language for a hypothetical computers, often called pscudo-machine or P-machine. The process of using such a P-code is