Lecture 14
Lecture 14
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 23
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
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