Sunteți pe pagina 1din 41

EX.

NO:
DATE:

STUDY OF PARSER GENERATOR


Aim:
To study about parser generator(YACC&LEX).

Description:

Yacc stands for “yet another compiler computer” reflecting the popularity of parser generators
in the early 1970’s when the first version of yacc was created on the UNIX system and has been used to
keys implementation of hundreds of compilers.
A translator can be constructed using YACC. First a file, say translate y, containing a YACC
specification of the translator is required.
The UNIX system command,
Yacc translate.y
Transform the file translate.y into c program y.tab.c using the LALR method. The program
y.tab.c is a representation of LALR method.The y.tab.c is written in c along with another c routines that
the user may prepared.By compiling y.tab.c along with the library that contains the LR parsing program
using the command,
Cc y.tab.c –ly
We obtain the desired objects program a.out that perform the translation by the original yacc
program. If other procedure are needed they can be compiled or loaded with y.tab.c, they stands with
any c program.
A yacc source program has three parts .
Declaration.
%%
` Translation files
%%
Supporting C routines.
Yacc specification of a simple desk calculator.consider the grammer for arithmetic expressions.
E ->E+T/T
T ->T*F/F
F ->(E)/digit
The token digit is a single digit between 0 and 7.

Lex:
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 turns the user's expressions and actions into the host general-purpose language; the generated
program is named yylex.The yylex program will recognize expressions in a stream (called input in this
memo) and perform the specified actions for each expression as it is detected.
+-------+
Source -> | Lex | -> yylex
+-------+

+-------+
Input -> | yylex | -> Output
+-------+

An overview of Lex
Figure 1

For a trivial example, consider a program to delete from the input all blanks or tabs at the ends of lines.
%%
[ \t]+$ ;

is all that is required. The program contains a %% delimiter to mark the beginning of the rules, and one
rule. This rule contains a regular expression which matches one or more instances of the characters
blank or tab (written \t for visibility, in accordance with the C language convention) just prior to the
end of a line. The brackets indicate the character class made of blank and tab; the + indicates ``one or
more ...''; and the $ indicates ``end of line,'' as in QED. No action is specified, so the program generated
by Lex (yylex) will ignore these characters. Everything else will be copied. To change any remaining
string of blanks or tabs to a single blank, add another rule:
%%
[ \t]+$ ;
[ \t]+ printf(" ");

The finite automaton generated for this source will scan for both rules at once, observing at the
termination of the string of blanks or tabs whether or not there is a newline character, and executing the
desired rule action. The first rule matches all strings of blanks or tabs at the end of lines, and the second
rule all remaining strings of blanks or tabs.
Lex can be used alone for simple transformations, or for analysis and statistics gathering on a lexical
level. Lex can also be used with a parser generator to perform the lexical analysis phase; it is
particularly easy to interface Lex and Yacc [3]. Lex programs recognize only regular expressions; Yacc
writes parsers that accept a large class of context free grammars, but require a lower level analyzer to
recognize input tokens. Thus, a combination of Lex and Yacc is often appropriate. When used as a
preprocessor for a later parser generator, Lex is used to partition the input stream, and the parser
generator assigns structure to the resulting pieces. The flow of control in such a case (which might be
the first half of a compiler, for example) is shown in Figure 2. Additional programs, written by other
generators or by hand, can be added easily to programs written by Lex.
lexical grammar
rules rules
| |
v v
+---------+ +---------+
| Lex | | Yacc |
+---------+ +---------+
| |
v v
+---------+ +---------+
Input -> | yylex | -> | yyparse | -> Parsed input
+---------+ +---------+

Lex with Yacc


Figure 2

Yacc users will realize that the name yylex is what Yacc expects its lexical analyzer to be named, so
that the use of this name by Lex simplifies interfacing.
Lex is not limited to source which can be interpreted on the basis of one character lookahead. For
example, if there are two rules, one looking for ab and another for abcdefg, and the input stream is
abcdefh, Lex will recognize ab and leave the input pointer just before cd. . . Such backup is more costly
than the processing of simpler languages.

Coding:

%s
#include<ctype.h>
%s}
%token DIGIT
%%
line:expr\n’{printf(“%d\n”,$1);}
;
expr:expr’+’term{$$=$1+$3;}
| term
;
term:term’*’factor{$$=$1*$3;}
| factor
;
Factor:’{‘expr’}’{$$=$2;}
| DIGIT
;
yylex(){
int c;
C=getchar();
If(is digit()){
yy val=c-‘0’;
Return DIGIT;
}
Return C;
}
The Declaration Part:
The declaration part of yacc program is delimited by %s and %y.There are two optional
selections in the declaration.In the first section, we put ordinary c declaration.Here we place declaration
of any temporaries used by the translation rules or procedures of the second and third sections.
The include statement #include <ctype.h>causes the c processor to include the std.Header
file <ctype.h>that contains the predicates its DIGIT.
Also in the declaration part ,are declared of grammer tokens.The statement
% token DIGIT to be token.Tokens declared in this section can be used in second and third parts of the
yacc specification.

The Translation Rules Part:


In the part of the yacc specification after the first %% pair,we put the translation after
rule.A set of production have been writing
<leftside>  <alt1/</<alt2>…/<altn>.
Would be written in yacc as
<leftside>|<alt1>{semantic action1}
|<alt2>{semantic action2}
|…
|<altn>{semantic action}

In tacc production,a quoted single character ‘C’ is taken to be the terminal symbol ‘c’ and the
unquoted string of letter and DIGIT not declared to the token and nonterminals
A yacc semantic action is the sequence of c statements.In a semantic action the symbol $$ refers to
the attribute value associated with the nonterminal on the left ,while $i refers to the value associated on
the right.
In a yacc specification we have two ‘E’ productions,
EE+T/T
And the associative semantic actions are,
Epr:expr’+’term{$$=$1+$3;}
|term
;

Error Handling:
The token error is reserved for error handling. The parser will detect the symbol error when it is
in a state when the action associated with the look ahead symbol is error.
A semantic action can cause a parser to initiate error handling. When YYERROR is executed semantic
action will cause the control to the parser. YYERROR can’t be used outside the semantic action.
Interface To The Lexical Analyzer:
The yylex() function is an integer valued function that return a token number representing the
kind of token read. If there is a value associated with token return yylex(), it will be assigned to the
external variables yyval().
If the parser and yylex() do not agree on this token numbers reliable communication between them
cannot occur. For (one character) literals, the token is simply a numerical values of the character in the
current character set.
If the token numbers are chosen by yacc the token other than end marker which has a token number
that is zero.
Computing The Program:
In addition to the yyparse() and yylex(), the function YYERROR are required to make a
complete program.
Yacc library:
Int main(void)
This function can run yyparse() and exit with an unspecified value.
Int yyerror(const char*s)
This function will return null terminal argument to standard errors followed by a new line
character.

Debugging The Parser:


The parser generated by the yacc will have a diagnostic facility init that can be optionally enabled
at either compile or run time. Compilation of run time debugging code is under the control of yydebug,
a preprocessor symbol, if YYDEBUG as an non zero value, the debugging code is coded.
When –t is specified, the code file will be built such that if DEBUG is not already defined at
compilation time –t. YYDEBUG is not readily defined, it will be set explicitly zero.

Limit:
The yacc utility may have several internal tables. The exact value of these values are
implementation dependent. The implementation will define the relationship between the values
inbetween them. Any error manages that the implementation may combine groups of this resources into
as long as the total available to the user does not fact below the sum of the sizes.
LIMIT MINIMUM ALLOCATION DESCRIPTION

{NTERMS} 126 No of tokens

{NNOTERMS} 200 No of non terminals

{NPROD} 300 No of rules

{NSTATES} 600 No of states

{MEMSIZE} 5200 Length of rules

{ACTSIZE} 4000 No of action

EXIT STATUS:
The following EXIT values are extended.
0 ->successful completion.
0 ->error occurs.
Result:
Thus the parser generator(YACC) has been studied.
EX.NO
DATE:

IMPLEMENTATION OF TOKEN SEPARATION

AIM:

To write a C program to implement the separation of tokens from a source program.

ALGORITHM:

1. Start the program.


2. The lexical analysis phase of the compiler (first phase of compiler) reads the character in the
source program one by one.
3. It groups them into a stream of tokens.
4. Each token represents logically cohesive sequence of characters such as an identifier, a
keyword, a punctuation character, or an operator like ‘=’, ‘+’, ’-‘, ‘*’, ‘/’.
5. The keywords, operators, data types are stored in separate array and they are used for
comparing the separated tokens from the source program.
6. The function sepr() is used to separate the tokens from the source program.
7. The function symsrch() is used to search the symbols in the source program.
8. The function tknsrch() is used to find the keywords and the datatypes in the source program.
9. The function consep() is for finding the constants in the source program.
10. The duplicates of all the above functions return values are eliminated using the function
elimdup().
11. Repeat the steps 5 to 10 until the end of file is encountered.
12. Stop the program.

PROGRAM:

#include <stdio.h>
#include <conio.h>
#include <ctype.h>
void main()
{
char expr[50];
char iden[20][20],oper[20][20],num[20][20];
int i=0,j,k,ir=0,ic=0,or=0,oc=0,nr=0,nc=0;
clrscr();
printf("Enter the expression\n");
expr[0]='a';
for(i=0;expr[i]!='\n';i++)
{
scanf("%c",&expr[i]);
if(expr[i]=='\n')
break;
}
for(k=0;k<i;k++)
{
if((expr[k]=='+')||(expr[k]=='*')||(expr[k]=='/')||(expr[k]=='-'))
{
printf("%c is an operator\n",expr[k]);
oper[or][oc]=expr[k];
or++;
}
else if((expr[k]==':')&&(expr[k+1]=='='))
{
printf("%c%c is an operator\n",expr[k],expr[k+1]);
oper[or][oc]=expr[k];
oper[or][oc+1]=expr[k+1];
k++;
or++;
}
else if(isalpha(expr[k]))
{
while(k>j)
{
printf("%c",expr[k]);
iden[ir][ic]=expr[k];
k++;
ic++;
if((expr[k]=='+')||(expr[k]=='*')||(expr[k]=='/')||(expr[k]=='- ')||(expr[k]==':')||(expr[k]=='=')||
(expr[k]==' '))
break;
}
ir++;
k--;
printf(" is an identifier\n");
ic=0;
}

else if(isdigit(expr[k]))
{
while(k>j)
{
printf("%c",expr[k]);
num[nr][nc]=expr[k];
nc++;
k++;
if((expr[k]=='+')||(expr[k]=='*')||(expr[k]=='/')||(expr[k]=='-')||(expr[k]==':')||
(expr[k]=='=')||(expr[k]==' ')||(isalpha(expr[k]))||(expr[k]=='\n'))
break;
}
k--;
printf(" is a number\n");
nr++;
nc=0;
}
}
printf("IDENTIFIERS IN TABLE FORMAT\n");
for(i=0;i<ir;i++)
printf("%d\t%s\n",i+1,iden[i]);
printf("OPERATORS IN TABLE FORMAT\n");
for(i=0;i<or;i++)
printf("%d\t%s\n",i+1,oper[i]);
printf("NUMBERS IN TABLE FORMAT\n");
for(i=0;i<nr;i++)
printf("%d\t%s\n",i+1,num[i]);
getch();
}

OUTPUT:

Enter the expression


pos:=init+rate*60
pos is an identifier
:= is an operator
init is an identifier
+ is an operator
rate is an identifier
* is an operator
60 is a number
IDENTIFIERS IN TABLE FORMAT
1 pos
2 init
3 rate
OPERATORS IN TABLE FORMAT
1 :=
2 +
3 *
NUMBERS IN TABLE FORMAT
1 60

RESULT;
Thus the implementation of token separation was designed and verified
successfully
EX.NO:
DATE: LEXICAL ANALYSIS USING LEXTOOL

AIM:
To write a Lex program for lexical Analysis using Lextool in Linux.
ALGORITHM:
1.Start the program.
2.Get the input file.
3.Identify the preprocessor directive, function and keywords.
4.Display the output.
5.Terminate the program.
PROGRAM:
$ vi lexp.l
/* Lexical Analysis Using Lex Tool */
identifier [_a-zA-Z][_a-zA-Z0-9]*
%%
#.* { printf("\n %s is a Preprocessor Directive",yytext); }
void |
int |
float |
double |
char |
do |
while |
for |
switch |
case |
break |
continue |
return |
goto { printf("\n\t%s is a Keyword",yytext); }
if\( { printf("\n\tif is a Keyword ( "); }
\/\*.*\*\/ |
\/\/.* { printf("\n\n Comment %s\n ",yytext); }
{identifier}\( { printf("\n\n\tFunction %s",yytext); }
\{ { printf("\n Block Begins %s",yytext); }
\} { printf("\n %s Block Ends",yytext); }
{identifier}(\[0-9\]*)? { printf("\n\t%s is an Identifier",yytext); }
\".*\" { printf("\n\t%s is a String",yytext); }
[0-9]+ { printf("\n\t%s is a Number",yytext); }
\)(\;)? ECHO;
\( ECHO;
\+ |
\- |
\* |
\/ |
\% { printf("\n\t%s is an Operator",yytext); }
= { printf("\n\t%s is an Assignment Operator",yytext); }
\> |
\< |
\>= |
\<= |
\== |
\!= { printf("\n\t%s is a Relational Operator",yytext); }
. |\n
%%
main(int argc,char **argv)
{
if(argc>1)
{
FILE *file;
file = fopen(argv[1],"r");
if(!file)
{
printf("\n Could not open the Specified file %s \n",argv[1]);
exit(0);
}
yyin = file;
}
yylex();
printf("\n\n");
}
int yywrap()
{
return 1;
}

INPUT FILE:

$cat>ip.c
#include<stdio.h>
#include<conio.h>
float great();
{
if(a>b)
return a;
else
return b;
}
void main()
{
int a,b;
float c;
c=great(a,b); //Function Call
}
COMPILATION PROCEDURE:

$ lex lexp.l (program must be saved with the extension “ .l ”)


$ cc lex.yy.c
$ ./a.out ip.c

OUTPUT:

#include<stdio.h> is a Preprocessor Directive


#include<conio.h> is a Preprocessor Directive
float is a Keyword
Function great();
Block Begins {
if is a Keyword (
a is an Identifier
> is a Relational Operator
b is an Identifier)
return is a Keyword
a is an Identifier;
else is an Identifier
return is a Keyword
b is an Identifier;
}
Block Ends
void is a Keyword
Function main()
Block Begins {
int is a Keyword
a is an Identifier,
b is an Identifier;
float is a Keyword
c is an Identifier;
c is an Identifier
= is an Assignment Operator
Function great(
a is an Identifier,
b is an Identifier);
Comment //Function Call
}
Block Ends

OUTPUT:
RESULT:
Thus a Lex program for lexical analysis is executed successfully and the output
was verified.
EX.NO:
DATE:
IMPLEMENTATION OF SYNTAX ANALYZER

Aim:
To execute a ‘C’ program for the implementation of Syntax Analyzer.

Algorithm:

Step 1: Start the program.


Step 2: Declare the required the variables.
Step 3: Open the required input file and read the data in that file.
Step 4: The data that has been read is grouped into tokens to find the errors in the input program.
Step 5: Open the required output file and write the required output into that file.
Step 6: Stop the program.

Coding:
//SYNTAX ANALZER
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
char input[20][100],str[100];
char test[100];
char var[20][20];
int n,vptr,a,b,c,d;
getfile()
{
int i=0;
FILE *f1;
f1=fopen("hello.txt","r");
while(!feof(f1))
fgets(input[i++],100,f1);
n=i;
return;
}
int nochar(char ch)
{
int i,j,noc=0;
for(i=0;i<n;i++)
for(j=0;input[i][j]!='\0';j++)
if(input[i][j]==ch)
noc++;
return noc;
}
void main()
{
int i,j,temp,offset;
char *cp,m;
vptr=0;
clrscr();
getfile();
for(i=0;i<n;i++)
if(input[i][0]=='#')
if(!strstr(input[i],"include")||!strpbrk(input[i],"<")||strpbrk(input[i],">"))
printf("\n line=%d error include line",i+1);
for(i=0;i<n;i++)
if(strstr(input[i],"main"))
{
if(!strpbrk(input[i],"("))
printf("\n line%d:error in main statement missing(",i+1);
else
if(!strpbrk(input[i],")"))
printf("\n line%d:error in main statement missing)",i+1);
break;
}
a=abs(nochar('{')-nochar('}'));
b=abs(nochar('}')-nochar('{'));
c=abs(nochar('(')-nochar(')'));
d=abs(nochar(')')-nochar('('));
if(nochar('{')<nochar('}'))
printf("\n error unmatched%d}paranthesis",a);
else
if(nochar('}')>nochar('{'))
printf("\n error unmatched%d{paranthesis",b);
else
if(nochar('(')<nochar(')'))
printf("\n error unmatched%d)paranthesis",c);
else
if(nochar(')')>nochar('('))
printf("\n error unmatched%d(paranthesis",d);
printf("\n");
getch();
}

Input file: hello.txt

void main()

int a,b,c;

a=b+c;

printf(“%d”,a);
}

Output:

Line 1: error in main statement missing ( error unmatched 1} paranthesis

RESULT:

Thus the ‘C’ program to implement the Syntax Analyzer was executed.
EX.NO:
DATE:

YACC TOOL WITH SIMPLE DESK CALCULATOR

AIM:

To implement simple desk calculator using yacc tool.

ALGORITHM:

Start the program.


Yacc program consists of three parts namely
Declarations
%%
Transition Rule
%%
Supporting C – routines.
Declaration part consists of two sections, first section contains only include statements and the
second statements contains declaration of the grammar tokens.
Each rule in set of transition rules consists of grammar production and semantic action. The set
of productions are of the form
<left side>: <alt 1> {semantic action 1}
| <alt 2> {semantic action 2}
…..
| <alt n> {semantic action n}
;
In the third part, error recovery routines are added.
The program is typed using vi editor, and saved with .y extension.
It is first compiled with the yacc compiler to produce the C code for C compiler (yacc samp.y).
After that compile that program with C compiler (cc y.tab.c – ly standard output file of yacc
compiler).
See the output using ./a.out.
Stop the program.

PROGRAM:

%{
#include<ctype.h>
#include<stdio.h>
#define YYSTYPE double
%}
%token NUMBER
%left '+' '-'
%left '*' '/'
%right '^'
%right UMINUS
%%
lines : lines expr '\n' {printf("%lf",$2);}
| lines '\n'
|
;
expr : expr '+' expr {$$=$1+$3;}
| expr '-' expr {$$=$1-$3;}
| expr '*' expr {$$=$1*$3;}
| expr '/' expr {if($3!=0) {$$=$1/$3;}
else yyerror("divident should be a positive no.\n");
}
| expr '^' expr { int i,sum=1;
for(i=1;i<=$3;i++)
{sum *= $1;}
$$=sum;
}
| '(' expr ')' {$$=$2;}
| '-' expr %prec UMINUS {$$= $2;}
| NUMBER
;
%%
yylex()
{
int c;
while((c=getchar())==' ');
if((c=='.')||(isdigit(c)))
{
ungetc(c,stdin);
scanf("%lf",&yylval);
return NUMBER;
}
return c;
}

OUTPUT:
RESULT:
Thus the above program is compiled and executed successfully and output is verified.
EX.NO:
DATE:

CONSTRUCTION OF NFA FROM REGULAR EXPRESSION

Aim:
To construct NFA for the given regular expression.

Algorithm:

Step 1:Get the regular expression.


Step 2:mark the initial state with a line and final state with double circle.
Step 3:Mark the intermediate states with a single circle and a line connecting previous state and
current state with an arrow towards the current state.
Step 4:Display the input above the arrow for every transition.
Step 5:Initial state must have no incoming states and final state should not have any outgoing
states.
Step 6:The input is, A REGULAR EXPRESSION ‘r’ OVER AN ALPHABET ‘E’.
Step 7:The output is , AN NFA ‘N’ ACCEPTING L(r).
Step 8:Parse ‘r’ into the sub expressions.
Step 9:Using the rules construct NFA for each of the basic symbols in ‘r’.

Coding:
#include<stdio.h>
#include<conio.h>
#include<dos.h>
#include<graphics.h>
#include<math.h>
void a(int,int);
void p();
void main()
{
int gd=DETECT, gm;
initgraph(&gd,&gm, “e:\\tc\\bgi\\);
int ch;
while(ch!=6)
{
printf(“Menu \n 1. Empty Input \n 2. a \n 3. a|b \n 4. ab\n 5. (a|b)^* \n Enter the exp “);
scanf(“%d”, &ch);
switch(ch)
{
case 1:
a(150,150);
circle(210,150,15);
outtextxy(180,135,”e”;
outtetxy(125,147,”>”);
line(115,150,140,150);
getch();
cleardevice();
break;
case 2:
a(150,150);
circle(210,150,15);
line(115,150,140,150);
outtextxy(125,147,”>”);
outtextxy(180,135,”a”);
getch();
cleardevice();
break;
case 3:
circle(245,200,15);
p();
getch();
cleardevice();
break;
case 4:
a(150,150);
a(275,150);
line(220,150,265,150);
circle(335,150,15);
outtextxy(175,140,”a”);
outtextxy(300,140,”b”);
outextxy(235,140,”e”);
outtextxy(125,147,”>”);
line(110,150,140,150);
line(315,150,310,145);
line(245,150,240,145);
line(245,150,240,155);
getch();
cleardevice();
break;
case 5:
p();
circle(300,200,10);
circle(300,200,15);
circle(65,200,10);
line(25,200,55,200);
line(255,200,285,200);
outtexty(65,200,”I”);
outtextxy(35,197,”>”);
outetxtxy(300,200,”F”);
arc(185,215,180,0,120);
outtextxy(185,332,”>”);
outextxy(265,185,”e”);
outtextxy(265,197,”>”);
outtextxy(85,185,”e”);
outtextxy(185,110,”e”);
outtextxy(185,320,”e”);
getch();
cleardeive();
}
}
getch();
closegraph();
}

void a(int x, int y)


{
int ch;
circle(x,y,10);
circle(x+60,y,10);
line(x+10,y,x+50,y);
outtextxy(x,y,”1”);
outtextxy(x+60,y,”2”);
line(185,y,180,y-5);
line(185,y,180,y+5);
}
void p()
{
a(150,150);
a(150,250);
circle(125,200,10);
outtextxy(120,170,”e”);
outtextxy(85,197,”>”);
outextxy(120,220,”e”);
outtextxy(240,170,”e”);
outtextxy(240,220,”e”);
outextxy(180,135,”a”);
outtextxy(180,260,”b”);
line(75,200,115,200);
line(125,190,140,155);
line(125,210,145,240);
circle(245,200,10);
line(220,155,240,185);
line(240,215,220,250);
outtextxy(125,200,”5”);
outextxy(245,200,”6”);
}
Output
Menu
1. E
2. a + b
3. a.b
4. a
5. (a/b)*

Enter the option


2

Result

Thus the program for Constructing NFA for the given regular expression is executed
successfully
EX.NO:
DATE:

IMPLEMENTATION OF SHIFT REDUCE PARSING

AIM:

To write a C program to implement the shift reduce parsing.

ALGORITHM:

a. Start the program.


b. Get the input string from the user.
c. Push $ onto top of the stack.
d. Set ip to point to the first input symbol.
e. If there is any production which can be used to reduce the input symbol reduce the string
otherwise push it to the top of the stack.
f. Set ip to point to next input symbol.
g. Repeat the above steps until the top of the stack contains the $ and the starting symbol. If so,
then the string is valid, otherwise the string is invalid, return an error message.
h. Stop the program.

PROGRAM:

#include<stdio.h>
#include<conio.h>
void pus(char);
void reduce();
char inp1[5][10]={"E+E","E*E","(E)","a"},stk[50],inpt1[10],stk1[50];
int ct=0;
void main()
{
int k,len;
char inpt[10];
clrscr();
printf("Enter The Input String\n\n");
gets(inpt);
printf("\n\n");
len=strlen(inpt);
inpt[len++]='$';
inpt[len]='\0';
strcpy(inpt1,inpt);
len=strlen(inpt);
inpt[len++]='$';
inpt[len++]='\0';
pus('$');
pus(inpt[0]);
for(k=1;k<len-1;k++)
{
if(!isupper(inpt[k-1]))
{
reduce();
if(inpt[k]!='$')
pus(inpt[k]);
}
}
if(stk[0]=='$' && stk[1]=='E' && stk[2]=='0' && inpt1[0]=='$')
printf("\n\n\n\t\tString Accepted");
else
printf("\n\n\n\t\tNot Accepted");
getch();
}
void pus(char inpt)
{
int i,n;
n=strlen(inpt1);
if(ct>0)
{
for(i=0;i<n;i++)
inpt1[i-1]=inpt1[i];
inpt1[n-1]='\0';
}
stk[ct++]=inpt;
i=0;
while(stk[i]!='0' && stk[i]!='\0')
printf("%c",stk[i++]);
printf("\t%s\tShift\n",inpt1);
}
void reduce()
{
int j=0,ct1,i,ct2,t,ct3,true=0;
char temp[10],tmp;
strcpy(stk1,stk);
for(i=0;i<5;i++)
{
if(stk[ct-1]==inp1[i][0])
{
if(stk[ct-1]!='('&&stk[ct-1]!=')')
stk[ct-1]='E';
i=0;
while(stk[i]!='0' && stk[i]!='\0')
printf("%c",stk[i++]);
printf("\t%s\tReduce\n",inpt1);
true=1;
}
}
for(i=0;i<4 ;i++)
{
j=0;
ct1=ct-strlen(inp1[i]);
ct2=ct1;
ct3=0;
while(ct1<ct && ct1>0 && stk[ct1]!=0)
temp[j++]=stk[ct1++];
temp[j]='\0';
if(strcmp(temp,inp1[i])==0)
{
stk[ct2]='E';
t=ct2;
while(ct2<=ct)
stk[++ct2]='0';
ct=t;
ct++;
true=0;
}
}
i=0;
while(stk[i]!='0' && stk[i]!='\0' && true==0)
printf("%c",stk[i++]);
if(true==0)
printf("\t%s\tReduce\n",inpt1);
}

OUTPUT:
RESULT:
Thus the above program is compiled and executed successfully and output is verified.
EX.NO:
DATE: IMPLEMENTATION OF LR PARSING

AIM:

To write a C program to implement simple ing algorithm.

ALGORITHM:

♦ Input: An input string w and an LR parsing table with functions action and goto for a grammar
G.
♦ Output: If w is in L(G), a bottom – up parse for w; otherwise an error indication.
♦ Method: Initially, the parser has s0 on its stack, s0 is the initial state, and w$ in the input buffer.
The parser then executes the program until accept or error action is encountered.

set ip to point to the first symbol of w$;


repeat forever begin
let s be the state on the top of the stack and
a the symbol pointed to by ip;
if action [s, a] = shift s then begin
push a then s on the top of the stack;
advance ip to the next input symbol
end
else if action [s, a] = reduce A   then begin
pop 2*|| symbols off the stack;
let s be the state now on top of the stack;
push A then goto [s, A] on top of the stack;
output the production A  
end
else if action [s, a] = accept then
return
else error()
end

PROGRAM:

char stk[10],inp[10],pat[20][20][20],prod[10][10],ipsymb[10];
int sp,ip,tp;
char c,v;
int i,k,t;

void gettable()
{
int i,j,k,n;
char c;
strcpy(pat[0][0],"s5");strcpy(pat[0][3],"s4");strcpy(pat[0][6],"1");
strcpy(pat[0][7],"2");strcpy(pat[0][8],"3");
strcpy(pat[1][5],"A"); strcpy(pat[1][1],"s6");
strcpy(pat[2][1],"r2");strcpy(pat[2][2],"s7");strcpy(pat[2][4],"r2");
strcpy(pat[2][5],"r2");
strcpy(pat[3][1],"r4");strcpy(pat[3][2],"r4");strcpy(pat[3][4],"r4"); strcpy(pat[3][5],"r4");
strcpy(pat[4][0],"s5");strcpy(pat[4][3],"s4");strcpy(pat[4][6],"8");
strcpy(pat[4][7],"2");strcpy(pat[4][8],"3");
strcpy(pat[5][2],"r6");strcpy(pat[5][1],"r6");strcpy(pat[5][4],"r6");
strcpy(pat[5][5],"r6");
strcpy(pat[6][0],"s5");strcpy(pat[6][3],"s4");strcpy(pat[6][7],"9");
strcpy(pat[6][8],"3");
strcpy(pat[7][0],"s5");strcpy(pat[7][3],"s4");strcpy(pat[7][8],"a");
strcpy(pat[8][1],"s6");strcpy(pat[8][4],"sb");
strcpy(pat[9][1],"r1");strcpy(pat[9][2],"s7");strcpy(pat[9][4],"r1");
strcpy(pat[9][5],"r1");
strcpy(pat[10][1],"r3");strcpy(pat[10][2],"r3");strcpy(pat[10][4],"r3");
strcpy(pat[10][5],"r3");
strcpy(pat[11][1],"r5");strcpy(pat[11][2],"r5");strcpy(pat[11][4],"r5");
strcpy(pat[11][5],"r5");
ipsymb[0]='i';ipsymb[1]='+';ipsymb[2]='*';ipsymb[3]='(';ipsymb[4]=')';
ipsymb[5]='$';ipsymb[6]='E';ipsymb[7]='T';ipsymb[8]='F';
strcpy(prod[0],"E'->E");strcpy(prod[1],"E->E+T");strcpy(prod[2],"E->T");
strcpy(prod[3],"T->T*F");strcpy(prod[4],"T->F");
strcpy(prod[5],"F->(E)");strcpy(prod[6],"F->i");
}
int ipnum(char c)
{
int i;
for(i=0;i<strlen(ipsymb);i++)
{
if(ipsymb[i]==c)
break;
}
return i;
}

int stknum(char c)
{
char t[10];
int i;
if(c<='9')
{
t[0]=c;t[1]='\0';
return atoi(t);
}
else
{
return(c-97+10);
}
}
void shift()
{
char t;
t=pat[i][k][1];
stk[++sp]=inp[ip++];
stk[++sp]=t;
}
void reduce()
{
int b,prev,z;
char t,pr[10],subs[10];
t=pat[i][k][1];
strcpy(pr,prod[t-48]);
b=2*(strlen(pr)-3);
sp=sp-b;
t=stk[sp];
prev=stknum(t);
stk[++sp]=pr[0];
z=ipnum(pr[0]);
stk[++sp]=pat[prev][z][0];
stk[sp+1]='\0';
}
void main()
{
int q;
clrscr();
printf("ENTER THE INPUT...");
scanf("%s",inp);
t=strlen(inp);
inp[t]='$';
inp[t+1]='\0';
stk[0]='0';
gettable();
printf("\n\n\nSTACK\t\tINPUT\t\tOPERATION\n");
while(1)
{
c=inp[ip];
v=stk[sp];
k=ipnum(c);
i=stknum(v);
if(pat[i][k][0]=='s')
shift();
else if(pat[i][k][0]=='r')
reduce();
else if(pat[i][k][0]=='A')
{
printf("\n\nVALID...");
getch();
exit(0);
}
else
{
printf("\n\nINVALID...");
getch();
exit(0);
}
printf("%s\t\t",stk);
q=ip;
while(inp[q]!='\0')
printf("%c",inp[q++]);
if(pat[i][k][0]=='s')
printf("\t\tShift\n");
else if(pat[i][k][0]=='r')
printf("\t\tReduced by %s\n",prod[pat[i][k][1]-48]);
}
}

OUTPUT:

RESULT:
Thus the above program is compiled and executed successfully and output is verified.
EX.NO:
DATE: IMPLEMENTATION OF INTERMEDIATE CODE GENERATION

AIM:
To write a C program to implement the intermediate code for the given set of input
expressions.

ALGORITHM:

a. Start the program.


b. Get the input expression from the user.
c. Check the expressions for its validation.
d. If it is invalid return the error message.
e. Otherwise, for each computation store the result in the three – address statement (store it
in temporary variable say t1, t2, etc.,) .
f. Assign the final temporary value to the variable in which the result has to be stored.
g. Stop the program.

PROGRAM:

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
void small();
void dove(int );
int p[5]={0,1,2,3,4},c=1,i,k,l,m,pi;
char sw[5]={'=','-','+','/','*'},j[20],a[5],b[5],ch[2];
void main()
{
clrscr();
printf("Enter the expression:");
scanf("%s",j);
printf("\n\n\tThe Intermediate code is:\n");
small();
}
void dove(int i)
{
a[0]='\0';b[0]='\0';
I f(!isdigit(j[i+2]) && !isdigit(j[i-2]))
{
a[0]=j[i-1];
b[0]=j[i+1];
}
if(isdigit(j[i+2]))
{
a[0]=j[i-1];
b[0]='t';
b[1]=j[i+2];
}
if(isdigit(j[i-2]))
{
b[0]=j[i+1];
a[0]='t';
a[1]=j[i-2];
b[1]='\0';
}
if(isdigit(j[i+2]) && isdigit(j[i-2]))
{
a[0]='t';
b[0]='t';
a[1]=j[i-2];
b[1]=j[i+2];
itoa(c,ch,10);
j[i+2]=j[i-2]=ch[0];
}
if(j[i]=='*')
printf("\tt%d=%s*%s\n",c,a,b);
if(j[i]=='/')
printf("\tt%d=%s/%s\n",c,a,b);
if(j[i]=='+')
printf("\tt%d=%s+%s\n",c,a,b);
if(j[i]=='-')
printf("\tt%d=%s-%s\n",c,a,b);
if(j[i]=='=')
printf("\t%c=t%d",j[i-1],--c);
itoa(c,ch,10);
j[i]=ch[0];
c++;
small();
}
void small()
{
pi=0;l=0;
for(i=0;i<strlen(j);i++)
{
for(m=0;m<5;m++)
if(j[i]==sw[m])
if(pi<=p[m])
{
pi=p[m];
l=1;
k=i;
}
}
if(l==1)
dove(k);
else
{
getch();
exit (0);
}
}

OUTPUT:

RESULT:
Thus the above program is compiled and executed successfully and output is verified.
EX.NO:
DATE: IMPLEMENTATION OF CODE GENERATION

AIM:
To write a C program to implement the code generation algorithm.

ALGORITHM:

The code generation algorithm takes as input a sequence of three – address statements
constituting a basic block. For each three – address statement of the form x := y op z we perform the
following actions:

i. Invoke a function getreg to determine the location L where the result of the computation
y op z should be stored. L will usually be a register, but it could also be a memory
location. We shall describe getreg shortly.
j. Consult the address descriptor for y to determine y, (one of) the current location(s) of
y. prefer the register for y if the value of y is currently both in memory and a register.
If the value of y is not already in L, generate the instruction MOV y, L to place a copy
of y in L.
k. Generate the instruction OP z, L where z is a current location of z. Again, prefer a
register to a memory location if z is in both. Update the address descriptor of x to
indicate that x is in location L. If L is a register, update its descriptor to indicate that it
contains the value of x, and remove x from all other register descriptors.
l. If the current values of y and/or z have no next users, are not live on exit from the block,
and are in register descriptor to indicate that, after execution of x := y op z, those
registers no longer will contain y and/or z, respectively.

PROGRAM:

#include<stdio.h>
#include<conio.h>
#include<string.h>
char exp[10][10],*ope;
int i,j,n,s[10],flag2,flag3,r1,r2;
void check();
void oper();
void main()
{
clrscr();
printf("\nEnter the No. of Expressions:\n");
scanf("%d",&n);
printf("\nEnter The Expression (In Three Address Code):\n");
for(i=0;i<n;i++)
{
scanf("%s",exp[i]);
s[i]=i;
}
printf("\n\nGenerated Code Is:\n\n");
oper();
getch();
}
void oper()
{
for(i=0;i<n;i++)
{
flag2=0;
flag3=0;
if(exp[i][3]=='*')
ope="MUL";
if(exp[i][3]=='/')
ope="DIV";
if(exp[i][3]=='+')
ope="ADD";
if(exp[i][3]=='-')
ope="SUB";
check();
printf("MOV R%d,%c\t(Result Moved To %c)\n",s[i],exp[i][0],exp[i][0]);
}
}
void check()
{
for(j=0;j<i;j++)
{
if(exp[i][2]==exp[j][0])
{
flag2=1;
r1=s[j];
}

if(exp[i][4]==exp[j][0])
{
flag3=1;
r2=s[j];
}
}
if(flag2==1&&flag3==1)
{
s[i]=0;
printf("%s R%d,R%d\t(Result In R%d)\n",ope,r2,r1,r1);
} else if(flag2==1&&flag3!=1)
{
s[i]=r1;
printf("%s %c,R%d\t(Result In R%d)\n",ope,exp[i][4],r1,r1);
} else if(flag2!=1&&flag3==1)
{
s[i]=r2;
printf("%s %c,R%d\t(Result In R%d)\n",ope,exp[i][2],r2,r2);
} else
{
printf("MOV %c,R%d\t(%c Moved To R%d)\n",exp[i][2],s[i],exp[i][2],s[i]);
printf("%s %c,R%d\t(Result In R%d)\n",ope,exp[i][4],s[i],s[i]);
}

}
OUTPUT:

RESULT:
Thus the above program is compiled and executed successfully and output is verified.
EX.NO:
DATE:

SYMBOL TABLE
AIM:
To implement the symbol table concept using the c programs.

ALGORITHM:

STEP 1: Give the corresponding program to the compiler


STEP 2; Declare the variables and constants.
STEP 3: Define the function on which the program modules will function.
STEP 4: Compile the program .
STEP 5: Check the symbol table and its contents for the relevant informations about the
identifiers and functions and procedures

PROGRAM:

//Symbol table
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
void main()
{
int i,j,k,n;
char e[10],st[10],as[10][10];
clrscr();
printf("\n Symbol Table\n");
printf("\n Enter the expression:");
scanf("%s",e);
for(i=0,j=0;i<strlen(e);i++)
{
if(isalpha(e[i]))
{
st[j]=e[i];
j++;
}
}
st[j]='\0';
fflush(stdin);
for(i=0;i<strlen(st);i++)
{
printf("Datatypes of %c:",st[i]);
scanf("%s",as[i]);
}
printf("\n Enter the base address:");
scanf("%d",&k);
printf("\n\n");
printf("\n ****************************************");
printf("\n The symbol table for datatype");
printf("\n ****************************************");
printf("\n\n");
printf("\n Variable \tDatatype Bytes Base Address\n");
for(i=0;i<strlen(st);i++)
{
if(as[i][0]=='i')
{
k+=10;
printf("\n %c\t\t %s\t %d\t%d",st[i],as[i],2,k);
printf("\n\n");
}
else if(as[i][0]=='f')
{
k+=32;
printf("\n %c\t\t %s\t %d\t d",st[i],as[i],4,k);
printf("\n\n");
}
else if(as[i][0]=='c')
{
k+=8;
printf("\n %c\t\t %s\t %d\t%d",st[i],as[i],1,k);
printf("\n\n");
}
else if(as[i][0]=='d')
{
k+=256;
printf("\n %c\t\t %s\t %d\t%d",st[i],as[i],4,k);
printf("\n\n");
}
else if(as[i][0]=='l')
{
k+=32;
printf("\n %c\t\t %s\t %d\t%d",st[i],as[i],8,k);
printf("\n\n");}}

;
}

OUTPUT:

Symbol Table
Enter the expression:p=i+r*6
Datatypes of p:int
Datatypes of i:int
Datatypes of r:int
Enter the base address:3000
****************************************
The symbol table for datatype
****************************************
Variable Datatype Bytes Base Address
p int 2 3010

i int 2 3020

r int 2 3030

RESULT:
Thus the above program is compiled and executed successfully and output is verified.

S-ar putea să vă placă și