0% found this document useful (0 votes)
20 views65 pages

EX - NO:1 Implementation of Symbol Table Date

Uploaded by

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

EX - NO:1 Implementation of Symbol Table Date

Uploaded by

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

EX.

NO:1 IMPLEMENTATION OF SYMBOL TABLE


DATE:

AIM:
To write a C program to implement a symbol table.

INTRODUCTION:
A symbol table is a data structure used by a language translator such as a compiler or interpreter,
where each identifier in a program's source code is associated with information relating to its declaration
or appearance in the source.
Possible entries in a symbol table:
• Name: a string.
• Attribute:
. Reserved word
. Variable name
. Type name
. Procedure name
. Constant name
.···
• Data type.
• Scope information: where it can be used.
• Storage allocation

ALGORITHM:

1. Start the program.


2. Get the input from the user with the terminating symbol ‘$’.
3. Allocate memory for the variable by dynamic memory allocation function.
4. If the next character of the symbol is an operator then only the memory is allocated.
5. While reading ,the input symbol is inserted in to symbol table along with its memory address.
6. The steps are repeated till ‘$’ is reached.
7. To reach a variable, enter the variable to the searched and symbol table has been checked for
corresponding variable, the variable along its address is displayed as result.
8. Stop the program.
PROGRAM:
#include<stdio.h>
//#include<conio.h>
#include<malloc.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
void main()
{
int i=0,j=0,x=0,n,flag=0;
void *p,*add[15];
char ch,srch,b[15],d[15],c;
//clrscr();
printf("expression terminated by $:");
while((c=getchar())!='$')
{
b[i]=c;
i++;
}
n=i-1;
printf("given expression:");
i=0;
while(i<=n)
{
printf("%c",b[i]);
i++;
}
printf("symbol table\n");
printf("symbol\taddr\ttype\n");
while(j<=n)
{
c=b[j];
if(isalpha(toascii(c)))
{
if(j==n)
{

p=malloc(c);
add[x]=p;
d[x]=c;
printf("%c\t%d\tidentifier\n",c,p);
}
else
{
ch=b[j+1];
if(ch=='+'||ch=='-'||ch=='*'||ch=='=')
{
p=malloc(c);
add[x]=p;
d[x]=c;
printf("%c\t%d\tidentifier\n",c,p);
x++;
}
}
}
j++;
}
printf("the symbol is to be searched\n");
srch=getch();
for(i=0;i<=x;i++)
{
if(srch==d[i])
{
printf("symbol found\n");
printf("%c%s%d\n",srch,"@address",add[i]);
flag=1;
}
}
if(flag==0)
printf("symbol not found\n");
//getch();
}

SAMPLE OUTPUT:
RESULT:
Thus the C program to implement the Symbol table was executed and the output is verified
successfully.
EX.NO:2 DEVELOP A LEXICAL ANALYZER TO RECOGNIZE A FEW PATTERNS IN C
DATE:

AIM:
To write a C program to develop a lexical analyzer to recognize a few patterns in c.
INTRODUCTION:
Lexical analysis is the process of converting a sequence of characters (such as in a computer
program or web page) into a sequence of tokens (strings with an identified "meaning"). A program that
performs lexical analysis may be called a lexer, tokenizer, or scanner.

Token
A token is a structure representing a lexeme that explicitly indicates its categorization for the
purpose of parsing. A category of tokens is what in linguistics might be called a part-of-speech. Examples
of token categories may include "identifier" and "integer literal", although the set of token categories
differ in different programming languages. The process of forming tokens from an input stream of
characters is called tokenization. Consider this expression in the C programming language:
sum = 3 + 2;
Tokenized and represented by the following table:
Lexeme Token category
sum "Identifier"
= "Assignment operator"
3 "Integer literal"
+ "Addition operator"
2 "Integer literal"
; "End of statement"

ALGORITHM:
1. Start the program.
2. Include the header files.
3. Allocate memory for the variable by dynamic memory allocation function.
4. Use the file accessing functions to read the file.
5. Get the input file from the user.
6. Separate all the file contents as tokens and match it with the functions.
7. Define all the keywords in a separate file and name it as key.c.
8. Define all the operators in a separate file and name it as oper.c.
9. Give the input program in a file and name it as input.c.
10. Finally print the output after recognizing all the tokens.
11. Stop the program.

PROGRAM:
#include<stdio.h>
#include<conio.h>
#include<ctype.h>
#include<string.h>
void main()
{
FILE *fi,*fo,*fop,*fk;
int flag=0,i=1;
char c,t,a[15],ch[15],file[20];
clrscr();
printf("\n Enter the File Name:");
scanf("%s",&file);
fi=fopen(file,"r");
fo=fopen("inter.c","w");
fop=fopen("oper.c","r");
fk=fopen("key.c","r");
c=getc(fi);
while(!feof(fi))
{
if(isalpha(c)||isdigit(c)||(c=='['||c==']'||c=='.'==1))
fputc(c,fo);
else
{
if(c=='\n')
fprintf(fo,"\t$\t");
else
fprintf(fo,"\t%c\t",c);
}
c=getc(fi);
}
fclose(fi);
fclose(fo);
fi=fopen("inter.c","r");
printf("\n Lexical Analysis");
fscanf(fi,"%s",a);
printf("\n Line: %d\n",i++);
while(!feof(fi))
{
if(strcmp(a,"$")==0)
{
printf("\n Line: %d \n",i++);
fscanf(fi,"%s",a);
}
fscanf(fop,"%s",ch);
while(!feof(fop))
{
if(strcmp(ch,a)==0)
{
fscanf(fop,"%s",ch);
printf("\t\t%s\t:\t%s\n",a,ch);
flag=1;
} fscanf(fop,"%s",ch);
}
rewind(fop);
fscanf(fk,"%s",ch);
while(!feof(fk))
{
if(strcmp(ch,a)==0)
{
fscanf(fk,"%k",ch);
printf("\t\t%s\t:\tKeyword\n",a);
flag=1;
}
fscanf(fk,"%s",ch);
}
rewind(fk);
if(flag==0)
{
if(isdigit(a[0]))
printf("\t\t%s\t:\tConstant\n",a);
else
printf("\t\t%s\t:\tIdentifier\n",a);
}
flag=0;
fscanf(fi,"%s",a); }
getch();
}
Key.C:
int
void
main
char
if
for
while
else
printf
scanf
FILE
include
stdio.h
conio.h
iostream.h
Oper.C:
( open para
) closepara
{ openbrace
} closebrace
< lesser
> greater
" doublequote
' singlequote
: colon
; semicolon
# preprocessor
= equal
== asign
% percentage
^ bitwise
& reference
* star
+ add
- sub
\ backslash
/ slash

Input.C:

#include "stdio.h"
#include "conio.h"
void main()
{
int a=10,b,c;
a=b*c;
getch();
}
OUTPUT:

RESULT:
Thus the above program for developing the lexical analyzer and recognizing the few patterns in c
is executed successfully and the output is verified.
EX.NO:3 IMPLEMENTATION OF LEXICAL ANALYZER USING LEX TOOL
DATE:

AIM:
To write a program to implement the Lexical Analyzer using Lex Tool.
INTRODUCTION:
THEORY:
o A language for specifying lexical analyzer.
o There is a wide range of tools for construction of lexical analyzer. The majority of these tools are
based on regular expressions.
o The one of the traditional tools of that kind is lex.We refer to the tool as the lex compiler and to its
input specification as the lex language.
LEX:
o The lex is used in the manner depicted.A specification of the lexical analyzer is preferred by
creating a program lex.l in the lex language.
o Then lex,l is run through the lex compiler to produce a ‘c’program lex.yy.c
o The program lex.yy.c consists of a tabular representation of a transition diagram constructed from
the regular expression of lex.l together with a standard routine that uses the table of recognize
leximes.
o Lex.yy.c is run through the ‘c’ compiler to produce as object program a.out,which is the lexical
analyzer that transform as input stream into sequence of tokens.
o Creating a lexical analyzer with lex is shown in below.
LEX SOURCE
ALGORITHM:
1. Start the program.
2. Lex program consists of three parts.
a. Declaration %%
b. Translation rules %%
c. Auxiliary procedure.
3. The declaration section includes declaration of variables, maintest, constants and regular
definitions.
4. Translation rule of lex program are statements of the form
a. P1 {action}
b. P2 {action}
c. …
d. …
e. Pn {action}
5. Write a program in the vi editor and save it with .l extension.
6. Compile the lex program with lex compiler to produce output file as lex.yy.c.
eg $ lex filename.l
$ gcc lex.yy.c -ll
7. Compile that file with C compiler and verify the output.

PROGRAM:
Program name: lexana.l
%{
int COMMENT=0;
%}
identifier[a-z][A-Z0-9]*
digit[0-9]
%%
#.* {printf("\n%s is a peprocessor diective",yytext);}
"int" |
"float" |
"char" |
"double" |
"for" |
"do" |
"if" |
"else" |
"break" |
"continue" |
"void" |
"case" |
"long" |
"struct" |
"typedef" |
"goto" |
"const" |
"while" |
"printf" |
"scanf" |
"switch" |
"main()" |
"return" {printf("\n\t%s is a keyword",yytext);}
"\*" {COMMENT=1;}
"*/" {COMMENT=0;}
\{ {if(!COMMENT) printf("\nblocks starts");}
\} {if(!COMMENT) printf("\n block end");}
{identifier} {if(!COMMENT) printf("\n\t%s is an identifier",yytext);}
\".*\" {if(!COMMENT) printf("\n\t%s is a string",yytext);}
{digit} {if(!COMMENT) printf("\n\t%s is a number",yytext);}
\)(\;)? {if(!COMMENT) printf("\n\t"); ECHO; printf("\n");}
\ECHO;
= {if(!COMMENT) printf("\n\t= is an assignment operator");}
\<= |
\>= |
\< |
== |
\> {if(!COMMENT) printf("\n\t%s is an relational operator");}
%%
int main(int argc,char **argv)
{
if(argc>1)
{
FILE *f1;
f1=fopen("file.c","r");
if(!f1)
{
printf("could not open%s\n",argv[1]);
exit(0);
}
yyin=f1;
}
yylex();
printf("\n");
return 1;
}
int yywrap()
{
return 0;
}

INPUT PROGRAM:
#include<stdio.h>
void main()
{
int a,b,c;
printf("enter the value for a,b");
scanf("%d%d",&a,&b)';
c=a+b;
printf("the value of c:%d",&c);
}

OUTPUT:

RESULT:
Thus the above program is compiled and executed successfully using the LEX tool and the sample
output is verified.
EX.NO:4 a SYNTAX ANALYSIS USING YACC
DATE:

AIM:
To write a Program to recognize a valid arithmetic expression that uses operator +, – , * and /.
INTRODUCTION
1. Introduction

The unix utility yacc (Yet Another Compiler Compiler) parses a stream of token, typically generated by
lex, according to a user-specified grammar.
2. Structure of a yacc file
A yacc file looks much like a lex file:
...definitions...
%%
...rules...
%%
...code...
In the example you just saw, all three sections are present:

Definitions
All code between %{ and %} is copied to the beginning of the resulting C file.
Rules
A number of combinations of pattern and action: if the action is more than a single command it needs to
be in braces.
Code
This can be very elaborate, but the main ingredient is the call to yylex, the lexical Analyzer. If the code
segment is left out, a default main is used which only calls yylex.

3. Definitions section

There are three things that can go in the definitions section:


C code Any code between %{ and %} is copied to the C file. This is typically used for defining file
variables, and for prototypes of routines that are defined in the code segment.
Definitions The definitions section of a lex file was concerned with characters; in yacc this is tokens.
These token definitions are written to a .h file when yacc compiles this file.
Associativity Rules These handle associativity and priority of operators.

4. Lex Yacc interaction


Conceptually, lex parses a file of characters and outputs a stream of tokens; yacc accepts stream of
tokens and parses it, performing actions as appropriate. In practice, they are more tightly coupled. If your
lex program is supplying a tokenizer, the yacc program will repeatedly call theyylex routine. The lex rules
will probably function by calling return every time they have parsed a token. We will now see the way lex
returns information in such a way that yacc can use it for parsing.

4.1 The shared header file of return codes


If lex is to return tokens that yacc will process, they have to agree on what tokens there are. This is done
as follows.
• The yacc file will have token definitions
%token NUMBER
in the definitions section.
• When the yacc file is translated with yacc -d, a header file y.tab.h is created that has
definitions like
#define NUMBER 258
This file can then be included in both the lex and yacc program.
• The lex file can then call return NUMBER, and the yacc program can match on this token.
The return codes that are defined from %TOKEN definitions typically start at around 258, so that single
characters can simply be returned as their integer value:
/* in the lex program */
[0-9]+ {return NUMBER}
[-+*/] {return *yytext}
/* in the yacc program */
sum : TERMS ’+’ TERM

4.2 Return values


In the above, very sketchy example, lex only returned the information that there was a number, not the
actual number. For this we need a further mechanism. In addition to specifying the return code, the lex
parse can return a symbol that is put on top of the stack, so that yacc can access it. This symbol is returned
in the variable yylval. By default, this is defined as an int, so the lex program would have
extern int llval;
%%
[0-9]+ {llval=atoi(yytext); return NUMBER;}
If more than just integers need to be returned, the specifications in the yacc code become more
complicated. Suppose we want to return double values, and integer indices in a table.
The following three actions are needed.
1. The possible return values need to be stated:
%union {int ival; double dval;}
2. These types need to be connected to the possible return tokens:

%token <ival> INDEX


%token <dval> NUMBER
3. The types of non-terminals need to be given:
%type <dval> expr
%type <dval> mulex

%type <dval> term


The generated .h file will now have
#define INDEX 258
#define NUMBER 259
typedef union {int ival; double dval;} YYSTYPE;
extern YYSTYPE yylval;

5. Rules section
The rules section contains the grammar of the language you want to parse. This looks like name1 : THING
something OTHERTHING {action}
| othersomething THING {other action}
name2 : .....
This is the general form of context-free grammars, with a set of actions associated with each matching
right-hand side. It is a good convention to keep non-terminals (names that can be expanded further) in
lower case and terminals (the symbols that are finally matched) in upper case.
The terminal symbols get matched with return codes from the lex tokenizer. They are typically defines
coming from %token definitions in the yacc program or character values;

6. User code section


The minimal main program is
int main()
{
yyparse();
return 0;
}
Extensions to more ambitious programs should be self-evident. In addition to the main program, the code
section will usually also contain subroutines, to be used either in the yacc or the lex program

ALGORITHM:
1. Start the program.
2. In lex program start lex specification with declarative section.
3. In translating rule section define data type identifier along with their action.
4. In main function open the input file in read mode.
5. The key words, identifiers and data type are defined.
6. Stop the program.

PROGRAM:
Program name: variable_test.l
%{
/* This LEX program returns the tokens for the Expression */
#include "y.tab.h"
%}
%%
"int " {return INT;}
"float" {return FLOAT;}
"double" {return DOUBLE;}
[a-zA-Z]*[0-9]*{
printf("\nIdentifier is %s",yytext);
return ID;
}
return yytext[0];
\n return 0;
int yywrap()
{
return 1;
}
Program name: variable_test.y
%{
#include
/* This YACC program is for recognising the Expression*/
%}
%token ID INT FLOAT DOUBLE
%%
D:T L;
L:L,ID
|ID
;
T:INT
|FLOAT
|DOUBLE
;
%%
extern FILE *yyin;
main()
{
do
{
yyparse();
}while(!feof(yyin));
}
yyerror(char*s)
{
}

OUTPUT:

[root@localhost]$ lex variable_test.I


[root@localhost]$ yacc –d variable_test.y
[root@localhost]$ gcc lex.yy.c y.tab.c
[root@localhost]$ ./a.out
int a,b;

Identifier is a
Identifier is b [root@localhost]$

RESULT:
Thus the program to recognize valid arithmetic expression that uses operator +, – , * and / was
executed and verified.

EX.NO:4 b SYNTAX ANALYSIS USING YACC


DATE:

AIM:
To write a Program to recognize a valid variable which starts with a letter followed by any number
of letters or digits.
ALGORITHM:
1. Start the program.
2. Declare the required variables and methods.
3. Get the input
4. Then check whether the given string is valid or not
5. Print the result
6. Stop the program

PROGRAM :
Program Name: 4b.y
%{
#include<stdio.h>
#include<ctype.h>
%}
%token LETTER DIGIT
%left '+' '-'
%left '*' '/'
%%
st:st expr '\n' {printf("\n valid expression \n");}
| st '\n'
|
;
expr:expr '+' expr
|expr '-' expr
|expr '*' expr
|expr '/' expr
|'(' expr ')'
| NUM
| LETTER
;
NUM: DIGIT
|NUM DIGIT
;
%%
int yylex()
{
char c;
while((c=getchar())==' ');
if(isalpha(c)) return LETTER;
if(isdigit(c)) return DIGIT;
return(c);
}
int main()
{
printf("\n enter an expression\n");
yyparse();
}
int yyerror()
{
printf("invalid\n");
return 0;
}

OUTPUT:

RESULT:
Thus the program to recognize a valid variable which starts with a letter followed by any number
of letters or digits was executed and verified.
EX.NO:4 c IMPLEMENTATION OF CALCULATOR USING LEX AND YACC
DATE:

AIM:
To write a Program to implement the calculator using lex and yacc.

ALGORITHM:
1. Start the program.

2. Declare the required variables and methods.

3. Get the input using NUM{DIGIT}+(\.{DIGIT}+)? as two integer value.

4. Then check whether the given number having operator such as + \ - * /

5. After that assign first number to f1 then check if f1==0

6. If it true then op1=atof(yytext)

7. else if assign the second number to f1 then check f2== -1

8. if it true then op2=atof(yytext)

9. By using switch check the operator +,- ,* , / do the corresponding calc operation.

10. Print the result.

11. Stop the program.

PROGRAM:
Program Name: input.l
%{
#include "y.tab.h"
#include<math.h>
%}

NUMBER [0-9]+|([0-9]*"."[0-9]+)

%%
{NUMBER} {yylval.dval=atof(yytext);
return NUMBER;}
sin|SIN {return SIN;}
cos|COS {return COS;}
tan|TAN {return TAN;}
sqrt|SQRT {return SQRT;}
square|SQUARE {return SQUARE;}
exp|EXP {return EXP;}
reci|RECI {return RECI;}
cube|CUBE {return CUBE;}
fact|FACT {return FACT;}
LOG { return LOG;}
ln|LN {return LN;}
MOD|mod {return MOD;}
[\t]+ ;
\n|. return yytext[0];
%%
int yywrap(void)
{ return 1;
}
Program Name: intput.y

%{
#include "y.tab.h"
#include <stdio.h>
#include <math.h>
#define PI 3.141592
int i,j;
%}

%union
{
double dval;
}
%token <dval> NUMBER
%token SIN COS TAN SQRT SQUARE RECI EXP MOD CUBE FACT
%left LN LOG

%left '+''-''*''/'
%right '^'

%nonassoc NEG
%type <dval> E

%%

SL : S '\n'
| SL S '\n'
;

S : E {printf("=%g\n",$1);}
;
E : E '+' E {$$=$1+$3;
printf("Addition is");}
|E '-' E {$$=$1-$3;
printf("substraction is");
}
|E '*' E {$$=$1*$3;
printf("Multiplication is");
}
|E '/' E {
if($3==0)
printf("Error! Divide by zero!!");
else
$$=$1/$3;
printf("Division is");
}

|E '^' E {$$=pow($1,$3);
printf("Power is=");
}
|SIN '(' E ')' {$$=sin($3/180*PI);
printf("SIN is=");
}
|COS '(' E ')' {$$=cos($3/180*PI);
printf("COS is");
}
|TAN '(' E ')' { if($3==90)
printf("Undefined (Infinity)");
else
$$=tan($3/180*PI);
printf("TAN is");
}
|SQRT '(' E ')' {$$=sqrt($3);
printf("Square Root is");
}
|SQUARE '(' E ')' {$$=$3*$3;
printf("square is=");
}
|EXP '(' E ')' {$$=exp($3);
printf("EXPONENTIAL is");
}
|RECI '(' E ')' {$$=1/($3);
printf("Reciprocal is");}

|CUBE '(' E ')' {$$=$3*$3*$3;


printf("Cube is");}
|FACT '(' E ')' {

$$=1;
for(j=1;j<=$3;j++)
$$=$$*j;
printf("Factorial is");
}
|'(' E ')' {$$=$2;
printf("The simple number is");}
|'-' E %prec NEG {$$=-$2;
printf("The number with Negative sign is ");
}
|LOG E {$$=log($2)/log(10);
printf("LOG of base 10 is");
}
|LN E { $$=log($2);
printf("LOG with base 2 is");
}
|MOD '(' E','E')' {$$=fmod($3,$5);
}
|NUMBER
;
%%
extern FILE*yyin;

int main()
{
do{
yyparse();
}while(!feof(yyin));
}

yyerror(char*a)
{
fprintf(stderr,"parse error!!!");
}
OUTPUT:

RESULT:
Thus the program to implement calculator using Lex and Yacc was executed and verified.
EX.NO:5 CONVERT THE BNF RULES INTO YACC FORM AND WRITE CODE TO
DATE: GENERATE ABSTRACT SYNTAX TREE.

AIM:
To write a program to convert BNF rules into YACC form and write code to generate Abstract
Syntax Tree using LEX and YACC.

INTRODUCTION:
Backus-Naur Form (BNF) notation
Backus-Naur form (BNF) is a formal notation for encoding grammars intended for human
consumption. Many programming languages, protocols or formats have a BNF description in their
specification.
Every rule in Backus-Naur form has the following structure:

\mathit{name} ::= \mathit{expansion}


The symbol ::= means "may expand into" and "may be replaced with."
In some texts, a name is also called a non-terminal symbol.

Every name in Backus-Naur form is surrounded by angle brackets, < >, whether it appears on the left- or
right-hand side of the rule.

An \mathit{expansion} is an expression containing terminal symbols and non-terminal symbols, joined


together by sequencing and choice.

A terminal symbol is a literal like ("+" or "function") or a class of literals (like integer).

Simply juxtaposing expressions indicates sequencing.

A vertical bar | indicates choice.

For example, in BNF, the classic expression grammar is:

<expr> ::= <term> "+" <expr>


| <term>

<term> ::= <factor> "*" <term>


| <factor>

<factor> ::= "(" <expr> ")"


| <const>

<const> ::= integer

Naturally, we can define a grammar for rules in BNF:


\mathit{rule} \rightarrow \mathit{name} ::= \mathit{expansion}
\mathit{name} \rightarrow < \mathit{identifier} >
\mathit{expansion} \rightarrow \mathit{expansion} \mathit{expansion}
\mathit{expansion} \rightarrow \mathit{expansion} | \mathit{expansion}
\mathit{expansion} \rightarrow \mathit{name}
\mathit{expansion} \rightarrow \mathit{terminal}
We might define identifiers as using the regular expression [-A-Za-z_0-9]+.
A terminal could be a quoted literal (like "+", "switch" or "<<=") or the name of a class of literals (like
integer).
The name of a class of literals is usually defined by other means, such as a regular expression or even
prose.

ALGORITHM:
1. Start a program
2. declare the declarations as a header file
{include<ctype.h>}
3. token digit
4. define the translations rules like line, expr, term, factor
Line:exp „\n‟ {print(“\n %d \n”,$1)}
Expr:expr‟+‟ term ($$=$1=$3}
Term:term „+‟ factor($$ =$1*$3}
Factor
Factor:‟(„enter‟) „{$$ =$2)
%%
5. define the supporting C routines
6. Stop the program

PROGRAM:
Program Name : int.l
%{
#include"y.tab.h"
#include<stdio.h>
#include<string.h>
int LineNo=1;
%}
identifier [a-zA-Z][_a-zA-Z0-9]*
number [0-9]+|([0-9]*\.[0-9]+)
%%
main\(\) return MAIN;
if return IF;
else return ELSE;
while return WHILE;
int |
char |
float return TYPE;
{identifier} {strcpy(yylval.var,yytext);
return VAR;}
{number} {strcpy(yylval.var,yytext);
return NUM;}
\< |
\> |
\>= |
\<= |
== {strcpy(yylval.var,yytext);
return RELOP;}
[ \t] ;
\n LineNo++;
. return yytext[0];
%%

Program Name : int.y


%{
#include<string.h>
#include<stdio.h>
struct quad
{
char op[5];
char arg1[10];
char arg2[10];
char result[10];
}QUAD[30];
struct stack
{
int items[100];
int top;
}stk;
int Index=0,tIndex=0,StNo,Ind,tInd;
extern int LineNo;
%}
%union
{
char var[10];
}
%token <var> NUM VAR RELOP
%token MAIN IF ELSE WHILE TYPE
%type <var> EXPR ASSIGNMENT CONDITION IFST ELSEST WHILELOOP
%left '-' '+'
%left '*' '/'
%%
PROGRAM : MAIN BLOCK
;
BLOCK: '{' CODE '}'
;
CODE: BLOCK
| STATEMENT CODE
| STATEMENT
;
STATEMENT: DESCT ';'
| ASSIGNMENT ';'
| CONDST
| WHILEST
;
DESCT: TYPE VARLIST
;
VARLIST: VAR ',' VARLIST
| VAR
;
ASSIGNMENT: VAR '=' EXPR{
strcpy(QUAD[Index].op,"=");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].arg2,"");
strcpy(QUAD[Index].result,$1);
strcpy($$,QUAD[Index++].result);
}
;
EXPR: EXPR '+' EXPR {AddQuadruple("+",$1,$3,$$);}
| EXPR '-' EXPR {AddQuadruple("-",$1,$3,$$);}
| EXPR '*' EXPR {AddQuadruple("*",$1,$3,$$);}
| EXPR '/' EXPR {AddQuadruple("/",$1,$3,$$);}
| '-' EXPR {AddQuadruple("UMIN",$2,"",$$);}
| '(' EXPR ')' {strcpy($$,$2);}
| VAR
| NUM
;
CONDST: IFST{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
}
| IFST ELSEST
;
IFST: IF '(' CONDITION ')' {
strcpy(QUAD[Index].op,"==");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].arg2,"FALSE");
strcpy(QUAD[Index].result,"-1");
push(Index);
Index++;
}
BLOCK {
strcpy(QUAD[Index].op,"GOTO");
strcpy(QUAD[Index].arg1,"");
strcpy(QUAD[Index].arg2,"");
strcpy(QUAD[Index].result,"-1");
push(Index);
Index++;
};
ELSEST: ELSE{
tInd=pop();
Ind=pop();
push(tInd);
sprintf(QUAD[Ind].result,"%d",Index);
}
BLOCK{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
};
CONDITION: VAR RELOP VAR {AddQuadruple($2,$1,$3,$$);
StNo=Index-1;
}
| VAR
| NUM
;
WHILEST: WHILELOOP{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",StNo);
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
}
;
WHILELOOP: WHILE '(' CONDITION ')' {
strcpy(QUAD[Index].op,"==");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].arg2,"FALSE");
strcpy(QUAD[Index].result,"-1");
push(Index);
Index++;
}
BLOCK {
strcpy(QUAD[Index].op,"GOTO");
strcpy(QUAD[Index].arg1,"");
strcpy(QUAD[Index].arg2,"");
strcpy(QUAD[Index].result,"-1");
push(Index);
Index++;
}
;
%%
extern FILE *yyin;
int main(int argc,char *argv[])
{
FILE *fp;
int i;
if(argc>1)
{
fp=fopen(argv[1],"r");
if(!fp)
{
printf("\n File not found");
exit(0);
}
yyin=fp;
}
yyparse();
printf("\n\n\t\t ----------------------------""\n\t\t Pos Operator Arg1 Arg2 Result" "\n\t\t
--------------------");
for(i=0;i<Index;i++)
{
printf("\n\t\t %d\t %s\t %s\t %s\t
%s",i,QUAD[i].op,QUAD[i].arg1,QUAD[i].arg2,QUAD[i].result);
}
printf("\n\t\t -----------------------");
printf("\n\n");
return 0;
}
void push(int data)
{
stk.top++;
if(stk.top==100)
{
printf("\n Stack overflow\n");
exit(0);
}
stk.items[stk.top]=data;
}
int pop()
{
int data;
if(stk.top==-1)
{
printf("\n Stack underflow\n");
exit(0);
}
data=stk.items[stk.top--];
return data;
}
void AddQuadruple(char op[5],char arg1[10],char arg2[10],char result[10])
{
strcpy(QUAD[Index].op,op);
strcpy(QUAD[Index].arg1,arg1);
strcpy(QUAD[Index].arg2,arg2);
sprintf(QUAD[Index].result,"t%d",tIndex++);
strcpy(result,QUAD[Index++].result);
}
yyerror()
{
printf("\n Error on line no:%d",LineNo);
}
Input Program: test.c
main()
{
int a,b,c;
if(a<b)
{
a=a+b;
}
while(a<b)
{
a=a+b;
}
if(a<=b)
{
c=a-b;
}
else
{
c=a+b;
}
}

SAMPLE OUTPUT:
[root@localhost]$ lex int.l
[root@localhost]$ yacc –d int.y
[root@localhost]$ gcc lex.yy.c y.tab.c –ll –lm
[root@localhost]$ ./a.out test.c
ACTUAL OUTPUT:

RESULT:
Thus the program for convert the bnf rules into yacc form and write code to generate abstract
syntax tree was executed and verified.
EX.NO:6 IMPLEMENTATION OF TYPE CHECKING
DATE:

AIM:
To write a program to implement type checking.

ALGORITHM:
1. Start a program.
2. Include all the header files.
3. Initialize all the functions and variables.
4. Get the expression from the user and separate into the tokens.
5. After separation, specify the identifiers, operators and number.
6. Print the output.
7. Stop the program.

PROGRAM:
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
#define SIZE 128
#define NONE -1
#define EOS '\0'
#define NUM 257
#define KEYWORD 258
#define ID 259
#define DONE 260
#define MAX 999
char lexemes[MAX];
char buffer[SIZE];
int lastchar=-1;
int lastentry=0;
int tokenval=DONE;
int lineno=1;
int lookahead;
struct entry
{
char *lexptr;
int token;
}
symtable[100];
struct entry
keywords[]={"if",KEYWORD,"else",KEYWORD,"for",KEYWORD,"int",KEYWORD,
"float",KEYWORD,"double",KEYWORD,"char",KEYWORD,"struct",KEYWORD,"ret
urn",KEYWORD,0,0};
void Error_Message(char *m)
{
fprintf(stderr,"line %d, %s \n",lineno,m);
exit(1);
}
int look_up(char s[ ])
{
int k;
for(k=lastentry;k>0;k--)
if(strcmp(symtable[k].lexptr,s)==0)
return k;
return 0;
}
int insert(char s[ ],int tok)
{
int len;
len=strlen(s);
if(lastentry+1>=MAX)
Error_Message("Symbpl table is full");
if(lastchar+len+1>=MAX)
Error_Message("Lexemes array is full");
lastentry=lastentry+1;
symtable[lastentry].token=tok;
symtable[lastentry].lexptr=&lexemes[lastchar+1];
lastchar=lastchar+len+1;
strcpy(symtable[lastentry].lexptr,s);
return lastentry;
}
/*void Initialize()
{
struct entry *ptr;
for(ptr=keywords;ptr->token;ptr+1)
insert(ptr->lexptr,ptr->token);
}*/
int lexer()
{
int t;
int val,i=0;
while(1)
{
t=getchar();
if(t==' '||t=='\t');
else
if(t=='\n')
lineno=lineno+1;
else
if(isdigit(t))
{
ungetc(t,stdin);
scanf("%d",&tokenval);
return NUM;
}
else
if(isalpha(t))
{
while(isalnum(t))
{
buffer[i]=t;
t=getchar();
i=i+1;
if(i>=SIZE)
Error_Message("Compiler error");
}
buffer[i]=EOS;
if(t!=EOF)
ungetc(t,stdin);
val=look_up(buffer);
if(val==0)
val=insert(buffer,ID);
tokenval=val;
return symtable[val].token;
}
else
if(t==EOF)
return DONE;
else
{
tokenval=NONE;
return t;
}
}
}
void Match(int t)
{
if(lookahead==t)
lookahead=lexer();
else
Error_Message("Syntax error");
}
void display(int t,int tval)
{
if(t=='+'||t=='-'||t=='*'||t=='/')
printf("\nArithmetic Operator: %c",t);
else if(t==NUM)
printf("\n Number: %d",tval);
else if(t==ID)
printf("\n Identifier: %s",symtable[tval].lexptr);
else
printf("\n Token %d tokenval %d",t,tokenval);
}
void F()
{
void E();
switch(lookahead)
{
case '(' : Match('(');
E();
Match(')');
break;
case NUM : display(NUM,tokenval);
Match(NUM);
break;
case ID : display(ID,tokenval);
Match(ID);
break;
default : Error_Message("Syntax error");
}
}
void T()
{
int t;
F();
while(1)
{
switch(lookahead)
{
case '*' : t=lookahead;
Match(lookahead);
F();
display(t,NONE);
continue;
case '/' : t=lookahead;
Match(lookahead);
display(t,NONE);
continue;
default : return;
}
}
}
void E()
{
int t;
T();
while(1)
{
switch(lookahead)
{
case '+' : t=lookahead;
Match(lookahead);
T();
display(t,NONE);
continue;
case '-' : t=lookahead;
Match(lookahead);
T();
display(t,NONE);
continue;
default : return;
}
}
}
void parser()
{
lookahead=lexer();
while(lookahead!=DONE)
{
E();
Match(';');
}
}
main()
{
char ans[10];
printf("\n Enter the expression ");
printf("And place ; at the end\n");
printf("Press Ctrl-Z to terminate\n");
parser();
}

RESULT:
Thus the program was executed and verified.
EX.NO:8 IMPLEMENTATION OF STORAGE ALLOCATION STRATEGY
DATE:

AIM:

To write a C program to implement heap storage allocation strategy.

INTRODUCTION:
Storage Allocation
Runtime environment manages runtime memory requirements for the following entities:

Code: It is known as the text part of a program that does not change at runtime. Its memory requirements
are known at the compile time.

Procedures: Their text part is static but they are called in a random manner. That is why, stack storage is
used to manage procedure calls and activations.

Variables: Variables are known at the runtime only, unless they are global or constant. Heap memory
allocation scheme is used for managing allocation and de-allocation of memory for variables in runtime.

Static Allocation
In this allocation scheme, the compilation data is bound to a fixed location in the memory and it
does not change when the program executes. As the memory requirement and storage locations are known
in advance, runtime support package for memory allocation and de-allocation is not required.

Stack Allocation
Procedure calls and their activations are managed by means of stack memory allocation. It works
in last-in-first-out (LIFO) method and this allocation strategy is very useful for recursive procedure calls.

Heap Allocation
Variables local to a procedure are allocated and de-allocated only at runtime. Heap allocation is
used to dynamically allocate memory to the variables and claim it back when the variables are no more
required.
Except statically allocated memory area, both stack and heap memory can grow and shrink
dynamically and unexpectedly. Therefore, they cannot be provided with a fixed amount of memory in the
system.
As shown in the image above, the text part of the code is allocated a fixed amount of memory.
Stack and heap memory are arranged at the extremes of total memory allocated to the program. Both
shrink and grow against each other.

ALGORITHM:

1. Start the program.


2. Enter the expression for which intermediate code is to be generated.
3. If the length of the string is greater than 3, then call the procedure to return the precedence
among the operands.
4. Assign the operand to exp array and operators to the array.
5. Create the three address code using quadruple structure.
6. Reduce the no of temporary variables.
7. Continue this process until we get an output.
8. Stop the program.

PROGRAM:

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
typedef struct Heap
{
int data;
struct Heap *next;
}node;
node *create();
void main()
{
int choice, val;
char ans;
node *head;
void display(node *);
node *search(node *,int);
node *insert(node *);
void dele(node **);
head=NULL;
do
{
clrscr();
printf("\n Program to perform various operations on heap using dynamic memory
management");
printf ("\n1.Create");
printf ("\n2.Display");
printf ("\n3.Insert an element in a list");
printf ("\n4.Delete an element from list");
printf ("\n5.Quit");
printf ("\n Enter Your Choice(1-5)");
scanf("%d",&choice);
switch(choice)
{
case 1:head=create();
break;
case 2:display(head);
break;
case 3:head=insert(head);
break;
case 4:dele(&head);
break;
case 5:exit(0);
default:clrscr();
printf("Invalid Choice,Try again");
getch();
}
}
while(choice!=5);
}
node *create()
{
node *temp,*new1,*head;
int val,flag;
char ans='y';
node *get_node();
temp=NULL;
flag=TRUE;
do
{
printf("\n Enter the Element");
scanf("%d",&val);
/*allocate new node*/
new1=get_node();
if(new1==NULL)
printf("\n Memory is not allocated");
new1-> data=val;
if (flag==TRUE)/* Executed only for the first time*/
{
head=new1;
temp=head; /*head is the first node in the heap*/
flag=FALSE;
}
else
{
temp->next=new1;
temp=new1;
}
printf("\nDo you want to enter more elements?(y/n)");
ans=getch();
}
while(ans=='y');
printf("\nThe list is created");
getch();
clrscr();
return head;
}
node *get_node()
{
node *temp;
temp=(node*)malloc(sizeof(node));
//using the mem. Allocation function
temp->next=NULL;
return temp;
}
void display(node*head)
{
node *temp;
temp=head;
if(temp==NULL)
{
printf("\n The list is empty\n");
getch();
clrscr();
return;
}
while(temp!= NULL)
{
printf("%d->",temp-> data);
temp=temp->next;
}
printf("NULL");
getch();
clrscr();
}
node *search(node *head,int key)
{
node *temp;
int found;
temp=head;
if (temp==NULL)
{
printf("The linked list is empty\n");
getch();
clrscr();
return NULL;
}
found=FALSE;
while(temp!=NULL&&found==FALSE)
{
if(temp->data != key)
temp = temp->next;
else
found=TRUE;
}
if(found == TRUE)
{
printf("\n The Elements is present in the list\n");
getch();
return temp;
}
else
printf("\n The Element is not present in the list\n");
getch();
return NULL;
}
node *insert(node *head)
{
int choice;
node *insert_head(node*);
void insert_after(node*);
void insert_last(node*);
printf("\n 1.Insert a node as a head node");
printf("\n 1.Insert a node as a last node");
printf("\n 1.Insert a node as at the intermediate position in the list ");
printf("\n 1.Enter your choice for insertion of node ");
scanf("%d",&choice);
switch(choice)
{
case 1:head = insert_head(head);
break;
case 2:insert_last(head);
break;
case 3:insert_after (head);
break;
}
return head;
}
node *insert_head(node*head)
{
node *New,*temp;
New=get_node();
printf ("\n Enter the element which you want to insert ");
scanf("%d",&New->data);
if(head == NULL)
head = New;
else
{
temp=head;
New->next = temp;
head= New;
}
return head;
}
void insert_last(node *head)
{
node *New,*temp;
New = get_node();
printf ("\n Enter the element which you want to insert ");
scanf("%d",&New->data);
if(head == NULL)
{
head = New;
}
else
{
temp=head;
while(temp->next!=NULL)
temp=temp->next;
temp->next=New;
New->next=NULL;
}
}
void insert_after(node *head)
{
int key;
node *New,*temp;
New = get_node();
printf("Enter the element after which you want to insert ");
scanf("%d",&key);
temp=head;
do
{
if(temp->data==key)
{
printf ("Enter element which you want to insert ");
scanf("%d",&New->data);
New->next=temp->next;
temp->next=New;
return;
}
else
temp=temp->next;
}
while(temp!=NULL);
}
node *get_prev(node *head,int val)
{
node *temp,*prev;
int flag;
temp = head;
if(temp == NULL)
return NULL;
flag=FALSE;
prev=NULL;
while(temp!=NULL && !flag)
{
if(temp->data!=val)
{
prev = temp;
temp = temp->next;
}
else
flag = TRUE;
}
if(flag) /*if Flag is true*/
return prev;
else
return NULL;
}
void dele(node **head)
{
int key;
node *New,*temp,*prev;
temp=*head;
if (temp== NULL)
{
printf ("\n The list is empty\n ");
getch();
clrscr();
return;
}
clrscr();
printf("\nENTER the Element you want to delete:");
scanf("%d",&key);
temp=search(*head,key);
if(temp!=NULL)
{
prev=get_prev(*head,key);
if(prev!=NULL)
{
prev ->next = temp-> next;
free(temp);
}
else
{
*head = temp->next;
free(temp); // using the mem. Dellocation function
}
printf("\n The Element is deleted\n");
getch();
clrscr();
}
}

SAMPLE OUTPUT:

Program to perform various operations on heap using Dynamic memory management.

1. Create
2. Display
3. Insert an element in a list
4. Delete an element from list
5. Quit
Enter your choice(1-5) 1

Enter the element: 10

Do you want to enter more elements? (y/n) y

Enter the element:20

Do you want to enter more elements?(y/n)y

Enter the element:30

Do you want to enter more elements?(y/n)n

The List is created

Program to perform various operations on Heap using Dynamic memory management.

1. Create
2. Display
3. Insert an element in a list
4. Delete an element from list
5. Quit
Enter your choice(1-5) 4

Enter the element you want to delete: 20


The element is present in the list

The element is deleted

Program to perform various operations on Heap using Dynamic memory management.

1. Create
2. Display
3. Insert an element in a list
4. Delete an element from list
5. Quit
Enter your choice(1-5) 2
10-> 30-> NULL
RESULT:

To write a C program to implement heap storage allocation strategy.

AIM:
To write a program to implement storage allocation method using STACK strategy.

ALGORITHM:
1. Start the program
2. Declare the necessary variables
3. Get the choice to insert, delete and display the values in stack
4. Perform PUSH( ) operation
t = newnode( )
Enter info to be inserted
Read n
t->info = n
t->next = top
top = t
Return
5. Perform POP( ) operation
If (top = NULL)
Print “underflow”
Return
x = top
top = top->next
delnode(x)
Return
6. Display the values
7. Stop the program
PROGRAM:
#include<stdio.h>
#include<conio.h>
struct stack
{
int no;
struct stack *next;
}
*start=NULL;
typedef struct stack st;
void push();
int pop();
void display();
void main()
{
char ch;
int choice,item;
do
{
clrscr();
printf("\n 1: push");
printf("\n 2: pop");
printf("\n 3: display");
printf("\n Enter your choice");
scanf("%d",&choice);
switch (choice)
{
case 1: push();
break;
case 2: item=pop();
printf("The delete element in %d",item);
break;
case 3: display();
break;
default : printf("\n Wrong choice");
};
printf("\n do you want to continue(Y/N)");
fflush(stdin);
scanf("%c",&ch);
}
while (ch=='Y'||ch=='y');
}
void push()
{
st *node;
node=(st *)malloc(sizeof(st));
printf("\n Enter the number to be insert");
scanf("%d",&node->no);
node->next=start;
start=node;
}
int pop()
{
st *temp;
temp=start;
if(start==NULL)
{
printf("stack is already empty");
getch();
exit();
}
else
{
start=start->next;
free(temp);
}
return(temp->no);
}
void display()
{
st *temp;
temp=start;
while(temp->next!=NULL)
{
printf("\nno=%d",temp->no);
temp=temp->next;
}
printf("\nno=%d",temp->no);
}

OUTPUT:
EX.NO:9 CONSTRUCTION OF DAG
DATE:

AIM:

To write a C program to construct of DAG.

ALGORITHM:

 Start the program.


 Include all the header files.
 Check for postfix expression and construct the inorder DAG representation.
 Print the output.
 Stop the program.

PROGRAM:
#include<stdio.h>
#include<conio.h>
#include<ctype.h>
#define size 20
typedef struct node
{
char data;
struct node *left;
struct node *right;
}btree;
btree *stack[size];
int top;
void main()
{
btree *root;
char exp[80];
btree *create(char exp[80]);
void dag(btree *root);
clrscr();
printf("\nEnter the postfix expression:\n");
scanf("%s",exp);
top=-1;
root=create(exp);
printf("\nThe tree is created.....\n");
printf("\nInorder DAG is : \n\n");
dag(root);
getch();
}

btree *create(char exp[])


{
btree *temp;
int pos;
char ch;
void push(btree*);
btree *pop();
pos=0;
ch=exp[pos];
while(ch!='\0')
{
temp=((btree*)malloc(sizeof(btree)));
temp->left=temp->right=NULL;
temp->data=ch;
if(isalpha(ch))
push(temp);
else if(ch=='+' ||ch=='-' || ch=='*' || ch=='/')
{
temp->right=pop();
temp->left=pop();
push(temp);
}
else
printf("\n Invalid char Expression\n");
pos++;
ch=exp[pos];
}
temp=pop();
return(temp);
}

void push(btree *Node)


{
if(top+1 >=size)
printf("Error:Stack is full\n");
top++;
stack[top]=Node;
}

btree* pop()
{
btree *Node;
if(top==-1)
printf("\nerror: stack is empty..\n");
Node=stack[top];
top--;
return(Node);
}

void dag(btree *root)


{
btree *temp;
temp=root;
if(temp!=NULL)
{
dag(temp->left);
printf("%c",temp->data);
dag(temp->right);
}
}

SAMPLE OUTPUT:
,
Enter the postfix expression : ab+cd-*

The tree is created.....

Inorder DAG is : a+b*c-d

ACTUAL OUTPUT:

RESULT:
EX.NO:10 BACK END COMPILER
DATE:

AIM:
To Implement the back end of the compiler which takes the three address code and produces the 8086
assembly language instructions that can be assembled and run using a 8086 assembler. The target
assembly instructions can be simple move, add, sub, jump. Also simple addressing modes are used.

INTRODUCTION:
A compiler is a computer program that implements a programming language specification to
"translate" programs, usually as a set of files which constitute the source code written in source language,
into their equivalent machine readable instructions (the target language, often having a binary form known
as object code). This translation process is called compilation.
Back end
 some local optimization
 register allocation
 peep-hole optimization
 code generation
 instruction scheduling

The main phases of the back end include the following:


 Analysis: This is the gathering of program information from the intermediate representation
derived from the input; data-flow analysis is used to build use-define chains, together
with dependence analysis, alias analysis, pointer analysis, escape analysis, etc. Accurate analysis is
the basis for any compiler optimization. The call graph and control are usually also built during the
analysis phase.

 Optimization: the intermediate language representation is transformed into functionally


equivalent but faster (or smaller) forms. Popular optimizations are expansion, dead, constant
propagation, loop transformation, register allocation and even automatic parallelization.
 Code generation: the transformed intermediate language is translated into the output language,
usually the native machine language of the system. This involves resource and storage decisions,
such as deciding which variables to fit into registers and memory and the selection and scheduling
of appropriate machine instructions along with their associated addressing modes. Debug data may
also need to be generated to facilitate debugging.
ALGORITHM:
1. Start the program.
2. Open the source file and store the contents as quadruples.
3. Check for operators, in quadruples, if it is an arithmetic operator generate it or if an assignment
operator generate it, else perform unary minus on register c.
4. Write the generated code into output definition of the file in outp.c.
5. Print the output.
6. Stop the program.

PROGRAM :
#include<stdio.h>
#include<stdio.h>
//#include<conio.h>
#include<string.h>
void main()
{
char icode[10][30],str[20],opr[10];
int i=0;
//clrscr();
printf("\n Enter the set of intermediate code (terminated by exit):\n");
do
{
scanf("%s",icode[i]);
} while(strcmp(icode[i++],"exit")!=0);
printf("\n target code generation");
printf("\n************************");
i=0;
do
{
strcpy(str,icode[i]);
switch(str[3])
{
case '+':
strcpy(opr,"ADD");
break;
case '-':
strcpy(opr,"SUB");
break;
case '*':
strcpy(opr,"MUL");
break;
case '/':
strcpy(opr,"DIV");
break;
}
printf("\n\tMov %c,R%d",str[2],i);
printf("\n\t%s%c,R%d",opr,str[4],i);
printf("\n\tMov R%d,%c",i,str[0]);
}while(strcmp(icode[++i],"exit")!=0);
//getch();
}
OUTPUT:
RESULT:
Thus the program to Implement the back end of the compiler which takes the three address code
and produces the 8086 assembly language instructions that can be assembled and run using a 8086
assembler was executed and verified.
EX.NO:11 IMPLEMENTATION OF SIMPLE CODE OPTIMIZATION TECHNIQUES
DATE:

AIM:

To write a C program to implement simple code optimization technique.

INTRODUCTION:
Optimization is a program transformation technique, which tries to improve the code by making it
consume less resource (i.e. CPU, Memory) and deliver high speed.
In optimization, high-level general programming constructs are replaced by very efficient low-level
programming codes. A code optimizing process must follow the three rules given below:
The output code must not, in any way, change the meaning of the program.
 Optimization should increase the speed of the program and if possible, the program should
demand less number of resources.
 Optimization should itself be fast and should not delay the overall compiling process.
Efforts for an optimized code can be made at various levels of compiling the process.
 At the beginning, users can change/rearrange the code or use better algorithms to write the code.
 After generating intermediate code, the compiler can modify the intermediate code by address
calculations and improving loops.
 While producing the target machine code, the compiler can make use of memory hierarchy and
CPU registers.
Optimization can be categorized broadly into two types : machine independent and machine dependent.
Machine-independent Optimization
In this optimization, the compiler takes in the intermediate code and transforms a part of the code that
does not involve any CPU registers and/or absolute memory locations. For example:

do
{

item = 10;
value = value + item;
} while(value<100);
This code involves repeated assignment of the identifier item, which if we put this way:

Item = 10;
do
{

value = value + item;


} while(value<100);

should not only save the CPU cycles, but can be used on any processor.

Machine-dependent Optimization
Machine-dependent optimization is done after the target code has been generated and when the code is
transformed according to the target machine architecture. It involves CPU registers and may have
absolute memory references rather than relative references. Machine-dependent optimizers put efforts to
take maximum advantage of memory hierarchy.

ALGORITHM:

1. Start the program.


2. Declare the variables andfunctions.
3. Enter the expression and state it in the variable a,b,c.
4. Calculate the variables b & c with ‘temp’ and store it in f1 and f2.
5. If (f1=null && f2=null) then expression could not be optimized.
6. Assign the results.
7. Print the results.
8. Stop the program.

PROGRAM:
#include<stdio.h>
#include<conio.h>
#include<string.h>
char s[20],o[20];
void main()
{
int i=0,j=0,k,f1=1,f=1,k1=0;
void part();
clrscr();
printf("\n Enter the input string\n");
scanf("%s",o);
strlen(o);
while(o[k1]!='\0')
{
if((o[k1]=='=')==1)
{
break;
}
k1++;
}
for(j=k1+1;j<strlen(o);j++)
{
s[i]=o[j];
i++;
}
s[i]='\0';
i=strlen(s);
j=0;
printf("\n Three address code is\n");
if(i>3)
{
while(s[j]!='\0')
{
if((s[j]=='*')==1||(s[j]=='/')==1)
{
k=j;
if(f1!=0)
{
printf("t1=%c\n",s[k+1]);
printf("t2=%c%ct1",s[k-1],s[k]);
}
else
{
if(k>3)
{
printf("t2=t1%c%c\n",s[k],s[k+1]);
}
else
{
printf("\t2=t1%c%c\n",s[k],s[k-1]);
}
}
f=0;
break;
}
j++;
}
j=0;
while(s[j]!='\0')
{
if((s[j]=='+')==1||(s[j]=='-')==1)
{
k=j;
if(f==0)
{
if(k<3)
{
printf("\nt3=t2%c%c\n",s[k],s[k-1]);
}
else
{
printf("\nt3=t2%c%c\n",s[k],s[k+1])
}
}
else
{
printf("t1=%c%c%c\n",s[k-1],s[k],s[k+1]);
}
f1=0;
}
j++;
}
printf("%c=t3",o[0]);
}
else
{
printf("t1=%s\n",s);
printf("%c=t1",o[0]);
}
part();
getch();
}
void part()
{
int i=0,j=0,k,f1=1,f=1,k1=0;
while(o[k1]!='\0')
{
if((o[k1]=='=')==1)
{
break;
}
k1++;
}
for(j=k1+1;j<strlen(o);j++)
{
s[i]=o[j];
i++;
}
s[i]='\0';
i=strlen(s);
j=0;
printf("\n OPTIMIZED CODE\n");
if(i>3)
{
while(s[j]!='\0')
{
if((s[j]=='*')==1||(s[j]=='/')==1)
{
k=j;
if(f1!=0)
{
printf("t1=%c%c%c\n",s[k-1],s[k],s[k+1]);
}
else
{
if(k>3)
{
printf("t2=t1%c%c\n",s[k],s[k+1]);
}
else
{
printf("\t2=t1%c%c\n",s[k],s[k-1]);
}
}
f=0;
break;
}
j++;
}
j=0;
while(s[j]!='\0')
{
if((s[j]=='+')==1||(s[j]=='-')==1)
{
k=j;
if(f==0)
{
if(k<3)
{
printf("t2=t1%c%c\n",s[k],s[k-1]);
}
else
{
printf("t2=t1%c%c\n",s[k],s[k+1]);
}
}
else
{
printf("t1=%c%c%c\n",s[k-1],s[k],s[k+1]);
}
f1=0;
}
j++;
}
printf("%c=t2",o[0]);
}
else
{
printf("t1=%s\n",s);
printf("%c=t1",o[0]);
}
}
SAMPLE OUTPUT:
Enter the input string
a=b+c*d

Three address code is


t1=d
t2=c*t1
t3=t2+b
a=t3

OPTIMIZED CODE
t1=c*d
t2=t1+b
a=t2

RESULT:
Thus the program for implementation of simple code optimization was executed and verified.

You might also like