0% found this document useful (0 votes)
1 views

compiler practical file (1)

The document outlines a lab assessment for Compiler and Translator Design at Netaji Subhas University of Technology, detailing various programming tasks related to compiler construction, including implementing a DFA, predictive parsing, infix to postfix conversion, symbol table implementation, and a simple calculator using Lex and Yacc. Each task includes the aim, code snippets, and expected outputs. The document is structured with a clear index and submission details.

Uploaded by

d36078067
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views

compiler practical file (1)

The document outlines a lab assessment for Compiler and Translator Design at Netaji Subhas University of Technology, detailing various programming tasks related to compiler construction, including implementing a DFA, predictive parsing, infix to postfix conversion, symbol table implementation, and a simple calculator using Lex and Yacc. Each task includes the aim, code snippets, and expected outputs. The document is structured with a clear index and submission details.

Uploaded by

d36078067
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

Netaji Subhas University of Technology

Compiler and Translator Design


Lab Assesment

Course Code: (ITITC20)

Submitted By:
Name Roll No.
Sumit 2022UIT3121

Submitted To: DR. ANKITA BANSAL


INDEX

S. No. Aim Date Signature


1 Write a program to implement DFA 10/1/25
(Deterministic Finite Automata) to
recognize the identifiers, keywords,
constants and comments of C
language.
2 Write a program for predictive 17/1/25
parser.
3 Write a program to convert infix to 24/1/25
postfix using Lex and Yacc .
4 Write a program to implement symbol 31/1/25
table.
5 Write a program to implement a 7/2/25
simple calculator using Lex and Yacc.
6 Write a program to implement lexical 14/2/25
analyzer for C language
7 Write a program to implement parser 28/3/25
for C language.
8 Generate 3 address codes for selected C 28/3/25
statements.
Practical – 1
Aim: Write a program to implement DFA (Deterministic Finite Automata) to
recognize the identifiers, keywords, constants and comments of C language.

Code:

#include <iostream>
#include <string>
#include <unordered_set>
#include <cctype>

using namespace std;

bool isConsonant(char c) {
string vowels = "aeiouAEIOU";
return isalpha(c) && vowels.find(c) == string::npos;
}

unordered_set<string> keywords = {
"auto", "break", "case", "char", "const", "continue", "default",
"do", "double", "else", "enum", "extern", "float", "for", "goto",
"if", "int", "long", "register", "return", "short", "signed",
"sizeof", "static", "struct", "switch", "typedef", "union",
"unsigned", "void", "volatile", "while"
};

void analyze(const string& input) {


size_t index = 0;
size_t n = input.size();
string state = "start";
string buffer;

while (index < n) {


char ch = input[index];

if (state == "start") {
if (ch == '/') {
buffer += ch;
state = "maybe_comment";
index++;
} else if (isalpha(ch) || ch == '_') {
buffer += ch;
state = "identifier";
index++;
} else {
index++;
}
} else if (state == "maybe_comment") {
if (ch == '*') {
buffer.clear();
state = "in_comment_block";
index++;
} else if (ch == '/') {
buffer.clear();
state = "in_comment_line";
index++;
} else {
buffer.clear();
state = "start";
}
} else if (state == "in_comment_block") {
if (ch == '*') {
state = "maybe_end_block";
}
buffer += ch;
index++;
} else if (state == "maybe_end_block") {
if (ch == '/') {
buffer.pop_back(); // Remove the last '*'
cout << "Comment: " << buffer << endl;
buffer.clear();
state = "start";
} else {
state = "in_comment_block";
buffer += ch;
}
index++;
} else if (state == "in_comment_line") {
if (ch == '\n') {
cout << "Comment: " << buffer << endl;
buffer.clear();
state = "start";
} else {
buffer += ch;
}
index++;
} else if (state == "identifier") {
if (isalnum(ch) || ch == '_') {
buffer += ch;
index++;
} else {
if (keywords.find(buffer) != keywords.end()) {
cout << "Keyword: " << buffer << endl;
} else {
bool hasLetters = false;
bool allConsonant = true;

for (char c : buffer) {


if (isalpha(c)) {
hasLetters = true;
if (!isConsonant(c)) {
allConsonant = false;
break;
}
}
}

if (hasLetters && allConsonant) {


cout << "Consonant Identifier: " << buffer << endl;
} else {
cout << "Identifier: " << buffer << endl;
}
}
buffer.clear();
state = "start";
}
} else {
index++;
}
}

if (state == "identifier" && !buffer.empty()) {


if (keywords.find(buffer) != keywords.end()) {
cout << "Keyword: " << buffer << endl;
} else {
bool hasLetters = false;
bool allConsonant = true;

for (char c : buffer) {


if (isalpha(c)) {
hasLetters = true;
if (!isConsonant(c)) {
allConsonant = false;
break;
}
}
}

if (hasLetters && allConsonant) {


cout << "Consonant Identifier: " << buffer << endl;
} else {
cout << "Identifier: " << buffer << endl;
}
}
} else if (state == "in_comment_line" && !buffer.empty()) {
cout << "Comment: " << buffer << endl;
}
}

int main() {
string input = R"(
int main() {
// This is a comment
int xyz = 123;
char consonant_test = 'a';
/* Another comment */
if (xyz) {
return 0;
}
}
)";

analyze(input);
return 0;
}

OUTPUT:
Practical – 2
Aim: Write a program for predictive parsing, in C language.

Code:

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

int i=0,top=0;
char stack[20],ip[20];

void push(char c){


if(top>=20){
printf("Stack Overflow\n");
exit(1);
}else{
stack[top++]=c;
}
}

void pop(void){
if(top<0){
printf("Stack underflow\n");
exit(1);
}else{
top--;
}
}
void error(void){
printf("\n\nSyntax Error!!!! String is invalid\n");
exit(0);
}

int main(){
int n;
printf("The given grammar is:\n\n");
printf("E -> TE'\n");
printf("E' -> +TE' | epsilon\n");
printf("T -> FT'\n");
printf("T' -> *FT' | epsilon\n");
printf("F -> (E) | d\n\n");

printf("Enter the string to be parsed: ");


scanf("%s",ip);
n=strlen(ip);
ip[n]='$';
ip[n+1]='\0';

push('$');
push('E');

while(ip[i]!='\0'){
if(ip[i]=='$' && stack[top-1]=='$'){
printf("\n\nSuccessful parsing of string\n");
return 1;
}
else if(ip[i]==stack[top-1]){
printf("\nMatch of %c\n",ip[i]);
i++;
pop();
}
else{
if(stack[top-1]=='E' && (ip[i]=='d' || ip[i]=='(')){
printf("\nE -> TE'\n");
pop();
push('\'');
push('T');
}
else if(stack[top-1]=='\'' && ip[i]=='+'){
printf("\nE' -> +TE'\n");
pop();
push('\'');
push('T');
push('+');
}
else if(stack[top-1]=='\'' && (ip[i]==')' || ip[i]=='$')){
printf("\nE' -> epsilon\n");
pop();
}
else if(stack[top-1]=='T' && (ip[i]=='d' || ip[i]=='(')){
printf("\nT -> FT'\n");
pop();
push('\'');
push('F');
}
else if(stack[top-1]=='\'' && ip[i]=='*'){
printf("\nT' -> *FT'\n");
pop();
push('\'');
push('F');
push('*');
}
else if(stack[top-1]=='\'' && (ip[i]=='+' || ip[i]==')' || ip[i]=='$')){
printf("\nT' -> epsilon\n");
pop();
}
else if(stack[top-1]=='F' && ip[i]=='d'){
printf("\nF -> d\n");
pop();
push('d');
}
else if(stack[top-1]=='F' && ip[i]=='('){
printf("\nF -> (E)\n");
pop();
push(')');
push('E');
push('(');
}
else{
error();
}
}
}

return 0;
}

Output:
Practical – 3
Aim: Write a program to convert infix to postfix using Lex and Yacc .

Code:

infix_to_postfix.y -
%{
#include<stdio.h>
%}
%token NUM
%left '+' '-'
%left '*' '/'
%right NEGATIVE
%%
S: E {printf("\n");}
;
E: E '+' E {printf("+");}
| E '*' E {printf("*");}
| E '-' E {printf("-");}
| E '/' E {printf("/");}
| '(' E ')'
| '-' E %prec NEGATIVE {printf("-");}
| NUM {printf("%d", yylval);}
;
%%
int main(){
yyparse();
}
int yyerror (char *msg) {
return printf ("error YACC: %s\n", msg);
}

infix_to_postfix.l -
%{
#include"infix_to_postfix.tab.h"
extern int yylval;
%}
%%
[0-9]+ {yylval=atoi(yytext); return NUM;}
\n return 0;
. return *yytext;
%%
int yywrap(){
return 1;
}
Practical – 4
Aim: Write a program to implement symbol table.

Code:

using namespace std;

unordered_map<string, string> m;

void display() {

if (m.empty()) {

cout << "Symbol table is empty!\n";

return;

for (auto &ite : m) {

cout << ite.first << " is present at " << ite.second << endl;

int main() {

int n;

do {

cout << "\nSYMBOL TABLE IMPLEMENTATION\n";

cout << "1. INSERT\n";

cout << "2. DISPLAY\n";

cout << "3. DELETE\n";

cout << "4. SEARCH\n";


cout << "5. MODIFY\n";

cout << "6. END\n";

cout << "Enter your option: ";

cin >> n;

switch (n) {

case 1: { // Insert

string x, y;

cout << "Enter the label and address: ";

cin >> x >> y;

if (m.find(x) != m.end()) {

cout << "Label already present!" << endl;

} else {

m[x] = y;

cout << "Label added successfully!" << endl;

break;

case 2: { // Display

display();

break;

case 3: { // Delete

string x;

cout << "Enter the label: ";

cin >> x;
if (m.find(x) == m.end()) {

cout << "Label not present in symbol table!" << endl;

} else {

m.erase(x);

cout << "Label deleted successfully!" << endl;

break;

case 4: { // Search

string x;

cout << "Enter the label to be searched: ";

cin >> x;

if (m.find(x) != m.end()) {

cout << "The label is already in the symbol table at address: " << m[x]
<< endl;

} else {

cout << "Label not found in symbol table!" << endl;

break;

case 5: { // Modify

string x, newAddr;

cout << "Enter the label to be modified: ";

cin >> x;
if (m.find(x) == m.end()) {

cout << "Label not present in symbol table!" << endl;

else {

cout << "Enter the new address: ";

cin >> newAddr;

m[x] = newAddr;

cout << "Label modified successfully!" << endl;

break;

case 6: { // Exit

cout << "Exiting program...\n";

break;

default:

cout << "Invalid option! Please try again.\n";

} while (n != 6);

return 0;

}
Output:
Practical – 5
Aim: Write a program to implement a simple calculator using Lex and Yacc.

Code:

calc.y -
%{

#include <stdio.h>
#include <stdlib.h>

extern int yylex();


extern int yyparse();
extern FILE* yyin;

void yyerror(const char* s);


%}

%union {
int ival;
float fval;
}

%token<ival> T_INT
%token<fval> T_FLOAT
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT
%token T_NEWLINE T_QUIT
%left T_PLUS T_MINUS
%left T_MULTIPLY T_DIVIDE

%type<ival> expression
%type<fval> mixed_expression

%start calculation

%%

calculation:
| calculation line
;

line: T_NEWLINE
| mixed_expression T_NEWLINE { printf("\tResult: %f\n", $1);}
| expression T_NEWLINE { printf("\tResult: %i\n", $1); }
| T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = $1; }
| mixed_expression T_PLUS mixed_expression { $$ = $1 + $3; }
| mixed_expression T_MINUS mixed_expression { $$ = $1 - $3; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = $1 * $3; }
| mixed_expression T_DIVIDE mixed_expression { $$ = $1 / $3; }
| T_LEFT mixed_expression T_RIGHT { $$ = $2; }
| expression T_PLUS mixed_expression { $$ = $1 + $3; }
| expression T_MINUS mixed_expression { $$ = $1 - $3; }
| expression T_MULTIPLY mixed_expression { $$ = $1 * $3; }
| expression T_DIVIDE mixed_expression { $$ = $1 / $3; }
| mixed_expression T_PLUS expression { $$ = $1 + $3; }
| mixed_expression T_MINUS expression { $$ = $1 - $3; }
| mixed_expression T_MULTIPLY expression { $$ = $1 * $3; }
| mixed_expression T_DIVIDE expression { $$ = $1 / $3; }
| expression T_DIVIDE expression { $$ = $1 / (float)$3; }
;

expression: T_INT { $$ = $1; }


| expression T_PLUS expression { $$ = $1 + $3; }
| expression T_MINUS expression { $$ = $1 - $3; }
| expression T_MULTIPLY expression { $$ = $1 * $3; }
| T_LEFT expression T_RIGHT { $$ = $2; }
;

%%

int main() {
yyin = stdin;

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

return 0;
}

void yyerror(const char* s) {


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

calc.l -
%option noyywrap

%{
#include <stdio.h>
#define YY_DECL int yylex()

#include "calc.tab.h"
%}

%%

[ \t] ; // ignore all whitespace


[0-9]+\.[0-9]+ {yylval.fval = atof(yytext); return
T_FLOAT;} [0-9]+ {yylval.ival = atoi(yytext); return
T_INT;}
\n {return
T_NEWLINE;} "+" {return
T_PLUS;}
"-" {return T_MINUS;}
"*" {return
T_MULTIPLY;} "/" {return
T_DIVIDE;} "(" {return
T_LEFT;}
")" {return
T_RIGHT;} "exit"
{return
T_QUIT;}
"quit" {return T_QUIT;}

%%
Practical 6

Aim: Write a program to implement lexical analyser for C language.

Code:
c_lex_analyser.l -
%{
int COMMENT=0;
%}
identifier [a-zA-Z][a-zA-Z0-9]*
%%
#.*\n {printf("%sThis is a PREPROCESSOR DIRECTIVE\n",yytext);}
auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|go
to|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|uns
igned|void|volatile|while {printf("\n%s is a KEYWORD",yytext);}
"/*" {COMMENT = 1;}
"*/" {COMMENT = 0;}
{identifier}\( {if(!COMMENT)printf("\nFUNCTION: \n%s",yytext);}
{identifier}(\[[0-9]*\])? {if(!COMMENT) printf("\n%s is an IDENTIFIER",yytext);}
\".*\" {if(!COMMENT)printf("\n%s is a STRING",yytext);}
[0-9]+ {if(!COMMENT) printf("\n%s is a NUMBER ",yytext);}
\{ {if(!COMMENT) printf("\nBLOCK BEGINS");}
\} {if(!COMMENT) printf("\nBLOCK ENDS");}
\) {if(!COMMENT);printf("\n)");}
= {if(!COMMENT) printf("\n%s is an ASSIGNMENT OPERATOR",yytext);}
\<= | \>= | \< | \== | \!= | \> {if(!COMMENT) printf("\n%s is a RELATIONAL
OPERATOR",yytext);}
\, | \; {if(!COMMENT) printf("\n%s is a SEPERATOR",yytext);}
%%
int main(int argc, char **argv)
{
FILE *file;
file=fopen("input.c","r");
if(!file)
{
printf("could not open the file");
exit(0);
}
yyin=file;
yylex();
printf("\n");
return(0);
}
int yywrap()
{ return(1);
}

Output:-
input.c -
#include <stdio.h>
#define PI 3.14
struct inp
{
int a;
};
int check(int a, int b)
{
return (a > b);
}
int main()
{
struct inp ab;
int r = 5;
printf("abc");
return 0;
}
Practical 7
Aim: Write a program to implement parser for C language.
Code:

YACC CODE
%{
#include <stdio.h>
#include <stdlib.h>
%}

%union {
int number;
char* str;
}

%token <number> NUMBER


%token <str> IDENTIFIER
%token INT FLOAT VOID IF ELSE RETURN WHILE FOR
%token PLUS MINUS STAR SLASH EQ NEQ LT GT ASSIGN LPAREN
RPAREN LBRACE RBRACE SEMICOLON COMMA

%type <number> expression


%type <str> identifier

%%

program:
declarations
;
declarations:
declaration
| declarations declaration
;

declaration:
type_specifier IDENTIFIER SEMICOLON
| type_specifier IDENTIFIER ASSIGN expression
SEMICOLON ;

type_specifier:
INT
| FLOAT
| VOID
;

expression:
NUMBER
| IDENTIFIER
| expression PLUS expression
| expression MINUS expression
| expression STAR expression
| expression SLASH expression
;
%%
int main(void) {
printf("Enter the C code:\n");
yyparse();
return 0;
}

int yyerror(char *s) {


fprintf(stderr, "Error: %s\n", s);
return 0;
}
INPUT:

OUTPUT:
I

Practical 8

Aim: Generate the three address code for selected C statements.

Code:

three_address.l
%{
#include"three_address.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;}

%%
three_address.y
%{
#include"three_address.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 <symbol> LETTER NUMBER
%type <symbol> 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<index1){
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");
}
}

int yywrap(){
return 1;
}

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

Create a GNU Makefile


Make reads a description of a project from a makefile (by default, called 'Makefile' in the current directory).
A makefile specifies a set of compilation rules in terms of targets (such as executables) and their
dependencies (such as object files and source files) in the following format:
target: dependencies command
For each target, make checks the modification time of the corresponding dependency files to determine
whether the target needs to be rebuilt using the corresponding command. Note that the command lines in a
makefile must be indented with a single TAB character, not spaces.
GNU Make contains many default rules, referred to as implicit rules, to simplify the construction of makefiles.
For example, these specify that '.o' files can be obtained from '.c' files by compilation, and that an executable
can be made by linking together '.o' files. Implicit rules are defined in terms of make variables, such as CC (the
C compiler) and CFLAGS (the compilation options for C programs), which can be set using
VARIABLE=VALUE lines in the makefile. For C++ the equivalent variables are CXX and CXXFLAGS,
while the make variable CPPFLAGS sets the preprocessor options. The implicit and user-defined rules are
automatically chained together as necessary by GNU Make.
A simple 'Makefile' for the project above can be written as follows:

You might also like