0% found this document useful (0 votes)
11 views

Chapter 7 - Compiler Construction

Uploaded by

merntechwizard
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)
11 views

Chapter 7 - Compiler Construction

Uploaded by

merntechwizard
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/ 23

Parsing

LALR

LALR Parser is lookahead LR parser. It is the most powerful parser which can handle large classes of
grammar. The size of CLR parsing table is quite large as compared to other parsing table. LALR
reduces the size of this table.LALR works similar to CLR. The only difference is , it combines the
similar states of CLR parsing table into one single state.
The general syntax becomes [A->∝.B, a ]
where A->∝.B is production and a is a terminal or right end marker $
LR(1) items=LR(0) items + look ahead

How to add lookahead with the production?

CASE 1 –

A->∝.BC, a

Suppose this is the 0th production.Now, since ‘ . ‘ precedes B,so we have to write B’s productions as
well.

B->.D [1st production]

Suppose this is B’s production. The look ahead of this production is given as- we look at previous
production i.e. – 0th production. Whatever is after B, we find FIRST(of that value) , that is the
lookahead of 1st production. So, here in 0th production, after B, C is there. Assume FIRST(C)=d, then
1st production become.

B->.D, d

CASE 2 –

Now if the 0th production was like this,

A->∝.B, a
Here,we can see there’s nothing after B. So the lookahead of 0th production will be the lookahead of
1st production. ie-

B->.D, a

CASE 3 –

Assume a production A->a|b

A->a,$ [0th production]

A->b,$ [1st production]

Here, the 1st production is a part of the previous production, so the lookahead will be the same as
that of its previous production.

Steps for constructing the LALR parsing table :

1. Writing augmented grammar

2. LR(1) collection of items to be found

3. Defining 2 functions: goto[list of terminals] and action[list of non-terminals] in the LALR


parsing table

Example Problem:

Question: Construct CLR parsing table for the given context free grammar

S -> AA

A -> aA|b

Solution:

STEP 1

Find augmented grammar


The augmented grammar of the given grammar is:-

S'-->.S ,$ [0th production]

S-->.AA ,$ [1st production]

A-->.aA ,a|b [2nd production]

A-->.b ,a|b [3rd production]

Let’s apply the rule of lookahead to the above productions.

 The initial look ahead is always $

 Now, the 1st production came into existence because of ‘ . ‘ before ‘S’ in 0th production. There
is nothing after ‘S’, so the lookahead of 0th production will be the lookahead of 1st
production. i.e. : S–>.AA ,$
 Now, the 2nd production came into existence because of ‘ . ‘ before ‘A’ in the 1st production.
After ‘A’, there’s ‘A’. So, FIRST(A) is a,b. Therefore, the lookahead of the 2 nd production
becomes a|b.

 Now, the 3rd production is a part of the 2nd production. So, the look ahead will be the same.

STEP 2

Find LR(0) collection of items


Below is the figure showing the LR(0) collection of items. We will understand everything one by one.

The terminals of this grammar are {a,b}


The non-terminals of this grammar are {S,A}

RULE: If any non-terminal has ‘ . ‘ preceding it, we have to write all its production and add ‘ . ‘
preceding each of its production.

RULE: From each state to the next state, the ‘ . ‘ shifts to one place to the right.

 In the figure, I0 consists of augmented grammar.


 Io goes to I1 when ‘ . ‘ of 0th production is shifted towards the right of S(S’->S.). This state is
the accept state . S is seen by the compiler. Since I1 is a part of the 0th production, the
lookahead is same i.e. $

 Io goes to I2 when ‘ . ‘ of 1st production is shifted towards right (S->A.A) . A is seen by the
compiler. Since I2 is a part of the 1st production, the lookahead is same i.e. $.

 I0 goes to I3 when ‘ . ‘ of 2nd production is shifted towards the right (A->a.A) . a is seen by the
compiler.since I3 is a part of 2nd production, the lookahead is same i.e. a|b.

 I0 goes to I4 when ‘ . ‘ of 3rd production is shifted towards right (A->b.) . b is seen by the
compiler. Since I4 is a part of 3rd production, the lookahead is same i.e. a|b.

 I2 goes to I5 when ‘ . ‘ of 1st production is shifted towards right (S->AA.) . A is seen by the
compiler. Since I5 is a part of the 1st production, the lookahead is same i.e. $.

 I2 goes to I6 when ‘ . ‘ of 2nd production is shifted towards the right (A->a.A) . A is seen by the
compiler. Since I6 is a part of the 2nd production, the lookahead is same i.e. $.
 I2 goes to I7 when ‘ . ‘ of 3rd production is shifted towards right (A->b.) . A is seen by the
compiler. Since I6 is a part of the 3rd production, the lookahead is same i.e. $.

 I3 goes to I3 when ‘ . ‘ of the 2nd production is shifted towards right (A->a.A) . a is seen by the
compiler. Since I3 is a part of the 2nd production, the lookahead is same i.e. a|b.

 I3 goes to I8 when ‘ . ‘ of 2nd production is shifted towards the right (A->aA.) . A is seen by the
compiler. Since I8 is a part of the 2nd production, the lookahead is same i.e. a|b.

 I6 goes to I9 when ‘ . ‘ of 2nd production is shifted towards the right (A->aA.) . A is seen by the
compiler. Since I9 is a part of the 2nd production, the lookahead is same i.e. $.

 I6 goes to I6 when ‘ . ‘ of the 2nd production is shifted towards right (A->a.A) . a is seen by the
compiler. Since I6 is a part of the 2nd production, the lookahead is same i.e. $.

 I6 goes to I7 when ‘ . ‘ of the 3rd production is shifted towards right (A->b.) . b is seen by the
compiler. Since I6 is a part of the 3rd production, the lookahead is same i.e. $.

STEP 3

Defining 2 functions: goto[list of terminals] and action[list of non-terminals] in the parsing


table.Below is the CLR parsing table

Once we make a CLR parsing table, we can easily make a LALR parsing table from it.

In the step 2 diagram, we can see that

 I3 and I6 are similar except their lookaheads.

 I4 and I7 are similar except their lookaheads.

 I8 and I9 are similar except their lookaheads.

In LALR parsing table construction , we merge these similar states.

 Wherever there is 3 or 6, make it 36(combined form)

 Wherever there is 4 or 7, make it 47(combined form)

 Wherever there is 8 or 9, make it 89(combined form)


Below is the LALR parsing table.

Now we have to remove the unwanted rows

 As we can see, 36 row has same data twice, so we delete 1 row.

 We combine two 47 row into one by combining each value in the single 47 row.

 We combine two 89 row into one by combining each value in the single 89 row.

The final LALR table looks like the below.

==================================================================================

CLR

LR parsers :
It is an efficient bottom-up syntax analysis technique that can be used to parse large classes of
context-free grammar is called LR(k) parsing.
L stands for the left to right scanning
R stands for rightmost derivation in reverse
k stands for no. of input symbols of lookahead

Advantages of LR parsing :

 It recognizes virtually all programming language constructs for which CFG can be written

 It is able to detect syntactic errors

 It is an efficient non-backtracking shift reducing parsing method.


Types of LR parsing methods :

1. SLR

2. CLR

3. LALR

CLR Parser :
The CLR parser stands for canonical LR parser.It is a more powerful LR parser.It makes use of
lookahead symbols. This method uses a large set of items called LR(1) items.The main difference
between LR(0) and LR(1) items is that, in LR(1) items, it is possible to carry more information in a
state, which will rule out useless reduction states.This extra information is incorporated into the state
by the lookahead symbol. The general syntax becomes [A->∝.B, a ]
where A->∝.B is the production and a is a terminal or right end marker $
LR(1) items=LR(0) items + look ahead

How to add lookahead with the production?


CASE 1 –

A->∝.BC, a

Suppose this is the 0th production.Now, since ‘ . ‘ precedes B,so we have to write B’s productions as
well.

B->.D [1st production]

Suppose this is B’s production. The look ahead of this production is given as we look at previous
productions ie 0th production. Whatever is after B, we find FIRST(of that value) , that is the
lookahead of 1st production.So,here in 0th production, after B, C is there. assume FIRST(C)=d, then
1st production become

B->.D, d

CASE 2–

Now if the 0th production was like this,

A->∝.B, a
Here, we can see there’s nothing after B. So the lookahead of 0th production will be the lookahead
of 1st production. ie-

B->.D, a

CASE 3–

Assume a production A->a|b

A->a,$ [0th production]

A->b,$ [1st production]

Here, the 1st production is a part of the previous production, so the lookahead will be the same as
that of its previous production.
These are the 2 rules of look ahead.
Steps for constructing CLR parsing table :

1. Writing augmented grammar

2. LR(1) collection of items to be found

3. Defining 2 functions: goto[list of terminals] and action[list of non-terminals] in the CLR


parsing table

Example Problem:

Question: Construct a CLR parsing table for the given context-free grammar

S-->AA

A-->aA|b

Solution:

STEP 1

Find augmented grammar

The augmented grammar of the given grammar is:-

S'-->.S ,$ [0th production]

S-->.AA ,$ [1st production]

A-->.aA ,a|b [2nd production]

A-->.b ,a|b [3rd production]

Let’s apply the rule of lookahead to the above productions

 The initial look ahead is always $

 Now, the 1st production came into existence because of ‘ . ‘ Before ‘S’ in 0th production.There
is nothing after ‘S’, so the lookahead of 0th production will be the lookahead of 1st
production. ie: S–>.AA ,$

 Now, the 2nd production came into existence because of ‘ . ‘ Before ‘A’ in the 1st production.
After ‘A’, there’s ‘A’. So, FIRST(A) is a,b
Therefore, the look ahead for the 2nd production becomes a|b.

 Now, the 3rd production is a part of the 2nd production. So, the look ahead will be the same.
STEP 2

Find LR(1) collection of items


Below is the figure showing the LR(1) collection of items. We will understand everything one by one.

The terminals of this grammar are {a,b}


The non-terminals of this grammar are {S,A}

RULE: If any non-terminal has ‘ . ‘ preceding it, we have to write all its production and add ‘ . ‘
preceding each of its production.

RULE: From each state to the next state, the ‘ . ‘ shifts to one place to the right.

RULE: All the rules of lookahead apply here.

 In the figure, I0 consists of augmented grammar.

 Io goes to I1 when ‘ . ‘ of 0th production is shifted towards the right of S(S’->S.). This state is
the accept state . S is seen by the compiler. Since I1 is a part of the 0th production, the
lookahead is the same ie $

 Io goes to I2 when ‘ . ‘ of 1st production is shifted towards right (S->A.A) . A is seen by the
compiler. Since I2 is a part of the 1st production, the lookahead is the same i.e. $.

 I0 goes to I3 when ‘ . ‘ of the 2nd production is shifted towards right (A->a.A) . a is seen by the
compiler. Since I3 is a part of the 2nd production, the lookahead is the same ie a|b.

 I0 goes to I4 when ‘ . ‘ of the 3rd production is shifted towards right (A->b.) . b is seen by the
compiler. Since I4 is a part of the 3rd production, the lookahead is the same i.e. a | b.

 I2 goes to I5 when ‘ . ‘ of 1st production is shifted towards right (S->AA.) . A is seen by the
compiler. Since I5 is a part of the 1st production, the lookahead is the same i.e. $.

 I2 goes to I6 when ‘ . ‘ of 2nd production is shifted towards the right (A->a.A) . A is seen by the
compiler. Since I6 is a part of the 2nd production, the lookahead is the same i.e. $.

 I2 goes to I7 when ‘ . ‘ of 3rd production is shifted towards right (A->b.) . A is seen by the
compiler. Since I6 is a part of the 3rd production, the lookahead is the same i.e. $.
 I3 goes to I3 when ‘ . ‘ of the 2nd production is shifted towards right (A->a.A) . a is seen by the
compiler. Since I3 is a part of the 2nd production, the lookahead is the same i.e. a|b.

 I3 goes to I8 when ‘ . ‘ of 2nd production is shifted towards the right (A->aA.) . A is seen by the
compiler. Since I8 is a part of the 2nd production, the lookahead is the same i.e. a|b.

 I6 goes to I9 when ‘ . ‘ of 2nd production is shifted towards the right (A->aA.) . A is seen by the
compiler. Since I9 is a part of the 2nd production, the lookahead is the same i.e. $.

 I6 goes to I6 when ‘ . ‘ of the 2nd production is shifted towards right (A->a.A) . a is seen by the
compiler. Since I6 is a part of the 2nd production, the lookahead is the same i.e. $.

 I6 goes to I7 when ‘ . ‘ of the 3rd production is shifted towards right (A->b.) . b is seen by the
compiler. Since I6 is a part of the 3rd production, the lookahead is the same ie $.

STEP 3

Defining 2 functions:goto[list of terminals] and action[list of non-terminals] in the parsing table.


Below is the CLR parsing table

 $ is by default a non terminal which takes accepting state.

 0,1,2,3,4,5,6,7,8,9 denotes I0,I1,I2,I3,I4,I5,I6,I7,I8,I9

 I0 gives A in I2, so 2 is added to the A column and 0 row.

 I0 gives S in I1,so 1 is added to the S column and 1st row.

 similarly 5 is written in A column and 2nd row, 8 is written in A column and 3rd row, 9 is
written in A column and 6th row.

 I0 gives a in I3, so S3(shift 3) is added to a column and 0 row.

 I0 gives b in I4, so S4(shift 4) is added to the b column and 0 row.

 Similarly, S6(shift 6) is added on ‘a’ column and 2,6 row ,S7(shift 7) is added on b column and
2,6 row,S3(shift 3) is added on ‘a’ column and 3 row ,S4(shift 4) is added on b column and 3
row.

 I4 is reduced as ‘ . ‘ is at the end. I4 is the 3rd production of grammar. So write r3(reduce 3) in


lookahead columns. The lookahead of I4 are a and b, so write R3 in a and b column.

 I5 is reduced as ‘ . ‘ is at the end. I5 is the 1st production of grammar. So write r1(reduce 1) in


lookahead columns. The lookahead of I5 is $ so write R1 in $ column.
 Similarly, write R2 in a,b column and 8th row, write R2 in $ column and 9th row.

==================================================================================

LL(1)

A top-down parser builds the parse tree from the top down, starting with the start non-terminal.
There are two types of Top-Down Parsers:

1. Top-Down Parser with Backtracking

2. Top-Down Parsers without Backtracking

Top-Down Parsers without backtracking can further be divided into two parts:

In this article, we are going to discuss Non-Recursive Descent which is also known as LL(1) Parser.

LL(1) Parsing: Here the 1st L represents that the scanning of the Input will be done from the Left to
Right manner and the second L shows that in this parsing technique, we are going to use the Left
most Derivation Tree. And finally, the 1 represents the number of look-ahead, which means how
many symbols are you going to see when you want to make a decision.

Essential conditions to check first are as follows:

1. The grammar is free from left recursion.

2. The grammar should not be ambiguous.

3. The grammar has to be left factored in so that the grammar is deterministic grammar.

These conditions are necessary but not sufficient for proving a LL(1) parser.

Algorithm to construct LL(1) Parsing Table:

Step 1: First check all the essential conditions mentioned above and go to step 2.

Step 2: Calculate First() and Follow() for all non-terminals.

1. First(): If there is a variable, and from that variable, if we try to drive all the strings then the
beginning Terminal Symbol is called the First.

2. Follow(): What is the Terminal Symbol which follows a variable in the process of derivation.

Step 3: For each production A –> α. (A tends to alpha)

1. Find First(α) and for each terminal in First(α), make entry A –> α in the table.
2. If First(α) contains ε (epsilon) as terminal, then find the Follow(A) and for each terminal in
Follow(A), make entry A –> ε in the table.

3. If the First(α) contains ε and Follow(A) contains $ as terminal, then make entry A –> ε in the
table for the $.
To construct the parsing table, we have two functions:

In the table, rows will contain the Non-Terminals and the column will contain the Terminal
Symbols. All the Null Productions of the Grammars will go under the Follow elements and the
remaining productions will lie under the elements of the First set.

Now, let’s understand with an example.

Question 1: Consider the Grammar:

E --> TE'
E' --> +TE' | ε
T --> FT'
T' --> *FT' | ε
F --> id | (E)

Step 1: The grammar satisfies all properties in step 1.

Step 2: Calculate first() and follow().

Find their First and Follow sets:


Step 3: Make a parser table.

Now, the LL(1) Parsing Table is:

As you can see that all the null productions are put under the Follow set of that symbol and all the
remaining productions lie under the First of that symbol.

Note: Every grammar is not feasible for LL(1) Parsing table. It may be possible that one cell may
contain more than one production.

Let’s see an example.

Question 2: Consider the Grammar

S --> A | a
A --> a

Step 1: The grammar does not satisfy all properties in step 1, as the grammar is ambiguous. Still, let’s
try to make the parser table and see what happens

Step 2: Calculating first() and follow()

Find their First and Follow sets:


Step 3: Make a parser table.

Parsing Table:

Here, we can see that there are two productions in the same cell. Hence, this grammar is not feasible
for LL(1) Parser.

Trick – Above grammar is ambiguous grammar. So the grammar does not satisfy the essential
conditions. So we can say that this grammar is not feasible for LL(1) Parser even without making the
parse table.

Question 3: Consider the Grammar


S -> (L) | a
L -> SL'
L' -> )SL' | ε

Step1: The grammar satisfies all properties in step 1

Step 2: Calculating first() and follow()


Step 3: Making a parser table

Parsing Table:

Here, we can see that there are two productions in the same cell. Hence, this grammar is not feasible
for LL(1) Parser. Although the grammar satisfies all the essential conditions in step 1, it is still not
feasible for LL(1) Parser. We saw in example 2 that we must have these essential conditions and in
example 3 we saw that those conditions are insufficient to be a LL(1) parser.

==================================================================================

Recursive Descent Parser

Parsing is the process to determine whether the start symbol can derive the program or not. If the
Parsing is successful then the program is a valid program otherwise the program is invalid.

There are generally two types of Parsers:

1. Top-Down Parsers:

 In this Parsing technique we expand the start symbol to the whole program.

 Recursive Descent and LL parsers are the Top-Down parsers.

2. Bottom-Up Parsers:

 In this Parsing technique we reduce the whole program to start symbol.

 Operator Precedence Parser, LR(0) Parser, SLR Parser, LALR Parser and CLR Parser are
the Bottom-Up parsers.

Recursive Descent Parser:

It is a kind of Top-Down Parser. A top-down parser builds the parse tree from the top to down,
starting with the start non-terminal. A Predictive Parser is a special case of Recursive Descent Parser,
where no Back Tracking is required.
By carefully writing a grammar means eliminating left recursion and left factoring from it, the
resulting grammar will be a grammar that can be parsed by a recursive descent parser.
Example:

Before removing left recursion After removing left recursion

E –> T E’
E –> E + T | T E’ –> + T E’ | e
T –> T * F | F T –> F T’
F –> ( E ) | id T’ –> * F T’ | e
F –> ( E ) | id

For Recursive Descent Parser,

we are going to write one program for every variable.


#include <stdio.h>
#include <string.h>
#define SUCCESS 1
#define FAILED 0
// Function prototypes
int E(), Edash(), T(), Tdash(), F();
const char *cursor;
char string[64];
int main() {
puts("Enter the string");
scanf("%s", string); // Read input from the user
cursor = string;
puts("");
puts("Input Action");
puts("--------------------------------");
// Call the starting non-terminal E
if (E() && *cursor == '\0') { // If parsing is successful and the
cursor has reached the end
puts("--------------------------------");
puts("String is successfully parsed");
return 0;
}
else {
puts("--------------------------------");
puts("Error in parsing String");
return 1;
}
}
// Grammar rule: E -> T E'
int E() {
printf("%-16s E -> T E'\n", cursor);
if (T()) { // Call non-terminal T
if (Edash()) // Call non-terminal E'
return SUCCESS;
else
return FAILED;
}
else
return FAILED;
}
// Grammar rule: E' -> + T E' | $
int Edash() {
if (*cursor == '+') {
printf("%-16s E' -> + T E'\n", cursor);
cursor++;
if (T()) { // Call non-terminal T
if (Edash()) // Call non-terminal E'
return SUCCESS;
else
return FAILED;
}
else
return FAILED;
}
else {
printf("%-16s E' -> $\n", cursor);
return SUCCESS;
}
}
// Grammar rule: T -> F T'
int T() {
printf("%-16s T -> F T'\n", cursor);
if (F()) { // Call non-terminal F
if (Tdash()) // Call non-terminal T'
return SUCCESS;
else
return FAILED;
}
else
return FAILED;
}
// Grammar rule: T' -> * F T' | $
int Tdash() {
if (*cursor == '*') {
printf("%-16s T' -> * F T'\n", cursor);
cursor++;
if (F()) { // Call non-terminal F
if (Tdash()) // Call non-terminal T'
return SUCCESS;
else
return FAILED;
}
else
return FAILED;
}
else {
printf("%-16s T' -> $\n", cursor);
return SUCCESS;
}
}

// Grammar rule: F -> ( E ) | i


int F() {
if (*cursor == '(') {
printf("%-16s F -> ( E )\n", cursor);
cursor++;
if (E()) { // Call non-terminal E
if (*cursor == ')') {
cursor++;
return SUCCESS;
}
else
return FAILED;
}
else
return FAILED;
}
else if (*cursor == 'i') {
printf("%-16s F -> i\n", cursor);
cursor++;
return SUCCESS;
}
else
return FAILED;
}

Example) Predictive Parsing code for Grammar:

E → T E'
E' → + T E' | ε
T → F T'
T' → * F T' | ε
F → ( E ) | id
#include <iostream>
#include <string>
using namespace std;

string input;
int pos = 0;
string lookahead;

// Forward declarations of functions for non-terminals


void E(); // Expression
void EPrime(); // Expression'
void T(); // Term
void TPrime(); // Term'
void F(); // Factor

// Utility function to get the next token


void nextToken() {
while (pos < input.length() && isspace(input[pos])) {
pos++; // Skip any whitespace characters
}
if (pos < input.length()) {
if (input.substr(pos, 2) == "id") {
lookahead = "id";
pos += 2;
} else {
lookahead = input[pos];
pos++;
}
} else {
lookahead = "\0"; // End of input
}
}
// Match function returns true if the token matches, false otherwise
bool match(string expected) {
if (lookahead == expected) {
nextToken();
return true;
}
return false;
}
// Grammar production for E -> T E'
void E() {
T();
EPrime();
}

// Grammar production for E' -> + T E' | ε


void EPrime() {
if (match("+")) {
T();
EPrime();
}
// else epsilon production (do nothing)
}

// Grammar production for T -> F T'


void T() {
F();
TPrime();
}

// Grammar production for T' -> * F T' | ε


void TPrime() {
if (match("*")) {
F();
TPrime();
}
// else epsilon production (do nothing)
}

// Grammar production for F -> ( E ) | id


void F() {
if (match("(")) {
E();
if (!match(")")) {
cerr << "Syntax error: expected ')' but found '" << lookahead
<< "'" << endl;
exit(1);
}
} else if (match("id")) {
// Match the identifier "id"
} else {
cerr << "Syntax error: unexpected token '" << lookahead << "'" <<
endl;
exit(1);
}
}

int main() {
cout << "Enter an expression: ";
getline(cin, input);

nextToken(); // Initialize the first lookahead token


E(); // Start parsing from the starting non-terminal E

if (lookahead == "\0") {
cout << "Parsing successful!" << endl;
} else {
cout << "Syntax error: unexpected input after parsing!" << endl;
}
return 0;
}

Example) Recursive Descent in C++

S → AB
A → aA
B → bB | ε
#include <iostream>
#include <string>
using namespace std;
class Parser {
string input;
int pos;
public:
Parser(string str): input(str),pos(0) {}
bool Parse(){
S();
return pos == input.length();
}
void S (){
A();
B();
}
void A (){
if(pos < input.length() && input[pos]==’a’){
pos++;
A();
} else {
error();
}
}
void B (){
if(pos < input.length() && input[pos]==’b’){
pos++;
B();
} else {
error();
}
}
};
int main(){
string input;
cout<<”Enter String: ”<<endl;
cin>> input;
Parser parser(input);
if(parser.parse()){
cout<<”Success”<<endl;
} else{
cout<<”Failure”<<endl;
}
return 0;
}

Example) Recursive Descent in C++ WITH BACK TRACKING

S → Be
B → CD
B → bCb
C → cC
C→ε
D → dD
D→ε
#include <iostream>
#include <string.h>
using namespace std;
class Parser {
Private:
string input;
int pos;
char currentChar (){
return pos < input.size() ? input[pos] : ‘\0’;
}
bool match (char expected){
if(currentChar() == expected){
pos++;
return true;
}
return false;
}
bool S (){
if(B()) {
return match(‘e’);
}
return false;
}
bool B (){
int entry = pos;
if(C() && D()) {
return true;
}
pos = entry; // BACKTRACKING IS IMPLEMENTED HERE
if(match(‘b’) && C() && match(‘b’)){
return true;
}
//another case if B → SC was present in our production; then code
will be as below:
// pos = entry;
// if (S() && C()){ ... }
return false;
}
bool C (){
if(match(‘c’) && C()) {
return true;
}
return true; //disputed\not confirmed case of epsilon
}
bool D (){
if(match(‘d’) && D()) {
return true;
}
return true; //disputed\not confirmed case of epsilon
}
Public:
Parser(string in): input(in), pos(0) {}
bool parse(){
if(S() && pos == input.size()) {
return true;
}
return false;
}
};
int main(){
string input;
cout<<”Enter String: ”<<endl;
cin>> input;
Parser p(input);
if(p.parse()){
cout<<”Success”<<endl;
} else{
cout<<”Failure”<<endl;
}
return 0;
}

Example) Recursive Descent in C++ WITH LOOKAHEAD

S → Be
B → CD
B → bCb
C → cC
C→ε
D → dD
D→ε
First(S) = {b, c, d, e} Follow(S) = {$}
First(B) = {b, c, d} Follow(B) = {e}
First(C) = {c, ε} Follow(C) = {b, d, e}
First(D) = {d, ε} Follow(D) = {e}

#include <iostream>
#include <string.h>
using namespace std;
class Parser {
Private:
string input;
int pos;
char currentChar (){
return pos < input.size() ? input[pos] : ‘\0’;
}

bool lookahead (char expected){


return (currentChar()== expected);
}

bool match (char expected){


if(currentChar() == expected){
pos++;
return true;
}
return false;
}

bool S (){
if(B()) {
return match(‘e’);
}
return false;
}

bool B (){
// In this first “if” statement below; here is the logic to
// to follow:
// Only put here those whose FIRST(CD) & FIRST(b)
// FIRST(CD) = {c, d, ε}
// FIRST(b)= {b}
if(lookahead(‘c’) || lookahead(‘d’)) {
// B → CD
return (C() && D());
} else if (lookahead(‘b’)){
return match(‘b’) && C() && match(‘b’);
} else{
return false;
}
}

bool C (){
// In this first “if” statement below; here is the logic to
// to follow:
// Only put here those whose FIRST(cC) & FOLLOW(C)
// FIRST(cC) = {c}
// FOLLOW(C)= {b, d, e}
if(lookahead(‘c’)) {
//C → cC
return (match(‘c’) && C());
} else if (lookahead(‘b’) || lookahead(‘d’) || lookahead(‘e’)){
// C → ε
// NOTE HERE THAT THE LOOKAHEADS() ARE FROM FOLLOW SET!!
return true;
}
return false;
}

bool D (){
// In this first “if” statement below; here is the logic to
// to follow:
// Only put here those whose FIRST(dD) & FOLLOW(D)
// FIRST(dD) = {d}
// FOLLOW(D)= {e}
if(lookahead(‘d’)) {
// D → dD
return (match(‘d’) && D());
} else if (lookahead(‘e’)){
// D → ε
// NOTE HERE THAT THE LOOKAHEADS() ARE FROM FOLLOW SET!!
return true;
}
return false;
}

Public:
Parser(string in): input(in), pos(0) {}
bool parse(){
if(S() && pos == input.size()) {
return true;
}
return false;
}
};
int main(){
string input;
cout<<”Enter String: ”<<endl;
cin>> input;
Parser p(input);
if(p.parse()){
cout<<”Success”<<endl;
} else{
cout<<”Failure”<<endl;
}
return 0;
}

You might also like