You are on page 1of 8

A BRIEF DISCRIPTION ON

OPERATOR PRECEDENCE GRAMMER


As a submission of semester-3 term work for ,

Subject: SYSTEM SOFTWARE

BY,

Roll No.: Name:

4 Bhatt Krutarth

23 Bhavsar Nirali

31 Gandhi Monil

32 Damani Krish

46 Thakkar Ashish

Supported by:

Prof. Tinal Parikh


Introduction:
An operator precedence grammar is a kind of context-free grammar
that can be parsed with an operator-precedence parser.

It has the property that no production has either an empty right-hand


side or two adjacent non-terminals in its right-hand side.

These properties allow the terminals of the grammar to be described


by a precedence relation, and the a parser that exploits that relation is
considerably simpler than more general-purpose parsers such as
LALR parsers.

Operator Precedence Parsing

1. Precedence Relations

Bottom-up parsers for a large class of context-free grammars can be


easily developed using operator grammars.

Operator grammars have the property that no production right side is


empty or has two adjacent non-terminals. This property enables the
implementation of efficient operator-precedence parsers. These parser
rely on the following three precedence relations:

Relation Meaning
a <• b a yields precedence to b
a =• b a has the same precedence as b
a •> b a takes precedence over b

These operator precedence relations allow to delimit the handles in


the right sentential forms:

<• marks the left end,

=• appears in the interior of the handle, and

•> marks the right end.


Let assume that between the symbols ai and ai+1 there is exactly one
precedence relation. Suppose that $ is the end of the string. Then for
all terminals we can write: $ <• b and b •> $. If we remove all
nonterminals and place the correct precedence relation: <•, =•, •>
between the remaining terminals, there remain strings that can be
analyzed by easily developed parser.

For example, the following operator precedence relations can be


introduced for simple expressions:

id + * $
id •> •> •>
+ <• •> <• •>
* <• •> •> •>
$ <• <• <•

Example: The input string: id1 + id2 * id3

after inserting precedence relations becomes $ <• id1 •> + <• id2 •> *
<• id3 •> $

Having precedence relations allows to identify handles as follows:

- scan the string from left until seeing •>

- scan backwards the string from right to left until seeing <•

- everything between the two relations <• and •> forms the handle

Note that not the entire sentential form is scanned to find the handle.

2. Operator Precedence Parsing Algorithm


let Stack contain "#";
nextToken = first input token;
while (topTerm(Stack) ≠ "#" and input ≠ "#") do begin
p = precedence [topTerm, nextToken];
if p == “A” or p == "8" then /* shift */
shift nextToken onto stack and advance input;
else if p == "S" then begin /* reduce */
find the shallowest pair of terminals d and s on the stack
such that d A s, where d is the deeper terminal;
pop everything above d off the stack;
push N, the general non-terminal, onto the stack;
end
else if p == "acc" then exit loop; /* accept */
else /* precedence undefined */ report error; /* error */

end.

3. Making Operator Precedence Relations


The operator precedence parsers usually do not store the precedence

table with the relations, rather they are implemented in a special way.

Operator precedence parsers use precedence functions that map


terminal symbols to integers, and so the precedence relations between
the symbols are implemented by numerical comparison.

Not every table of precedence relations has precedence functions but


in practice for most grammars such functions can be designed.

Algorithm for Constructing Precedence Functions


1. Create functions fa for each grammar terminal a and for the end of
string symbol;
2. Partition the symbols in groups so that fa and gb are in the same
group if a =· b ( there can be symbols in the same group even if they
are not connected by this relation);
3. Create a directed graph whose nodes are in the groups, next for
each symbols a and b do: place an edge from the group of gb to the
group of fa if a <· b, otherwise if a ·> b place an edge from the group
of fa to that of gb;
4. If the constructed graph has a cycle then no precedence functions
exist. When there are no cycles collect the length of the longest
paths from the groups of fa and gb respectively.
Example: Consider the above table
id + * $
id ·> ·> ·>
+ <· ·> <· ·>
* <· ·> ·> ·>
$ <· <· <· ·>

Using the algorithm leads to the following graph:

gid fid

f* g*

g+ f+

f$ g$

from which we extract the following precedence functions:

id + * $
f 4 2 4 0
g 5 1 3 0
4. Operator precedence example:

stack input action


$ id+id*id$ $ <. id shift
$id +id*id$ id .> + reduce E 
id
$ +id*id$ shift
$+ id*id$ shift
$+id *id$ id .> * reduce E  id
$+ *id$ shift
$+* id$ shift
$+*id $ id .> $ reduce E  id

$+* $ * .> $ reduce E  E*E


$+ $ + .> $ reduce E  E+E
$ $ accept

How to Create Operator-Precedence Relations


 We use associativity and precedence relations among operators.

1. If operator q1 has higher precedence than operator q 2,


è q 1 .> q 2 and q 2 <. q 1
2. If operator q 1 and operator q 2 have equal precedence,
they are left-associative è q 1 .> q 2 and q 2 .> q 1
they are right-associative è q 1 <. q 2 and q 2 <. q 1
3. For all operators q, q <. id, id .> q, q <. (, (<. q, q .> ), ) .> q, q .>
$, and $ <. q
4. Also, let

(=·) $ <. ( id .> ) ) .> $

( <. ( $ <. id id .> $ ) .> )

( <. Id

Operator-Precedence Relations

+ - * / ^ id ( ) $
. .
+ > > <. <. <. <. <. .
> .
>
. .
- > > <. <. <. <. <. .
> .
>
. . . .
* > > > > <. <. <. .
> .
>
. . . .
/ > > > > <. <. <. .
> .
>
. . . .
^ > > > > <. <. <. .
> .
>
. . . . . . .
id > > > > > > >
( <. <. <. <. <. <. <. =·
. . . . . . .
) > > > > > > >
$ <. <. <. <. <. <. <.

Handling Unary Minus


 Operator-Precedence parsing cannot handle the unary minus
when we also have the binary minus in our grammar.
 The best approach to solve this problem, let the lexical analyzer
handle this problem.
The lexical analyzer will return two different tokens for the
unary minus and the binary minus.
The lexical analyzer will need a lookhead to distinguish the binary
minus from the unary minus.
 Then, we make

q <. unary-minus for any operator

unary-minus .> q if unary-minus has higher precedence than


q

unary-minus <. q if unary-minus has lower (or equal)


precedence than q

You might also like