CS3501 - Compiler Design Lab Manual
CS3501 - Compiler Design Lab Manual
AND ENGINEERING
REG.NO…………………………………..…
NAME……………………………………….
SRI RANGAPOOPATHI COLLEGE OF ENGINEERING
Alampoondi-604 151, Gingee - TK
BONAFIDE CERTIFICATE
NAME :
REGISTER NO. :
Certified that this is a bonafide record of work done by the above student in the
b.
Program to recognize a valid
variable which starts with a
letter followed by any
number of letters or digits.
c.
Program to recognize a valid
control structures syntax of C
language (For loop, while
loop, if-else, if-else-if, switch
case, etc.).
Implementation of calculator
d. using lex and yacc
5.
Implement type checking
using Lex and Yacc.
AIM:
ALGORITHM:
PROGRAM:
OUTPUT:
RESULT:
Thus the program for developing a lexical analyzer to recognize a few patterns in C has
been executed successfully.
2. IMPLEMENT A LEXICAL ANALYZER USING LEX TOOL
AIM:
IM To write a program for implementing a Lexical analyser using LEX tool in Linux
platform.
ALGORITHM:
Step 1: Lex program contains three sections: definitions, rules, and user subroutines. Each
section must be separated from the others by a line containing only the delimiter, %%.
The format is as follows: definitions %% rules %% user_subroutines
Step 2: In definition section, the variables make up the left column, and their definitions make
up the right column. Any C statements should be enclosed in %{..}%. Identifier is
defined such that the first letter of an identifier is alphabet and remaining letters are
alphanumeric.
Step 3: In rules section, the left column contains the pattern to be recognized in an input file to
yylex(). The right column contains the C program fragment executed when that pattern
is recognized. The various patterns are keywords, operators, new line character, number,
string, identifier, beginning and end of block, comment statements, preprocessor
directive statements etc.
Step 4: Each pattern may have a corresponding action, that is, a fragment of C source code to
execute when the pattern is matched.
Step 5: When yylex() matches a string in the input stream, it copies the matched text to an
external character array, yytext, before it executes any actions in the rules section.
Step 6: In user subroutine section, main routine calls yylex(). yywrap() is used to get more
input.
Step 7: The lex command uses the rules and actions contained in file to generate a program,
lex.yy.c, which can be compiled with the cc command. That program can then receive
input, break the input into the logical pieces defined by the rules in file, and run
program fragments contained in the actions in file.
PROGRAM:
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:
//var.c
#include
#include
void main()
{
int a,b,c;
a=1;
b=2;
c=a+b;
printf("Sum:%d",c);
}
OUTPUT:
RESULT:
Thus the program for implementation of Lexical Analyzer using Lex tool has been
executed successfully.
3. GENERATE YACC SPECIFICATION FOR A FEW
SYNTACTIC CATEGORIES
PROGRAM:
Program name:arith_id.l
%{
/* This LEX program returns the tokens for the expression */
#include “y.tab.h”
%}
%%
“=” {printf(“\n Operator is EQUAL”);}
“+” {printf(“\n Operator is PLUS”);}
“-“ {printf(“\n Operator is MINUS”);}
“/” {printf(“\n Operator is DIVISION”);}
“*” {printf(“\n Operator is MULTIPLICATION”);}
[a-z A-Z]*[0-9]* {
printf(“\n Identifier is %s”,yytext);
return ID;
}
return yytext[0];
\n return 0;
%%
int yywrap()
{
return 1;
}
OUTPUT:
PROGRAM:
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]#
c) 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 recognize the valid syntax of control structures in the C programming language using
Yacc (Yet Another Compiler Compiler),
ALGORITHM:
Define a Yacc specification file (.y file) that describes the grammar
rules for these control structures. Here's an example of a Yacc
specification for recognizing the syntax of various control structures in
C:
Define the grammar rules for each control structure such as if-else,
while, for, and switch-case has been defined.
The %token declarations at the beginning of the Yacc file define the
tokens used in the grammar.
PROGRAM:
%{
#include<stdio.h>
%}
%token IF ELSE WHILE FOR SWITCH CASE BREAK DEFAULT
%%
program : control_structures
;
control_structures : control_structure
| control_structures control_structure
;
control_structure : if_else
| while_loop
| for_loop
| switch_case
;
if_else : IF '(' expression ')' statement %prec LOWER_THAN_ELSE
| IF '(' expression ')' statement ELSE statement
;
while_loop : WHILE '(' expression ')' statement
;
for_loop : FOR '(' expression_opt ';' expression_opt ';' expression_opt ')' statement
;
switch_case : SWITCH '(' expression ')' '{' case_list '}' %prec
LOWER_THAN_ELSE
;
case_list : case
| case_list case
;
case : CASE constant_expression ':' statement_list
| DEFAULT ':' statement_list
;
expression_opt : /* empty */
| expression
;
expression : /* define your expression grammar here */
;
constant_expression : /* define your constant expression grammar here */
;
statement : /* define your statement grammar here */
;
%%
int main() {
yyparse();
return 0;
}
void yyerror(const char *s) {
printf("Syntax error: %s\n", s);
}
OUTPUT:
RESULT:
Thus the program for control constructs with Yacc Specification has been executed
successfully.
d) Implementation of Calculator using LEX and YACC
PROGRAM:
Program name:calci.l
%{
#include "y.tab.h" /*defines the tokens*/
#include ,math.h.
%}
%%
/*To recognise a valid number*/
([0-9] + |([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) {yylval.dval = atof(yytext);
return NUMBER;}
/*For log no | Log no (log base 10)*/
log | LOG {return LOG;}
/*For ln no (Natural Log)*/
ln {return nLOG;}
/*For sin angle*/
sin | SIN {return SINE;}
/*For cos angle*/
cos | COS {return COS;}
/*For tan angle*/
tan | TAN {return TAN;}
/*For memory*/
mem {return MEM;}
[\t] ; /*Ignore white spaces*/
/*End of input*/
\$ {return 0;}
/*Catch the remaining and return a single character token to
the parser*/
\n| return yytext[0];
%%
AIM:
ALGORITHM:
3. EXECUTION
In the main function, the program prompts the user to enter an expression.
The yyparse function is called to start the parsing process.
The parsed expression is then evaluated and stored in the arr array.
Finally, the threeAdd, fouradd, and triple functions are called to print the
intermediate results in different formats.
PROGRAM:
CODE:
Generates Three Address, Four Address, Triple Intermediate Code.
Lex:
%{
#include"y.tab.h"
extern char yyval;
%}
%%
[0-9]+ {yylval.symbol=(char)(yytext[0]);return NUMBER;}
[a-z] {yylval.symbol= (char)(yytext[0]);return LETTER;}
. {return yytext[0];}
\n {return 0;}
%%
YACC:
%{
#include"y.tab.h"
#include<stdio.h>
char addtotable(char,char,char);
int index1=0;
char temp = 'A'-1;
struct expr{
char operand1;
char operand2;
char operator;
char result;
};
%}
%union{
char symbol;
}
%left '+' '-'
%left '/' '*'
%token LETTER NUMBER
%type exp
%%
statement: LETTER '=' exp ';' {addtotable((char)$1,(char)$3,'=');};
exp: exp '+' exp {$$ = addtotable((char)$1,(char)$3,'+');}
|exp '-' exp {$$ = addtotable((char)$1,(char)$3,'-');}
|exp '/' exp {$$ = addtotable((char)$1,(char)$3,'/');}
|exp '*' exp {$$ = addtotable((char)$1,(char)$3,'*');}
|'(' exp ')' {$$= (char)$2;}
|NUMBER {$$ = (char)$1;}
|LETTER {(char)$1;};
%%
struct expr arr[20];
void yyerror(char *s){
printf("Errror %s",s);
}
char addtotable(char a, char b, char o){
temp++;
arr[index1].operand1 =a;
arr[index1].operand2 = b;
arr[index1].operator = o;
arr[index1].result=temp;
index1++;
return temp;
}
void threeAdd(){
int i=0;
char temp='A';
while(i
printf("%c:=\t",arr[i].result);
printf("%c\t",arr[i].operand1);
printf("%c\t",arr[i].operator);
printf("%c\t",arr[i].operand2);
i++;
temp++;
printf("\n");
}
}
void fouradd(){
int i=0;
char temp='A';
while(i<index1){
printf("%c\t",arr[i].operator);
printf("%c\t",arr[i].operand1);
printf("%c\t",arr[i].operand2);
printf("%c",arr[i].result);
i++;
temp++;
printf("\n");
}
}
int find(char l){
int i;
for(i=0;i<index1;i++)
if(arr[i].result==l) break;
return i;
}
void triple(){
int i=0;
char temp='A';
while(i<index1){
printf("%c\t",arr[i].operator);
if(!isupper(arr[i].operand1))
printf("%c\t",arr[i].operand1);
else{
printf("pointer");
printf("%d\t",find(arr[i].operand1));
}
if(!isupper(arr[i].operand2))
printf("%c\t",arr[i].operand2);
else{
printf("pointer");
printf("%d\t",find(arr[i].operand2));
}
i++;
temp++;
printf("\n");
}
}
int yywrap(){
return 1;
}
int main(){
printf("Enter the expression: ");
yyparse();
threeAdd();
printf("\n");
fouradd();
printf("\n");
triple();
return 0;
}
RESULT :
Thus the program for three address code generation has been executed
successfully.
5. IMPLEMENT TYPE CHECKING USING LEX AND YACC
AIM:
To write a C program to implement type checking
ALGORITHM:
Step 1: Track the global scope type information (e.g. classes and their members)
Step 2: Determine the type of expressions recursively, i.e. bottom-up, passing the
resulting types upwards.
Step 3: If type found correct, do the operation
Step 4: Type mismatches, semantic error will be notified
PROGRAM:
break; }
else
{ printf("Identifier %c must be a float type..!\n",vari[i]);
break; } }
else
{ printf("\nthe datatype is correctly defined..!\n");
break; } }
}
return 0;
}
OUTPUT:
RESULT:
Thus the above program is compiled and executed successfully and output
is verified.
6. IMPLEMENT SIMPLE CODE OPTIMIZATION TECHNIQUES
(CONSTANT FOLDING, STRENGTH REDUCTION AND ALGEBRAIC
TRANSFORMATION)
AIM:
To write a program for implementation of Code Optimization Technique.
ALGORITHM:
Step 1: Generate the program for factorial program using for and do-while loop to specify
optimization technique.
Step 2: In for loop variable initialization is activated first and the condition is checked next.
If the condition is true the corresponding statements are executed and specified
increment / decrement operation is performed.
Step 3: The for loop operation is activated till the condition failure.
Step 4: In do-while loop the variable is initialized and the statements are executed then the
condition checking and increment / decrement operation is performed.
Step 5: When comparing both for and do-while loop for optimization do while is best
because first the statement execution is done then only the condition is checked. So,
during the statement execution itself we can find the inconvenience of the result
and no need to wait for the specified condition result.
Step 6: Finally, when considering Code Optimization in loop do-while is best with respect
to performance.
PROGRAM:
RESULT:
Thus the program to implement code optimization technique has been executed
successfully.
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
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
#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 was implemented to the TAC has been successfully executed.