0% found this document useful (0 votes)
20 views30 pages

CD Unit-4 LM

This document covers semantic analysis and runtime environment in programming languages, focusing on syntax-directed translation, symbol table organization, and storage allocation strategies. It discusses semantic rules, symbol tables, and various storage methods, including static and stack allocation. Learning outcomes include understanding syntax-directed translation and symbol table organization for both block and non-block structured languages.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views30 pages

CD Unit-4 LM

This document covers semantic analysis and runtime environment in programming languages, focusing on syntax-directed translation, symbol table organization, and storage allocation strategies. It discusses semantic rules, symbol tables, and various storage methods, including static and stack allocation. Learning outcomes include understanding syntax-directed translation and symbol table organization for both block and non-block structured languages.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

UNIT – IV

Semantic Analysis and Runtime Environment

Objectives

To gain knowledge on syntax directed translation ,symbol table organization for languages and various
storage allocation strategies

Syllabus

Semantic analysis, SDT, evaluation of semantic rules.


Symbol tables- Use of symbol tables, contents of symbol-table, operations on symbol tables, symbol table
organization for block and non-block structured languages.
Runtime Environment- Storage organization- static, stack allocation, access to non-local data, heap
management.

Learning Outcomes:

Students will be able to

 Understand syntax-directed translation.


 Understand symbol table organization for the block structured and non-block structured languages.
 Understand various storage allocation strategies.

Learning Material

Semantic Analysis

 Semantic analysis is the task of ensuring that the declarations and statements of a program are
semantically correct, i.e that their meaning is clear and consistent with the way in which control
structures and data types are supposed to be used.
 A compiler must check that the source program follows both the syntactic and semantic conventions
of the source language.
 This checking called static checking ensures that certain kinds of programming errors will be detected
and reported.

Input string parse tree dependency graph evaluation order for


semantic rules
Conceptual view of syntax directed translation

a+b*c , int a,b,c;

CFG

ATTRIBUTE THE GRAMMAR(S-ATTRIBUTED/L-ATTRIBUTED)

WRITE SYNTAX DIRECTED DEFINITIONS

CONSTRUCT ANOTATED PARSE TREE

DRAW DEPENDANCY GRAPH

EVALUATE USING
TREE TRAVERSAL TECHNIQUE
(PREORDER/POSTORDER/INORDER/
DEPTH FIRST SEARCH)

FINAL RESULT

Syntax-Directed Definitions and Translation Schemes


When we associate semantic rules with productions, we use two notations:
– Syntax-Directed Definitions
– Translation Schemes

Syntax-Directed Definitions (SDD’s):

 A syntax-directed definition is a generalization of a context-free grammar in which:


o Each grammar symbol is associated with a set of attributes.
o This set of attributes for a grammar symbol is partitioned into two subsets called
 synthesized and
 inherited attributes of that grammar symbol.
o Each production rule is associated with a set of semantic rules.
 A syntax directed definition specifies the values of attributes by associating semantic rules with the
grammar productions
 SDD’s hide many implementation details such as order of evaluation of semantic actions.
 The value of a synthesized attribute at a node is computed from the values of attributes at the
children in that node of the parse tree
 The value of an inherited attribute at a node is computed from the values of attributes at the
siblings and parent of that node of the parse tree
 In a syntax-directed definition, a semantic rule may just evaluate a value of an attribute or it may
have some side effects such as printing values.
An attribute may hold almost anything i.e. a string, a number, a memory location, a complex record.
Attribute Grammar
• An attribute grammar is a syntax-directed definition in which the functions in the semantic rules
cannot have side effects (they can only evaluate values of attributes).
Examples:

E→E1+E2 {E.val =E1.val + E2.val} Here val is a Synthesized attribute

A→XYZ {Y.val = 2 * A.val} Here val is a Inherited attribute

1. Semantic rules set up dependencies between attributes which can be represented by a dependency
graph.
2. This dependency graph determines the evaluation order of these semantic rules.
Example:

Write SDD for a simple Desk Calculator grammar.

Production Semantic Rules

L→En print(E.val)
E → E1 + T E.val = E1.val + T.val
E→T E.val = T.val
T → T1 * F T.val = T1.val * F.val
T→F T.val = F.val
F→(E) F.val = E.val
F → digit F.val = digit.lexval

 Symbols E, T, and F are associated with a synthesized attribute val.


 The token digit has a synthesized attribute lexval (it is assumed that it is evaluated by
the lexical analyzer).
 Terminals are assumed to have synthesized attributes only. Values for attributes of
terminals are usually supplied by the lexical analyzer.
 The start symbol does not have any inherited attribute unless otherwise stated.

S-attributed definition

• A syntax directed translation that uses synthesized attributes exclusively is said to be a S-attributed
definition.
• An SDD is S-attributed if every attribute is synthesized.
• A parse tree for a S-attributed definition can be annotated by evaluating the semantic rules for the
attributes at each node, bottom up from leaves to the root.
• We can have a post-order traversal of parse-tree to evaluate attributes in S-attributed definitions
postorder(N)
{
for (each child C of N, from the left) postorder(C);
evaluate the attributes associated with node N;
}
• S-Attributed definitions can be implemented during bottom-up parsing without the need to explicitly
create parse trees
Annotated Parse Tree
1. A parse tree showing the values of attributes at each node is called an annotated parse tree.
2. Values of Attributes in nodes of annotated parse-tree are either,
– initialized to constant values or by the lexical analyzer.
– determined by the semantic-rules.
3. The process of computing the attributes values at the nodes is called annotating (or decorating) of
the parse tree.
4. The order of these computations depends on the dependency graph induced by the semantic rules.
Example

Evaluation orders for SDD’s

• A dependency graph is used to determine the order of computation of attributes


• Dependency Graph
Directed Graph
Shows interdependencies between attributes.

– Put each semantic rule into the form b=f(c1,…,ck) by introducing dummy synthesized attribute
b for every semantic rule that consists of a procedure call.
– The graph has a node for each attribute and an edge to the node for b from the node for c if
attribute b depends on attribute c
– If a semantic rule defines the value of synthesized attribute A.b in terms of the value of X.c
then the dependency graph has an edge from X.c to A.b
– If a semantic rule defines the value of inherited attribute B.c in terms of the valueof X.a then
the dependency graph has an edge from X.a to B.c
• If an attribute b at a node depends on an attribute c, then the semantic rule for b at that node must be
evaluated after the semantic rule that defines c.
Dependency Graph Construction

Production Semantic Rule

E→E1 + E2 E.val = E1.val + E2.val

E . val

E1. Val + E2 . val

• E.val is synthesized from E1.val and E2.val


• The dotted lines represent the parse tree that is not part of the dependency graph.
Dependency Graph

Inherited attributes

• An inherited value at a node in a parse tree is defined in terms of attributes at the parent and/or
siblings of the node.
• Convenient way for expressing the dependency of a programming language construct on the context
in which it appears.
• Example: The inherited attribute distributes type information to the various identifiers in a
declaration.
Syntax-Directed Definition – Inherited Attributes

Production Semantic Rules

D→TL L.in = T.type


T → int T.type = integer
T → real T.type = real
L → L1 id L1.in = L.in, add type (id.entry,L.in)
L → id addtype(id.entry,L.in)

1. Symbol T is associated with a synthesized attribute type.


2. Symbol L is associated with an inherited attribute in.
L-Attributed definitions

• A SDD is L-Attributed if the edges in dependency graph goes from Left to Right but not from Right
to Left.
• More precisely, each attribute must be either
– Synthesized
– Inherited, but if there is a production A->X1X2…Xn and there is an inherited attribute Xi.a
computed by a rule associated with this production, then the rule may only use:
• Inherited attributes associated with the head A
• Either inherited or synthesized attributes associated with the occurrences of symbols
X1,X2,…,Xi-1 located to the left of Xi
• Inherited or synthesized attributes associated with this occurrence of Xi itself, but in
such a way that there is no cycle in the graph
Annotated parse tree

Input: real p,q,r

parse tree annotated parse tree

D D

T L

T.type=real L1.in=real

real L , id3

real L1.in=real , id3

L , id2

id1 L1.in=real , id2

id1

Evaluation Order

 A topological sort of a directed acyclic graph is any ordering m1,m2…mk of the nodes of the graph
such that edges go from nodes earlier in the ordering to later nodes.
. i.e if there is an edge from mi to mj them mi appears before mj in the ordering
 Any topological sort of dependency graph gives a valid order for evaluation of semantic rules
associated with the nodes of the parse tree.
– The dependent attributes c1,c2….ck in b=f(c1,c2….ck ) must be available before f is
evaluated.
 Translation specified by Syntax Directed Definition
Dependency Graph

Translation Schemes:
• A translation scheme is a context-free grammar in which:
– attributes are associated with the grammar symbols and
– semantic actions enclosed between braces {} are inserted within the right sides of
productions.
Each semantic rule can only use the information compute by already executed semantic rules.
• Ex: A → { ... } X { ... } Y { ... }

Semantic Actions

– indicate the order of evaluation of semantic actions associated with a production rule.
– In other words, translation schemes give a little bit information about implementation details.
• Translation schemes describe the order and timing of attribute computation.
Translation Schemes for S-attributed Definitions
• useful notation for specifying translation during parsing.
• Can have both synthesized and inherited attributes.
• If our syntax-directed definition is S-attributed, the construction of the corresponding translation
scheme will be simple.
• Each associated semantic rule in a S-attributed syntax-directed definition will be inserted as a
semantic action into the end of the right side of the associated production.
Production Semantic Rule

E → E1 + T E.val = E1.val + T.val a production of a syntax directed definition


E → E1 + T {E.val = E1.val + T.val} the production of the corresponding translation scheme

Example

• A simple translation scheme that converts infix expressions to the corresponding postfix expressions.
E→TR
R → + T { print(“+”) } R1
R→ε
T → id { print(id.name) }
a+b+c ab+c+

infix expression postfix expression

Application of Syntax Directed Translation

• Type checking
• intermediate code generation (chapter 6)
• Construction of syntax trees
– Leaf nodes: Leaf(op,val)
– Interior node: Node(op,c1,c2,…,ck)

SYMBOL TABLE ORGANIZATION


 A symbol table is a series of rows, each row containing a list of attribute values that are associated
with a particular variable.
 The kinds of attributes appearing in a symbol table are dependent to some degree on the nature of the
programming language for which the compiler is written.
 The organization of the symbol table will vary depending on memory and access-time constraints.
 The primary measure which is used to determine the complexity of a symbol-table operation is the
average length of search.
 This measure is the average number of comparisons required to retrieve a symbol-table record in a
particular table organization.
 The collection of attributes stored in the table for a given variable will be called a symbol-table
record.
 The name of the variable for which an insertion or lookup operation is to be performed will be
referred to as the search argument.

Symbol-Table Contents
The following list of attributes are not necessary for all compilers.
1. Variable name
2. Object-code address
3. Type
4. Dimension or number of parameters for a procedure
5. Source line number at which the variable is declared
6. Source line numbers at which the variable is referenced
7. Link field for listing in alphabetical order

Variable Line Lines


Address Type Dimension Pointer
Name Declared Referenced
»
1 COMPANY# 0 2 2 9, 14,25 7
1

2 X3 4 1 0 3 12,14 0

3 FORM 1 8 3 2 4 36,37,38 6

10, 11,13,
4B 48 1 0 5 1
23

5 ANS 52 1 0 5 11,23,25 4

6M 56 6 0 6 17,21 2

28, 29, 30,


7 FIRST 64 1 0 7 3
38

A second approach is to place a string descriptor in the variable-name field of the table. The
descriptor contains position and length subfields. The pointer subfield indicates the position of the first
character of the variable name in a general string area, and the length subfield describes the number of
characters in the variable name.
Using a string descriptor to represent a variable name.

Operations On Symbol Tables


 The two operations that are most commonly performed on symbol tables are insertion and lookup
(also referred to as retrieval).
 For languages in which explicit declaration of all variables is mandatory, the two operations are
invoked at clearly defined points in the compilation.
 When a programming language permits implicit declarations of variables, the operations of
insertion and retrieval are closely linked.
 For block-structured languages, two additional operations, which we denote as set and reset, are
required for symbol-table interaction.
• The set operation is invoked when the beginning of a block is recognized during
compilation.
• The complementary operation, the reset operation, is applied when the end of a block
is encountered.
Symbol-Table Organizations For Non-Block-Structured Language
By a non-block-structured language we mean a language in which each separately compiled unit is a single
module that has no sub modules. All variables declared in a module are known throughout the module.
The symbol table organizations for non block structured languages are:
 Unordered Symbol Tables
 Ordered Symbol Tables
 Tree Structured Symbol Table
 Hash Symbol Tables

Unordered Symbol Tables


 The simplest method of organizing a symbol table is to add the attribute entries to the table in the
order in which the variables are declared.
 In an insertion operation no comparisons are required (other than checking for symbol-table
overflow), since the attributes for a newly defined variable are simply added at the current end of the
table.
 The lookup operation requires, on the average, a search length of (n + l)/2, assuming that there are n
records in the table.
 An unordered table organization should be used only if the expected size of the symbol table is small,
since the average time for lookup and insertion is directly proportional to the table size.
Ordered Symbol Tables
An ordered symbol table is lexically ordered on the variable names. While a number of table-lookup
strategies can be applied to such a table organization, we will examine the two most popular search
techniques: the linear search and the binary search.
Type
Variable
Dimension Other Attributes
Name

ANS 1 0

B 1 0

COMPANY* 2 1

FIRST 1 0

FORM1 3 2

M 6 0

X3 1 0

Figure 8-7 An ordered symbol table.


One major advantage is that the ordered symbol table can be used in the direct generation of a
cross-reference listing, whereas an unordered table would have to be sorted before printing such a listing.
Tree-Structured Symbol Tables
o The time to perform a table-insertion operation can be reduced from that of an ordered table
by using a tree-structured type of storage organization.
o In this type of organization an attempt is made to reflect the search structure of the binary
search in the structural links of a binary-search tree.
o A binary tree-structured symbol table that contains the two new fields are present in a
record structure.
o These two link fields will be called the left pointer and right pointer fields. Access to the tree
is gained through the root node (i.e., the top node of the tree).
o A search proceeds down the structural links of the tree until the desired node is found or a
NULL link field (denoted by /) is encountered. The search is unsuccessful, since a match
between the search argument and the names in the table is not achieved.

Binary-tree organization of a symbol table showing the logical relationships


Table Left Right
Name Field Type Dimension Other Attributes
Position Pointer Pointer
....... !'
1 FIRST 1 0 5
2

2 B 1 0 3 4

3 ANS 1 0 0 0

COMPANY
4 2 1 0 0
#

5 M 6 0 6 7

6 F0RM1 3 2 0 0

7 X3 1 0 0 0

(6)

Binary-tree organization of a symbol table showing a physical representation.


A major problem exists with the binary tree organization is an insertion always takes place at the
leaves of the tree, a search tree can become very unbalanced.
To avoid the problem in unbalanced binary tree can be avoided by optimally balanced binary
tree.
Hash Symbol Tables
 The best search methods for the symbol-table organizations had an average length of search
requiring on the order of log2n comparisons.
 An organization in which the search time is essentially independent of the number of records in the
table (i.e., the search time is constant for any n).
 The name space (also called identifier space or key space) is the set K of unique variable names
that can appear in a program.
 For example, in FORTRAN, the name space is the set of one to six character identifiers each of
which begins with a letter and consists of letters and digits.
 The address space (or table space) A is the set of record locations {1,2,…, m) in a table.
 A hashing function (or key-to-address transformation) is defined as a mapping

That is, a hashing function H takes as its argument a variable name and
produces a table address (i.e., location) at which the set of attributes for that variable are stored. The
function generates this address by performing some simple arithmetic or logical operations on the
name or some part of the name.
 The most widely accepted hashing function is the division method, which is defined as H(x) =(x
mod m)+1 for divisor m.
 A second hashing function that performs reasonably well is the midsquare hashing-method. In this
method, a key is multiplied by itself and an address is obtained by truncating bits or digits at both
ends of the product until the number of bits or digits left is equal to the desired address length.
 For the folding method, a key is partitioned into a number of parts, each of which has the same
length as the required address with the possible exception of the last part. The parts are then added
together, ignoring the final carry, to form an address. If the keys are in binary form, the exclusive-or
operation may be substituted for addition.
 Another hashing technique, referred to as a length-dependent method is used commonly in
symbol-table handling. In this approach, the length of the variable name is used in conjunction with
some subpart of the name to produce either a table address directly or, more commonly, an
intermediate key which is use.
Figure 8-24 Hashing using a hash table.
Two records cannot occupy the same location, and therefore some method must be used to resolve the
collisions that can result. There are basically two collision-resolution techniques: open addressing and
separate chaining.

Symbol-Table Organizations For Block-Structured Languages


 By a block-structured language we mean a language in which a module can contain nested sub
modules and each sub module can have its own set of locally declared variables.
 A variable declared within a module A is accessible throughout that module unless the same
variable name is redefined within a sub module of A.
 The redefinition of a variable holds throughout the scope (i.e., physical limits) of the sub
module.
Block-Structured Language Concepts
The two additional symbol-table operations, set and reset, were introduced for block-structured
languages.

A program segment from a nested language.

A trace showing the effects of the set and reset operations


Symbol-table contents (variable name only)
Operation
Active Inactive
Set BLK.1 empty Empty

Set BLK2 Ml, NAME, Y, X Empty


Reset BLK2 X, IND, Ml, NAME, Y, X Empty

Set BLK3 M2, Ml, NAME, Y, X X, IND

Set BLK4 J, M2, Ml, NAME, Y, X X, IND

TEST1, F, J, M2, Ml, NAME,


Reset BLK4 X, IND
Y, X

Reset BLK3 J, M2, Ml, NAME, Y, X TEST1, F, X, IND

Reset BLK1 M2, Ml, NAME, Y, X J, TEST1, F, X, IND

End of M2, Ml, NAME. Y.


empty
compilation X. J.

TEST1, F, X, IND

Stack Symbol Tables


 The conceptually simplest symbol-table organization for a block-structured language is the
stack symbol table.
 In this organization the records containing the variables’ attributes are simply stacked as the
declarations are encountered.
 Upon reaching the end of a block, all records for variables declared in the block are removed
since these variables cannot be referenced outside the block.
Example of a stack symbol table.
 The insertion operation is very simple in a stack symbol table. New records are added at the
top location in the stack.
 The lookup operation involves a linear search of the table from the top to the bottom. The
search must be conducted in this order to guarantee that the latest occurrence of a variable
with a particular name is located first..
 The set operation for a stack symbol table generates a new block index entry at the top of the
block index structure. This entry is assigned the value of the current top of the symbol stack
and therefore establishes a pointer to the first record location for a record in the block just
entered.
 The reset operation effectively removes all the records in the stack symbol table for the
block just compiled. This is accomplished by setting TOP, the index pointing at the first open
record location at the top of the symbol table, to the value of the top element in the block
index.
 The stack symbol table also suffers from the same poor performance characteristics
Stack-Implemented Tree-Structured Symbol Tables
 The two possible approaches for organizing a symbol table using a tree-structured
organization:
 The first approach involves a single tree organization. The major difference that arises when
the compilation of block-structured languages is considered is the fact that records for a block
must be removed from the table when the compilation of the block is completed. As a result,
the problem of deleting table records must be addressed. Since the records for all blocks are
merged in one tree, a number of steps are necessary in order to delete a record:
1. Locate the position of the record in the tree.
2. Remove the record from the tree by altering the structural links so as to bypass
the record.
3. Rebalance the tree if the deletion of the record has left the tree unbalanced.
 A second organization which we will call a forest of trees is amenable to the problem of
deleting records. In this organization each block is allocated its own tree-structured table.
When the compilation of a block is finished, the entire table associated with that block is
released.
Figure 8-27 Example of a stack-implemented, tree-structured symbol table.
Stack-Implemented Hash-Structured Symbol Tables
 Initially, it may appear that it is difficult to apply a hashing scheme to a symbol table for a
block-structured language.
 Because hashing is, in general, a non-order-preserving transformation and because block-
structured languages require that the variables in a block be grouped in some manner, it would
seem that a hashing methodology and a symbol-table organization for block-structured
languages are incompatible.
 The use of an intermediate hash table, as discussed in Sec. 8-5.4, hashing can be used in a
relatively straightforward manner.
 Figure 8-28 depicts a symbol-table organization for the program segment in Fig. 8-25,
assuming a hashing function which performs the following transformations:
the names X and M1 are mapped to 1
the name NAME is mapped to 3
the names IND and J are mapped to 5
the name TEST1 is mapped to 6
the names F and Y are mapped to 8
the name M2 is mapped to 11
 An intermediate hash table of size 11 is used in the example.
 The insert and lookup operations for stack-implemented hash symbol tables are essentially the
same
 The expected length of search may be slightly less than for the hash symbol table for non-block-
structured languages because local variables are deleted as blocks are compiled in a block-structured
language.
 The set operation again involves a simple update to the block index. When a new block is
recognized during compilation, the block index is set to the value of TOP, the index pointing to the
top location in the symbol table.
 The reset operation is, much more complicated. When a block has been compiled, its associated
records must be removed, either logically or physically, from the active part of the symbol table. The
logical deletion of a record requires that the variable name be hashed to generate a hash-table location
and that the collision chain associated with the hash-table location be altered so as to remove the
record.

Figure 8-28 Example of a stack-implemented hash symbol table.


Runtime Environment

 The compiler creates and manages a run-time environment in which it assumes its target
programs are being executed.
 This environment deals with a variety of issues such as the layout and allocation of storage
locations for the objects named in the source program, the mechanisms used by the target
program to access variables, the linkages between procedures, the mechanisms for passing
parameters, and the interfaces to the operating system, input/output devices, and other
programs.
Storage Organization

The executing target program runs in its own logical address space in which each program value has a
location. The management and organization of this logical address space is shared between the compiler,
operating system, and target machine. The operating system maps the logical addresses into physical
addresses, which are usually spread throughout memory.

Typical subdivision of run-time memory into code and data areas

Static versus Dynamic Storage Allocation


The layout and allocation of data to memory locations in the run-time environment are key issues in storage
management.
Two types of storage allocations:
1) Static storage allocation
2) Dynamic storage allocation
Static Storage Allocation:
 A storage-allocation decision is static, if it can be made by the compiler looking only at the text of the
program, not at what the program does when it executes.
 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.
 Since the bindings do not change at run time, every time a procedure is activated its names are bound
to the same storage locations.
 The compiler must eventually decide where the activation records go, relative to the target code.
 Fortran was designed to permit static storage allocation.

Limitations of Static Allocation


 The size of a data object and constraints on its position in memory must be known at compile time.
 Recursive procedures are restricted, because all activation of a procedure use the same bindings for
local names.
 Data structures cannot be created dynamically, since there is no mechanism for storage allocation at
run time.
Dynamic Storage Allocation:
A storage allocation decision is dynamic if it can be decided only while the program is running.
There are two strategies for dynamic storage allocation:
Stack storage allocation:
 Static allocation manages the run time storage as a stack.
 Stack allocation is based on the idea of a control stack.
 Activation records are pushed and popped as activation begin and end.
 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.
 Almost all compilers for languages that use procedures, functions, or methods as units of user-defined
actions manage at least part of their run-time memory as a stack.
 Each time a procedure is called, space for its local variables is pushed onto a stack, and when the
procedure terminates, that space is popped off the stack.
Activation Records
 Procedure calls and returns are usually managed by a run-time stack called the control stack.
 Each live activation has an activation record (sometimes called a frame) on the control stack, with the
root of the activation tree at the bottom, and the entire sequence of activation records on the stack
corresponding to the path in the activation tree to the activation where control currently resides. The
latter activation has its record at the top of the stack.
The contents of activation records vary with the language being implemented

A general activation record

1. Temporary values, such as those arising from the evaluation of expressions, in cases where those
temporaries cannot be held in registers.
2. Local data belonging to the procedure whose activation record this is.
3. A saved machine status, with information about the state of the machine just before the call to the
procedure. This information typically includes the return address (value of the program counter, to which the
called procedure must return) and the contents of registers that were used by the calling procedure and that
must be restored when the return occurs.
4. An "access link" may be needed to locate data needed by the called procedure but found elsewhere, e.g.,
in another activation record.
5. A control link, pointing to the activation record of the caller.
6. Space for the return value of the called function, if any. Again, not all called procedures return a value,
and if one does, we may prefer to place that value in a register for efficiency.
7. The actual parameters used by the calling procedure. Commonly, these values are not placed in the
activation record but rather in registers, when possible, for greater efficiency.
Example:

Sketch of a quicksort program


Activation Tree
We can represent the activations of procedures during the running of an entire program by a tree,
called an activation tree.
Each node corresponds to one activation, and the root is the activation of the "main" procedure that
initiates execution of the program.
At a node for an activation of procedure p, the children correspond to activations of the procedures
called by this activation of p.
We show these activations in the order that they are called, from left to right. Notice that one child
must finish before the activation to its right can begin.
The use of a run-time stack is enabled by several useful relationships between the activation tree and
the behavior of the program:
1. The sequence of procedure calls corresponds to a preorder traversal of the activation tree.
2. The sequence of returns corresponds to a postorder traversal of the activation tree.
3. Suppose that control lies within a particular activation of some procedure, corresponding to a node N of
the activation tree. Then the activations that are currently open (live) are those that correspond to node N and
its ancestors. The order in which these activations were called is the order in which they appear along the
path to N, starting at the root, and they will return in the reverse of that order.

Activation tree representing calls during an execution of quicksort


Downward-growing stack of activation records

Variable-Length Data on the Stack


 The run-time memory-management system must deal frequently with the allocation
of space for objects the sizes of which are not known at compile time,but which are local to a
procedure and thus may be allocated on the stack.
 A common strategy for allocating variable-length arrays (i.e., arrays whosesize depends on the value
of one or more parameters of the called procedure) is shown in fig

Access to dynamically allocated arrays


 Procedure p has three local arrays, whose sizes we suppose cannot be determined at compile time.
The storage for these arrays is not part of the activation record for p, although it does appear on the
stack. Only a pointer to the beginning of each array appears in the activation record itself. Thus, when
p is executing, these pointers are at known offsets from the top-of-stack pointer, so the target code
can access array elements through these pointers.
 Fig shows the activation record for a procedure q, called by p. The activation record for q begins after
the arrays of p, and any variable-length arrays of q are located beyond that.
 Access to the data on the stack is through two pointers, top and top-sp. Here, top marks the actual top
of stack; it points to the position at which the next activation record will begin. The second, top-sp is
used to find local, fixed-length fields of the top activation record.
Access to Nonlocal Data on the Stack
Stack allocation of activation record and heap allocation of activation records are same to access
non local data.
There are two ways of finding the activation records containing the storage bound to nonlocal names:
access links and displays
Access links:
A direct implementation of lexical scope for nested procedures is obtained by adding a pointer called
access link to each activation record. If procedure p is nested immediately within q in the source text, then
the access link in an activation record for p points to the access link the record for the most recent activation
of q.

Displays:
Faster access to nonlocals than with access links can be obtained using an array d of pointers to
activation records, called a display. We maintain the display so that storage for a nonlocal a at nesting depth
i is in the activation record pointed to by display element d[i].

Maintaining the display when procedures are not passed as parameters


Heap storage:
 Data that may outlive the call to the procedure that created it is usually allocated on a "heap" of
reusable storage.
 The heap is an area of virtual memory that allows objects or other data elements to obtain storage
when they are created and to return that storage when they are invalidated.
 To support heap management, "garbage collection" enables the run-time system to detect useless data
elements and reuse their storage, even if the programmer does not return their space explicitly.
 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
shrinkdynamically and unexpectedly. Therefore, they cannot be provided with a fixed amount of
memory in the system.
 For example, both C + + and Java give the programmer new to create objects that may be passed —
or pointers to them may be passed — from procedure to procedure, so they continue to exist long
after the procedure that created them is gone. Such objects are stored on a heap.
Advantages:
The stack allocation strategy cannot be used if either of the following is possible:
1. The values of local names must be retained when activation ends.
2. A called activation outlives the caller. This possibility cannot occur for those languages where activation
trees correctly depict the flow of control between the procedures.

Records for live activations need not be adjacent in a heap


Assignment-Cum-Tutorial Questions

A. Questions testing the understanding / remembering level of students


I) Objective Questions
1. If a parent node takes a value from its children is called ____________attributes.
2. Every S-attributed definition is L-attributed definition. [True | False]
3. A programming language which allows recursion can be implemented with static storage allocation.
[True | False]
4. The interdependencies among attributes are shown by ________________ graph.
5. Symbol Table can be used for:
a. Checking type compatibility
b. Suppressing duplication of error message
c. Storage allocation
d. All of these
6. The two basic operations that are often performed in the symbol table are [ ]
a. Set and reset
b. Insert and lookup
c. Set and insert
d. Reset and lookup
7. In ordered symbol tables, the entries in the table are lexically ordered on the [ ]
a. Variable names
b. variable size
c. variable type
d.All of the above
8. Information needed by a single execution of a procedure is managed using a contiguous block of
storage called_________________.
9. The static binding occurs during: [ ]
a. Compile time
b.Run time
c. Linking time
d.Pre-processing time
10. The dynamic binding occurs during the: [ ]
a. Compile time
b.Run time
c. Linking time
d.Pre-processing time.
11. Type checking is normally done during [ ]
a. Lexical analysis b. Synatx analysis
c. Syntax directed translation d. Code generation

II) Descriptive Questions


1. Define synthesized and inherited attributes with an example.
2. Explain S-attributed definition and L-attributed definition with an example.
3. Describe the contents of symbol table.
4. Explain the operations on symbol tables for block-structured languages.
5. Explain various fields of an activation record.
6. Define static and dynamic storage allocation.
B. Question testing the ability of students in applying the concepts.
I) Multiple Choice Questions:
1. A shift reduce parser carries out the actions specified within braces immediately after reducing with
the corresponding rule of grammar [ ]
S----> xxW ( PRINT "1")
S----> y { print " 2 " }
S----> Sz { print " 3 " )
What is the translation of xxxxyzz using the syntax directed translation scheme described by the
above rules ?
a. 23131 b. 11233 c. 11231 d. 33211

2. Consider the following Syntax Directed Translation Scheme (SDTS),with nonterminals


{ S,A} and terminals {a ,b} [ ]
S->aA {print 1}
S->a {print 2}
A->Sb {print 3}
Using the above SDTS, the output printed by a bottom-up parser for the input aab is

a. 1 3 2 b. 2 2 3 c. 2 3 1 d Syntax error

3. A->BC {B.s=A.s} [ ]
a. S-attributed b. L-attributed c. Both d. None

4. Consider the following translation scheme.

S → ER
R → *E {print(“*”);}R | ε
E→F+E {print(“+”);} | F
F → (S) | id {print(id.value);}
Here id is a token that represents an integer and id.value represents the corresponding integer value.
For an input ‘2 * 3 + 4′, this translation scheme prints [ ]

a. 2 * 3 + 4 b. 2 * +3 4 c. 2 3 * 4 + d. 2 3 4+*

5. Which languages necessarily need heap allocation in the runtime environment? [ ]


a. Those that support recursion
b. Those that use dynamic scoping
c. Those that allow dynamic data structures
d. Those that use global variables

6. Synthesized attribute can be easily simulated by a [ ]


a. LL grammar
b.Ambiguous grammar
c. LR grammar
d.None of the above
7. A parse tree is an annotated parse tree if: (J-2008) [ ]
a. it shows attribute values at each node.
b.there are no inherited attributes.
c. it has synthesized nodes as terminal nodes.
d.every non-terminal nodes is an inherited attribute.

8. Consider the following Syntax Directed Translation Scheme (SDTS),with non terminals {
E,T,F} and terminals {2,4} [ ]

E->E*T {E.VAL=E.VAL*T.VAL;}
E->T {E.VAL=T.VAL;}
T->F-T {T.VAL=F.VAL-T.VAL;}
T->F {T.VAL=F.VAL;}
F->2 {F.VAL=2;}
F->4 {F.VAL=4;}
Using the above SDTS, the total number of reductions done by a bottom-up parser
for the input 4-2-4*2 is
a. 10 b. 9 c. 11 d 13

9. A->LM {L.i=f(A.i);M.i=f(L.S); A.S=f(M.S);} [ ]


A->QR {R.i=f(A.i); Q.i=f(R.i); A.S=f(Q.S);}
a. S-attributed b. L-attributed c. both d. none

II) Problems

1. Construct the syntax-directed definition for simple desk calculator grammar.


2. Construct an annotated parse tree according to the SDD For the input expression (4*7+1)*2.
L->En print(E.val)
E->E1 + T E.val=E1.val + T.val
E->T E.val=T.val
T->T1*F T.val=T1.val*F.val
T->F T.val=F.val
F->(E) F.val=E.val
F->digit F.val=digit.lexval
3. Construct an SDD to covert an infix notation into postfix notation.
4. Build tree-structured symbol tables for the below code
#include <stdio.h>
void main()
{
int firstNumber, secondNumber, sumOfTwoNumbers;
printf("Enter two integers: ");
scanf("%d %d", &firstNumber, &secondNumber);
sumOfTwoNumbers = firstNumber + secondNumber;
printf("%d + %d = %d", firstNumber,secondNumber,sumOfTwoNumbers);
}

5. Construct the ordered symbol table for the language


#include <stdio.h>
#include <math.h>
int main()
{
double a, b, c, determinant, root1,root2, realPart, imaginaryPart;
printf("Enter coefficients a, b and c: ");
scanf("%lf %lf %lf",&a, &b, &c);
determinant = b*b-4*a*c;
if (determinant > 0)
{
root1 = (-b+sqrt(determinant))/(2*a);
root2 = (-b-sqrt(determinant))/(2*a);
printf("root1 = %.2lf and root2 = %.2lf",root1 , root2);
}
else if (determinant == 0)
{
root1 = root2 = -b/(2*a);
printf("root1 = root2 = %.2lf;", root1);
}
else
{
realPart = -b/(2*a);
imaginaryPart = sqrt(-determinant)/(2*a);
printf("root1 = %.2lf+%.2lfi and root2 = %.2f-%.2fi",
realPart, imaginaryPart, realPart, imaginaryPart);

}
6. Construct annotated parse tree according to the SDD for the input string 1011
N->L {N.C=L.C}
L->L,B {L.C=L,.C+B.C}
L->B {L.C=B.C}
B->0 {B.C=0}
B->1 {B.C=1}
7. Construct annotated parse tree according to the SDD for the input string 2+3*4
E->E1+T {E.nptr=mknode(E1.nptr,+,T.npr);}
E->T {E.nptr=T.nptr;}
T->T1*F {T.nptr=mknode(T1.nptr,*,F.nptr);}
T->F {T.nptr=F.nptr}
F->id {F.nptr=mknode(null,id.name,null);}

8.Contruct activation tree for the following program


#include<stdio.h>
int fact(int);
int main( )
{
int num,f;
printf("\nEnter a number: ");
scanf("%d",&num);
f=fact(num);
printf("\nFactorial of %d is: %d",num,f);
return 0;
}
int fact(int n){
if(n==1)
return 1;
else
return(n*fact(n-1));
}
C. Questions testing the analyzing / evaluating ability of students
1. Compare stack and heap allocation strategies.
2. Distinguish between static and dynamic storage allocation strategies.

D.GATE/NET/SLET
1. Consider the grammar with the following translation rules and E as the start symbol.

E -> E1 #T {E.value = E1.value * T.value}

| T {E.value = T.value}

T -> T1 & F {T.value = T1.value + F.value}

|F {T.value= F.value}

F -> num {F.value = num.value}

Compute E.value for the root of the parse tree for the expression: 2 # 3 & 5 # 6 &4. [ ]
(GATE CS 2004)
a. 200
b. 180
c. 160
d. 40
2. Consider the program given below, in a block-structured pseudo-language with lexical scoping and
nesting of procedures permitted. [ ](Gate 2012)

Program main;
Var ...
Procedure A1;
Var ...
Call A2;
End A1
Procedure A2;
Var ...
Procedure A21;
Var ...
Call A1;
End A21
Call A21;
End A2
Call A1;
End main.
Consider the calling chain: Main →→ A1 →→ A2 →→ A21 →→ A1

The correct set of activation records along with their access links is given by

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy