Unit 3 - Sessions 7 (B) - 8
Unit 3 - Sessions 7 (B) - 8
COMPILER DESIGN
UNIT 3
SESSION 7 & 8
Topics that will be covered in this Session
• Advantage
• Simplicity
• Powerful enough for expressions in programming languages
• Disadvantage
• It is hard to handle tokens like the minus sign, which has two different precedences (unary
minus and binary minus)
• We cannot be sure that the parser accepts exactly the desired language
• Only a small class of grammars can be parsed using operator-precedence techniques
Precedence Relations
• There are 3 disjoint precedence relations between certain pairs of terminals
+ <. >
.
<. >
.
$ <. id .> + <. id .> * <. id .> $ E id $ id + id * id $
* < .
>
.
>
.
>
.
$ <. + <. id .> * <. id .> $ E id $ E + id * id $
$ <. <. <. $ <. + <. * <. id .> $ E id $ E + E * id $
• Parse the string $ <. + <. * .> $ E E*E $ E + E * .E $
id + id * id $ <. + .> $ E E+E $E+E$
• The given string with the precedence $$ $E$
relations inserted is
$ <. id .> + <. id .> * <. id .> $
Stack Implementation of Operator Precedence Parsing /
Algorithm:- Operator Precedence Parsing
The input string is w$, the initial stack is $ and a table holds precedence relations between certain terminals
Algorithm:
set p to point to the first symbol of w$ ;
repeat forever
if ( $ is on top of the stack and p points to $ ) then return
else {
let a be the topmost terminal symbol on the stack and let b be the symbol pointed to by p;
if ( a <. b or a =· b ) then { /* SHIFT */
push b onto the stack;
advance p to the next input symbol;
}
else if ( a .> b ) then /* REDUCE */
repeat pop stack
until ( the top of stack terminal is related by <. to the terminal most recently popped );
else error();
}
Example – Stack Implementation of Operator Precedence Parsing
• Consider the grammar
E → E+E | E*E | id
• The operator precedence relations are Stack Input Action
defined in the table given below: $ id + id * id $ $ <. id shift
$ id + id * id $ id .> + reduce by E id (Pop)
id + * $
$ + id * id $ $ <. + shift
id >
.
>
.
>
.
$+ id * id $ + <. id shift
+ < .
>
.
< .
>
.
$ + id * id $ id .> * reduce by E id (Pop)
* < .
>
.
>
.
>
.
$+ * id $ + <. * shift
$ <. <. <. $ +* id $ * <. id shift
For a language of arithmetic expressions, operator-precedence relations can be created by using the
associativity and precedence rules as follows:
1. If operator O1 has higher precedence than operator O2,
O1 .> O2 and O2 <. O1
2. If operator O1 and operator O2 have equal precedence,
and if they are left-associative O1 .> O2 and O2 .> O1
if they are right-associative O1 <. O2 and O2 <. O1
3. For all operators O,
O <. id, id .> O, O <. (, (<. O, O .> ), ) .> O, O .> $, and $ <. O
4. Also, let
(=·) $ <. ( id .> ) ) .> $
( <. ( $ <. id id .> $ ) .> )
( <. id
Example – Table Construction
+ .
> .
> <. <. <. <. <. .
> .
> $ * ( ↑ id ) – id / id $ Reduce
$*(↑ ) – id / id $ Reduce
- .
> .
> <. <. <. <. <. .
> .
> $*( ) – id / id $ Shift
* .
> .
> .
> .
> <. <. <. .
> .
> $*()
$*(
– id / id $
– id / id $
Reduce
( =. ) Pop ( also
/ .
> .
> .
> .
> <. <. <. .
> .
> $* – id / id $ Reduce
$ – id / id $ Shift
^ .
> .
> .
> .
> <. <. <. .
> .
> $- id / id $ Shift
id .
> .
> .
> .
> .
> .
> .
> $ - id / id $ Reduce
$ - / id $ Shift
( <. <. <. <. <. < .
<. =· $-/ id $ Shift
) .
> .
> .
> .
> .
> .
> .
> $ - / id $ Reduce
$-/ $ Reduce
$ <. <. <. <. <. < .
<.
$- $ Reduce
$ $ Accept
Handling Unary Operators
• Consider a unary operator such as logical negation, which is not also a binary operator
• Suppose ! is a unary prefix operator, then
• Make θ <. ! for any operator θ
• If ! has higher precedence than θ, make ! .> θ
• If ! has lower precedence than θ make ! <. θ
• The rule for unary postfix operators is analogous
Operators that act as both unary and binary
• In case of operators like minus sign – that is both unary and binary, the best approach is to use
the lexical analyzer to distinguish between unary minus and binary minus by returning
different tokens
• The lexical analyser cannot use lookahead to distinguish the two
• It must remember the previous token
• For example, a minus sign is unary if the previous token was an operator, a left parenthesis, a
comma or an assignment symbol
Precedence Functions
• Compilers using operator-precedence parsers need not store the table of precedence
relations
• In most cases, the table can be encoded by two precedence functions f and g that map
terminal symbols to integers.
• We attempt to select f and g so that, for symbols a and b,
Algorithm for computing Precedence Functions
Input : An operator precedence matrix
Output : Precedence functions f(a) and g(a) representing the input matrix or an indication that
none exist
Method
1. Create symbols and for each a that a terminal or $
2. Partition the created symbols into as many groups as possible, in such a way that
i. If , then and are in the same group
ii. If and then and are in the same group
3. Create a directed graph whose nodes are the groups found in step 2
1. If a<. b, place an edge from and
2. If a.> b, place an edge from and
4. If the graph constructed has a cycle, then no precedence functions exist. If there are no
cycles, let f(a) be the length of the longest path beginning at . Let g(a) be the length of the
longest path from
Example for computing Precedence Functions
Consider the following operator precedence Step 3
matrix
id + * $
id >
. .
> .
>
+ <. >
.
<. .
>
* <. >
. .
> .
>
$ <. <. <.
There are two points in the parsing process at which an operator-precedence parser can discover
syntactic errors
1. If no precedence relation holds between the terminal on top of the stack and the current
input
2. If a handle has been found, but there is no production with this handle as a right side
Error Recovery
4. Decides the popped handle “looks like” which right hand side and tries to recover from
that situation
COMPUTATION OF
LEADING & TRAILING
Constructing Operator Precedence Parsing Table – Method 2
Mechanical way by computing LEADING and TRAILING
Steps Involved
• Ensure that the grammar is an operator grammar
• Compute the function LEADING()
• Compute the function TRAILING
• Construct the Operator Precedence Parsing Table from the functions LEADING and TRAILING
• Compute precedence functions
• Parse the given input string using the table
LEADING and TRAILING
LEADING(A)
• LEADING(A) for a non-terminal A is the set of terminals a such that a is the leftmost terminal in
some string derived from A
• Rule 1 :
• Rule 2 : If there is a production of the form , then add everything in LEADING(B) to LEADING(A)
TRAILING(A)
• TRAILING(A) for a non-terminal A is the set of terminals a that can be the rightmost in a some
string derived from A
• Rule 1 :
• Rule 2 : If there is a production of the form , then add everything in TRAILING(B) to TRAILING(A)
Computation of LEADING and TRAILING – Examples
Example 1 Example 2
Compute LEADING and TRAILING for the Compute LEADING and TRAILING for the
non-terminals in the grammar given below: non-terminals in the grammar given below:
S→(L)|a S→iEtSeS|iEtS|a
L→L,S|S E→b
LEADING(S) = { ( , a } LEADING(S) = { i , a }
LEADING(L) = { , , LEADING(S) } LEADING(E) = { b }
={,,(,a}
TRAILING(S) = { e , t , a }
TRAILING(S) = { ) , a } TRAILING(E) = { b }
TRAILING(L) = { , , TRAILING(S) }
={,,),a}
Computation of LEADING and TRAILING – Examples
Example 3
Compute LEADING and TRAILING for the non-terminals in the grammar given below:
S → L = R| R
L → * R | id
R→L
LEADING(S) = { = , LEADING(L),
TRAILING(S) = { = , TRAILING(R) }
LEADING(R) }
= { = , * , id }
= { = , * , id }
TRAILING(L) = { * , id }
LEADING(L) = { * , id }
TRAILING(R) = { TRAILING(L) }
LEADING(R) = { LEADING(L) }
= { * , id }
= { * , id }
Computation of LEADING and TRAILING – Examples
Example 4
Compute LEADING and TRAILING for the non-terminals in the grammar given below:
→ or |
→ and r |
→ not | ( ) | true | false
The terminals in the grammar are given in bold
) .
> .
> .
> $( )$ Pop
$() $ Pop
, <. <. .
> .
>
$( $ ( = ) Pop (stack top & most
$ <. <. recently popped)
$ $ Accept
Example 2 Stack Input Action
Construct operator precedence parsing table for the $ * id = id $ Shift
grammar given below and parse the strings *id=id and
$* id = id $ Shift
id*id=id
S → L = R| R $ * id = id $ Pop
L → * R | id $* = id $ Pop
R→L $ = id $ Shift
$= id $ Shift
Find LEADING and TRAILING $ = id $ Pop
LEADING(S) = { = , * , id } $= $ Pop
LEADING(L) = { * , id } $ $ Accept
LEADING(R) = { * , id }
= * id $
= <. <. .
> Stack Input Action
* .
> <. <. .
> $ id * id = id $ Shift
id .
> .
>
$ id * id = id $ Error
$ <. < .
< .