0% found this document useful (0 votes)
25 views52 pages

Lecture 14

Uploaded by

hamza ahmed
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views52 pages

Lecture 14

Uploaded by

hamza ahmed
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 52

Compiler

Construction
Sohail Aslam
Lecture 14
Predictive Parsing
The LL(1) Property
If A →  and A →  both
appear in the grammar, we
would like
FIRST()  FIRST() = 

2
Predictive Parsing
Predictive parsers accept LL(k)
grammars
“left-to-right” scan of input
“k” tokens of lookahead
LL(k)
left-most derivation
3
Predictive Parsing
The LL(1) Property
FIRST()  FIRST() = 
allows the parser to make a
correct choice with a
lookahead of exactly one
symbol!
4
Predictive Parsing
What about -productions?
They complicate the
definition of LL(1)

5
Predictive Parsing
What about -productions?
They complicate the
definition of LL(1)

6
Predictive Parsing
If A →  and A →  and
  FIRST() , then we need
to ensure that FIRST() is
disjoint from FOLLOW(),
too

7
Predictive Parsing
FOLLOW()
is the set of all words in
the grammar that can
legally appear after an .

8
Predictive Parsing
For a non-terminal X,
FOLLOW(X )
is the set of symbols
that might follow the
derivation of X.
9
Predictive Parsing
FIRST and FOLLOW
X

FIRST FOLLOW
10
Predictive Parsing
Define FIRST+() as
FIRST()  FOLLOW(), if
  FIRST()
FIRST(), otherwise

11
Predictive Parsing
Then a grammar is LL(1)
iff A →  and A → 
implies

FIRST+()  FIRST+() =

12
Predictive Parsing
Given a grammar that has
the is LL(1) property
• we can write a simple
routine to recognize each
lhs
• code is simple and fast
13
Predictive Parsing
Given a grammar that has
the is LL(1) property
• we can write a simple
routine to recognize each
lhs
• code is simple and fast
14
Predictive Parsing
Given a grammar that has
the is LL(1) property
• we can write a simple
routine to recognize each
lhs
• code is simple and fast
15
Predictive Parsing
Consider
A → 1 23
which satisfies the LL(1)
property FIRST+()FIRST+
() = 

16
/* find an A */
if(token  FIRST(1))
find a 1 and return true
else if(token  FIRST(2))
find a 2 and return true
if(token  FIRST(3))
find a 3 and return true
else error and return false
17
/* find an A */
if(token  FIRST(1))
find a 1 and return true
else if(token  FIRST(2))
find a 2 and return true
if(token  FIRST(3))
find a 3 and return true
else error and return false
18
/* find an A */
if(token  FIRST(1))
find a 1 and return true
else if(token  FIRST(2))
find a 2 and return true
if(token  FIRST(3))
find a 3 and return true
else error and return false
19
/* find an A */
if(token  FIRST(1))
find a 1 and return true
else if(token  FIRST(2))
find a 2 and return true
if(token  FIRST(3))
find a 3 and return true
else error and return false
20
/* find an A */
if(token  FIRST(1))
find a 1 and return true
else if(token  FIRST(2))
find a 2 and return true
if(token  FIRST(3))
find a 3 and return true
else error and return false
21
Predictive Parsing
Grammar with the LL(1)
property are called predictive
grammars because the parser
can “predict” the correct
expansion at each point in the
parse.
22
Predictive Parsing
 Parsers that capitalize on
the LL(1) property are
called predictive parsers
 One kind of predictive
parser is the recursive
descent parser
23
Predictive Parsing
 Parsers that capitalize on
the LL(1) property are
called predictive parsers
 One kind of predictive
parser is the recursive
descent parser
24
Recursive Descent Parsing
1 Goal → expr
2 expr → term expr'
3 expr' → + term expr'
4 | - term expr'
5 | 
6 term → factor term'
7 term' → * factor term'
8 | ∕ factor term'
9 | 
10 factor → number
11 | id
12 | ( expr ) 25
Recursive Descent Parsing
This leads to a parser with
six mutually recursive
routines
Goal Term
Expr TPrime
EPrime Factor
26
Recursive Descent Parsing
Each recognizes one non-
terminal (NT) or terminal (T)

Goal Term
Expr TPrime
EPrime Factor
27
Recursive Descent Parsing
 The term descent refers to
the direction in which the
parse tree is built.
 Here are some of these
routines written as functions

28
Recursive Descent Parsing
 The term descent refers to
the direction in which the
parse tree is built.
 Here are some of these
routines written as functions

29
Goal() {
token = next_token();
if(Expr() == true && token == EOF)
next compilation step
else {
report syntax error;
return false;
}
}
30
Expr()
{
if(Term() == false)
return false;
else
return Eprime();
}
31
Eprime() {
token_type op = next_token();
if( op == PLUS || op == MINUS ) {
if(Term() == false)
return false;
else
return Eprime();
}
}
32
Recursive Descent Parsing

Functions for other non-


terminals Term, Factor,
Tprime follow the same
pattern.

33
Recursive Descent in C++
Shortcomings
 Too procedural
 No convenient way to
build parse tree

34
Recursive Descent in C++
Using an OO Language
 Associate a class with
each non-terminal symbol
 Allocated object contains
pointer to the parse tree
35
Recursive Descent in C++
Using an OO Language
 Associate a class with
each non-terminal symbol
 Allocated object contains
pointer to the parse tree
36
Recursive Descent in C++
Using an OO Language
 Associate a class with
each non-terminal symbol
 Allocated object contains
pointer to the parse tree
37
Non-terminal Classes
class NonTerminal {
public:
NonTerminal(Scanner* sc){
s = sc; tree = NULL; }
virtual ~NonTerminal(){}
virtual bool isPresent()=0;
TreeNode* AST(){
return tree;
}
38
class NonTerminal {
public:
NonTerminal(Scanner* sc){
s = sc; tree = NULL; }
virtual ~NonTerminal(){}
Constructor: stores the pointer
virtual
to bool (lexer)
the scanner isPresent()=0;
in
TreeNode*
protected AST(){and
variable
return
initializes tree;
tree pointer to NULL.
}
39
class NonTerminal {
public:
NonTerminal(Scanner* sc){
s = sc; tree = NULL; }
virtual ~NonTerminal(){}
virtual bool isPresent()=0;
Polymorphic default destructor.
TreeNode* AST(){
Called in case derived classes
return tree;
do not define their own
}
40
class NonTerminal {
public:
isPresent is pure virtual (=0).
NonTerminal(Scanner* sc){
Base class will not provide
s = sc; tree = NULL; }
implementation
virtual ~NonTerminal(){}
virtual bool isPresent()=0;
TreeNode* AST(){
return tree;
}
41
class NonTerminal {
public:
NonTerminal(Scanner* sc){
Return pointer to Abstract
s = sc; tree = NULL; }
Syntax tree. Available to all
virtual ~NonTerminal(){}
subclasses
virtual bool isPresent()=0;
TreeNode* AST(){
return tree;
}
42
class NonTerminal {
public:
NonTerminal(Scanner* sc){
s = sc; tree = NULL; }
virtual ~NonTerminal(){}
virtual bool isPresent()=0;
TreeNode* AST(){
return tree;
}

43
class NonTerminal {
. . . . .
. . . . .
protected:
Scanner* s;
TreeNode* tree;
}

44
class Expr:public NonTerminal
{
public:
Expr(Scanner* sc):
NonTerminal(sc){ }
virtual bool isPresent();
}

45
class Expr:public NonTerminal
{
public:
NonTerminal is the base
Expr(Scanner* sc):
class; Expr is the derived
NonTerminal(sc){ }
class.
virtual bool isPresent();
}

46
class Expr:public NonTerminal
{
public:
Expr(Scanner* sc):
NonTerminal(sc){ }
virtual bool isPresent();
}
Expr’s constructor calls the
base class constructor
explicitly.
47
class Expr:public NonTerminal
{
public:
isPresent() is a
Expr(Scanner*
polymorphic sc):
function.
NonTerminal(sc){ }
virtual bool isPresent();
}

48
class Eprime:public
NonTerminal {
public:
Eprime(Scanner* sc,
TreeNode* t):
NonTerminal(sc){
exprSofar = t; }
virtual bool isPresent();
protected:
TreeNode* exprSofar;
}
49
class Term:public NonTerminal
{
public:
Term(Scanner* sc):
NonTerminal(sc){ }
virtual bool isPresent();
}

50
class Tprime:public
NonTerminal {
public:
Tprime(Scanner* sc,
TreeNode* t):
NonTerminal(sc){
exprSofar = t; }
virtual bool isPresent();
protected:
TreeNode* exprSofar;
}
51
class Factor:public
NonTerminal {
public:
Factor(Scanner* sc,
TreeNode* t):
NonTerminal(sc){ };
virtual bool isPresent();
}

52

You might also like