Code:: Compiler Design (3170701) 190090107055
Code:: Compiler Design (3170701) 190090107055
Practical 1
Design a lexical analyzer for a given language and the lexical
analyzer should ignore redundant spaces, tabs and newlines. It
should also ignore comments. Although the syntax specification
states that identifiers can be arbitrarily long, you may restrict the
length to some reasonable value. Simulate the same in C language.
• Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char keywords[32][10] = {"auto", "break", "case", "char", "const", "continue", "default", "do",
"double", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long", "register", "return",
"short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void",
"volatile", "while"};
int i, flag = 0;
if (strcmp(keywords[i], buffer) == 0)
flag = 1;
1|Page
Compiler Design (3170701) 190090107055
break;
return flag;
int main()
FILE *fp;
int i, j = 0;
fp = fopen("c:\\practical.txt", "r");
if (fp == NULL)
exit(0);
if (ch == operators[i])
if (isalnum(ch))
2|Page
Compiler Design (3170701) 190090107055
buffer[j++] = ch;
buffer[j] = '\0';
j = 0;
if (isKeyword(buffer) == 1)
else
fclose(fp);
return 0;
3|Page
Compiler Design (3170701) 190090107055
• Text File:
• Output:
4|Page
Compiler Design (3170701) 190090107055
Practical 2
Implement generic DFA to recognize any regular any regular
expression and perform string validation.
• Code:
#include
<stdio.h>
#include
<conio.h>
int ninputs;
//function
declarationint
check(char,
int); int
dfa[10][10];
char c[10],
string[10];int
main()
{
int nstates,
nfinals;int
f[10];
int i, j, s = 0, final = 0;
printf("enter the number of states that your dfa consist
of \n");scanf("%d", &nstates);
printf("enter the number of input symbol that dfa
have \n");scanf("%d", &ninputs);
printf("\n enter input
symbols\t");for (i = 0; i <
ninputs; i++)
5|Page
Compiler Design (3170701) 190090107055
{
printf("\n\n %d input\t",
i + 1);printf("%c", c[i] =
getch());
}
printf("\n\n enter number of final
states\t");scanf("%d", &nfinals);
or (i = 0; i < nfinals; i++)
{
printf("\n\n Final state %d : q",
i + 1);scanf("%d", &f[i]);
}
printf(" ");
printf("\n\ndefine transition rule as (initial state, input symbol ) = final
state\n");for (i = 0; i < ninputs; i++)
{
for (j = 0; j < nstates; j++)
{
printf("\n(q%d , %c ) = q", j, c[i]);
scanf("%d", &dfa[i][j]);
}
}
do
{
i = 0;
printf("\n\n Enter Input
String.. ");scanf("%s",
string);
while (string[i] != '\0')
if ((s = check(string[i++],
s)) < 0)break;
for (i = 0; i <
nfinals; i++)if (f[i]
== s)
6|Page
Compiler Design (3170701) 190090107055
final = 1;
if (final == 1)
printf("\n valid string");
else
printf("invalid
string");getch();
printf("\n Do you want to continue.? \n(y/n) ");
}
while (getch() == 'y');
getch();
}
int check(char b, int d)
{
int j;
for (j = 0; j <
ninputs; j++)if (b ==
c[j])
return
(dfa[d][j]);
return -1;
}
7|Page
Compiler Design (3170701) 190090107055
• Output:
8|Page
Compiler Design (3170701) 190090107055
Practical 3
Implement generic DFA to recognize any regular any regular
expression and perform string validation.
o Lex is a program that generates lexical analyzer. It is used with YACC parser generator.
o The lexical analyzer is a program that transforms an input stream into a sequence of tokens.
o It reads the input stream and produces the source code as output through implementing the
lexical analyzer in the C program.
o Firstly, lexical analyzer creates a program lex. l in the Lex language. Then Lex compiler
runs the lex. l program and produces a C program lex.yy.c.
o Finally, C compiler runs the lex.yy.c program and produces an object program a.out.
o a.out is lexical analyzer that transforms an input stream into a sequence of tokens.
o Lex is a lexical analysis tool that can be used to identify specific text strings in a structured
way from source text. Yacc is a grammar parser; it reads text and can be used to turn a
sequence of words into a structured format for processing.
9|Page
Compiler Design (3170701) 190090107055
o lex.l is an a input file written in a language which describes the generation of lexical
analyzer. The lex compiler transforms lex.l to a C program known as lex.yy.c.
o lex.yy.c is compiled by the C compiler to a file called a.out.
o The output of C compiler is the working lexical analyzer which takes stream of input
characters and produces a stream of tokens.
o yylval is a global variable which is shared by lexical analyzer and parser to return the name
and an attribute value of token.
o The attribute value can be numeric code, pointer to symbol table or nothing.
o Another tool for lexical analyzer generation is Flex.
declarations
%%
Translation rules
%%
auxiliary functions
10 | P a g e
Compiler Design (3170701) 190090107055
Conflict arises when several prefixes of input matches one or more patterns. This can be
resolved by the following:
o Always prefer a longer prefix than a shorter prefix.
o If two or more patterns are matched for the longest prefix, then the first pattern listed
in lex program is preferred.
• Lookahead Operators:
o Lookahead operator is the additional operator that is read by lex in order to distinguish
additional pattern for a token.
o Lexical analyzer is used to read one character ahead of valid lexeme and then retracts to
produce token.
o At times, it is needed to have certain characters at the end of input to match with a pattern.
11 | P a g e
Compiler Design (3170701) 190090107055
Regular Meaning
Expression
* Matches with zero or more occurrences of preceding expressions.
For example, 1* occurrence of 1 for any number of times.
. Matches any single character other than new line character.
[] A character class which matches any character within the bracket.
For example, [a-z] matches with any alphabet in lower case.
() Group of regular expressions together put into a new regular
expression.
““ The string written in quotes matches literally. For example,
“Hanumaan” matches with the string Hanumaan.
$ Matches with the end of line as last character.
+ Matches with one or more occurrences of preceding expression.
For example, [0 – 9] + any number but not empty string.
? Matches zero or one occurrence of preceding regular expression.
For example, [+ -] ? [0 – 9] + a number with unary operator.
^ Matches the beginning of a line as first character.
[^] Used as for negation. For example, [^verb] means except verb
match with anything else.
\ Used as escape metacharacter.
For example, \n is a new line character.
\# prints the # literally
| To represent the or i.e. another alternative.
For example, a | b means match with either a or b.
• LEX Actions:
There are various LEX actions that can be used for ease of programming using LEX tool.
1. BEGIN – It indicates the start state. The lexical analyzer starts at state 0.
12 | P a g e
Compiler Design (3170701) 190090107055
3. yytext – When laxer matches or recognize the token from input token then the lexeme is
stored in a null terminated string called yytext.
As soon as new token is found the contents of yytext are replaced bt new token.
5. yywrap() – The function yywrap() is called when scanner encounters end of file. If yywrap()
returns 0 then scanner continues scanning. When yywrap() returns 1 that means end of file is
encountered.
6. yyin – It is the standard input file that stores input source program.
7. yyleng – When a laxer recognize token then the lexeme is stored in a null terminated string
called yytext. And yyleng stores the length or number of characters in input string. The value
in yyleng is same as strlen() functions.
13 | P a g e
Compiler Design (3170701) 190090107055
We have to construct recognizer that looks for the lexemes stored in the input buffer.
It works using these two rules -
1. If more than one pattern matches then recognizer has to choose the longest lexeme matched.
2. If there are two or more pattern that match the longest lexeme, the first listed matching
pattern is chosen.
o The command line parameters that are appearing on the shell prompt.
o The command line interface is the interface which allows the user to interact with the
computer by typing the commands.
o In C we can pass these parameters to the main function to the form of character array.
For example:
$ cp abc.txt pqr.txt
Here
argv[0] = cp
argv[1] = abc.txt
argv[2] = pqr.txt
As there are three such parameters that are present at the command line interface argc value
will be 3.
14 | P a g e
Compiler Design (3170701) 190090107055
• CODE:
%{
int flag = 0;
%}
%%
15 | P a g e
Compiler Design (3170701) 190090107055
[aeiouAEIOU].[a-zA-Z0-9.]+ flag=1;[a-zA-Z0-9]+
%%
main()
{
yylex();
if (flag == 1) printf("Accepted");
else
printf("Not Accepted");
}
• CODE:
%{
#include<stdio.h>#include<string.h> inti = 0;
%}
/* Rules Section*/
%%
([a-zA-Z0-9])* {i++;} /* Rule for counting
number of words*/
return 0;
}
• CODE:
%{
#include<stdio.h>
int lines=0, words=0,s_letters=0,c_letters=0, num=0, spl_char=0,total=0;
%}
16 | P a g e
Compiler Design (3170701) 190090107055
%%
\n { lines++; words++;}[\t ' ']words++;
[A-Z]
c_letters++; [a-z]s_letters++; [0-9]num++;
. spl_char++;
%%
int main()
{
yyin= fopen("test.txt","r");yylex();
total=s_letters+c_letters+num+spl_char;
printf(" This File contains ..."); printf("\n\t%d lines", lines); printf("\n\t%d words",words);
printf("\n\t%d small letters", s_letters); printf("\n\t%d capital letters",c_letters);printf("\n\t%d
digits", num);
printf("\n\t%d special characters",spl_char);printf("\n\tIn total %d characters..\n",total);
}
int yywrap(void){}
• CODE:
%%
{lower} {printf("%c",yytext[0]- 32);}
{CAPS} {printf("%c",yytext[0]+ 32);}
{space} ECHO;
. ECHO;
%%
main()
{
yylex();
}
int yywrap(void){}
17 | P a g e
Compiler Design (3170701) 190090107055
Practical 4
Implement the following programs using Lex.
A. Create a program to take input from a text file and count no
of characters, no. of lines & no. of words.
B. Count the number of vowels and consonants in a given input
string.
C. Print only numbers from the given file.
D. Convert Roman to Decimal
E. Print all HTML tags from the given file.
F. Add line numbers to the given file and display them on the
standard output.
G. Count the number of comment lines in a given C program.
H. Eliminate comments from a given C program and create a
separate file without comments.
I. Generate Histogram of Words
J. Caesar Cypher
K. Check weather given statement is compound or simple
• Code:
%
{
#include<studio.h> int n_chars=0;
int n_lines=0; int n_words = 0;
%}
%%
\n {n_chars++;n_lines++;}
[^ \n\t]+ {n_words++, n_chars=n_chars+yyleng;}
18 | P a g e
Compiler Design (3170701) 190090107055
. {n_chars++;}
%%
int yywrap(){}
int main(int argc[],char *argv[])
{
yyin=fopen("c:\\practical.txt", "r");
yylex();
printf("no of characters: %d",n_chars); printf("\n");
printf("no of lines: %d",n_lines); printf("\n");
printf("no of words: %d",n_words); printf("\n");
return 0;
}
• Text File:
19 | P a g e
Compiler Design (3170701) 190090107055
• Output:
• Code:
%
{
int vow_count=0; int const_count =0;
%}
%%
[aeiouAEIOU] {vow_count++;} [a-zA-Z] {const_count++;}
%%
int yywrap(){} int main()
{
printf("Enter the string of vowels and consonants:"); yylex();
printf("Number of vowels are: %d\n", vow_count); printf("Number of consonants are: %d\n",
const_count); return 0;
}
20 | P a g e
Compiler Design (3170701) 190090107055
• Output:
• Code:
%
{
#include<stdio.h> int num_count=0;
%}
num [0-9]+
%%
{num} {num_count++; printf("%s",yytext);
}
%%
int yywrap(void){} int main()
{
yyin = fopen("c:\\practical.txt", "r");
yylex();
printf("\nTotal of numbers: %d",num_count);
}
21 | P a g e
Compiler Design (3170701) 190090107055
• Text File:
• Output:
22 | P a g e
Compiler Design (3170701) 190090107055
• Code:
%{
%}
%%
"<"[^>]*> {printf("%s\n", yytext); } /* if anything enclosed in
these < > occur print text*/
. ; // else do nothing
%%
int yywrap(){}
return 0;
}
• Output:
23 | P a g e
Compiler Design (3170701) 190090107055
F. Add line numbers to the given file and display them on the
standard output.
• Code:
%
{
int line_number = 1;
line .*\n
%%
{line} { printf("%10d %s", line_number++, yytext); }
%%
int yywrap(){}
• Text File:
• Output:
25 | P a g e
Compiler Design (3170701) 190090107055
• Code:
%{#include<stdio.h>
int count = 0;
%}
%x C
%%
"/*"][.]*"*/" {count++;}
"/*" {BEGIN C;}
<C>"*/" {BEGIN 0; count++;}
<C>\n {;}
<C>. {;}
\/\/.* {count++;}
%%
void main()
{
char file[] = "data.c";
yyin = fopen("c:\\practical.txt", "r");
yylex();
printf("Number of comment lines in c file %s is %d\n", file, count);
}
int yywrap()
{
return 1;
}
26 | P a g e
Compiler Design (3170701) 190090107055
• Text File:
• Output:
27 | P a g e
Compiler Design (3170701) 190090107055
• Code:
%
{
#include<stdio.h>
%}
%%
\/\/(.*) {};
\/\*(.*\n)*.*\*\/ {};
%%
int yywrap()
{
return 1;
}
int main()
{
yyin=fopen("c:\\practical.txt", "r");
yyout=fopen("C:\\out.c","w");
yylex();
return 0;
}
28 | P a g e
Compiler Design (3170701) 190090107055
• Output:
• Code:
%
{
#include<stdio.h>
#include<string.h>
29 | P a g e
Compiler Design (3170701) 190090107055
%}
%%
[a-zA-Z]+ { if(strcmp(yytext, word)==0)
count++; }
. ;
%%
int yywrap()
{
return 1;
}
int main()
{
extern FILE *yyin, *yyout;
yyin=fopen("input.txt", "r");
yylex();
printf("%d", count);
}
• Output:
30 | P a g e
Compiler Design (3170701) 190090107055
J. Caesar Cypher
• Code:
%%
[a-z] {char ch = yytext[0];
ch += 3;
if (ch> 'z') ch -= ('z'+1- 'a');
printf ("%c" ,ch );
}
[A-Z] { char ch = yytext[0] ;
ch += 3;
if (ch> 'Z') ch -= ('Z'+1- 'A');
printf("%c",ch);
}
%%
• Output:
31 | P a g e
Compiler Design (3170701) 190090107055
• Code:
%{
#include<stdio.h>
int flag=0;
%}
%%
and |
or |
but |
because |
if |
then |
nevertheless { flag=1; }
. ;
\n { return 0; }
%%
int main()
{
printf("Enter the sentence:\n");
yylex();
if(flag==0)
printf("Simple sentence\n");
else
printf("compound sentence\n");
}
int yywrap( )
{
32 | P a g e
Compiler Design (3170701) 190090107055
return 1;
}
• Output:
33 | P a g e
Compiler Design (3170701) 190090107055
Practical 5
Write a C program to find FIRST and FOLLOW of specific
grammar.
Input: The string consists of grammar symbols.
Output: The First and Follow set for a given string. Explanation:
The student has to assume a typical grammar. The program when
run will ask for the string to be entered. The program will find
the First and Follow set of the
given string.
• Code:
#include<stdio.h>
#include<ctype.h>
char a[8][8];
int n=5 ; struct firTab
{
int n;
char firT[5];
};
struct folTab
{
int n;
char folT[5];
};
struct folTab follow[5]; struct firTab first[5]; int col;
void findFirst(char,char); void findFollow(char,char);
void folTabOperation(char,char); void firTabOperation(char,char); void main()
{
int i,j,c=0,cnt=0; char ip;
char b[8];
printf("\n\t\t======FIRST AND FOLLOW SET====== \n\nEnter Production Amount : ");
scanf("%d",&n);
printf("\n\tenter %d productions in format E->T+G\n",n); printf("\t \n");
for(i=0; i<n; i++)
{
scanf("%s",&a[i]);
}
for(i=0; i<n; i++)
{ c=0;
for(j=0; j<i+1; j++)
{
if(a[i][0] == b[j])
34 | P a g e
Compiler Design (3170701) 190090107055
c=1;
break;
}
}
if(c !=1)
{
b[cnt] = a[i][0]; cnt++;
}
}
printf("\n");
printf(" %c",follow[i].folT[j]);
}
}
printf(" } ");
printf("\n");
}
}
void findFirst(char ip,char pos)
{
int i;
for(i=0; i<n; i++)
{
if(ip == a[i][0])
{
if(isupper(a[i][3]))
{
findFirst(a[i][3],pos);
}
else
{
first[pos].firT[col]=a[i][3]; first[pos].n++;
col++;
}
}
}
}
void findFollow(char ip,char row)
{
int i,j;
if(row==0 && col==1)
{
follow[row].folT[col]= '$'; col++;
follow[row].n++;
}
for(i=0; i<n; i++)
{
for(j=3; j<7; j++)
{
if(a[i][j] == ip)
{
if(a[i][j+1] == '\0')
{
if(a[i][j] != a[i][0])
{
folTabOperation(a[i][0],row);
}
36 | P a g e
Compiler Design (3170701) 190090107055
}
else if(isupper(a[i][j+1]))
{
if(a[i][j+1] != a[i][0])
{
firTabOperation(a[i][j+1],row);
}
}
else
{
follow[row].folT[col] = a[i][j+1]; col++;
follow[row].n++;
}
}
}
}
}
void folTabOperation(char ip,char row)
{
int i,j;
for(i=0; i<5; i++)
{
if(ip == follow[i].folT[0])
{
for(j=1; j<=follow[i].n; j++)
{
follow[row].folT[col] = follow[i].folT[j]; col++;
follow[row].n++;
}
}
}
}
folTabOperation(ip,row);
}
}
}
}
}
• Output:
38 | P a g e
Compiler Design (3170701) 190090107055
Practical 6
Write a C program for constructing LL (1) parsing using FIRST
and FOLLOW generated in the above program.
• Code:
#include<stdio.h>
#include<string.h>
#define TSIZE 128
// table[i][j] stores
// the index of production that must be applied on
// ith varible if the input is
// jth nonterminal
int table[100][TSIZE];
// stores all list of terminals
// the ASCII value if use to index terminals
// terminal[i] = 1 means the character with
// ASCII value is a terminal
char terminal[TSIZE];
// stores all list of terminals
// only Upper case letters from 'A' to 'Z'
// can be nonterminals
// nonterminal[i] means ith alphabet is present as
// nonterminal is the grammar
char nonterminal[26];
// structure to hold each production
// str[] stores the production
// len is the length of production
struct product {
char str[100];
int len;
}pro[20];
// no of productions in form A->ß
int no_pro;
char first[26][TSIZE];
char follow[26][TSIZE];
// stores first of each production in form A->ß
char first_rhs[100][TSIZE];
// check if the symbol is nonterminal
39 | P a g e
Compiler Design (3170701) 190090107055
int isNT(char c) {
return c >= 'A' && c <= 'Z';
}
// reading data from the file
void readFromFile() {
FILE* fptr;
fptr = fopen("text.txt", "r");
char buffer[255];
int i;
int j;
while (fgets(buffer, sizeof(buffer), fptr)) {
printf("%s", buffer);
j = 0;
nonterminal[buffer[0] - 'A'] = 1;
for (i = 0; i < strlen(buffer) - 1; ++i) {
if (buffer[i] == '|') {
++no_pro;
pro[no_pro - 1].str[j] = '\0';
pro[no_pro - 1].len = j;
pro[no_pro].str[0] = pro[no_pro - 1].str[0];
pro[no_pro].str[1] = pro[no_pro - 1].str[1];
pro[no_pro].str[2] = pro[no_pro - 1].str[2];
j = 3;
}
else {
pro[no_pro].str[j] = buffer[i];
++j;
if (!isNT(buffer[i]) && buffer[i] != '-' && buffer[i] != '>') {
terminal[buffer[i]] = 1;
}
}
}
pro[no_pro].len = j;
++no_pro;
}
}
void add_FIRST_A_to_FOLLOW_B(char A, char B) {
int i;
for (i = 0; i < TSIZE; ++i) {
if (i != '^')
follow[B - 'A'][i] = follow[B - 'A'][i] || first[A - 'A'][i];
}
40 | P a g e
Compiler Design (3170701) 190090107055
}
void add_FOLLOW_A_to_FOLLOW_B(char A, char B) {
int i;
for (i = 0; i < TSIZE; ++i) {
if (i != '^')
follow[B - 'A'][i] = follow[B - 'A'][i] || follow[A - 'A'][i];
}
}
void FOLLOW() {
int t = 0;
int i, j, k, x;
while (t++ < no_pro) {
for (k = 0; k < 26; ++k) {
if (!nonterminal[k]) continue;
char nt = k + 'A';
for (i = 0; i < no_pro; ++i) {
for (j = 3; j < pro[i].len; ++j) {
if (nt == pro[i].str[j]) {
for (x = j + 1; x < pro[i].len; ++x) {
char sc = pro[i].str[x];
if (isNT(sc)) {
add_FIRST_A_to_FOLLOW_B(sc, nt);
if (first[sc - 'A']['^'])
continue;
}
else {
follow[nt - 'A'][sc] = 1;
}
break;
}
if (x == pro[i].len)
add_FOLLOW_A_to_FOLLOW_B(pro[i].str[0], nt);
}
}
}
}
}
}
void add_FIRST_A_to_FIRST_B(char A, char B) {
int i;
for (i = 0; i < TSIZE; ++i) {
if (i != '^') {
41 | P a g e
Compiler Design (3170701) 190090107055
42 | P a g e
Compiler Design (3170701) 190090107055
if (isNT(sc)) {
add_FIRST_A_to_FIRST_RHS__B(sc, i);
if (first[sc - 'A']['^'])
continue;
}
else {
first_rhs[i][sc] = 1;
}
break;
}
if (j == pro[i].len)
first_rhs[i]['^'] = 1;
}
++t;
}
}
int main() {
readFromFile();
follow[pro[0].str[0] - 'A']['$'] = 1;
FIRST();
FOLLOW();
FIRST_RHS();
int i, j, k;
43 | P a g e
Compiler Design (3170701) 190090107055
44 | P a g e
Compiler Design (3170701) 190090107055
}
printf("\n");
int p = 0;
for (i = 0; i < no_pro; ++i) {
if (i != 0 && (pro[i].str[0] != pro[i - 1].str[0]))
p = p + 1;
for (j = 0; j < TSIZE; ++j) {
if (first_rhs[i][j] && j != '^') {
table[p][j] = i + 1;
}
else if (first_rhs[i]['^']) {
for (k = 0; k < TSIZE; ++k) {
if (follow[pro[i].str[0] - 'A'][k]) {
table[p][k] = i + 1;
}
}
}
}
}
k = 0;
for (i = 0; i < no_pro; ++i) {
if (i == 0 || (pro[i - 1].str[0] != pro[i].str[0])) {
printf("%-10c", pro[i].str[0]);
for (j = 0; j < TSIZE; ++j) {
if (table[k][j]) {
printf("%-10s", pro[table[k][j] - 1].str);
}
else if (terminal[j]) {
printf("%-10s", "");
}
}
++k;
printf("\n");
}
}
}
45 | P a g e
Compiler Design (3170701) 190090107055
• Text File:
• Output:
46 | P a g e
Compiler Design (3170701) 190090107055
Practical 7
Implementation of Recursive Descent Parser without
backtracking
Input: The string to be parsed.
Output: Whether string parsed successfully or not.
• Code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
charinput[10];
int i,
error;
void E();
void T();
void Eprime();
void Tprime();
void F();
main()
{
printf("\nRecursivedescentparsingfor thefollowinggrammar\n");
printf("\nE -> E+T |T\nT -> T*F |F\nF -> (E) |id\n");
i = 0;
error = 0;
printf("\nEnteranarithmeticexpression : ");//Eg:a+a*a gets(input);
E();
if (strlen(input) == i && error == 0)
printf("\nParsing Successful..!!!\n");
else
printf("\nError..!!!\n");
47 | P a g e
Compiler Design (3170701) 190090107055
void E()
{
T();
Eprime();
}
void Eprime()
{
if (input[i] == '+')
{
i++;
T();
Eprime();
}
}
void T()
{
F();
Tprime();
}
void Tprime()
{
if (input[i] == '*')
{
i++; F();
Tprime();
}
}
void F()
{
if (isalnum(input[i])) i++;
else if (input[i] == '(')
48 | P a g e
Compiler Design (3170701) 190090107055
{
i++; E();
if(input[i] ==')') i++;
else
error = 1;
}
else
error = 1;
}
Output:
49 | P a g e
Compiler Design (3170701) 190090107055
Practical 8
Write a C program to implement operator precedence parsing.
• Code:
#include<stdio.h>
#include<string.h>
char *input;
int i=0;
char lasthandle[6],stack[50],handles[][5]={")E(","E*E","E+E","i","E^E"};
//(E) becomes )E( when pushed to stack
int top=0,l;
char prec[9][9]={
/*input*/
/*stack + - * / ^ i ( ) $ */
/* + */ '>', '>','<','<','<','<','<','>','>',
/* - */ '>', '>','<','<','<','<','<','>','>',
/* * */ '>', '>','>','>','<','<','<','>','>',
/* / */ '>', '>','>','>','<','<','<','>','>',
/* ^ */ '>', '>','>','>','<','<','<','>','>',
/* i */ '>', '>','>','>','>','e','e','>','>',
50 | P a g e
Compiler Design (3170701) 190090107055
/* ( */ '<', '<','<','<','<','<','<','>','e',
/* ) */ '>', '>','>','>','>','e','e','>','>',
/* $ */ '<', '<','<','<','<','<','<','<','>',
};
int getindex(char c)
{
switch(c)
{
case '+':return 0;
case '-':return 1;
case '*':return 2;
case '/':return 3;
case '^':return 4;
case 'i':return 5;
case '(':return 6;
case ')':return 7;
case '$':return 8;
}
}
int shift()
{
stack[++top]=*(input+i++);
stack[top+1]='\0';
}
int reduce()
51 | P a g e
Compiler Design (3170701) 190090107055
{
int i,len,found,t;
for(i=0;i<5;i++)//selecting handles
{
len=strlen(handles[i]);
if(stack[top]==handles[i][0]&&top+1>=len)
{
found=1;
for(t=0;t<len;t++)
{
if(stack[top-t]!=handles[i][t])
{
found=0;
break;
}
}
if(found==1)
{
stack[top-t+1]='E';
top=top-t+1;
strcpy(lasthandle,handles[i]);
stack[top+1]='\0';
return 1;//successful reduction
}
}
}
return 0;
}
void dispstack()
{
52 | P a g e
Compiler Design (3170701) 190090107055
int j;
for(j=0;j<=top;j++)
printf("%c",stack[j]);
}
void dispinput()
{
int j;
for(j=i;j<l;j++)
printf("%c",*(input+j));
}
void main()
{
int j;
input=(char*)malloc(50*sizeof(char));
printf("\nEnter the string\n");
scanf("%s",input);
input=strcat(input,"$");
l=strlen(input);
strcpy(stack,"$");
printf("\nSTACK\tINPUT\tACTION");
while(i<=l)
{
shift();
printf("\n");
dispstack();
printf("\t");
53 | P a g e
Compiler Design (3170701) 190090107055
dispinput();
printf("\tShift");
if(prec[getindex(stack[top])][getindex(input[i])]=='>')
{
while(reduce())
{
printf("\n");
dispstack();
printf("\t");
dispinput();
printf("\tReduced: E->%s",lasthandle);
}
}
}
if(strcmp(stack,"$E$")==0)
printf("\nAccepted;");
else
printf("\nNot Accepted;");
}
54 | P a g e
Compiler Design (3170701) 190090107055
• Output:
55 | P a g e
Compiler Design (3170701) 190090107055
Practical 9
Implement a C program to implement LALR parsing.
• Code:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
void push(char *, int *, char);
char stacktop(char *);
void isproduct(char, char);
int ister(char);
int isnter(char);
int isstate(char);
void error();
void isreduce(char, char); char pop(char *, int *);
void printt(char *, int *, char[], int); void rep(char[], int);
struct action
{
char row[6][5];
};
const struct action A[12] = {
{"sf", "emp", "emp", "se", "emp", "emp"},
{"emp", "sg", "emp", "emp", "emp", "acc"},
{"emp", "rc", "sh", "emp", "rc", "rc"},
{"emp", "re", "re", "emp", "re", "re"},
{"sf", "emp", "emp", "se", "emp", "emp"},
{"emp", "rg", "rg", "emp", "rg", "rg"},
{"sf", "emp", "emp", "se", "emp", "emp"},
{"sf", "emp", "emp", "se", "emp", "emp"},
{"emp", "sg", "emp", "emp", "sl", "emp"},
56 | P a g e
Compiler Design (3170701) 190090107055
57 | P a g e
Compiler Design (3170701) 190090107055
};
void main()
{
char inp[80], x, p, dl[80], y, bl = 'a'; int i = 0, j, k, l, n, m, c, len;
printf(" Enter the input :"); scanf("%s", inp);
len = strlen(inp); inp[len] = '$';
inp[len + 1] = '\0'; push(stack, &top, bl); printf("\n stack \t\t\t input"); printt(stack, &top, inp,
i);
do
{
x = inp[i];
p = stacktop(stack); isproduct(x, p);
if (strcmp(temp, "emp") == 0) error();
if (strcmp(temp, "acc") == 0) break;
else
{
if (temp[0] == 's')
{
push(stack, &top, inp[i]); push(stack, &top, temp[1]); i++;
}
else
{
if (temp[0] == 'r')
{
j = isstate(temp[1]); strcpy(temp, rl[j - 2].right); dl[0] = rl[j - 2].left;
dl[1] = '\0';
n = strlen(temp);
for (k = 0; k < 2 * n; k++) pop(stack, &top);
for (m = 0; dl[m] != '\0'; m++)
push(stack, &top, dl[m]); l = top;
y = stack[l - 1]; isreduce(y, dl[0]);
for (m = 0; temp[m] != '\0'; m++) push(stack, &top, temp[m]);
58 | P a g e
Compiler Design (3170701) 190090107055
}
}
}
printt(stack, &top, inp, i);
} while (inp[i] != '\0');
if (strcmp(temp, "acc") == 0) printf(" \n accept the input "); else
printf(" \n do not accept the input "); getch();
}
void push(char *s, int *sp, char item)
{
if (*sp == 100) printf(" stack is full "); else
{
*sp = *sp + 1; s[*sp] = item;
}
}
char stacktop(char *s)
{
char i;
i = s[top]; return i;
}
void isproduct(char x, char p)
{
int k, l;
k = ister(x);
l = isstate(p);
strcpy(temp, A[l - 1].row[k - 1]);
}
int ister(char x)
{
int i;
for (i = 0; i < 6; i++) if (x == ter[i]) return i + 1;
return 0;
59 | P a g e
Compiler Design (3170701) 190090107055
}
int isnter(char x)
{
int i;
for (i = 0; i < 3; i++) if (x == nter[i]) return i + 1;
return 0;
}
int isstate(char p)
{
int i;
for (i = 0; i < 12; i++) if (p == states[i]) return i + 1;
return 0;
}
void error()
{
printf(" error in the input "); exit(0);
}
void isreduce(char x, char p)
{
int k, l;
k = isstate(x); l = isnter(p);
strcpy(temp, G[k - 1].r[l - 1]);
}
char pop(char *s, int *sp)
{
char item;
if (*sp == -1)
printf(" stack is empty "); else
{
item = s[*sp];
*sp = *sp - 1;
}
60 | P a g e
Compiler Design (3170701) 190090107055
return item;
}
void printt(char *t, int *p, char inp[], int i)
{
int r; printf("\n");
for (r = 0; r <= *p; r++) rep(t, r); printf("\t\t\t");
for (r = i; inp[r] != '\0'; r++)
printf("%c", inp[r]);
}
void rep(char t[], int r)
{
char c; c = t[r];
switch (c)
{
case 'a': printf("0"); break; case 'b': printf("1"); break; case 'c': printf("2"); break; case 'd':
printf("3"); break; case 'e': printf("4"); break; case 'f': printf("5"); break; case 'g': printf("6");
break; case 'h':
printf("7"); break; case 'm': printf("8"); break; case 'j': printf("9"); break; case 'k':
printf("10"); break;
case 'l': printf("11"); break; default:
printf("%c", t[r]); break;
}
}
61 | P a g e
Compiler Design (3170701) 190090107055
• Output:
62 | P a g e
Compiler Design (3170701) 190090107055
Practical 10
To Study about Yet Another Compiler-Compiler (YACC).
● It is used to produce the source code of the syntactic analyzer of the languageproduced
by LALR (1) grammar.
● The input of YACC is the rule or grammar and the output is a Cprogram.
Input File :
/* definitions */
....
%%
/* rules */
....
%%
/* auxiliary routines */
....
Definition Part:
The definition part includes information about the tokens used in the syntax
definition. Yacc also recognizes single characters as tokens. The definition part can
include C code external to the definition of the parser and variable declarations,
within %{ and %} in the first column.
63 | P a g e
Compiler Design (3170701) 190090107055
Rule Part:
The rules part contains grammar definition in a modified BNF form. Actions is C code in { }
and can be embedded inside (Translation schemes).
The auxiliary routines part is only C code. It includes function definitions for every function
needed in rules part. It can also contain the main() function definition if the parser is going
to be run as a program. The main() function must call the function yyparse().
Output Files :
64 | P a g e
Compiler Design (3170701) 190090107055
Example:
%{
#include<ctype.h>
#include<stdio.h> #define
YYSTYPE double
}%
%%
Lines : Lines S ‘\n’ { printf(“OK \n”);}
| S ‘\n’
| error ‘\n’ {yyerror(“Error: reenter last line:”);
yyerrok; };
S : ‘(’ S ‘)’
| ‘[‘ S ‘]’
|
%%
#include “lex.yy.c”
int main(void){
Return yyparse();
}
%{
%}
65 | P a g e
Compiler Design (3170701) 190090107055
%%
[ \t] {}
\n]. { return yytext[0];}
%%
66 | P a g e
Compiler Design (3170701) 190090107055
Practical 11
Create Yacc and Lex specification files to recognizes arithmetic
expressions involving +, -, * and / .
• Code
test.l file:
test.l file:
%option noyywrap %{
#include "stdio.h" #include "test.tab.h" extern int yylval;
%}
%%
[0-9]+ {yylval=atoi(yytext);return number;} \+ { return plus;}
\- { return minus;}
\* { return multiply;}
\/ {return divide;}
. {return yytext[0];} [\t]+;
\n return 0;
%%
test.y file:
%{
#include "stdio.h" int result=0;
void yyerror(const char *str)
{
fprintf(stderr,"error: %s\n",str); } int yywrap(void)
{
return 1;
67 | P a g e
Compiler Design (3170701) 190090107055
}
%}
%token number plus minus divide multiply %left plus minus
%left multiply divide
%right '^'
%nonassoc UMINUS %% ae: exp {result=$1;} ; exp: number { $$ = $1;}
| exp minus exp {$$ = $1 - $3;} | exp plus exp { $$ = $1 + $3;} | exp divide exp { if($3==0)
yyerror("divide by zero"); else $$ = $1 / $3;}
| minus exp %prec UMINUS {$$ = -$2; } | exp multiply exp { $$ = $1 * $3 ;} |exp'^'exp{}
;
%%
• Output
68 | P a g e
Compiler Design (3170701) 190090107055
Practical 12
Generate 3-tuple intermediate code for given infix expression
• Code:
#include<stdio.h>
#include<string.h>
void pm();
void plus();
void div();
int i,ch,j,l,addr=100;
char ex[10], exp[10] ,exp1[10],exp2[10],id1[5],op[5],id2[5];
void main()
{
clrscr();
while(1)
{
printf("\n1.assignment\n2.arithmetic\n3.relational\n4.Exit\nEnter the choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("\nEnter the expression with assignment operator:");
scanf("%s",exp);
l=strlen(exp);
exp2[0]='\0';
i=0;
while(exp[i]!='=')
{
i++;
}
69 | P a g e
Compiler Design (3170701) 190090107055
strncat(exp2,exp,i);
strrev(exp);
exp1[0]='\0';
strncat(exp1,exp,l-(i+1));
strrev(exp1);
printf("Three address code:\ntemp=%s\n%s=temp\n",exp1,exp2);
break;
case 2:
printf("\nEnter the expression with arithmetic operator:");
scanf("%s",ex);
strcpy(exp,ex);
l=strlen(exp);
exp1[0]='\0';
for(i=0;i<l;i++)
{
if(exp[i]=='+'||exp[i]=='-')
{
if(exp[i+2]=='/'||exp[i+2]=='*')
{
pm();
break;
}
else
{
plus();
break;
}
}
else if(exp[i]=='/'||exp[i]=='*')
{
div();
70 | P a g e
Compiler Design (3170701) 190090107055
break;
}
}
break;
case 3:
printf("Enter the expression with relational operator");
scanf("%s%s%s",&id1,&op,&id2);
if(((strcmp(op,"<")==0)||(strcmp(op,">")==0)||(strcmp(op,"<=")==0)||(strcmp(op,">=")==0)||(s
trcmp(op,"==")==0)||(strcmp(op,"!=")==0))==0)
printf("Expression is error");
else
{
printf("\n%d\tif %s%s%s goto %d",addr,id1,op,id2,addr+3);
addr++;
printf("\n%d\t T:=0",addr);
addr++;
printf("\n%d\t goto %d",addr,addr+2);
addr++;
printf("\n%d\t T:=1",addr);
}
break;
case 4:
exit(0);
}
}
}
void pm()
{
strrev(exp);
j=l-i-1;
strncat(exp1,exp,j);
strrev(exp1);
71 | P a g e
Compiler Design (3170701) 190090107055
• Output:
72 | P a g e
Compiler Design (3170701) 190090107055
Practical 13
Extract Predecessor and Successor from given Control Flow
Graph.
• Code:
#include <iostream>
using namespace std;
// BST Node
struct Node
{
int key;
struct Node *left, *right;
};
73 | P a g e
Compiler Design (3170701) 190090107055
pre = tmp ;
}
74 | P a g e
Compiler Design (3170701) 190090107055
return temp;
}
75 | P a g e
Compiler Design (3170701) 190090107055
if (suc != NULL)
cout << "Successor is " << suc->key;
else
cout << "No Successor";
return 0;
}
• Output
76 | P a g e