Unit - 3
Unit - 3
Syntax Directed Translation has augmented rules to the grammar that facilitate
semantic analysis. SDT involves passing information bottom-up and/or top-down
to the parse tree in form of attributes attached to the nodes.
The general approach to Syntax-Directed Translation is to construct a parse tree
or syntax tree and compute the values of attributes at the nodes of the tree by
visiting them in some order.
Ex.
1. S-attributed SDT :
If an SDT uses only synthesized attributes, it is called as
S-attributed SDT.
S-attributed SDTs are evaluated in bottom-up parsing, as
the values of the parent nodes depend upon the values of
the child nodes.
Semantic actions are placed in rightmost place of RHS.
2. L-attributed SDT:
If an SDT uses both synthesized attributes and inherited
attributes with a restriction that inherited attribute can
inherit values from left siblings only, it is called as L-
attributed SDT.
Attributes in L-attributed SDTs are evaluated by depth-first
and left-to-right parsing manner.
Semantic actions are placed anywhere in RHS.
Type Checking
Example 1)
Static vs Dynamic Checking ( Types of type
checking)
a) Static Type
1) for each operation: The number, order, and data type, of its arguments.
Example-
A+B
In this data type, the value and name is specified and in further if checked value assigned
should match its data type.
• It is done at runtime.
• It uses concept of type tag which is stored in each data objects that indicates the data type of the
object.
Example:
So Operation only be performed after type checking sequence in which type tag of each
argument is checked. If the types are not correct then error will be generated.
• Perl and Prolog follow basically dynamically type checking because data type of variables A+B
in this case may be changed during program execution.
• It is much flexible in designing programs or we can say that the flexibility in program design.
• In this programmer are free from most concern about data type.
• Difficult to debug: We need to check program execution paths for testing and in dynamic type
checking; program execution path for an operation is never checked.
• Extra storage: Dynamic type checking need extra storage to keep type information during
execution.
Type Conversion
Type Conversion
A type cast is basically a conversion from one type to another. There are two types of type
conversion:
o Done by the compiler on its own, without any external trigger from the user.
o Generally takes place when in an expression more than one data type is present.
In such condition type conversion (type promotion) takes place to avoid loss of
data.
o All the data types of the variables are upgraded to the data type of the variable
with largest data type.
o
o bool -> char -> short int -> int ->
o unsigned int -> long -> unsigned ->
o long long -> float -> double -> long double
o It is possible for implicit conversions to lose information, signs can be lost (when
signed is implicitly converted to unsigned), and overflow can occur (when long
long is implicitly converted to float).
Output:
x = 107, z = 108.000000
This process is also called type casting and it is user defined. Here the user can type cast
the result to make it of a particular data type.
The syntax in C:
(type) expression
Type indicated the data type to which the final result is converted.
int main()
{
double x = 1.2;
// Explicit conversion from double to int
int sum = (int)x + 1;
return 0;
}
Output:
sum = 2
Function Overloading
Function Overloading is defined as the process of
having two or more function with the same name,
but different in parameters is known as function
overloading in C++. In function overloading, the
function is redefined by using either different types
of arguments or a different number of arguments.
Runtime Environments
A translation needs to relate the static source text of a program
to the dynamic actions that must occur at runtime to implement
the program. The program consists of names for procedures,
identifiers etc., that require mapping with the actual memory
location at runtime. Runtime environment is a state of the target
machine, which may include software libraries, environment
variables, etc., to provide services to the processes running in
the system.
Storage Allocation
Runtime environment manages runtime memory requirements for the
following entities:
Code : It is known as the text part of a program that does not
change at runtime. Its memory requirements are known at the
compile time.
Procedures : Their text part is static but they are called in a
random manner. That is why, stack storage is used to manage
procedure calls and activations.
Variables : Variables are known at the runtime only, unless they
are global or constant. Heap memory allocation scheme is used
for managing allocation and de-allocation of memory for
variables in runtime.
Static Allocation
In this allocation scheme, the compilation data is bound to a fixed
location in the memory and it does not change when the program
executes. As the memory requirement and storage locations are
known in advance, runtime support package for memory allocation
and de-allocation is not required.
Stack Allocation
Procedure calls and their activations are managed by means of stack
memory allocation. It works in last-in-first-out (LIFO) method and this
allocation strategy is very useful for recursive procedure calls.
Heap Allocation
Variables local to a procedure are allocated and de-allocated only at
runtime. Heap allocation is used to dynamically allocate memory to
the variables and claim it back when the variables are no more
required.
Except statically allocated memory area, both stack and heap memory
can grow and shrink dynamically and unexpectedly. Therefore, they
cannot be provided with a fixed amount of memory in the system.
As shown in the image above, the text part of the code is allocated a
fixed amount of memory. Stack and heap memory are arranged at the
extremes of total memory allocated to the program. Both shrink and
grow against each other.
Parameter Passing
The communication medium among procedures is known as
parameter passing. The values of the variables from a calling
procedure are transferred to the called procedure by some
mechanism. Before moving ahead, first go through some basic
terminologies pertaining to the values in a program.
r-value
The value of an expression is called its r-value. The value contained in
a single variable also becomes an r-value if it appears on the right-
hand side of the assignment operator. r-values can always be
assigned to some other variable.
l-value
The location of memory (address) where an expression is stored is
known as the l-value of that expression. It always appears at the left
hand side of an assignment operator.
For example:
day = 1;
week = day * 7;
month = 1;
year = month * 12;
From this example, we understand that constant values like 1, 7, 12,
and variables like day, week, month and year, all have r-values. Only
variables have l-values as they also represent the memory location
assigned to them.
For example:
7 = x + y;
is an l-value error, as the constant 7 does not represent any memory
location.
Formal Parameters
Variables that take the information passed by the caller procedure are
called formal parameters. These variables are declared in the
definition of the called function.
Actual Parameters
Variables whose values or addresses are being passed to the called
procedure are called actual parameters. These variables are specified
in the function call as arguments.
Example:
fun_one()
{
int actual_parameter = 10;
call fun_two(int actual_parameter);
}
fun_two(int formal_parameter)
{
print formal_parameter;
}
Formal parameters hold the information of the actual parameter,
depending upon the parameter passing technique used. It may be a
value or an address.
Pass by Value
In pass by value mechanism, the calling procedure passes the r-value
of actual parameters and the compiler puts that into the called
procedure’s activation record. Formal parameters then hold the values
passed by the calling procedure. If the values held by the formal
parameters are changed, it should have no impact on the actual
parameters.
Pass by Reference
In pass by reference mechanism, the l-value of the actual parameter is
copied to the activation record of the called procedure. This way, the
called procedure now has the address (memory location) of the actual
parameter and the formal parameter refers to the same memory
location. Therefore, if the value pointed by the formal parameter is
changed, the impact should be seen on the actual parameter as they
should also point to the same value.
Pass by Copy-restore
This parameter passing mechanism works similar to ‘pass-by-
reference’ except that the changes to actual parameters are made
when the called procedure ends. Upon function call, the values of
actual parameters are copied in the activation record of the called
procedure. Formal parameters if manipulated have no real-time effect
on actual parameters (as l-values are passed), but when the called
procedure ends, the l-values of formal parameters are copied to the l-
values of actual parameters.
Example:
int y;
calling_procedure()
{
y = 10;
copy_restore(y); //l-value of y is passed
printf y; //prints 99
}
copy_restore(int x)
{
x = 99; // y still has value 10 (unaffected)
y = 0; // y is now 0
}