COMPILER
A compiler or interpreter for a programinning language is often decomposed into two
parts:
Lex and Yacc can generate program fragments that solve the first task.
The task of discovering the source structure again is decomposed into subtasks:-
Lex reads an input stream specifying the lexical analyzer and outputs source code
implementing the lexer in the C programming language.
Lex is a program generator designed for lexical processing of character input streams. It
accepts a high-level, problem oriented specification for character string matching, and
produces a program in a general purpose language which recognizes regular expressions.
The regular expressions are specified by the user in the source specifications given to
Lex. The Lex written code recognizes these expressions in an input stream and partitions
the input stream into strings matching the expressions. At the boundaries between strings
program sections provided by the user are executed. The Lex source file associates the
regular expressions and the program fragments. As each expression appears in the input
to the program written by Lex, the corresponding fragment is executed.
Lex is not a complete language, but rather a generator representing a new language
feature which can be added to different programming languages, called ``host languages.''
At present, the only supported host language is C, although FORTRAN has been
available in the past. Lex itself exists on UNIX, GCOS, and OS/370; but the code
generated by Lex may be taken anywhere the appropriate compilers exist.
Definition section
%%
Rules section
%%
C code section
The definition section is the place to define macros and to import header files
written in C. It is also possible to write any C code here, which will be copied
verbatim into the generated source file.
The rules section is the most important section; it associates patterns with C
statements. Patterns are simply regular expressions. When the lexer sees some
text in the input matching a given pattern, it executes the associated C code. This
is the basis of how lex operates.
The C code section contains C statements and functions that are copied verbatim
to the generated source file. These statements presumably contain code called by
the rules in the rules section. In large programs it is more convenient to place this
code in a separate file and link it in at compile time.
%{
/* C code to be copied verbatim */
#include <stdio.h>
%}
%%
/*** Rules section ***/
%%
/*** C Code section ***/
int main(void)
{
/* Call the lexer, then quit. */
yylex();
return 0;
}
If this input is given to flex, it will be converted into a C file, lex.yy.c. This can be
compiled into an executable which matches and outputs strings of integers.
abc123z.!&*2ghj6
Use:
Lex is good at pattern matching.
Lex’s Limitations
LEX cannot be used to recognize nested structures such as parentheses. Nested
structures are handled by incorporating a stack. Whenever we encounter a "(" we push it
on the stack. When a ")" is encountered we match it with the top of the stack and pop the
stack. However lex only has states and transitions between states. Since it has no stack it
is not well suited for parsing nested structures.
YACC: Yet Another Compiler-Compiler
The computer program yacc is a parser generator developed by Stephen C. Johnson at
AT&T for the Unix operating system. It generates a parser (the part of a compiler that
tries to make syntactic sense of the source code) based on an analytic grammar written in
a notation similar to BNF. Yacc generates the code for the parser in the C programming
language.
YACC provides a general tool for describing the input to a computer program. The Yacc
user specifies the structures of his input, together with code to be invoked as each such
structure is recognized. Yacc turns such a specification into a subroutine that handles the
input process; frequently, it is convenient and appropriate to have most of the flow of
control in the user's application handled by this subroutine. The input subroutine
produced by Yacc calls a user-supplied routine to return the next basic input item. Thus,
the user can specify his input in terms of individual input characters or in terms of higher
level constructs such as names and numbers. The user-supplied routine may also handle
idiomatic features such as comment and continuation conventions, which typically defy
easy grammatical specification.
Yacc is written in portable C. In addition to compilers for C, APL, Pascal, RATFOR, etc.,
Yacc has also been used for less conventional languages.
Definition section
%%
Rules section
%%
C code section
The definition section is the place to define macros and to import header files
written in C. Lex file is concerned with characters while YACC file is concerned
with tokens.
The rules section is the most important section; it associates patterns with C s
was the case of lex.
The C code section contains is the call to yyparse,the grramatical parse.
Use:
YACC augments an FSA with a stack and can process constructs such as parentheses
with ease. The important thing is to use the right tool for the job. YACC is appropriate
for more challenging tasks.
PROGRAM-2
AIM - WAP to check whether a string belong to the grammar or not.
#include<iostream.h>
#include<conio.h>
#include<string.h>
#include<process.h>
void main()
{
clrscr();
char str[20];
char ch;
cout<<"The grammar is ASB"<<endl;
cout<<"A->a\n"<<"B->b\n"<<"C->c\n";
do
{
clrscr();
cout<<"\nThe String is:";
cin>>str;
int k=0,h=0;
for(int i=0;i<strlen(str);i++)
{
if(str[i]=='a'||str[i]=='A')
{
k++;
}
}
cout<<"\nThe no. of a in string is: "<<k;
for(i=0;i<strlen(str);i++)
{
if(str[i]=='b'||str[i]=='B')
{
h++;
}
}
cout<<"\nThe no. of b in string is: "<<h;
if(h==k)
cout<<"\n\n\tThe Grammar has equal no. of a and b";
else
cout<<"\n \n\tString has incorrect Grammar";
cout<<"\n\n Do You To Continue: ";
cin>>ch;
}while(ch=='y');
if(ch!='y')
cout<<"\n\nOK!!!!";
getch();
}
OUTPUT
PROGRAM-3
AIM: WAP to generate a parse tree.
#include<iostream.h>
#include<conio.h>
#include<string.h>
#include<graphics.h>
void main()
{
clrscr();
char s[5],a[5][5],b[5][2],cq[5][2],z[5];
int p=0;
cout<<"\nEnter the productions for S -> ";
cin>>s;
int len=strlen(s);
cout<<"\nProductions for S -> "<<s;
for(int i=0;i<5;i++)
if((s[i]>='A')&&(s[i]<='Z'))
{ z[p]=s[i]; p++; }
int o=p;
cout<<"\nValue: "<<o;
for(p=0;p<o;p++)
{
cout<<"\nEnter the productions for "<<z[p]<<" -> ";
cin>>a[p];
cout<<"\nProduction for "<<z[p]<<" -> "<<a[p];
}
clrscr();
int driver,mode;
driver=DETECT;
initgraph(&driver,&mode,"c:\\tc\\bgi");
outtextxy(320,50,"S");
int count;
int g=0,h=-100,c,u,y=200;
p=0;
for(u=0;u<len;u=u+1)
{
y=y+50;
lineto(y,100);
b[u][0]=s[u];
b[u][1]='\0';
outtext(*(b+u));
if((s[u]>='A')&&(s[u]<='Z'))
{
count=strlen(a[g]);
a[g][count+1]='\0';
c=0;
for(int q=0;q<count;q++)
{
h=h+50;
moveto(y,100);
linerel(h,100);
cq[p][0]=*(*(a+g)+c);
cq[p][1]='\0';
outtext(cq[p]);
++p;
++c;
}
g++;
}
moveto(320,50);
}
getch();
}
OUTPUT
PROGRAM-4
AIM: WAP to compute FIRST of non-terminals.
#include<conio.h>
#include<iostream.h>
#include<string.h>
void first(char s[10]);
void main()
{
clrscr();
char s[10];
int r=1;
while(r==1)
{
cout<<"\n\nenter the symbol: ";
cin>>s;
first(s);
cout<<" is First of "<<s[0]<<"\n";
cout<<"\n\npress 1 for another production:";
cin>>r;
}
getch();
}
int k=0;
i=0;
if(a[i] >= 'A' && a[i] <= 'Z')
{
first(a);
}
else
{
b[k]=a[i];
cout<<"\n"<<b[0];
}
}
OUTPUT
EXPERIMENT NO 5
AIM - WAP to compute FOLLOW of non-terminals.
#include<iostream.h>
#include<conio.h>
#include<graphics.h>
#include<string.h>
char s[5];
char a[5][10];
char f[5][10];
void follow( int d);
void main()
{
clrscr();
int i,p1=-1,p2=-1;
//char a[5][10],f[5][10];
for(i=0;i<5;i++)
{
cout<<"\n\nenter the symbol"<<(i+1)<<": ";
cin>>s[i];
cout<<"enter production value for "<<s[i]<<"--> ";
cin>>a[i];
}
cout<<"\n\n";
for(i=0;i<5;i++)
{
p1=-1;
p2=-1;
for(int j=0;j<5;j++)
{
int len1 = strlen(a[j]);
for(int k=0;k<len1;k++)
{
if(s[i]==a[j][k])
{
p1=j;
p2=k;
}
}
}
if(p1==-1 && p2==-1)
{
if(i!=0)
{
cout<<"\n null";
}
else
{}
}
else if(a[p1][p2+1]!=NULL)
{
char first[10];
cout<<"\nenter first of "<<a[p1][p2+1]<<"\n";
cin>>first;
cout<<"\n "<<first;
}
else
{
cout<<"\n ";
follow(p1);
}
if(i==0)
{
cout<<" $";
}
cout<<" is FOLLOW of "<<s[i]<<"\n\n";
}
getch();
}
#include<iostream.h>
#include<conio.h>
#include<string.h>
void main()
{
clrscr();
char a[10],b[10],s;
cout<<"\nEnter the symbol:";
cin>>s;
cout<<"\nEnter the first RHS for"<<s<<"->";
cin>>a;
cout<<"\nEnter the second RHS for:"<<s<<"->";
cin>>b;
int len1,len2;
len1=strlen(a);
len2=strlen(b);
if(s==a[0])
{
for(int i=0;i<len1;i++)
{
a[i]=a[i+1];
}
cout<<"\n Grammar is Left Recursive\n";
cout<<"\n Apply the rule for \n A->Aa\n A->b\n like \n A->bA'\n A'->aA'\n A'->NULL";
cout<<"\n\n The solution is \n"<<s<<"->"<<b<<s<<"'\n"<<s<<"'-
>"<<a<<s<<"'\n"<<s<<"'->NULL";
}
else
{
cout<<"\n Grammar is NOT Left Recursive";
}
getch();
}
OUTPUT
PROGRAM-7
AIM - WAP to remove left factoring.
#include<iostream.h>
#include<conio.h>
void main()
{
char A,K,L,M,N;
clrscr();
cout<<"enter the value for start symabol :";
cin>>A;
cout<<"enter the Alpha before \ : \n";
cin>>K;
cout<<"enter the Beta value :\n ";
cin>>L;
cout<<"enter the Alpha after \ : \n";
cin>>N;
cout<<"enter the Gama value :\n ";
cin>>M;
cout<<"prod is\n"<<A<<"->"<<K<<L<<"/"<<N<<M;
if(K==N)
{
cout<<"\n\n grammar is left factored";
cout<<"\n\n after removal of left factoring :\n\n";
cout<<A<<"->"<<K<<A<<"\'";
cout<<"\n\n";
cout<<A<<"\'"<<"->"<<L<<"/"<<M;
}
getch();
}
OUTPUT
PROGRAM-8
AIM - WAP to show all the operations of a stack.
ALGORITHM:
INSERTION
PUSH (item)
1. if (item=max of stack)
print "overflow"
Return
2. top=top+1
3. stack [top]=item
4. return
DELETION
POP (item)
1. if (top=-1)
print "underflow"
return
2. Item=stack [top]
3. top=top-1
4. return
DISPLAY
1. if top = -1
print "underflow"
2. Repeat step 3 for i=top to i>=0
3. print stack[i]
4. return
PROGRAM:
#include<stdio.h>
#include<conio.h>
#include<process.h>
#define MAXSIZE 10
void push();
int pop();
void traverse();
int stack[MAXSIZE];
int Top=-1;
void main()
{
int choice;
char ch;
do
{
clrscr();
printf("\n1.PUSH");
printf("\n2.POP");
printf("\n3.TRAVERSE");
printf("\n\nEnter your choice: ");
scanf("%d",&choice);
switch(choice)
{
case 1: push();
break;
case 2: printf("\n\nThe deleted element is: %d",pop());
break;
case 3: traverse();
break;
default:printf("\n\nYou entered a wrong choice");
}
printf("\nDo you wish to continue(Y/N): ");
fflush(stdin);
scanf("%c",&ch);
}
while(ch=='Y' || ch=='y');
}
void push()
{
int item;
if(Top==MAXSIZE - 1)
{
printf("\n\nThe Stack is Full");
getch();
exit(0);
}
else
{
printf("\nEnter the element to be inserted: ");
scanf("%d",&item);
Top=Top+1;
stack[Top]=item;
}
}
int pop()
{
int item;
if(Top== -1)
{
printf("\nThe stack is Empty");
getch();
exit(0);
}
else
{
item=stack[Top];
Top=Top-1;
}
return(item);
}
void traverse()
{
if(Top== -1)
{
printf("\nThe stack is empty");
getch();
exit(0);
}
else
{
for(int i=Top;i>=0;i--)
printf("\nTraverse the element");
printf("\n%d" ,stack[i]);
}
}
OUTPUT
PROGRAM-9
AIM - WAP to show various operations i.e. red, write and modify in a
text file.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
void main()
{
FILE *fp;
int i,num;
clrscr();
fp=fopen("INTEGER.DAT","w");
if(fp==NULL)
{
printf("error opening file");
exit(1);
}
for(i=0;i<5;i++)
{
scanf("%d",&num);
if(num==-99)
break;
putw(num,fp);
}
fclose(fp);
fp=fopen("INTEGER.DAT","r");
if(fp==NULL)
{
printf("error opening file");
exit(1);
}
while((num=getw(fp)) !=EOF)
{
printf("%d",num);
fclose(fp);
}
getch();
}
OUTPUT