Compiler - Design - Lab Final 2024

Download as pdf or txt
Download as pdf or txt
You are on page 1of 45

CS3501 – COMPILER DESIGN LAB

TABLE OF CONTENTS

Date S. Page No.


List of Exercises CO
No

1. Using the LEX tool, Develop a lexical analyzer to recognize a few


patterns in C. (Ex. identifiers, constants, comments, operators etc.). CO1
Create a symbol table, while recognizing identifiers.

2. Implement a Lexical Analyzer using LEX Tool CO2

3. Generate YACC specification for a few syntactic categories.


a,b a. Program to recognize a valid arithmetic expression that uses
operator +, -, * and /. CO2
b. Program to recognize a valid variable which starts with a letter
followed by any number of letters or digits.

3c, Generate YACC specification for a few syntactic categories


d c. Program to recognize a valid control structures syntax of C
language (For loop, while loop, if-else, if-else-if, switch-case, etc.). CO3
d. Implementation of calculator using LEX and YACC

4. Generate three address code for a simple program using LEX and
CO3
YACC.

5. Implement type checking using LEX and YACC. CO4

6. Implement simple code optimization techniques (Constant folding,


Strength reduction and Algebraic transformation) CO5

7. Implement back-end of the compiler for which the three address


code is given as input and the 8086 assembly language code is CO6
produced as output.

8. Implement Shift reduce Parser


Ex:01(a) Recognizing Patterns in C using LEX tool
Program:

%{
/* program to recognize a C program */
int COMMENT = 0;
int cnt = 0;
%}

identifier [a-zA-Z][a-zA-Z0-9]*

%%

#.* {
printf("\n%s is a PREPROCESSOR DIRECTIVE", yytext);
}

int |
float |
char |
double |
while |
for |
do |
if |
break |
continue |
void |
switch |
case |
long |
struct |
const |
typedef |
return |
else |
goto {
printf("\n\t%s is a KEYWORD", yytext);
}

"/*" {
COMMENT = 1;
}
"*/" {
COMMENT = 0;
cnt++;
}

{identifier}\( {
if (!COMMENT)
printf("\n\nFUNCTION\n\t%s", yytext);
}

\{ {
if (!COMMENT)
printf("\n BLOCK BEGINS");
}

\} {
if (!COMMENT)
printf("\n BLOCK ENDS");
}

{identifier}(\[[0-9]*\])? {
if (!COMMENT)
printf("\n %s IDENTIFIER", yytext);
}

\".*\" {
if (!COMMENT)
printf("\n\t%s is a STRING", yytext);
}

[0-9]+ {
if (!COMMENT)
printf("\n\t%s is a NUMBER", yytext);
}

\)(\;)? {
if (!COMMENT)
printf("\n\t");
ECHO;
printf("\n");
}

\( ECHO;

={
if (!COMMENT)
printf("\n\t%s is an ASSIGNMENT OPERATOR", yytext);
}

\<= |
\>= |
\< |
== |
\> {
if (!COMMENT)
printf("\n\t%s is a RELATIONAL OPERATOR", yytext);
}

%%

int main(int argc, char **argv) {


if (argc > 1) {
FILE *file;
file = fopen(argv[1], "r");
if (!file) {
printf("could not open %s\n", argv[1]);
exit(0);
}
yyin = file;
}
yylex();
printf("\n\n Total No.Of comments are %d", cnt);
return 0;
}

int yywrap() {
return 1;
}

How to Run:
$ lex c_lexical_analyzer.l
$ gcc -o c_lexical_analyzerlex.yy.c -ll
Input File
$ ./c_lexical_analyzerinput_file.c

#include <stdio.h>
int main() {
// This is a sample C program
int x = 10;
float y = 3.14;
char str[] = "Hello, World!";
return 0;
}

Output
#include <stdio.h> is a PREPROCESSOR DIRECTIVE
int is a KEYWORD
main is a KEYWORD
(
) is a RELATIONAL OPERATOR
{ is a RELATIONAL OPERATOR
This is a sample C program is a PREPROCESSOR DIRECTIVE
int is a KEYWORD
x is an IDENTIFIER
= is an ASSIGNMENT OPERATOR
10 is a NUMBER
; is a RELATIONAL OPERATOR
float is a KEYWORD
y is an IDENTIFIER
= is an ASSIGNMENT OPERATOR
3.14 is a NUMBER
; is a RELATIONAL OPERATOR
char is a KEYWORD
str is an IDENTIFIER
[ is a RELATIONAL OPERATOR] is a RELATIONAL OPERATOR
= is an ASSIGNMENT OPERATOR
"Hello, World!" is a STRING
; is a RELATIONAL OPERATOR
return is a KEYWORD
0 is a NUMBER
; is a RELATIONAL OPERATOR
} is a RELATIONAL OPERATOR

Total No. Of comments are 1


Ex:01(b) Symbol table for C pattern using LEX

Program:

%{
#include <stdio.h>
%}

%option noyywrap

%%
"auto"|"break"|"case"|"char"|"const"|"continue"|"default"|"do"|"double"|"else"|"enum"|"ext
ern"|"float"|"for"|"goto"|"if"|"int"|"long"|"register"|"return"|"short"|"signed"|"sizeof"|"static"|"
struct"|"switch"|"typedef"|"union"|"unsigned"|"void"|"volatile"|"while" {
printf("Keyword: %s\n", yytext);
}

[a-zA-Z_][a-zA-Z0-9_]* { printf("Identifier: %s\n", yytext); }

[0-9]+ { printf("Integer Constant: %s\n", yytext); }

[0-9]+"."[0-9]* { printf("Float Constant: %s\n", yytext); }

\"[^\n]*\" { printf("String: %s\n", yytext); }

"="|"+"|"-"|"*"|"/"|"=="|"!="|"<"|">"|"<="|">=" { printf("Operator: %s\n", yytext); }

"(" { printf("Left Parenthesis: %s\n", yytext); }

")" { printf("Right Parenthesis: %s\n", yytext); }

";" { printf("Semicolon: %s\n", yytext); }

[\t\n] { // Ignore tabs and newlines. }

. { printf("Invalid Character: %s\n", yytext); }


%%
int main() {
// Open the input file
FILE *input_file = fopen("input_file.c", "r");
if (!input_file) { perror("Error opening file"); return 1; }

// Set Flex to read from the file


yyin = input_file;

// Call the lexer


yylex();

// Close the input file


fclose(input_file);

return 0;
}

Output:
$ flex token_recognizer.l
$ gcc -o token_recognizer lex.yy.c -ll
$ ./token_recognizer
#include <stdio.h>

int main() {
int x = 10;
float y = 3.14;
char str[] = "Hello, World!";
return 0;
}

Keyword: #include
Keyword: <stdio.h>
Keyword: int
Keyword: main( )
Keyword: int
Identifier: x= 10
Keyword: float
Identifier: y= 3.14
Keyword: char
Identifier: str= "Hello, World!"
Keyword: return 0
Ex:02 Lexical Analyzer Using Lex Tool

Program:
//Implementation of Lexical Analyzer using Lex tool
%{
int COMMENT=0;
%}

identifier [a-zA-Z][a-zA-Z0-9]*

%%
#.* {printf("\n%s is a preprocessor directive",yytext);}
int |
float |
char |
double |
while |
for |
struct |
typedef |
do |
if |
break |
continue |
void |
switch |
return |
else |
goto {printf("\n\t%s is a keyword",yytext);}
"/*" {COMMENT=1;}{printf("\n\t %s is a COMMENT",yytext);}
{identifier}\( {if(!COMMENT)printf("\nFUNCTION \n\t%s",yytext);}
\{ {if(!COMMENT)printf("\n BLOCK BEGINS");}
\} {if(!COMMENT)printf("BLOCK ENDS ");}
{identifier}(\[[0-9]*\])? {if(!COMMENT) printf("\n %s IDENTIFIER",yytext);}
\".*\" {if(!COMMENT)printf("\n\t %s is a STRING",yytext);}
[0-9]+ {if(!COMMENT) printf("\n %s is a NUMBER ",yytext);}
\)(\:)? {if(!COMMENT)printf("\n\t");ECHO;printf("\n");}
\( ECHO;
= {if(!COMMENT)printf("\n\t %s is an ASSIGNMENT OPERATOR",yytext);}
\<= |
\>= |
\< |
== |
\> {if(!COMMENT) printf("\n\t%s is a RELATIONAL OPERATOR",yytext);}
%%
int main(int argc, char **argv)
{
FILE *file;
file=fopen("var.c","r");
if(!file)
{
printf("could not open the file");
exit(0);
}
yyin=file;
yylex();
printf("\n");
return(0);
}
int yywrap()
{
return(1);
}

Input:

#include <stdio.h>
int main() {
int x = 42;
char name[] = "John";
printf("Hello, %s!\n", name);
return 0;
}

Output:

#include <stdio.h> is a preprocessor directive


int is a keyword
main is a keyword
( is a RELATIONAL OPERATOR
) is a RELATIONAL OPERATOR
{ is a BLOCK BEGINS
int is a keyword
x is a IDENTIFIER
= is an ASSIGNMENT OPERATOR
42 is a NUMBER
; is a NUMBER
char is a keyword
name is a IDENTIFIER
[ is a NUMBER] is a NUMBER
= is an ASSIGNMENT OPERATOR
"John" is a STRING
; is a NUMBER
printf is a IDENTIFIER
("Hello, %s!\n", name) is a STRING
; is a NUMBER
return is a keyword
0 is a NUMBER
; is a NUMBER
}BLOCK ENDS
Ex:03(a) YACC Program for Valid Arithmetic Expression

Program: LEX

%{
#include "y.tab.h"
%}

%%

[a-zA-Z_][a-zA-Z_0-9]* return id;

[0-9]+(\.[0-9]*)? return num;

[+/*] return op;


. return yytext[0];
\n return 0;

%%

int yywrap()
{
return 1;
}

YACC :

%{
#include<stdio.h>
int valid=1;
%}

%token num id op

%%
start : id '=' s ';'
s : id x
| num x
| '-' num x
| '(' s ')' x
;
x : op s
| '-' s
|
;

%%

int yyerror()
{
valid=0;
printf("\nInvalidexpression!\n");
return 0;
}

int main()
{
printf("\nEnter the expression:\n");
yyparse();
if(valid)
{
printf("\nValidexpression!\n");
}
}

Output:
$yacc –d arithmetic.y
$lex arithmetic.l
$gcc lex.yy.c y.tab.c -w
$./a.out
Enter the Expression: a=b*c+d
Valid Expression
Enter the Expression: b?a*c
Invalid Expression
Enter the Expresson: c=2*a+b
Valid Expression
Ex:03(b) YACC Program to Recognize valid Variable

Program: LEX

%{
#include "y.tab.h"
%}

%%
[a-zA-Z_][a-zA-Z_0-9]* return letter;

[0-9] return digit;


. return yytext[0];
\n return 0;
%%

int yywrap()

{
return 1;
}

YACC:

%{

#include<stdio.h>
int valid=1;
%}

%token digit letter

%%
start : letter s

s: letter s
| digit s
|
;

%%

int yyerror()
{
printf("\nIts not aidentifier!\n");
valid=0;
return 0;
}

int main()
{
printf("\nEnter a name to tested for identifier: ");

yyparse();
if(valid)
{
printf("\nIt is aidentifier!\n");
}
}

Output:
$yacc –d Variable.y
$lex Variable.l
$gcc lex.yy.c y.tab.c -w
$./a.out
Enter a name to tested for identifier: Counter01
Its a identifier!
$./a.out
Enter a name to tested for identifier: 1sequence
Its not identifier!
Ex:03(c) YACC Program to Validate Control Structures in C

Program: Lex:

%{
#include <stdio.h>
#include "y.tab.h"
%}

%%
"for" { return FOR; }
"while" { return WHILE; }
"if" { return IF; }
"else" { return ELSE; }
"switch" { return SWITCH; }
"case" { return CASE; }
"break" { return BREAK; }
"{" { return OPEN_BRACE; }
"}" { return CLOSE_BRACE; }
"(" { return OPEN_PAREN; }
")" { return CLOSE_PAREN; }
";" { return SEMICOLON; }
"" ; // Ignore whitespace
. ;

%%

YACC:
%{
#include <stdio.h>
int yylex(void);
void yyerror(const char *s);
%}

%token FOR WHILE IF ELSE SWITCH CASE BREAK


%token OPEN_BRACE CLOSE_BRACE OPEN_PAREN CLOSE_PAREN
SEMICOLON

%%
program:
control_structure
;

control_structure:
for_loop { printf("Valid control structure\n"); }
| while_loop { printf("Valid control structure\n"); }
| if_else { printf("Valid control structure\n"); }
| switch_case { printf("Valid control structure\n"); }
;

for_loop:
FOR OPEN_PAREN SEMICOLON SEMICOLON CLOSE_PAREN OPEN_BRACE
control_structure CLOSE_BRACE
;

while_loop:
WHILE OPEN_PAREN CLOSE_PAREN OPEN_BRACE control_structure
CLOSE_BRACE
;

if_else:
IF OPEN_PAREN CLOSE_PAREN OPEN_BRACE control_structure
CLOSE_BRACE
| IF OPEN_PAREN CLOSE_PAREN OPEN_BRACE control_structure
CLOSE_BRACE ELSE OPEN_BRACE control_structure CLOSE_BRACE
;

switch_case:
SWITCH OPEN_PAREN CLOSE_PAREN OPEN_BRACE case_statements
CLOSE_BRACE
;

case_statements:
CASE constant COLON control_structure
| CASE constant COLON control_structure case_statements
;

constant:
/* Your implementation of constant here */
;

%%
void yyerror(const char *s) {
fprintf(stderr, "Syntax error: %s\n");
}

int main(void) {
yyparse();
return 0;
}

Output:
$yacc –d Control.y
$lex Control.l
$gcc lex.yy.c y.tab.c -w
$./a.out
For Loop:
for(i = 0; i < 10; i++) {
printf("%d", i);
}
Valid control structure
While Loop:
while (i< 10) {
printf("%d", i);
i++;
}
Valid control structure

Switch-Case:
switch (choice) {
case 1:
printf("Choice is 1");
break;
case 2:
printf("Choice is 2");
default:
printf("Choice is not 1 or 2");
}

Valid control structure

Invalid For Loop:


for (i = 0; i < 10; i++) {
printf("%d", i);
Syntax error: syntax error
Ex: 03(d) Calculator using LEX and YACC

Program: LEX:

//Program to implement scientific calculator using LEX and YACC


//lexcalc.l
%{
#include "y.tab.h"
#include <math.h>
%}
%%
([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) { yylval.dval = atof(yytext); return NUMBER; }
log |
LOG { return LOG; }
ln { return nLOG; }
sin |
SINE { return SINE; }
cos |
COS { return COS; }
tan |
TAN { return TAN; }
mem { return MEM; }
[\t];
\$ { return 0; }
\n|. return yytext[0];
%%

//yaccalc.y

%{
double memvar;
%}
%union
{
double dval;
}
%token <dval> NUMBER
%token <dval> MEM
%token LOG SINE nLOG COS TAN
%left '-' '+'
%left '*' '/'
%right '^'
%left LOG SINE nLOG COS TAN
%nonassoc UMINUS
%type <dval>expr
%%
start : statement '\n'
| start statement '\n'
;
statement : MEM '=' expr { memvar = $3; }
| expr { printf("Answer = %g\n",$1); }
;
expr: expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr
{
if($3==0)
printf("Divide by zero");
else
$$ = $1 / $3;
}
| expr '^' expr { $$ = pow($1,$3); }
;
expr : '-' expr %prec UMINUS { $$ = -$2; }
| '(' expr ')' { $$ = $2; }
| LOG expr { $$ = log($2)/log(10); }
| nLOG expr { $$ = log($2); }
| SINE expr { $$ = sin($2 * 3.1415/180); }
| COS expr { $$ = cos($2*3.1415/180); }
| TAN expr { $$ = tan($2*3.1415/180); }
| NUMBER { $$ = $1; }
| MEM { $$ = memvar; }
;
%%
main()
{
printf("Enter the Expression\n");
yyparse();
}
SAMPLE INPUT & OUTPUT

Input:
Enter the Expression
log100

Output:
Answer = 2

Input:
Enter the Expression
tan45

Output:
Answer = 0.999954
Ex:04 Three Address Code Generation

Program: Lex:

%{
#include "y.tab.h"
%}

%%
[0-9]+? {yylval.sym=(char)yytext[0]; return NUMBER;}
[a-zA-Z]+? {yylval.sym=(char)yytext[0];return LETTER;}
\n {return 0;}
. {return yytext[0];}

%%
yywrap()
{
return 1;
}

YACC:
%{
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void ThreeAddressCode();
void triple();
void qudraple();
char AddToTable(char ,char, char);

int ind=0;//count number of lines


char temp = '1';//for t1,t2,t3.....
struct incod
{
char opd1;
char opd2;
char opr;
};
%}

%union
{
char sym;
}
%token <sym> LETTER NUMBER
%type <sym> expr
%left '+'
%left '*''/'
%left '-'
%%

statement: LETTER '=' expr ';' {AddToTable((char)$1,(char)$3,'=');}


| expr ';'
;
expr:
expr '+' expr {$$ = AddToTable((char)$1,(char)$3,'+');}
| expr '-' expr {$$ = AddToTable((char)$1,(char)$3,'-');}
| expr '*' expr {$$ = AddToTable((char)$1,(char)$3,'*');}
| expr '/' expr {$$ = AddToTable((char)$1,(char)$3,'/');}
| '(' expr ')' {$$ = (char)$2;}
| NUMBER {$$ = (char)$1;}
| LETTER {$$ = (char)$1;}
|'-' expr {$$ = AddToTable((char)$2,(char)'\t','-');}
;
%%

yyerror(char *s)
{
printf("%s",s);
exit(0);
}

struct incod code[20];

char AddToTable(char opd1,char opd2,char opr)


{
code[ind].opd1=opd1;
code[ind].opd2=opd2;
code[ind].opr=opr;
ind++;
return temp++;
}

void ThreeAddressCode()
{
int cnt = 0;
char temp = '1';
printf("\n\n\t THREE ADDRESS CODE\n\n");
while(cnt<ind)
{
if(code[cnt].opr != '=')
printf("t%c : = \t",temp++);

if(isalpha(code[cnt].opd1))
printf(" %c\t",code[cnt].opd1);
else if(code[cnt].opd1 >='1' && code[cnt].opd1 <='9')
printf("t%c\t",code[cnt].opd1);

printf(" %c\t",code[cnt].opr);

if(isalpha(code[cnt].opd2))
printf(" %c\n",code[cnt].opd2);
else if(code[cnt].opd2 >='1' && code[cnt].opd2 <='9')
printf("t%c\n",code[cnt].opd2);

cnt++;
}
}

void quadruple()
{
int cnt = 0;
char temp = '1';
printf("\n\n\t QUADRAPLE CODE\n\n");
while(cnt<ind)
{
printf(" %c\t",code[cnt].opr);
if(code[cnt].opr == '=')
{
if(isalpha(code[cnt].opd2))
printf(" %c\t \t",code[cnt].opd2);
else if(code[cnt].opd2 >='1' && code[cnt].opd2 <='9')
printf("t%c\t \t",code[cnt].opd2);

printf(" %c\n",code[cnt].opd1);
cnt++;
continue;
}
if(isalpha(code[cnt].opd1))
printf(" %c\t",code[cnt].opd1);
else if(code[cnt].opd1 >='1' && code[cnt].opd1 <='9')
printf("t%c\t",code[cnt].opd1);

if(isalpha(code[cnt].opd2))
printf(" %c\t",code[cnt].opd2);
else if(code[cnt].opd2 >='1' && code[cnt].opd2 <='9')
printf("t%c\t",code[cnt].opd2);
else printf(" %c",code[cnt].opd2);

printf("t%c\n",temp++);

cnt++;
}
}

void triple()
{
int cnt=0;
char temp='1';
printf("\n\n\t TRIPLE CODE\n\n");
while(cnt<ind)
{
printf("(%c) \t",temp);
printf(" %c\t",code[cnt].opr);
if(code[cnt].opr == '=')
{
if(isalpha(code[cnt].opd2))
printf(" %c \t \t",code[cnt].opd2);
else if(code[cnt].opd2 >='1' && code[cnt].opd2 <='9')
printf("(%c)\n",code[cnt].opd2);
cnt++;
temp++;
continue;
}
if(isalpha(code[cnt].opd1))
printf(" %c \t",code[cnt].opd1);
else if(code[cnt].opd1 >='1' && code[cnt].opd1 <='9')
printf("(%c)\t",code[cnt].opd1);

if(isalpha(code[cnt].opd2))
printf(" %c \n",code[cnt].opd2);
else if(code[cnt].opd2 >='1' && code[cnt].opd2 <='9')
printf("(%c)\n",code[cnt].opd2);
else printf(" %c\n",code[cnt].opd2);

cnt++;
temp++;
}
}
main()
{
printf("\n Enter the Expression : ");
yyparse();
ThreeAddressCode();
quadruple();
triple();
}

Output:
$ lex calculator.l
$ yacc -d calculator.y
$ gcc lex.yy.c y.tab.c -o calculator -ll
$ ./calculator

Enter the Expression : (5 + 3) * 4

THREE ADDRESS CODE

t1 := 5
t2 := 3
t3 := t1 + t2
t4 := 4
t5 := t3 * t4

QUADRUPLE CODE

+ 5 3
+ t1 t2
* t3 4
* t5 t4

TRIPLE CODE

(1) + 5 3
(2) + t1 t2
(3) * t3 4
(4) * t5 t4
Ex: 05 Type Checking Using LEX and YACC

Program: LEX:

%{
#include "y.tab.h"
%}

%%
int {
yylval.type = "int";
return INT;
}
float {
yylval.type = "float";
return FLOAT;
}
[0-9]+ {
yylval.type = "int";
return INT_LITERAL;
}

[0-9]+"."[0-9]+ {
yylval.type = "float";
return FLOAT_LITERAL;
}

[\t \n] ; // Ignore whitespace and tabs

. return yytext[0]; // Return other characters as-is


%%
YACC PROGRAM

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void yyerror(const char* s);


int yylex();
%}

%union {
char* type;
}

%token <type> INT FLOAT


%token <type> INT_LITERAL FLOAT_LITERAL
%type <type> expression

%%
program: expression {
if (strcmp($1, "int") == 0 || strcmp($1, "float") == 0) {
printf("Type checked successfully: %s\n", $1);
} else {
printf("Type error: Incompatible type %s\n", $1);
}
}

expression: INT { $$ = $1; }


| FLOAT { $$ = $1; }
| expression '+' expression {
if (strcmp($1, "int") == 0 && strcmp($3, "int") == 0) {
$$ = "int";
} else if ((strcmp($1, "int") == 0 && strcmp($3, "float") == 0) ||
(strcmp($1, "float") == 0 && strcmp($3, "int") == 0) ||
(strcmp($1, "float") == 0 && strcmp($3, "float") == 0)) {
$$ = "float";
} else {
yyerror("Type error");
exit(1);
}
}
| expression '-' expression {
// Similar type checking logic as for addition
}
| expression '*' expression {
// Similar type checking logic as for addition
}
| expression '/' expression {
// Similar type checking logic as for addition
}
| INT_LITERAL { $$ = "int"; }
| FLOAT_LITERAL { $$ = "float"; }
;

%%

void yyerror(const char* s) {


fprintf(stderr, "Parser error: %s\n", s);
exit(1);
}

int main() {
yyparse();
return 0;
}
Output:
$ lex type_checker.l
$ yacc -d type_checker.y
$ gcc lex.yy.c y.tab.c -o type_checker
./type_checker

Enter expressions for type checking (e.g., "5 + 3.2"):


5 + 3.2
Type checked successfully: float

Enter expressions for type checking (e.g., "5 + 3.2"):


5 + "hello"
Type error: Incompatible type "int"

Enter expressions for type checking (e.g., "5 + 3.2"):


(7 + 3) * 2.5
Type checked successfully: float
Ex: 06 Simple Code Optimization Techniques

Program:
#include <stdio.h>
#include <string.h>
#include <stdbool>
#include <math.h>

struct op {
char l;
char r[20];
};

void main() {
int a, i, k, j, n, z = 0, m, q;
char *p, *l;
char temp, t;
char *tem;
struct op op[10], pr[10];

printf("Enter the Number of Values:");


scanf("%d", &n);

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


printf("left: ");
scanf(" %c", &op[i].l);
printf("right: ");
scanf(" %s", &op[i].r);
}
printf("Intermediate Code\n");
for (i = 0; i< n; i++) {
printf("%c=", op[i].l);
printf("%s\n", op[i].r);
}
for (i = 0; i< n - 1; i++) {
temp = op[i].l;
for (j = 0; j < n; j++) {
p = strchr(op[j].r, temp);
if (p) {
pr[z].l = op[i].l;
strcpy(pr[z].r, op[i].r);
z++;
}
}
}

pr[z].l = op[n - 1].l;


strcpy(pr[z].r, op[n - 1].r);
z++;

printf("\nAfter Dead Code Elimination\n");

for (k = 0; k < z; k++) {


printf("%c\t=", pr[k].l);
printf("%s\n", pr[k].r);
}

for (m = 0; m < z; m++) {


tem = pr[m].r;

for (j = m + 1; j < z; j++) {


p = strstr(tem, pr[j].r);

if (p) {
t = pr[j].l;
pr[j].l = pr[m].l;
for (i = 0; i< z; i++) {
l = strchr(pr[i].r, t);

if (l) {
a = l - pr[i].r;
pr[i].r[a] = pr[m].l;
}
}
}
}
}

printf("Eliminate Common Expression\n");

for (i = 0; i< z; i++) {


printf("%c\t=", pr[i].l);
printf("%s\n", pr[i].r);
}

// Reduction in Strength and Constant Folding


printf("After Reduction in Strength and Constant Folding\n");

for (i = 0; i< z; i++) {


bool optimized = false;
char result[20];
strcpy(result, pr[i].r);

for (j = 0; result[j]; j++) {


if (result[j] == '*' &&result[j + 1] == '*') {
// Check for '**' operator
char x, y;
if (sscanf(result, "%*[^*]*%c %c%*[^a-zA-Z]%c", &x, &y, &y) == 3) {
double result = pow(x, y);
printf("%c\t=", pr[i].l);
printf("%.2lf\n", result);
optimized = true;
}
}
}

if (!optimized) {
// Perform constant folding
double value = 0;
char op;
if (sscanf(result, "%lf %c %lf", &value, &op, &value) == 3) {
double result = 0;
if (op == '+') result = value + value;
if (op == '-') result = value - value;
if (op == '*') result = value * value;
if (op == '/') result = value / value;

printf("%c\t=", pr[i].l);
printf("%.2lf\n", result);
} else {
printf("%c\t=", pr[i].l);
printf("%s\n", pr[i].r);
}
}
}
}

Output:
Enter the Number of Values: 4
left: x
right: a ** b
left: y
right: a + a
left: z
right: x * x
left: w
right: b - b

Intermediate Code
x=a**b
y=a+a
z=x*x
w=b-b

After Dead Code Elimination


x =a**b
y =a+a
z =x*x
w =b-b

Eliminate Common Expression


x =a**b
y =a+a
z =x*x
w =b-b

After Reduction in Strength and Constant Folding


x =a**b
y =2*a
z =x*x
w 0.00
Ex:07 Implement Backend of the Compiler

Program:
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int n, rlen = 0;
char icode[25][25], reg[25][25];

int isopr(char c) {
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '\0')
return 1;
return 0;
}

int getregno(char *tmp) {


int i;
for (i = 0; i < rlen; i++) {
if (strcmp(tmp, reg[i]) == 0)
return i;
}
return -1;
}

int addtoreg(char *tmp) {


strcpy(reg[rlen], tmp);
rlen++;
return (rlen - 1);
}

void genopr(char op) {


switch (op) {
case '+':
printf("\nADD ");
break;
case '-':
printf("\nSUB ");
break;
case '*':
printf("\nMUL ");
break;
case '/':
printf("\nDIV ");
break;
}
}

int main() {
int i, j, k, rno1, rno2;
char tmp[25];

printf("Enter the number of Intermediate code Entries: ");


scanf("%d", &n);

printf("\nEnter the Intermediate code\n");


for (i = 0; i < n; i++)
scanf("%s", icode[i]);

for (i = 0; i < n - 1; i++) {


for (j = 0; icode[i][j] != '='; j++);

if (icode[i][j + 1] == '-') {
strcpy(tmp, "00");
j++;
} else {
for (k = 0, j = j + 1; isopr(icode[i][j]) == 0; k++, j++)
tmp[k] = icode[i][j];
tmp[k] = '\0';
}

rno1 = getregno(tmp);

if (rno1 == -1) {
rno1 = addtoreg(tmp);
if (isdigit(tmp[0]))
printf("\nMOV #%s,R%d", tmp, rno1);
else
printf("\nMOV %s,R%d", tmp, rno1);
} else if (tmp[0] == 't') {
rno2 = addtoreg(tmp);
printf("\nMOV R%d,R%d", rno1, rno2);
}

genopr(icode[i][j]);

for (k = 0, j = j + 1; isopr(icode[i][j]) == 0; k++, j++)


tmp[k] = icode[i][j];
tmp[k] = '\0';
rno2 = getregno(tmp);

if (rno2 == -1) {
if (isdigit(tmp[0]))
printf("#%s,R%d", tmp, rno1);
else
printf("%s,R%d", tmp, rno1);
} else {
printf("R%d,R%d", rno2, rno1);
}

for (k = 0; isopr(icode[i][k]) == 0; k++)


tmp[k] = icode[i][k];
tmp[k] = '\0';
strcpy(reg[rno1], tmp);
}

for (k = 0; isopr(icode[i][k]) == 0; k++)


tmp[k] = icode[i][k];
tmp[k] = '\0';
printf("\nMOV R%d,%s\n", rno1, tmp);

return 0;
}

Output:
Enter the number of Intermediate code Entries: 5
Enter the Intermediate code
t1 = 5
t2 = t1 + 3
t3 = t2 - 2
t4 = t3 * 4
t5 = t4 / 2

Three Address Code:


MOV #5,R0
ADD R0,R1
MOV R1,R2
SUB #2,R2
MOV R2,R3
MUL #4,R3
MOV R3,R4
DIV #2,R4
Shift Reduce Parser in C Program:
Program in C
#include <stdio.h>
#include <string.h>

struct ProductionRule
{
char left[10];
char right[10];
};

int main()
{
char input[20], stack[50], temp[50], ch[2], *token1, *token2, *substring;
int i, j, stack_length, substring_length, stack_top, rule_count = 0;
struct ProductionRule rules[10];

stack[0] = '\0';

// User input for the number of production rules


printf("\nEnter the number of production rules: ");
scanf("%d", &rule_count);

// User input for each production rule in the form 'left->right'


printf("\nEnter the production rules (in the form 'left->right'): \n");
for (i = 0; i < rule_count; i++)
{
scanf("%s", temp);
token1 = strtok(temp, "->");
token2 = strtok(NULL, "->");
strcpy(rules[i].left, token1);
strcpy(rules[i].right, token2);
}
// User input for the input string
printf("\nEnter the input string: ");
scanf("%s", input);

i = 0;
while (1)
{
// If there are more characters in the input string, add the next character to the
stack
if (i < strlen(input))
{
ch[0] = input[i];
ch[1] = '\0';
i++;
strcat(stack, ch);
printf("%s\t", stack);
for (int k = i; k < strlen(input); k++)
{
printf("%c", input[k]);
}
printf("\tShift %s\n", ch);
}

// Iterate through the production rules


for (j = 0; j < rule_count; j++)
{
// Check if the right-hand side of the production rule matches a substring in the
stack
substring = strstr(stack, rules[j].right);
if (substring != NULL)
{
// Replace the matched substring with the left-hand side of the production rule
stack_length = strlen(stack);
substring_length = strlen(substring);
stack_top = stack_length - substring_length;
stack[stack_top] = '\0';
strcat(stack, rules[j].left);
printf("%s\t", stack);
for (int k = i; k < strlen(input); k++)
{
printf("%c", input[k]);
}
printf("\tReduce %s->%s\n", rules[j].left, rules[j].right);
j = -1; // Restart the loop to ensure immediate reduction of the newly derived
production rule
}
}

// Check if the stack contains only the start symbol and if the entire input string has
been processed
if (strcmp(stack, rules[0].left) == 0 && i == strlen(input))
{
printf("\nAccepted");
break;
}

// Check if the entire input string has been processed but the stack doesn't match
the start symbol
if (i == strlen(input))
{
printf("\nNot Accepted");
break;
}
}

return 0;
}
Output:
input String: id*id+id

You might also like