Nellai College of Engineering
(An ISO 9001 – 2015 certified Institution)
Maruthakulam, Tirunelveli – 627 151
Department of Computer Science And Engineering
CS3501-COMPLER DESIGN LABORATORY
Name : __________________________________________
Roll No. : ______________ Register No. ________________
Semester: V Branch: Computer Science And Engineering
Nellai College of Engineering
Maruthakulam, Tirunelveli-627 151
Department of Computer Science And Engineering
BONAFIDE CERTIFICATE
Certified that this practical work entitles CS3501 – Compiler Design Laboratory is
the bonafide record of work done by Mr. /Ms. ________________________________ of the
V Semester in Department of Computer Science and Engineering during the year July-
November, 2023.
Register No.
Staff in – Charge Head of the Department
Submitted for the Anna University B.E Degree Practical Examination held at Nellai College of
Engineering on_______________.
Internal Examiner External Examiner
LIST OF EXPERIMENTS
Sl.No. Date Experiment Name Page Signature
No.
Using the lex tool, Develop a lexical
analyzer to recognize a few patterns in C.
1 08.08.23
Create a symbol table, while recognizing
identifiers.
Implement a lexical analyzer using LEX
2 19.08.23
tool.
Program to recognize a valid arithmetic
3a 21.08.23
expression that uses operator +,-,* and /.
Program to recognize a valid variable which
3b 22.08.23 starts with a letter followed by any number
of letters or digits.
Program to recognize a valid control
structures syntax of C language (For loop,
3c 29.08.23
while loop, if-else, if-else-if, switch-case,
etc.)
Implementation of calculator using LEX
3d 5.09.23
and YACC.
Generate three address code for a simple
4 12.09.23
program using LEX and YACC.
Implement type checking using LEX and
5 3.10.23
YACC.
Implement simple code optimization
6 10.10.23
techniques.
Implement back-end of the compiler for
which the three address code is given as
7 17.10.23
input and the 8086 assembly language code
is produced as output.
Ex.No:1 Using the lex tool, Develop a lexical analyzer to recognize a few
patterns in C. Create a symbol table, while recognizing identifiers
Aim:
To develop a lexical analyzer to recognize patterns in C and to create a symbol table.
Algorithm:
1. Include necessary header files, declare a symbol table to store identifiers and their
addresses.
2. Define the patterns and corresponding actions for various token types using regular
expressions.
3. Check if a filename is provided as a command-line argument (argc > 1).
4. Set yyin to the opened file for lex to read from it.
5. Call yylex to start tokenizing and processing the file.
6. After processing the input, print the contents of the symbol table.
Program:
%{
#include <stdio.h>
#include <string.h>
typedef struct {
char name[256];
void* address;
} SymbolEntry;
#define MAX_SYMBOLS 1000
SymbolEntry symbolTable[MAX_SYMBOLS];
int symbolCount = 0;
// Function to add an identifier to the symbol table
void addIdentifier(char* identifier, void* address) {
1
if (symbolCount < MAX_SYMBOLS) {
strcpy(symbolTable[symbolCount].name, identifier);
symbolTable[symbolCount].address = address;
symbolCount++;
} else {
fprintf(stderr, "Symbol table overflow\n");
%}
%%
"auto"|"break"|"case"|"char"|"const"|"continue"|"default"|"do"|"double"|"else"|"enum"|"extern
"|"float"|"for"|"goto"|"if"|"int"|"long"|"register"|"return"|"short"|"signed"|"sizeof"|"static"|"stru
ct"|"switch"|"typedef"|"union"|"unsigned"|"void"|"volatile"|"while" {
printf("Keyword: %s\n", yytext);
[a-zA-Z_][a-zA-Z0-9_]*\(\) { printf("Function: %s\n", yytext); }
[a-zA-Z_][a-zA-Z0-9_]* {
void* address;
addIdentifier(yytext, address);
printf("Identifier: %s (Address: %p)\n", yytext, address);
#.* {printf("preprocessor dir: %s\n",yytext);}
[0-9]+ {
printf("Constant: %s\n", yytext);
2
\/\/[^\n]* {
printf("Comment: %s\n", yytext);
\/\*[^*]*\*+([^/*][^*]*\*+)*\/ {
printf("Comment: %s\n", yytext);
[+\-*/=] {
printf("Operator: %s\n", yytext);
[ \t\n] {
// Ignore whitespace and newlines
.{
printf("Unknown: %s\n", yytext);
%%
int main(int argc,char **argv)
if(argc>1)
FILE *file;
file=fopen(argv[1],"r");
if(!file)
3
Output:
4
{
printf("\n couldnot open %s\n",argv[1]);
exit(0);
yyin=file;
yylex();
printf("\nSymbol Table:\n");
for (int i = 0; i < symbolCount; i++)
printf("Name: %s, Address: %p\n", symbolTable[i].name, symbolTable[i].address);
int yywrap()
return 0;
Result:
Thus the lex program was executed successfully, for recognizing patterns in C and
symbol table creation while recognizing identifiers.
5
Ex.No:2 Implement a lexical analyzer using LEX tool
Aim:
To implement a lexical analyzer using LEX tool.
Algorithm:
1. Declare and initialize the required variable.
2. If the statement starts with #.* print it as preprocessor directive.
3. Check for the given list of keywords and print them as keyword if it is encountered.
4. If the given string is ‘/*’ or ‘*/’ print it as comment line.
5. For a function, print the beginning and ending of the function block.
6. Similarly print the corresponding statements for numbers, identifiers and assignment
operators.
7. In the main function get the input file as argument and open the file in read mode.
8. Then read the file and print the corresponding lex statement given above.
LEX program:
%{
%}
identifier [a-z|A-Z]|[a-z|A-Z|0-9]*
%%
#.* {printf("\n%s is a preprocessor dir",yytext);}
int {printf("\n\t%s is a keyword",yytext);}
{identifier}\( {printf("\n\nFUNCTION\n\t%s",yytext);}
\{ {printf("\nBLOCK BEGINS");}
\} {printf("\nBLOCK ENDS");}
{identifier} {printf("\n%s is an IDENTIFIER",yytext);}
. | \n
%%
int main(int argc,char **argv)
{
if(argc>1)
{
FILE *file;
file=fopen(argv[1],"r");
6
Output:
7
if(!file)
{
printf("\n couldnot open %s\n",argv[1]);
exit(0);
}
yyin=file;
}
yylex();
printf("\n\n");
return 0;
}
int yywrap()
{
return 0;
}
Input (input.c):
#include <stdio.h>
int main()
{
int a, b, sum;
printf("Enter two integers: ");
scanf("%d %d", &a, &b);
sum = a + b;
printf("%d + %d = %d", a, b, sum);
return 0;
}
Result:
Thus the lexical analyzer was implemented successfully using LEX tool.
8
Ex.No:3a Program to recognize a valid arithmetic expression that uses operator
+,-,* and /
Aim:
To write a program to recognize a valid arithmetic expression that uses operator +,-*
and / using YACC.
Algorithm:
LEX:
1. Declare the required header file and variable declaration with in ‘%{‘ and ‘%}’.
2. LEX requires regular expressions to identify valid arithmetic expression token of
lexemes.
3. LEX call yywrap() function after input is over. It should return 1 when work is done
or should return 0 when more processing is required.
YACC:
1. Declare the required header file and variable declaration with in ‘%{‘ and ‘%}’.
2. Define tokens in the first section and also define the associativity of the operations
3. Mention the grammar productions and the action for each production.
4. Call yyparse() to initiate the parsing process.
5. yyerror() function is called when all productions in the grammar in second section
doesn't match to the input statement.
LEX program:
%{
#include<stdio.h>
#include "ex3a.tab.h"
%}
%%
[a-zA-Z][0-9a-zA-Z]* {return ID;}
[0-9]+ {return DIG;}
[\t]+ {;}
. {return yytext[0];}
\n {return 0;}
%%
int yywrap()
9
{
return 1;}
YACC program:
%{
#include<stdio.h>
%}
%token ID DIG
%left '+''-'
%left '*''/'
%right UMINUS
%%
stmt:expn ;
expn:expn'+'expn
|expn'-'expn
|expn'*'expn
|expn'/'expn
|'-'expn %prec UMINUS
|'('expn')'
|DIG
|ID
;
%%
int main()
{
printf("Enter the Expression \n");
yyparse();
printf("valid Expression \n");
return 0;
}
int yyerror()
{
printf("Invalid Expression");
exit(0);
}
10
Output:
11
Result:
Thus the program was executed successfully for recognizing a valid arithmetic
expression that uses operator ,-,* and /.
12
Ex.No:3b Program to recognize a valid variable which starts with a letter
followed by any number of letters or digits
Aim:
To write a program to recognize a valid variable which starts with a letter followed by
any number of letters or digits using YACC.
Algorithm:
LEX:
1. Declare the required header file and variable declaration with in ‘%{‘ and ‘%}’
2. LEX requires regular expressions or patterns to identify token of lexemes for
recognize a valid variable.
3. Lex call yywrap() function after input is over. It should return 1 when work is done or
should return 0 when more processing is required.
YACC:
1. Declare the required header file and variable declaration with in ‘%{‘ and ‘%}’.
2. Define tokens in the first section and also define the associativity of the operations.
3. Mention the grammar productions and the action for each production.
4. Call yyparse() to initiate the parsing process.
5. yyerror() function is called when all productions in the grammar in second section doesn't
match to the input statement.
LEX program:
%{
#include "ex3b.tab.h"
%}
%%
[a-zA-Z] {return LET;}
[0-9] {return DIG;}
. {return yytext[0];}
\n {return 0;}
%%
int yywrap() {
return 1;
}
13
Output:
14
YACC program:
%{
#include<stdio.h>
%}
%token LET DIG
%%
variable:var
;
var:var DIG
|var LET
|LET ;
%%
int main()
{
printf("Enter the variable:\n");
yyparse();
printf("Valid variable\n");
return 0;
}
int yyerror()
{
printf("Invalid variable \n");
exit(1);
}
Result:
Thus the program was implemented successfully to recognize valid variable which
starts with a letter followed by any number of letters or digits using YACC.
15
Ex.No:3c Program to recognize a valid control structures syntax of C language
(For loop, while loop, if-else, if-else-if, switch-case, etc.)
Aim:
To generate YACC specification program to recognize a valid control structures
syntax of C language (For loop, while loop, if-else, if-else-if, switch-case, etc.).
Algorithm:
LEX:
1. Define patterns and actions for tokenizing input.
2. Recognize keywords like "for," "while," "if," "else," etc., and returns corresponding
tokens like WHILE, IF, ELSE, etc.
3. Skip Whitespace characters.
YACC:
1. Define the token types using %token.
2. Set precedence and associativity rules for operators like '+', '-', '*', '/', and unary minus
('UMINUS').
3. The %start program specifies that the entry point of the grammar is the "program"
rule.
4. The grammar includes various constructs like iteration statements, if statements,
switch statements, declarations, and expressions.
5. Call yyparse() to start parsing.
6. Call the yyerror function when there is a syntax error in the input. It prints an error
message to stderr.
Program:
LEX:
%{
#include<stdio.h>
#include "ex3c.tab.h"
%}
%%
"for" { return WHILE; }
"while" { return WHILE; }
16
"if" { return IF; }
"else" { return ELSE; }
"switch" { return SWITCH; }
"case" { return CASE; }
"break" { return BREAK; }
"int" { return INT; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
[a-zA-Z_][a-zA-Z0-9_]* { yylval = atoi(yytext); return IDENTIFIER; }
[ \t\n] ; // Skip whitespace
. { return yytext[0]; } // Return single characters as tokens
%%
int yywrap() {
return 1;
}
YACC:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern FILE *yyin;
extern int yylex();
extern void yyerror(const char*);
int yyparse();
union YYSTYPE{
int integer;
char* string;
};
%}
%token FOR WHILE IF ELSE SWITCH CASE BREAK INT NUMBER IDENTIFIER
%left '+' '-'
%left '*' '/'
%left UMINUS
%start program
17
%%
program: /* empty */
| statement
;
statement: iteration_statement
| if_statement
| if_else_statement
| if_else_if_statement
| else_if_statement
| else_if_else_if_statement
| switch_statement
| INT declaration_list ';'
| expression ';'
| BREAK ';'
;
declaration_list: IDENTIFIER
| declaration_list ',' IDENTIFIER
;
iteration_statement: WHILE '(' expression ')' statement
| FOR '(' expression ';' expression ';' expression ')' statement
;
if_statement: IF '(' expression ')' statement;
if_else_statement: IF '(' expression ')' statement ELSE statement;
if_else_if_statement: IF '(' expression ')' statement else_if_statement;
else_if_statement: ELSE IF '(' expression ')' statement;
else_if_else_if_statement: else_if_statement ELSE IF '(' expression ')' statement;
switch_statement: SWITCH '(' expression ')' '{' case_statements '}' ;
case_statements: CASE NUMBER ':' statements
| case_statements CASE NUMBER ':' statements
;
statements: statement
| statements statement
;
expression: IDENTIFIER
18
| NUMBER
| expression '+' expression
| expression '=' expression
| expression '-' expression
| expression '*' expression
| expression '/' expression
| '(' expression ')'
;
%%
int main(int argc,char **argv)
{
if(argc>1)
{
FILE *file;
file=fopen(argv[1],"r");
if(!file)
{
printf("\n couldnot open %s\n",argv[1]);
exit(0);
}
yyin=file;
yyparse();
printf("\n\n");
return 1;
}
}
void yyerror(const char* s) {
fprintf(stderr, "Syntax error: %s\n", s);
}
Input C program:
if(i=5)
break;
else
break;
19
Output:
20
Result:
Thus the YACC program was generated successfully for recognizing a valid control
structures syntax of C language.
21
Ex.No:3d Implementation of calculator using LEX and YACC
Aim:
To implement calculator using lex and yacc.
Algorithm:
1. Start the program.
2. In the declaration part of lex, includes declaration of regular definitions as digit.
3. In the translation rules part of lex, specifies the pattern and its action that is to be
executed whenever a lexeme matched by pattern is found in the input in the
calculator.l.
4. By use of Yacc program,all the Arithmetic operations are done such as +,-,*,/,%.
5. Display error is persist.
6. Provide the input.
7. Verify the output.
8. End the program.
LEX program:
%{
#include<stdio.h>
#include "calculator.tab.h"
extern int yylval;
%}
%%
[0-9]+ { yylval=atoi(yytext);
return NUMBER;
}
[\t] ;
[\n] return 0;
. return yytext[0];
%%
YACC program:
%{
#include<stdio.h>
int flag=0;
%}
%{
22
int yylex();
void yyerror();
%}
%token NUMBER;
%left '+' '-'
%left '*' '/' '%'
%left '(' ')'
%%
ArithmeticExpression: E{ printf("\nResult=%d\n",$$);
return 0;
};
E:E '+' E{$$=$1+$3;}
|E '-' E{$$=$1-$3;}
|E'*'E{$$=$1*$3;}
|E'/'E{$$=$1/$3;}
|E'%'E{$$=$1%$3;}
|'('E')'{$$=$2;}
|NUMBER{$$=$1;}
;
%%
//driver code
void main()
{
printf("\nEnter Any Arithmetic Expression which can have operations +,-,*,/,Modulus and
Round brackets:\n");
yyparse();
if(flag==0)
printf("\nEntered arithmetic expression is Valid\n\n");
}
void yyerror()
{
printf("\nEntered arithmetic expression is Invalid\n\n");
flag=1;
}
23
Output:
24
Result:
Thus the calculator was implemented successfully using lex and yacc.
25
Ex.No:4 Generate three address code for a simple program using LEX and
YACC
Aim:
To generate three address code for a simple program using LEX and YACC.
Algorithm:
LEX:
4. Declare the required header file and variable declaration with in ‘%{‘ and ‘%}’.
5. LEX requires regular expressions to identify valid arithmetic expression token of
lexemes.
6. LEX call yywrap() function after input is over. It should return 1 when work is done
or should return 0 when more processing is required.
YACC:
6. Declare the required header file and variable declaration with in ‘%{‘ and ‘%}’.
7. Define tokens in the first section and also define the associativity of the operations
8. Mention the grammar productions and the action for each production.
9. Call yyparse() to initiate the parsing process.
10. yyerror() function is called when all productions in the grammar in second section
doesn't match to the input statement.
11. Make_symtab_entry() function to make the symbol table entry.
LEX program:
%{
#include<stdio.h>
#include<string.h>
#include "ex4.tab.h"
%}
%%
[ \n\t]+ ;
main {return MAIN;}
int|float|double|char {strcpy(yylval.string,yytext); return TYPE; }
[a-zA-Z][a-zA-Z0-9_]* {strcpy(yylval.string,yytext);return ID; }
[0-9]+ |
26
[0-9]+\.[0-9]+ {
yylval.dval=atof(yytext);
return NUMBER;
}
. return yytext[0];
%%
int yywrap(){
return 1;
}
YACC program:
%{
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Symbol_Table
{
char sym_name[10];
char sym_type[10];
double value;
}Sym[10];
int sym_cnt=0;
int Index=0;
int temp_var=0;
int search_symbol(char []);
void make_symtab_entry(char [],char [],double);
void display_sym_tab();
void addQuadruple(char [],char [],char [],char []);
void display_Quadruple();
void push(char*);
char* pop();
27
struct Quadruple
{
char operator[5];
char operand1[10];
char operand2[10];
char result[10];
}QUAD[25];
struct Stack
{
char *items[10];
int top;
}Stk;
%}
%union
{
int ival;
double dval;
char string[10];
}
%token <dval> NUMBER
%token <string> TYPE
%token <string> ID
%type <string>varlist
%type <string> expr
%token MAIN
%left '+' '-'
%left '*' '/'
%%
program:MAIN '('')''{' body '}'
;
28
body: varstmtstmtlist
;
varstmt: vardeclvarstmt|
;
vardecl:TYPEvarlist ';'
;
varlist: varlist ',' ID { int i;
i=search_symbol($3);
if(i!=-1)
printf("\n Multiple Declaration of Variable");
else
make_symtab_entry($3,$<string>0,0);
}
| ID'='NUMBER {
int i;
i=search_symbol($1);
if(i!=-1)
printf("\n Multiple Declaration of Variable");
else
make_symtab_entry($1,$<string>0,$3);
}
|varlist ',' ID '=' NUMBER {
int i;
i=search_symbol($3);
if(i!=-1)
printf("\n Multiple Declaration of Variable");
else
29
make_symtab_entry($3,$<string>0,$5);
}
|ID { int i;
i=search_symbol($1);
if(i!=-1)
printf("\n Multiple Declaration of Variable");
else
make_symtab_entry($1,$<string>0,0);
}
;
stmtlist: stmtstmtlist|
;
stmt : ID '=' NUMBER ';' {
int i;
i=search_symbol($1);
if(i==-1)
printf("\n Undefined Variable");
else
{
char temp[10];
if(strcmp(Sym[i].sym_type,"int")==0)
sprintf(temp,"%d",(int)$3);
else
snprintf(temp,10,"%f",$3);
addQuadruple("=","",temp,$1);
}
}
| ID '=' ID ';'{
int i,j;
30
i=search_symbol($1);
j=search_symbol($3);
if(i==-1 || j==-1)
printf("\n Undefined Variable");
else
addQuadruple("=","",$3,$1);
}
| ID '=' expr ';' {addQuadruple("=","",pop(),$1); }
expr :expr '+' expr {
char str[5],str1[5]="t";
sprintf(str, "%d", temp_var);
strcat(str1,str);
temp_var++;
addQuadruple("+",pop(),pop(),str1);
push(str1);
}
|expr '-' expr {
char str[5],str1[5]="t";
sprintf(str, "%d", temp_var);
strcat(str1,str);
temp_var++;
addQuadruple("-",pop(),pop(),str1);
push(str1);
|expr '*' expr {
char str[5],str1[5]="t";
31
sprintf(str, "%d", temp_var);
strcat(str1,str);
temp_var++;
addQuadruple("*",pop(),pop(),str1);
push(str1);
}
|expr '/' expr {
char str[5],str1[5]="t";
sprintf(str, "%d", temp_var);
strcat(str1,str);
temp_var++;
addQuadruple("/",pop(),pop(),str1);
push(str1);
|ID { int i;
i=search_symbol($1);
if(i==-1)
printf("\n Undefined Variable");
else
push($1);
|NUMBER { char temp[10];
snprintf(temp,10,"%f",$1);
push(temp);
}
;
32
%%
extern FILE *yyin;
int main()
{
Stk.top = -1;
yyin = fopen("input.txt","r");
yyparse();
display_sym_tab();
printf("\n\n");
display_Quadruple();
printf("\n\n");
return(0);
}
int search_symbol(char sym[10])
{
int i,flag=0;
for(i=0;i<sym_cnt;i++)
{
if(strcmp(Sym[i].sym_name,sym)==0)
{
flag=1;
break;
}
}
if(flag==0)
return(-1);
else
return(i);
}
void make_symtab_entry(char sym[10],char dtype[10],double val)
{
33
strcpy(Sym[sym_cnt].sym_name,sym);
strcpy(Sym[sym_cnt].sym_type,dtype);
Sym[sym_cnt].value=val;
sym_cnt++;
}
void display_sym_tab()
{
int i;
printf("\n\n The Symbol Table \n\n");
printf(" Name Type Value");
for(i=0;i<sym_cnt;i++)
printf("\n %s %s %f",Sym[i].sym_name,Sym[i].sym_type,Sym[i].value);
}
void display_Quadruple()
{
int i;
printf("\n\n The INTERMEDIATE CODE Is : \n\n");
printf("\n\n The Quadruple Table \n\n");
printf("\n Result Operator Operand1 Operand2 ");
for(i=0;i<Index;i++)
printf("\n %d %s %s %s
%s",i,QUAD[i].result,QUAD[i].operator,QUAD[i].operand1,QUAD[i].operand2);
}
int yyerror()
{
printf("\nERROR!!\n");
return(1);
}
void push(char *str)
{
34
Output:
35
Stk.top++;
Stk.items[Stk.top]=(char *)malloc(strlen(str)+1);
strcpy(Stk.items[Stk.top],str);
}
char * pop()
{
int i;
if(Stk.top==-1)
{
printf("\nStack Empty!! \n");
exit(0);
}
char *str=(char *)malloc(strlen(Stk.items[Stk.top])+1);;
strcpy(str,Stk.items[Stk.top]);
Stk.top--;
return(str);
}
void addQuadruple(char op[10],char op2[10],char op1[10],char res[10]){
strcpy(QUAD[Index].operator,op);
strcpy(QUAD[Index].operand2,op2);
strcpy(QUAD[Index].operand1,op1);
strcpy(QUAD[Index].result,res);
Index++;
}
Result:
Thus the three address code was generated successfully for a simple program using
LEX and YACC.
36
Ex.No:5 Implement type checking using LEX and YACC
Aim:
To implement type checking using LEX and YACC.
Algorithm:
Lex:
1. Initialize the symbol table (symbol_table) and symbol_count to keep track of
variables and their types.
2. Define token patterns using regular expressions for types, integers, identifiers, and
operators.
3. Define actions for each token pattern.
4. Define the `yywrap` function to indicate the end of input.
5. The Lex code, when executed, will tokenize the input program and perform basic type
checking by checking if identifiers are declared with valid types and printing
appropriate messages.
Yacc:
1. Define the token names and their precedence and associativity rules.
2. Define the grammar rules for the programming language, including program structure,
statements, declarations, and expressions.
3. Implement semantic actions for each grammar rule.
4. Define the `main` function to call the Yacc parser (`yyparse`) and check its return
value.
5. Define the `yyerror` function to handle parse errors by printing an error message.
6. The Yacc code, when executed, will parse the input program based on the defined
grammar rules and perform type checking. It will print messages indicating whether
the input code has valid type declarations and assignments.
Program:
Lex:
%{
#include "ex5new.tab.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int yylval;
extern FILE* yyin;
typedef struct {
37
char name[50];
int type; // 0 for integer, 1 for float
} Symbol;
Symbol symbol_table[100]; // A simple symbol table (limited to 100 entries)
int symbol_count = 0;
// Function to search for an identifier in the symbol table
int lookup(char* name, int type) {
for (int i = 0; i<symbol_count; i++) {
if (strcmp(symbol_table[i].name, name) == 0 &&symbol_table[i].type == type) {
return 1; // Identifier found
}
}
return 0; // Identifier not found
}
%}
%%
int|float {yylval = strcmp(yytext, "int") == 0 ? 0 : 1; return TYPE; }
[0-9]+ { yylval = atoi(yytext); return INTEGER; }
[a-zA-Z_][a-zA-Z0-9_]* {
if (lookup(yytext, yylval)) {
printf("Identifier '%s' has a valid type.\n", yytext);
}
return IDENTIFIER;
}
[ \t\n] ; // Ignore whitespace and newline characters
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return MULTIPLY; }
"/" { return DIVIDE; }
"=" { return ASSIGN; }
38
";" { return SEMICOLON; }
. { returnyytext[0]; }
%%
int yywrap(){
return 1;
}
YACC:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lex.yy.c"
extern char *yytext;
int yylex(void);
void yyerror(const char* s);
%}
%token TYPE INTEGER IDENTIFIER PLUS MINUS MULTIPLY DIVIDE ASSIGN
SEMICOLON
%left PLUS MINUS
%left MULTIPLY DIVIDE
%%
program : /* empty */
| program statement
;
statement : declaration SEMICOLON { printf("Declaration\n"); }
| expression SEMICOLON {printf("Expression\n"); }
| error SEMICOLON {yyerrok; printf("Syntax error\n"); }
;
declaration : TYPE IDENTIFIER {
// Add the identifier to the symbol table with the specified type
strcpy(symbol_table[symbol_count].name, yytext);
39
symbol_table[symbol_count].type = yylval;
symbol_count++;
}
;
expression : IDENTIFIER ASSIGN expression {
// Check if the identifier is declared with the correct type
if (!lookup(yytext, yylval)) {
printf("Error: Identifier '%s' is undeclared or has an incorrect type.\n", yytext);
}
}
| expression PLUS expression
| expression MINUS expression
| expression MULTIPLY expression
| expression DIVIDE expression
| INTEGER
| IDENTIFIER
| '(' expression ')'
;
%%
int main() {
if (yyparse() == 0) {
printf("Type checking successful.\n");
} else {
printf("Type checking failed.\n");
}
return 0;
}
void yyerror(const char* s) {
printf("Parse error: %s\n", s);
}
40
Output:
41
Result:
Thus the type checking was implemented successfully using lex and yacc.
42
Ex.No:6 Implement simple code optimization techniques
Aim:
To write a C program to implement the code optimization techniques.
Algorithm:
1. Generate the input three address code.
2. Do the constant folding by replacing t1 + t2 with the computed value t3.
3. Do the strength reduction by replacing t3 * 2 with t3 << 1 (left shift by 1).
4. Perform the algebraic transformation by simplifying 2 * t4 to 2 * (t3 << 1).
5. Print the optimized three address code.
Program:
#include <stdio.h>
int main() {
// Given three-address code
int t1 = 5;
int t2 = 10;
int t3, t4, t5;
// Original three-address code
printf("Original Code:\n");
printf("t1 = 5\n");
printf("t2 = 10\n");
printf("t3 = t1 + t2\n");
printf("t4 = t3 * 2\n");
printf("t5 = t4 + t4\n");
// Optimization Techniques
// 1. Constant Folding
t3 = t1 + t2; // Constant folding: t3 = 15
// 2. Strength Reduction
t4 = t3 << 1; // Strength reduction: t4 = t3 * 2 = t3 << 1
// 3. Algebraic Transformation
t5 = 2 * t4; // Algebraic transformation: t5 = 2 * t4
// Optimized three-address code
printf("\nOptimized Code:\n");
printf("t1 = 5\n");
printf("t2 = 10\n");
printf("t3 = 15\n");
printf("t4 = t3 << 1\n");
43
Output:
Original Code:
t1 = 5
t2 = 10
t3 = t1 + t2
t4 = t3 * 2
t5 = t4 + t4
Optimized Code:
t1 = 5
t2 = 10
t3 = 15
t4 = t3 << 1
t5 = 2 * t4
Result: t5 = 60
44
printf("t5 = 2 * t4\n");
printf("\nResult: t5 = %d\n", t5);
return 0;
}
Result:
Thus the program for code optimization successfully exec
45
Ex.No:7 Implement back-end of the compiler for which the three address code
is given as input and the 8086 assembly language code is produced as
output
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.
Algorithm:
1. Initialize variables.
a) icode: A 2D character array to store intermediate code instructions.
b) str: A character array to temporarily store each instruction.
c) opr: A character array to store the corresponding assembly operation for arithmetic
operators.
d) i: An integer variable to keep track of the current instruction index.
2. Read the intermediate code instructions one by one and store them.
3. Print a header for the target code generation section.
4. Reset the value of i to 0 to iterate through the intermediate code instructions again.
5. Enter a loop to generate target code for each intermediate code instruction
a. Copy the current intermediate code instruction to the str variable.
b. Extract the operator (e.g., +, -, *, /) from the fourth character of str and determine
the corresponding assembly operation (opr).
c. Print the assembly code for the intermediate code instruction:
Mov instruction to load a value into a temporary register.
Arithmetic operation (ADD, SUB, MUL, or DIV) using the temporary register
and the value from str.
Mov instruction to store the result back into a variable.
d. Increment i to process the next intermediate code instruction.
6. Continue the loop until "exit" is encountered.
Program:
#include<stdio.h>
#include<stdio.h>
#include<string.h>
void main()
{
char icode[10][30],str[20],opr[10];
int i=0;
46
//clrscr();
printf("\n Enter the set of intermediate code (terminated by ex):\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);
47
Output:
Enter the set of intermediate code (terminated by ex):
d=2/3
c=4/5
a=2*e
exit
target code generation
************************
Mov 2,R0
DIV3,R0
Mov R0,d
Mov 4,R1
DIV5,R1
Mov R1,c
Mov 2,R2
MULe,R2
Mov R2,a
48
printf("\n\tMovR%d,%c",i,str[0]);
}while(strcmp(icode[++i],"exit")!=0);
//getch();
}
Result:
Thus the program was implemented to generate an assembly language code has been
successfully executed.
49