UNIT-3 Odg
UNIT-3 Odg
UNIT-3 Odg
In the next few slides we will see how abstract syntax trees can be constructed from syntax
directed definitions. Abstract syntax trees are condensed form of parse trees. Normally operators
and keywords appear as leaves but in an abstract syntax tree they are associated with the interior
nodes that would be the parent of those leaves in the parse tree. This is clearly indicated by the
examples in these slides. Chain of single productions may be collapsed, and operators move to the
parent nodes
Chain of single productions are collapsed into one node with the operators moving up to become
the node.
Advantages
Here are some advantages of polish notation in compiler design:
1.No need for parentheses: In polish notation, there is no need for parentheses
while writing the arithmetic expressions as the operators come before the operands.
2.Efficient Evaluation: The evaluation of an expression is easier in polish notation
because in polish notation stack can be used for evaluation.
3.Easy parsing: In polish notation, the parsing can easily be done as compared to the
infix notation.
4.Less scanning: The compiler needs fewer scans as the parentheses are not used
in the polish notations, and the compiler does not need to scan the operators and
operands differently.
Disadvantages
Here are some disadvantages of polish notation in compiler design:
1.Vague: If someone sees the polish notation for the first time and doesn’t know about
it. It will be very hard to understand how to evaluate the expression.
2.Not used commonly: The polish notation is not commonly used in day-to-day life.
These are mostly used for scientific purposes.
3.Difficult for programmers: It will be difficult for programmers who need to become
more familiar with polish notations to read the expression.
→In the semantic rule, attribute is VAL and an attribute may hold anything like a
string, a number, a memory location and a complex record
Example
Production Semantic Rules
E→E+T E.val := E.val + T.val
Symbol Table
→Symbol table is an important data structure used in a compiler.
→Symbol table is used to store the information about the occurrence of various entities
such as objects, classes, variable name, interface, function name etc. it is used by both the
analysis and synthesis phases.
It is used to store the name of all entities in a structured form at one place.
Hash table
Operations
The symbol table provides the following operations:
Insert ()
Insert () operation is more frequently used in the analysis phase when the tokens
are identified and names are stored in the table.
The insert() operation is used to insert the information in the symbol table like the
unique name occurring in the source code.
1. int x;
Should be processed by the compiler as:
lookup()
In the symbol table, lookup() operation is used to search a name. It is used to determine:
1. lookup (symbol)
This format is varies according to the programming language.
ORGANIZATION FOR BLOCK STRUCTURES:
A block is a any sequence of operations or instructions that are used to perform a [sub] task. In
any programming language,
Blocks contain its own local data structure.
Blocks can be nested and their starting and ends are marked by a delimiter.
They ensure that either block is independent of other or nested in another block. That is,
it is not possible for two blocks B1 and B2 to overlap in such a way that first block B1
begins, then B2, but B1 end before B2.
This nesting property is called block structure. The scope of a declaration in a block-
structured language is given by the most closely nested rule:
1. The scope of a declaration in a block B includes B.
2. If a name X is not declared in a block B, then an occurrence of X in B is in the scope
of a declaration of X in an enclosing block B ' such that. B ' has a declaration of X, and. B
' is more closely nested around B then any other block with a declaration of X.
Storage Allocation
The different ways to allocate memory are:
If memory is created at compile time then the memory will be created in static
area and only once.
Static allocation supports the dynamic data structure that means memory is
created only at compile time and deallocated after program completion.
The drawback with static storage allocation is that the size and position of data
objects should be known at compile time.
An activation record is pushed into the stack when activation begins and it is
popped when the activation end.
Activation record contains the locals so that they are bound to fresh storage in
each activation record. The value of locals is deleted when the activation ends.
It works on the basis of last-in-first-out (LIFO) and this allocation supports the
recursion process.
Allocation and deallocation of memory can be done at any time and at any place
depending upon the user's requirement.
Heap allocation is used to allocate memory to the variables dynamically and when
the variables are no more used then claim it back.
Example:
1. fact (int n)
2. {
3. if (n<=1)
4. return 1;
5. else
6. return (n * fact(n-1));
7. }
8. fact (6)
The dynamic allocation is as follows: