You are on page 1of 22

Practical : 01

Objective : “Write a program to identify and count the distinct tokens in the input file using
FLEX.”
>> Lexical Analysis is the first phase of compiler also known as scanner. It converts the input program
into a sequence of Tokens.

>> A lexical token is a sequence of characters that can be treated as a unit in the grammar of the
programming languages.

Example of tokens:
▪ Type token (id, number, real, . . . )
▪ Punctuation tokens (IF, void, return, . . . )
▪ Alphabetic tokens (keywords)
Example of Non-Tokens:
▪ Comments, pre-processor directive, macros, blanks, tabs, newline etc

Code:
%{

#include<stdio.h>

int statements = 0;

int ids = 0;

int assign = 0;

int rel = 0;

int keywords = 0;

int integers = 0;

%}

DIGIT [0-9]
LETTER [A-Za-z]

TYPE int|char|bool|float|void|for|do|while|if|else|return|void

%%

\n {statements++;}

{TYPE} {printf("%s ",yytext);keywords++;}

(<|>|<=|>=|==) {rel++;}

'#'/[a-zA-Z0-9]* {;}

[a-zA-Z]+[a-zA-Z0-9]* {printf("%s ",yytext);ids++;}

= {assign++;}

[0-9]+ {integers++;}

. {;}

%%

void main(int argc, char **argv)

FILE *fh;

if (argc == 2 && (fh = fopen(argv[1], "r"))) {

yyin = fh;
}

yylex();

printf("\n");

printf("statements = %d ids = %d assign = %d rel = %d keywords = %d


integers = %d \n",statements,ids,assign,rel,keywords,integers);

}Input file.c

#include<stdio.h>

int main()
{
int a;
float b;
char c;
printf("Enter a random int,float and character Value \n");
scanf("%d",&a);
scanf("%f",&b);
scanf("%c",&c);

if(a>b){
printf("%d \n",a);
}
if(a==b){
printf("%f \n",b);
}

return 0;
}
Output:

mani6@mani6-Aspire-V3-574G:~/Desktop$ lex m.l

mani6@mani6-Aspire-V3-574G:~/Desktop$ gcc -lfl lex.yy.c

mani6@mani6-Aspire-V3-574G:~/Desktop$ ./a.out file.c

include stdio h int main int a float b char c printf Enter a


random int float and character Value n scanf d a scanf f b
scanf c c if a b printf d n a if a b printf f n b return

statements = 21 ids = 36 assign = 0 rel = 4 keywords = 9 integers = 1


practical: 02
Objective : “Write a program to find first set for a given grammar.”

FIRST(X) for a grammar symbol X is the set of terminals that begin the strings derivable from X.
Rules to compute FIRST set:
1. If x is a terminal, then FIRST(x) = { ‘x’ }
2. If x-> Є, is a production rule, then add Є to FIRST(x).
3. If X->Y1 Y2 Y3….Yn is a production,
1. FIRST(X) = FIRST(Y1)
2. If FIRST(Y1) contains Є then FIRST(X) = { FIRST(Y1) – Є } U { FIRST(Y2) }
3. If FIRST (Yi) contains Є for all i = 1 to n, then add Є to FIRST(X).

Code:
#include<stdio.h>
#include<ctype.h>
void FIRST(char[],char );
void addToResultSet(char[],char);
int numOfProductions;
char productionSet[10][10];
main()
{
int i;
char choice;
char c;
char result[20];
printf("How many number of productions ? :");
scanf(" %d",&numOfProductions);
for(i=0;i<numOfProductions;i++)
{
printf("Enter productions Number %d : ",i+1);
scanf(" %s",productionSet[i]);
}
do
{
printf("\n Find the FIRST of :");
scanf(" %c",&c);
FIRST(result,c);
printf("\n FIRST(%c)= { ",c);
for(i=0;result[i]!='\0';i++)
printf(" %c ",result[i]);
printf("}\n");
printf("press 'y' to continue : ");
scanf(" %c",&choice);
}
while(choice=='y'||choice =='Y');
}
void FIRST(char* Result,char c)
{
int i,j,k;
char subResult[20];
int foundEpsilon;
subResult[0]='\0';
Result[0]='\0';

if(!(isupper(c)))
{
addToResultSet(Result,c);
return ;
}

for(i=0;i<numOfProductions;i++)
{
if(productionSet[i][0]==c)
{
if(productionSet[i][2]=='#') addToResultSet(Result,'#');
else
{
j=2;
while(productionSet[i][j]!='\0')
{
foundEpsilon=0;
FIRST(subResult,productionSet[i][j]);
for(k=0;subResult[k]!='\0';k++)
addToResultSet(Result,subResult[k]);
for(k=0;subResult[k]!='\0';k++)
if(subResult[k]=='#')
{
foundEpsilon=1;
break;
}

if(!foundEpsilon)
break;
j++;
}
}
}
}
return ;
}
void addToResultSet(char Result[],char val)
{
int k;
for(k=0 ;Result[k]!='\0';k++)
if(Result[k]==val)
return;
Result[k]=val;
Result[k+1]='\0';
}

Output:
How many number of productions ? :8

Enter productions Number 1 : E=TX

Enter productions Number 2 : X=+TX

Enter productions Number 3 : X=#

Enter productions Number 4 : T=FY

Enter productions Number 5 : Y=*FY

Enter productions Number 6 : Y=#

Enter productions Number 7 : F=(E)

Enter productions Number 8 : F=i

Find the FIRST of :E

FIRST(E)= { ( i }

press 'y' to continue : Y

Find the FIRST of :T

FIRST(T)= { ( i }

press 'y' to continue : Y

Find the FIRST of :F

FIRST(F)= { ( i }

press 'y' to continue : Y

Find the FIRST of :X

FIRST(X)= { + # }

press 'y' to continue :


PRACTICAL: 03
Objective: “Write a program to find follow set for a given grammar”

Follow(X) to be the set of terminals that can appear immediately to the right of Non-Terminal X in
some sentential form.

Rules to compute FOLLOW set:

1) FOLLOW(S) = { $ } // where S is the starting Non-Terminal

2) If A -> pBq is a production, where p, B and q are any grammar symbols,

then everything in FIRST(q) except Є is in FOLLOW(B).

3) If A->pB is a production, then everything in FOLLOW(A) is in FOLLOW(B).

4) If A->pBq is a production and FIRST(q) contains Є,

then FOLLOW(B) contains { FIRST(q) – Є } U FOLLOW(A)

code:
#include<stdio.h>
#include<string.h>
int n,m=0,p,i=0,j=0;
char a[10][10],followResult[10];
void follow(char c);
void first(char c);
void addToResult(char);
int main()
{
int i;
int choice;
char c,ch;
printf("Enter the no.of productions: ");
scanf("%d", &n);
printf(" Enter %d productions\n", n);
for(i=0;i<n;i++)
scanf("%s%c",a[i],&ch);

do
{
m=0;
printf("Find FOLLOW of -->");
scanf(" %c",&c);
follow(c);
printf("FOLLOW(%c) = { ",c);
for(i=0;i<m;i++)
printf("%c ",followResult[i]);
printf(" }\n");
printf("Do you want to continue(Press 1 to continue....)?");
scanf("%d%c",&choice,&ch);
}
while(choice==1);
}
void follow(char c)
{
if(a[0][0]==c)addToResult('$');
for(i=0;i<n;i++)
{
for(j=2;j<strlen(a[i]);j++)
{
if(a[i][j]==c)
{
if(a[i][j+1]!='\0')first(a[i][j+1]);
if(a[i][j+1]=='\0'&&c!=a[i][0])
follow(a[i][0]);
}
}
}
}
void first(char c)
{
int k;
if(!(isupper(c)))

addToResult(c);
for(k=0;k<n;k++)
{
if(a[k][0]==c)
{
if(a[k][2]=='$') follow(a[i][0]);
else if(islower(a[k][2]))

addToResult(a[k][2]);
else first(a[k][2]);
}
}
}
void addToResult(char c)
{
int i;
for( i=0;i<=m;i++)
if(followResult[i]==c)
return;
followResult[m++]=c;
}

Output:

Enter the no.of productions: 3

Enter 3 productions

S=CC

C=aC

C=d

Find FOLLOW of -->S


FOLLOW(S) = { $ }

Do you want to continue(Press 1 to continue....)?1

Find FOLLOW of -->C

FOLLOW(C) = { a d $ }

PRACTICAL : 04
Objective : “Write a program to implement shift- reduce parser.”

Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cout<<"Enter Number of Productions: ";
cin>>n;

vector <string> rhs;


vector <char> sk;
string productions[n];

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

cin>>productions[i];
for(int j=3;j<productions[i].size();j++){

string temp="";
while(productions[i][j]!='|' &&
j<productions[i].size()){

temp+=productions[i][j];
j++;
}

if(temp.size()>0){

rhs.push_back(temp);
sk.push_back(productions[i][0]);
}
}
}

cout<<"Enter any Input String: ";


string s;
cin>>s;
string check="";
string k1 = s;

cout<<endl<<check<<"$\t"<<s<<"$\tShift\n";
for(int i=0;i<s.size();i++){

int f=0;
check+=s[i];
k1.erase(k1.begin());

for(int j=0;j<rhs.size();j++){

if(check.find(rhs[j])<check.size()){

f++;

cout<<"$"<<check<<"\t"<<k1<<"$\t\tReduce\n";

int temp=rhs[j].size();
while(temp--) check.erase(check.end()-1);

check+=sk[j];
j=-1;
}
}

if(!k1.empty())
cout<<"$"<<check<<"\t"<<k1<<"$\t\tShift\n";
}
cout<<"$"<<check<<"\t"<<k1<<"$\n\n";

if(check=="S" && k1.size()==0) cout<<"Accepted"<<endl;


else cout<<"Rejected"<<endl;
}

Output:

mani6@mani6-Aspire-V3-574G:~$ cd Desktop

mani6@mani6-Aspire-V3-574G:~/Desktop$ g++ shift.cpp

mani6@mani6-Aspire-V3-574G:~/Desktop$ ./a.out

Enter Number of Productions: 1

s=s+s|s*s|i

Enter any Input String: i+i+i

$ i+i+i$ Shift

$i +i+i$ Reduce

$s +i+i$ Shift

$s+ i+i$ Shift

$s+i +i$ Reduce

$s+s +i$ Reduce

$ss +i$ Shift

$ss+ i$ Shift
$ss+i $ Reduce

$ss+s $ Reduce

$sss $

Rejected

PRACTICAL : 05
Objective: “Write a program to implement basic arithmetic operation using FLEX”

Code:
%{
#include<stdio.h>
int op=0,i;
float a,b;
void operation();
%}
dig [0-9]+|([0-9]*)"."([0-9]+)
add "+"
sub "-"
mul "*"
div "/"
ln \n
%%
{dig} {operation();}
{add} {op=1;}
{sub} {op=2;}
{mul} {op=3;}
{div} {op=4;}
{ln} {printf("\n the result :%f\n\n",a);
}
%%
void operation()
{
if(op==0)
a=atof(yytext);
else
{
b=atof(yytext);
switch(op){
case 1:a=a+b;
break;
case 2:a=a-b;
break;
case 3:a=a*b;
break;
case 4:a=a/b;
break;
}
op=0;
}

int main(int argv,char *argc[])


{
yylex();
return 0;
}

Output:

mani6@mani6-Aspire-V3-574G:~$ cd Desktop
mani6@mani6-Aspire-V3-574G:~/Desktop$ lex art.l

mani6@mani6-Aspire-V3-574G:~/Desktop$ gcc -lfl lex.yy.c

art.l:23:1: warning: return type defaults to ‘int’ [-Wimplicit-int]

operation()

^~~~~~~~~

art.l:23:1: warning: conflicting types for ‘operation’

art.l:5:6: note: previous declaration of ‘operation’ was here

void operation();

^~~~~~~~~

mani6@mani6-Aspire-V3-574G:~/Desktop$ ./a.out

2*3

the result :6.000000

2/3

the result :0.666667

7+4

the result :11.000000

1-2

the result :-1.000000

PRACTICAL: 06
Objective: “Write a program to check for balanced parenthesis in a statement using FLEX
Input file contains number of expressions.”

code:
%{
#include <stdio.h>
int i=0;
void pcheck();
%}
operator [0-9]|[A-Za-z]|+|*|-|/|%
open "{"
close "}"
ln \n

%%
{open} {i++;}
{close} {i--;}
operator {printf(" ");}
{ln} {pcheck();}

%%

void pcheck()
{
if(i==0){
printf("\nparenthesis are matching \n");
}
if(i>0){
printf("\nleft one are more\n");
}
if(i<0){
printf("\nRight one are more\n");
}
i=0;
}

int main()
{
yylex();
return 0;
}

Output:

Practical : 07
Objective : Write a program to implement FLEX functions :

yymore() , yyless() ,yyterminate() , unput() ,input() .


● Yymore( ): ‘ yymore()' tells the scanner that the next time it matches a rule, the
corresponding token should be appended onto the current value of yytext rather than
replacing it. For example, given the input "mega-kludge" the following will write
"mega-mega-kludge" to the output:
%%
mega- ECHO; yymore();
kludge ECHO;

>>First "mega-" is matched and echoed to the output. Then "kludge" is matched, but
the previous "mega-" is still hanging around at the beginning of yytext so the `ECHO'
for the "kludge" rule will actually write "mega-kludge".
Two notes regarding use of `yymore()'. First, `yymore()' depends on the value of
yyleng correctly reflecting the size of the current token, so you must not modify
yyleng if you are using `yymore()'. Second, the presence of `yymore()'in the scanner's
action entails a minor performance penalty in the scanner's matching speed.

● yyless(n) : `yyless(n)' returns all but the first n characters of the current token back to
the input stream, where they will be rescanned when the scanner looks for the next
match. yytext and yyleng are adjusted appropriately (e.g., yylengwill now be equal to
n ). For example, on the input "foobar" the following will write out "foobarbar":
%%
foobar ECHO; yyless(3);
[a-z]+ ECHO;

An argument of 0 to yyless will cause the entire current input string to be scanned
again. Unless you've changed how the scanner will subsequently process its input
(using BEGIN, for example), this will result in an endless loop. Note that yyless is a
macro and can only be used in the flex input file, not from other source files.
● yyterminate( ) : `yyterminate()' can be used instesd of a return statement in an action.
It terminates the scanner and returns a 0 to the scanner's caller, indicating "all done".
By default, `yyterminate()' is also called when an end-of-file is encountered. It is a
macro and may be redefined.
● Unput ( ) : `unput(c)' puts the character c back onto the input stream. It will be the
next character scanned. The following action will take the current token and cause it
to be rescanned enclosed in parentheses.
{
int i;
/* Copy yytext because unput() trashes yytext */
char *yycopy = strdup( yytext );
unput( ')' );
for ( i = yyleng - 1; i >= 0; --i )
unput( yycopy[i] );
unput( '(' );
free( yycopy );
}

Note that since each `unput()' puts the given character back at the beginning of the
input stream, pushing back strings must be done back-to-front. An important potential
problem when using `unput()' is that if you are using `%pointer' (the default), a call to
`unput()' destroys the contents of yytext, starting with its rightmost character and
devouring one character to the left with each call. If you need the value of yytext
preserved after a call to `unput()' (as in the above example), you must either first copy
it elsewhere, or build your scanner using `%array' instead (see How The Input Is
Matched). Finally, note that you cannot put back EOF to attempt to mark the input
stream with an end-of-file.

● input( ) : `input()' reads the next character from the input stream. For example, the
following is one way to eat up C comments:
%%
"/*" {
register int c;
for ( ; ; )
{
while ( (c = input()) != '*' &&
c != EOF )
; /* eat up text of comment */

if ( c == '*' )
{
while ( (c = input()) == '*' )
;
if ( c == '/' )
break; /* found the end */
}

if ( c == EOF )
{
error( "EOF in comment" );
Break;}

} }

Sample Code:
%{

#include <stdio.h>

%}

%%

twinkle- ECHO; yymore();

little ECHO;printf(" yymore used \n");

manis ECHO; yyless(4);

[a-z]+ ECHO;

\n {

unput( ')' );

unput( '(' );printf(" unput used:\n");

%%

int main(){

yylex();

return 0;

Output:
PRACTICAL: 08
Objective: Write a flex program that accepts the language “L”

L=a^n-1.b^n+m; n>=1
m>=0

code:
%{

#include<stdio.h>

int acount=0;

int bcount=0;

int flag=0;

void operation();

%}

A "a"

B "b"
ln \n

%%

{A} {if( bcount==0){

acount++;

if(bcount>0) { ;};}

{B} {bcount++;}

{ln} {operation();}

%%

void operation()

//printf("%d,%d",acount,bcount);

if(((acount==0)&&(bcount==0))||((bcount-acount)<1)){

printf("Rejected \n");

if((bcount-acount)>=1 ){

printf("Accepted \n");

acount=0;

bcount=0;

int main()

yylex();

return 0;
}

Output:

practical : 09
Objective: Write a yacc program that evaluates postfix notation.

code:
Pos.y

%{
#include<stdio.h>
#include<ctype.h>
%}
%token num
%left '+''-'
%left '*' '/'
%right '^'
%%
s:e'\n'{printf("\n%d",$1);}
e:e e'+'{$$=$1+$2;}
|e e'-'{$$=$1-$2;}
|e e'*'{$$=$1*$2;}
|e e'/'{$$=$1/$2;}
|num
;
%%
yylex()
{
int c;
c=getchar();
if(isdigit(c))
{ yylval=c-'0';
return num;
}return c;
}
int main()
{
yyparse();
return 1;
}
int yyerror()
{
return 1;
}
int yywrap()
{
return 1;
}
Output:

You might also like