Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

BCSE307L Lab 5 21BAI1743

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 23

BCSE307L -Compiler Design Lab

Winter Semester 2023-24

Prepared by:

Name : Sandhit Karmakar – 21BAI743

Slot: L15+L16
LAB -5

Submitted to: Dr. Sureshkumar WI


AIM : Implementation of three address codes for a simple
program using LEX and YACC tools.

ALGORITHM :
Define tokens: Use LEX to define tokens like identifiers,
constants, operators, etc.
Define grammar: In YACC, define grammar rules for
expressions, statements, and control structures.
Generate three-address codes: Within YACC actions, generate
three-address codes for each grammar rule. Use temporary
variables to store intermediate results.
Handle control flow: Implement control flow statements (if,
else, while) using labels and jumps in three-address codes.
Optimize codes: Apply optimizations like constant folding, dead
code elimination, and common subexpression elimination.
Generate final output: Output the optimized three-address
codes for the given program.

CODE :
Lex file
%{
#include <string.h>
#include "y.tab.h"
%}

%%
[a-z] { yylval.val = strdup(yytext); return VAR; }
[0-9]+ { yylval.val = strdup(yytext); return NUM; }
[\n] { return *yytext; }
. { return yytext[0]; }
%%

int yywrap() {}

Yacc file
%{
#include <stdio.h>
#include <string.h>

char temp[3] = "t1";


char st[10][10];
int top = -1;

int yylex(void);
int yyerror(char *s);
void codegen(char);
void push(char *);

%}

%union
{
char *val;
}

%token<val> VAR
%token<val> NUM
%type<val> E
%type<val> T
%left '='
%left '+' '-'
%left '*' '/'

%%
S: E { return 0; };
E: E '=' T { codegen('='); }
|T
;

T: T '+' F { codegen('+'); }
| T '-' F { codegen('-'); }
|F
;

F: F '*' G { codegen('*'); }
| F '/' G { codegen('/'); }
|G
;

G: '(' E ')' { push($2); }


| VAR { push($1); }
| NUM { push($1); }
;
%%

int main()
{
printf("Enter the infix expression:\n");
yyparse();
return 0;
}

int yyerror(char *s)


{
printf("\n Expression is invalid\n");
}

void push(char *ch)


{
top = top + 1;
strcpy(st[top], ch);
}
void codegen(char a)
{
if (a == '=') {
printf("%s = %s\n", st[top - 1], st[top]);
strcpy(st[top - 1], st[top]);
top--;
} else {
printf("%s = %s %c %s\n", temp, st[top - 1], a, st[top]);
strcpy(st[top - 1], temp);
top--;
temp[1]++;
}
}

OUTPUT :
AIM : Implement simple code optimization techniques
(Constant folding, Strength reduction and Algebraic
transformation).

ALGORITHM :
Tokenize the input code and build a parse tree using lexical
analysis (LEX) and syntax analysis (YACC).
Traverse the parse tree and evaluate constant expressions.
Replace nodes with constant expressions with their computed
values.
Identify opportunities to replace expensive operations with
cheaper ones.
Replace multiplications by powers of 2 with bit shifts, and
simplify other arithmetic expressions.
Apply algebraic identities to simplify expressions wherever
possible.
Examples include x * 0 to 0, x * 1 to x, x + 0 to x, x - 0 to x, etc.
Generate optimized code based on the modified parse tree.
Emit efficient instructions or three-address codes reflecting the
optimized logic.
Test the optimized code to ensure correctness and validate
against the original code's behavior.

CODE :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_VALUES 10
#define MAX_EXPR_LENGTH 20

struct op {
char l[MAX_EXPR_LENGTH];
char r[MAX_EXPR_LENGTH];
} op[MAX_VALUES], pr[MAX_VALUES];

int evaluateExpression(char *expr) {


char *endptr;
return strtol(expr, &endptr, 10);
}

int evaluateArithmeticExpressionWithVariables(char *expr, int


n) {
char *remainingExpr = strdup(expr);
char *token = strtok(remainingExpr, "+-*/");
int result = 0;
if (isdigit(token[0])) {
result = evaluateExpression(token);
} else {
for (int i = 0; i < n; i++) {
if (strcmp(op[i].l, token) == 0) {
result = evaluateExpression(op[i].r);
break;
}
}
}
token = strtok(NULL, "+-*/");
while (token != NULL) {
char operator = expr[token - remainingExpr - 1];
int operand = 0;
if (isdigit(token[0])) {
operand = evaluateExpression(token);
} else {
for (int i = 0; i < n; i++) {
if (strcmp(op[i].l, token) == 0) {
operand = evaluateExpression(op[i].r);
break;
}
}
}
if (operator == '*') {
result *= operand;
} else if (operator == '/') {
if (operand != 0) {
result /= operand;
} else {
printf("Error: Division by zero\n");
return 0;
}
} else if (operator == '+') {
result += operand;
} else if (operator == '-') {
result -= operand;
}
token = strtok(NULL, "+-*/");
}
free(remainingExpr);
return result;
}

int main() {
int i, j, n, z = 0;
printf("Enter the Number of Values: ");
scanf("%d", &n);

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


printf("left: ");
scanf("%s", op[i].l);
printf("right: ");
scanf("%s", op[i].r);
}

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


if (strchr(op[i].r, '+') || strchr(op[i].r, '-') || strchr(op[i].r,
'*') || strchr(op[i].r, '/')) {
int result =
evaluateArithmeticExpressionWithVariables(op[i].r, n);
sprintf(op[i].r, "%d", result);
}
}

printf("\nCode after Constant Folding\n");


for (i = 0; i < n; i++) {
printf("%s=%s\n", op[i].l, op[i].r);
}

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


if (strchr(op[i].r, '+') || strchr(op[i].r, '-') || strchr(op[i].r,
'*') || strchr(op[i].r, '/')) {
int result =
evaluateArithmeticExpressionWithVariables(op[i].r, n);
sprintf(op[i].r, "%d", result);
}
}
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
if (strcmp(op[i].r, op[j].r) == 0 && strcmp(op[i].l, op[j].l)
== 0) {
strcpy(op[j].r, "");
}
}
}

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


if (!isdigit(op[i].r[0])) {
int result =
evaluateArithmeticExpressionWithVariables(op[i].r, n);
sprintf(op[i].r, "%d", result);
}
}

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


if (strcmp(op[i].r, "") != 0) {
strcpy(pr[z].l, op[i].l);
strcpy(pr[z].r, op[i].r);
z++;
}
}

int result_d =
evaluateArithmeticExpressionWithVariables(pr[z - 1].r, n);
sprintf(pr[z - 1].r, "%d", result_d);

printf("\nCode after Constant Propogation\n");


for (i = 0; i < z; i++) {
printf("%s=%s\n", pr[i].l, pr[i].r);
}

return 0;
}
OUTPUT :
AIM : Implement Back-End of the compiler for which three
address code is given as input and the 8086 assembly language
is produced as output.

ALGORITHM :
Read the three-address code instructions, which typically
involve operations with temporary variables and memory
locations.
Maintain a symbol table to keep track of variables, their types,
and memory locations.
Allocate memory for variables and temporary results based on
their data types.
Traverse each three-address code instruction.
Convert each instruction into equivalent 8086 assembly
language instructions.
Handle arithmetic operations, conditional jumps, loops,
function calls, and memory accesses according to the 8086
architecture.
Apply optimization techniques such as constant folding,
strength reduction, and algebraic transformations to optimize
the generated assembly code.
Optimize memory accesses and register usage for efficiency.
CODE :
#include <stdio.h>
#include <string.h>

int main() {
char icode[10][30], str[20], opr[10], var[5], op1[5], op2[5];
int i = 0;

printf("\nEnter the set of intermediate code:\n");


printf("Press Exit to get the Assembly language code\n");
do {
scanf("%s", icode[i]);
} while (strcmp(icode[i++], "exit") != 0);

printf("\n\nTarget code generation\n\n");


// Iterate through the intermediate code
for (int j = 0; j < i; j++) {
strcpy(str, icode[j]);

// Check if "exit" is encountered


if (strcmp(str, "exit") == 0)
break;

// Find the position of the '=' sign


char *equalPos = strchr(str, '=');
if (equalPos == NULL) {
printf("Invalid intermediate code: %s\n", str);
return 1;
}

// Split the string at '=' to separate variable and expression


*equalPos = '\0';
strcpy(var, str); // Copy the variable name
strcpy(str, equalPos + 1); // Copy the expression to str

// If there's no arithmetic operation, it's a simple


assignment
if (strpbrk(str, "+-*/") == NULL) {
printf("\n\tMov %s, %s", str, var);
continue; // Move to the next iteration of the loop
}

// Find the position of the arithmetic operation


char operation;
char *opPos = strpbrk(str, "+-*/");
if (opPos == NULL) {
printf("Invalid operation: %s\n", str);
return 1;
}

// Get the operation character and split the string at the


operation to separate operands
operation = *opPos;
*opPos = '\0';
strcpy(op1, str); // Copy the first operand
strcpy(op2, opPos + 1); // Copy the second operand
// Set the operation string based on the operation
character
switch (operation) {
case '+':
strcpy(opr, "ADD");
break;
case '-':
strcpy(opr, "SUB");
break;
case '*':
strcpy(opr, "MUL");
break;
case '/':
strcpy(opr, "DIV");
break;
default:
printf("Invalid operation: %c\n", operation);
return 1; // Exit with error if an invalid operation is
encountered
}

// Print assembly code for the arithmetic operation


printf("\n\tMov %s, R%d", op1, j);
printf("\n\t%s %s, R%d", opr, op2, j);
printf("\n\tMov R%d, %s", j, var);
}

return 0;
}
OUTPUT :

You might also like