0% found this document useful (0 votes)
287 views28 pages

Compiler Lab

The program takes a context-free grammar as input and eliminates left recursion and performs left factoring. For left recursion, it separates the left recursive and non-left recursive parts into two productions. For left factoring, it identifies the common prefix between two productions, separates it as a new non-terminal and updates the original productions accordingly. The program outputs the grammar after eliminating left recursion and left factoring.

Uploaded by

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

Compiler Lab

The program takes a context-free grammar as input and eliminates left recursion and performs left factoring. For left recursion, it separates the left recursive and non-left recursive parts into two productions. For left factoring, it identifies the common prefix between two productions, separates it as a new non-terminal and updates the original productions accordingly. The program outputs the grammar after eliminating left recursion and left factoring.

Uploaded by

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

COMPILER DESIGN LAB

(Code 18CSC304J)
B. Tech (CSE) – 3rd year/6th Semester

Name:

Registration No:

DEPARTMENT OF COMPUTER SCIENCE & ENGINEERING


FACULTY OF ENGINEERING & TECHNOLOGY
SRM INSTITUTE OF SCIENCE & TECHNOLOGY,
delhi ncr CAMPUS, MODINAGAR
SIKRI KALAN, DELHI MEERUT ROAD, DIST. – GHAZIABAD - 201204
https://www.srmup.in/

Even Semester (2022-2023)


BONAFIDE CERTIFICATE

Registration no.: ____________


Certified to be the bonafide record of work done by ____________of 6th
semester 3rd year B. TECH degree course in SRM INSTITUTE OF
SCIENCE AND TECHNOLOGY, NCR Campus of Department of
Computer Science & Engineering, in Compiler Design Laboratory
during the academic year 2022-23.

Lab In Charges Head of the Department

(Dr. R. P. Mahapatra)

Submitted for university examination held on __/____/___ at SRM IST, NCR


Campus.

Internal Examiner-I Internal Examiner-II


INDEX

Exp. Title of Experiment Date Date of Teacher’s


No. of Completion Signature
Experiment of Experiment

1 Implementation of Lexical Analyzer

2 Regular Expression to NFA

3 Conversion from NFA to DFA

4 Elimination of Ambiguity, Left Recursion and


Left Factoring

5 Computation of FIRST and FOLLOW

6 Computation of Predictive Parsing

Computation of Shift Reduce Parsing


7

Computation of LEADING and TRAILING


8

10

11

12

13

14

15

EXPERIMENT-1
Implementation of Lexical Analyzer

Aim: Write a program in C/C++ to implement a lexical analyzer.

Theory:

Lexical Analysis is the very first phase in the compiler designing. A Lexer takes the modified
source code which is written in the form of sentences . In other words, it helps you to convert
a sequence of characters into a sequence of tokens. The lexical analyzer breaks this syntax
into a series of tokens. It removes any extra space or comment written in the source code.

Programs that perform Lexical Analysis in compiler design are called lexical analyzers or
lexers. A lexer contains tokenizer or scanner. If the lexical analyzer detects that the token is
invalid, it generates an error. The role of Lexical Analyzer in compiler design is to read
character streams from the source code, check for legal tokens, and pass the data to the syntax
analyzer when it demands.

Program:

#include<iostream>

#include<cstring>

#include<stdlib.h>

#include<ctype.h>

using namespace std;

string arr[] = { "void", "using", "namespace", "int", "include", "iostream", "std", "main",

"cin", "cout", "return", "float", "double", "string" };

bool isKeyword(string a) {

for (int i = 0; i < 14; i++) {

if (arr[i] == a) {

return true;

return false;

int main() {
printf(“Aditya Saxena\n”);

string input;

cout << "Enter the program code: ";

getline(cin, input);

string s;

for (int i = 0; i < input.length(); i++) {

char c = input[i];

if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {

if (s != "") {

if (isKeyword(s)) {

cout << s << " is a keyword\n";

} else if (s == "+" || s == "-" || s == "" || s == "/" || s == "^" || s == "&&" || s == "||" ||


s == "=" || s == "==" || s == "&" || s == "|" || s == "%" || s == "++" || s == "--" || s == "+=" || s
== "-=" || s == "/=" || s == "=" || s == "%=") {

cout << s << " is an operator\n";

} else if (s == "(" || s == "{" || s == "[" || s == ")" || s == "}" || s == "]" || s == "<" || s


== ">" || s == "()" || s == ";" || s == "<<" || s == ">>" || s == "," || s == "#") {

cout << s << " is a symbol\n";

} else if (isdigit(s[0])) {

int x = 0;

if (!isdigit(s[x++])) {

continue;

} else {

cout << s << " is a constant\n";

} else {

cout << s << " is an identifier\n";

}
s = "";

} else {

s += c;

return 0;

Result: The Program Executed successfully.

EXPERIMENT-2
Regular Expression to NFA

Aim: To convert the given Regular expression to NFA by using JFLAP.

Theory:

In NDFA, for a particular input symbol, the machine can move to any combination of the
states in the machine. In other words, the exact state to which the machine moves cannot be
determined. Hence, it is called Non-deterministic Automaton. Regular expressions are a
concise way to represent a set of strings in formal languages and automata theory. They are a
notation for describing regular languages, which can be recognized by finite state automata.

A regular expression is another representation of a regular language, and is defined over an


alphabet (defined as Σ). The simplest regular expressions are symbols from λ, ∅, and symbols
from Σ. Regular expressions can be built from these simple regular expressions with
parenthesis, in addition to union, Kleene star and concatenation operators. In JFLAP, the
concatenation symbol is implicit whenever two items are next to each other, and it is not
explicitly stated. 

1. (0+1)*011(0+1)*

2. (0+1)*1(0+1)
3.(a+b)*a

Result: We converted the given Regular expression to NFA.

EXPERIMENT-3

NFA to DFA

Aim: To convert the given NFA to DFA by using JFLAP.

Theory:

An NFA can have zero, one or more than one move from a given state on a given input
symbol. An NFA can also have NULL moves (moves without input symbol). On the other
hand, DFA has one and only one move from a given state on a given input symbol.This
operator may be applied to any nondeterministic FA. At the end of the operation, there will
be a completed NFA. The conversion practice used is the standard canonical method of
creating an equivalent DFA from an NFA, that is: each state in the DFA being built
corresponds to a nonempty set of states in the original NFA. Therefore, for an NFA
with n states, there are potentially 2n - 1 states in the DFA, though realistically this upper
bound is rarely met.

1. Input NFA
Output DFA

2. Input NFA

Output DFA
Result: We converted the given NFA to DFA.

EXPERIMENT-4

Elimination of Ambiguity, Left Recursion and Left Factoring

Aim: Write a program in C/C++ to Elimination of Ambiguity, Left Recursion and Left
Factoring for a given set of production rule of a grammar.

Theory:

Left Recursion

 Left Recursion. The production is left-recursive if the leftmost symbol on the right
side is the same as the non-terminal on the left side.

 For example, expr → expr + term. If one were to code this production in a recursive-
descent parser, the parser would go in an infinite loop.
Left Factoring

 Left factoring is another useful grammar transformation used in parsing


 Left Factoring is a grammar transformation technique. It consists in "factoring out"
prefixes which are common to two or more productions.

Program

Left Recursion

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#define SIZE 20

int main()

    printf("Aditya Saxena\n");

    char pro[SIZE], alpha[SIZE], beta[SIZE];

    int nont_terminal,i,j, index=3;

    printf("Enter the Production as E->E|A: ");

    scanf("%s", pro);

    nont_terminal=pro[0];

    if(nont_terminal==pro[index])

  {

        for(i=++index,j=0;pro[i]!='|';i++,j++){

            alpha[j]=pro[i];

            if(pro[i+1]==0){

                printf("This Grammar CAN'T BE REDUCED.\n");

                exit(0);

      }

    }

        alpha[j]='\0';
        if(pro[++i]!=0)

    {

            for(j=i,i=0;pro[j]!='\0';i++,j++){

                beta[i]=pro[j];

      }

            beta[i]='\0';

            printf("\nGrammar Without Left Recursion: \n\n");

            printf(" %c->%s%c'\n", nont_terminal,beta,nont_terminal);

            printf(" %c'->%s%c'|#\n", nont_terminal,alpha,nont_terminal);

    }

        else

            printf("This Grammar CAN'T be REDUCED.\n");

  }

    else

        printf("\n This Grammar is not LEFT RECURSIVE.\n");

Left Factoring

#include<stdio.h>

#include<string.h>

int main()

    printf("Aditya Saxena");

    char gram[20],part1[20],part2[20],modifiedGram[20],newGram[20],tempGram[20];

    int i,j=0,k=0,l=0,pos;

    printf("Enter Production : A->");


    gets(gram);

    for(i=0;gram[i]!='|';i++,j++)

        part1[j]=gram[i];

    part1[j]='\0';

    for(j=++i,i=0;gram[j]!='\0';j++,i++)

        part2[i]=gram[j];

    part2[i]='\0';

    for(i=0;i<strlen(part1)||i<strlen(part2);i++){

        if(part1[i]==part2[i]){

            modifiedGram[k]=part1[i];

            k++;

            pos=i+1;

    }

  }

    for(i=pos,j=0;part1[i]!='\0';i++,j++){

        newGram[j]=part1[i];

  }

    newGram[j++]='|';

    for(i=pos;part2[i]!='\0';i++,j++){

        newGram[j]=part2[i];

  }

    modifiedGram[k]='X';

    modifiedGram[++k]='\0';

    newGram[j]='\0';

    printf("\nGrammar Without Left Factoring : : \n");

    printf(" A->%s",modifiedGram);
    printf("\n X->%s\n",newGram);

Result: The Program Executed successfully.

EXPERIMENT-5

Computation of FIRST and FOLLOW in a grammar

Aim: Write a program in C/C++ to find a FIRST and FOLLOW set from a given set
of production rule.

Theory:-

FIRST and FOLLOW are two functions associated with grammar that help us fill in the
entries of an M-table.
FIRST ()− It is a function that gives the set of terminals that begin the strings derived from
the production rule.
A symbol c is in FIRST (α) if and only if α ⇒ cβ for some sequence β of grammar symbols.
A terminal symbol a is in FOLLOW (N) if and only if there is a derivation from the start
symbol S of the grammar such that S ⇒ αNαβ, where α and β are a (possible empty)
sequence of grammar symbols. In other words, a terminal c is in FOLLOW (N) if c can
follow N at some point in a derivation.

Program:-

#include <ctype.h>

#include <stdio.h>

#include <string.h>

void followfirst(char, int, int);

void follow(char c);

void findfirst(char, int, int);

int count, n = 0;

char calc_first[10][100];

char calc_follow[10][100];

int m = 0;

char production[10][10];

char f[10], first[10];

int k;

char ck;

int e;

int main(int argc, char** argv)

printf("Aditya Saxena\n\n");

int jm = 0;

int km = 0;

int i, choice;

char c, ch;

count = 8;

strcpy(production[0], "X=TnS");

strcpy(production[1], "X=Rm");

strcpy(production[2], "T=q");
strcpy(production[3], "T=#");

strcpy(production[4], "S=p");

strcpy(production[5], "S=#");

strcpy(production[6], "R=om");

strcpy(production[7], "R=ST");

int kay;

char done[count];

int ptr = -1;

for (k = 0; k < count; k++) {

for (kay = 0; kay < 100; kay++) {

calc_first[k][kay] = '!';

int point1 = 0, point2, xxx;

for (k = 0; k < count; k++) {

c = production[k][0];

point2 = 0;

xxx = 0;

for (kay = 0; kay <= ptr; kay++)

if (c == done[kay])

xxx = 1;

if (xxx == 1)

continue;

findfirst(c, 0, 0);

ptr += 1;

done[ptr] = c;

printf("\n First(%c) = { ", c);

calc_first[point1][point2++] = c;

for (i = 0 + jm; i < n; i++) {

int lark = 0, chk = 0;


for (lark = 0; lark < point2; lark++) {

if (first[i] == calc_first[point1][lark]) {

chk = 1;

break;

if (chk == 0) {

printf("%c, ", first[i]);

calc_first[point1][point2++] = first[i];

printf("}\n");

jm = n;

point1++;

printf("\n");

printf("-----------------------------------------------"

"\n\n");

char donee[count];

ptr = -1;

for (k = 0; k < count; k++) {

for (kay = 0; kay < 100; kay++) {

calc_follow[k][kay] = '!';

point1 = 0;

int land = 0;

for (e = 0; e < count; e++) {

ck = production[e][0];

point2 = 0;
xxx = 0;

for (kay = 0; kay <= ptr; kay++)

if (ck == donee[kay])

xxx = 1;

if (xxx == 1)

continue;

land += 1;

follow(ck);

ptr += 1;

donee[ptr] = ck;

printf(" Follow(%c) = { ", ck);

calc_follow[point1][point2++] = ck;

for (i = 0 + km; i < m; i++) {

int lark = 0, chk = 0;

for (lark = 0; lark < point2; lark++) {

if (f[i] == calc_follow[point1][lark]) {

chk = 1;

break;

if (chk == 0) {

printf("%c, ", f[i]);

calc_follow[point1][point2++] = f[i];

printf(" }\n\n");

km = m;

point1++;

}
void follow(char c)

int i, j;

if (production[0][0] == c) {

f[m++] = '$';

for (i = 0; i < 10; i++) {

for (j = 2; j < 10; j++) {

if (production[i][j] == c) {

if (production[i][j + 1] != '\0') {

followfirst(production[i][j + 1], i,

(j + 2));

if (production[i][j + 1] == '\0'

&& c != production[i][0]) {

follow(production[i][0]);

void findfirst(char c, int q1, int q2)

int j;

if (!(isupper(c))) {

first[n++] = c;

for (j = 0; j < count; j++) {

if (production[j][0] == c) {

if (production[j][2] == '#') {
if (production[q1][q2] == '\0')

first[n++] = '#';

else if (production[q1][q2] != '\0'

&& (q1 != 0 || q2 != 0)) {

findfirst(production[q1][q2], q1,

(q2 + 1));

else

first[n++] = '#';

else if (!isupper(production[j][2])) {

first[n++] = production[j][2];

else {

findfirst(production[j][2], j, 3);

void followfirst(char c, int c1, int c2)

int k;

if (!(isupper(c)))

f[m++] = c;

else {

int i = 0, j = 1;

for (i = 0; i < count; i++) {

if (calc_first[i][0] == c)

break;

}
while (calc_first[i][j] != '!') {

if (calc_first[i][j] != '#') {

f[m++] = calc_first[i][j];

else {

if (production[c1][c2] == '\0') {

follow(production[c1][0]);

else {

followfirst(production[c1][c2], c1,

c2 + 1);

j++;

Result: The Program Executed successfully.

EXPERIMENT-6

Computation of Predictive Parsing

Aim: Write a program in C/C++ for construction of predictive parser table.

Theory:

A predictive parser is a recursive descent parser with no backtracking or backup. It is a top-


down parser that does not require backtracking. At each step, the choice of the rule to be
expanded is made upon the next terminal symbol.
Consider  

A -> A1 | A2 | ... | An
If the non-terminal is to be further expanded to ‘A’, the rule is selected based on the current
input symbol ‘a’ only.

Program:-

#include <stdio.h>

#include <string.h>

char prol[7][10] = { "S", "A", "A", "B", "B", "C", "C" };

char pror[7][10] = { "A", "Bb", "Cd", "aB", "@", "Cc", "@" };

char prod[7][10] = { "S->A", "A->Bb", "A->Cd", "B->aB", "B->@", "C->Cc", "C->@" };

char first[7][10] = { "abcd", "ab", "cd", "a@", "@", "c@", "@" };

char follow[7][10] = { "$", "$", "$", "a$", "b$", "c$", "d$" };

char table[5][6][10];

int numr(char c)

switch (c)

case 'S':

return 0;

case 'A':

return 1;

case 'B':

return 2;

case 'C':

return 3;

case 'a':

return 0;

case 'b':

return 1;
case 'c':

return 2;

case 'd':

return 3;

case '$':

return 4;

return (2);

int main(){

int i, j, k;

for (i = 0; i < 5; i++)

for (j = 0; j < 6; j++)

strcpy(table[i][j], " ");

printf("The following grammar is used for Parsing Table:\n");

for (i = 0; i < 7; i++)

printf("%s\n", prod[i]);

printf("\nPredictive parsing table:\n");

fflush(stdin);

for (i = 0; i < 7; i++){

k = strlen(first[i]);

for (j = 0; j < 10; j++)

if (first[i][j] != '@')

strcpy(table[numr(prol[i][0]) + 1][numr(first[i][j]) + 1], prod[i]);

for (i = 0; i < 7; i++){


if (strlen(pror[i]) == 1){

if (pror[i][0] == '@'){

k = strlen(follow[i]);

for (j = 0; j < k; j++)

strcpy(table[numr(prol[i][0]) + 1][numr(follow[i][j]) + 1], prod[i]);

strcpy(table[0][0], " ");

strcpy(table[0][1], "a");

strcpy(table[0][2], "b");

strcpy(table[0][3], "c");

strcpy(table[0][4], "d");

strcpy(table[0][5], "$");

strcpy(table[1][0], "S");

strcpy(table[2][0], "A");

strcpy(table[3][0], "B");

strcpy(table[4][0], "C");

printf("\n--------------------------------------------------------\n");

for (i = 0; i < 5; i++)

for (j = 0; j < 6; j++)

printf("%-10s", table[i][j]);

if (j == 5)

printf("\n--------------------------------------------------------\n");

}
}

Result: The Program Executed successfully.

EXPERIMENT-7

Computation of Shift Reduce Parsing

Aim: Write a program in C/C++ to implement the shift reduce parsing.

Theory:-

Shift Reduce parser attempts for the construction of parse in a similar manner as done in
bottom-up parsing i.e. the parse tree is constructed from leaves(bottom) to the root(up). A
more general form of the shift-reduce parser is the LR parser. 

This parser requires some data structures i.e. 

 An input buffer for storing the input string.


 A stack for storing and accessing the production rules.

Program:-

#include<stdio.h>

#include<string.h>

int k=0,z=0,i=0,j=0,c=0;

char a[16],ac[20],stk[15],act[10]; void check();

int main(){

    printf("Aditya Saxena\n");

    puts("GRAMMAR is \n E->E+E \n E->E*E \n E->(E) \n E->id"); puts("Enter input string


");

    fgets(a, sizeof(a), stdin);

    c=strlen(a);

    strcpy(act,"SHIFT->");

    puts("STACK \t  INPUT \tCOMMENT");

    printf("$   \t%s$\n",a);

    for(k=0,i=0; j<c; k++,i++,j++){

        if(a[j]=='i' && a[j+1]=='d'){

            stk[i]=a[j];

            stk[i+1]=a[j+1];

            stk[i+2]='\0';

            a[j]=' ';

            a[j+1]=' ';

    }

        else{

            stk[i]=a[j];

            stk[i+1]='\0';

            a[j]=' ';
            printf("\n$%s\t%s$\t%ssymbols",stk,a,act);

            check();

    }

  }

void check(){

    strcpy(ac,"REDUCE TO E");

    for(z=0; z<c; z++)

        if(stk[z]=='i' && stk[z+1]=='d'){

            stk[z]='E';

            stk[z+1]='\0';

            printf("\n$%s\t%s$\t%s",stk,a,ac);

            j++;

    }

    for(z=0; z<c; z++)

        if(stk[z]=='E' && stk[z+1]=='+' && stk[z+2]=='E'){

            stk[z]='E';

            stk[z+1]='\0';

            stk[z+2]='\0';

            printf("\n$%s\t%s$\t%s",stk,a,ac);

            i=i-2;

    }

    for(z=0; z<c; z++)

        if(stk[z]=='E' && stk[z+1]=='*' && stk[z+2]=='E'){

            stk[z]='E';

            stk[z+1]='\0';
            stk[z+1]='\0';

            printf("\n$%s\t%s$\t%s",stk,a,ac);

            i=i-2;

    }

    for(z=0; z<c; z++)

        if(stk[z]=='(' && stk[z+1]=='E' && stk[z+2]==')'){

            stk[z]='E';

            stk[z+1]='\0';

            stk[z+1]='\0';

            printf("\n$%s\t%s$\t%s",stk,a,ac);

            i=i-2;

    }

Result: The Program Executed successfully.

You might also like