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

Lab Report Merge (G.rabbi)

Uploaded by

dhakaknight007
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

Lab Report Merge (G.rabbi)

Uploaded by

dhakaknight007
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 42

Green University of Bangladesh

Department of Computer Science and Engineering (CSE)


Faculty of Sciences and Engineering

Semester: (Summer 2024, Year: 2024), B.Sc. in CSE (Day)

Lab Report Merge

Course Title: Compiler Lab

Course Code :CSE - 306 Section: 222_D2

Student Details

Name ID
GOLAM RABBI 221902328

1.

Course Teacher’s Name: Tasnim Tayiba Zannat

Lab Report Status

Marks: ………………………………… Signature:.....................


Comments:.............................................. Date:..............................
1. TITLE OF THE LAB REPORT EXPERIMENT
Design a lexical analyzer for given language.

2. OBJECTIVES/AIM

• To design a compiler that can recognize tokens from a given statement.

• To gather practical knowledge about lexical analyzer.

3. IMPLEMENTATION

• Write a program to recognize identifiers.

#include <stdio.h>

#include <string.h>

#include <ctype.h>

#define MAX_IDENTIFIER_LENGTH 50

int isIdentifier(char *str) {

if (!isalpha(str[0]) && str[0] != '_')

return 0;

for (int i = 1; i < strlen(str); i++) {

if (!isalnum(str[i]) && str[i] != '_')

return 0;

return 1;

int main() {

char identifier[MAX_IDENTIFIER_LENGTH];

printf("Enter an identifier: ");

scanf("%s", identifier);

if (isIdentifier(identifier))

printf("'%s' is a valid identifier.\n", identifier);

else

printf("'%s' is not a valid identifier.\n", identifier);


return 0;

}
• Write a program to recognize constants

#include <stdio.h>

#include <string.h>

#include <ctype.h>

#define MAX_CONSTANT_LENGTH 50

int isConstant(char *str) {

int dotCount = 0;

for (int i = 0; i < strlen(str); i++) {

if (!isdigit(str[i]) && str[i] != '.') {

return 0;

if (str[i] == '.') {

dotCount++;

if (dotCount > 1)

return 0;

return 1;

}
int main() {

char constant[MAX_CONSTANT_LENGTH];

printf("Enter a constant: ");

scanf("%s", constant);

if (isConstant(constant))

printf("'%s' is a valid constant.\n", constant);

else

printf("'%s' is not a valid constant.\n", constant);

return 0;

• Write a program to recognize keywords and identifiers.


#include <stdio.h>

#include <string.h>

#include <ctype.h>

#define MAX_IDENTIFIER_LENGTH 50

int isKeyword(char *str) {

char keywords[32][10] = {

"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"

};
for (int i = 0; i < 32; i++) {

if (strcmp(keywords[i], str) == 0)

return 1;

return 0;

int isIdentifier(char *str) {

if (!isalpha(str[0]) && str[0] != '_')

return 0;

for (int i = 1; i < strlen(str); i++) {

if (!isalnum(str[i]) && str[i] != '_')

return 0;

return 1;

int main() {

char token[MAX_IDENTIFIER_LENGTH];

printf("Enter a token: ");

scanf("%s", token);

if (isKeyword(token))

printf("'%s' is a keyword.\n", token);

else if (isIdentifier(token))

printf("'%s' is an identifier.\n", token);

else

printf("'%s' is neither a keyword nor an identifier.\n", token);

return 0;

}
• Write a program to ignore the comments in the given input source program.

#include <stdio.h>

int main() {

int prev_char = EOF;

int current_char;

while ((current_char = getchar()) != EOF) {

if (prev_char == '/' && current_char == '/') {

while ((current_char = getchar()) != EOF && current_char != '\n');


if (current_char == EOF)

break;

} else if (prev_char == '/' && current_char == '*') {


int comment_closed = 0;

while (!comment_closed && (current_char = getchar()) != EOF) {


if (prev_char == '*' && current_char == '/')

comment_closed = 1;

prev_char = current_char;

if (current_char ==
EOF) break;

} else {

putchar(prev_char);

prev_char = current_char;

if (prev_char != EOF)
putchar(prev_char);

return 0;
}

4. Discussion

In this lab experiment this functions provide essential functionalities for lexical analysis
and preprocessing:

▪ Identifier Recognition: Determines the validity of C identifiers based on language rules.

▪ Constant Recognition: Identifies valid integer and floating-point constants in C.

▪ Keyword and Identifier Recognition: Distinguishes between C keywords and valid


identifiers.

• Comment Ignoring: Removes comments from C source files, aiding in code readability.

Each program contributes to understanding core concepts of C programming and


preprocessing. These programs facilitate

Fundamental understanding and form the backbone of lexical analysis in C

Lab Report 2: Comment Analysis in Code

Objectives
1. Write a program to recognize comments and count the number of letters in
these comments.

2. Write a program to recognize the types of comments.


3. Write a program to find the number of lines where the comments are written.

Task 1: Recognize Comments and Count Letters


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

int count_letters_in_comments(const char *code) {


int total_letters = 0;

const char *line = strtok(strdup(code), "\n");


while (line != NULL) {
char *comment = strstr(line, "//");

if (comment != NULL) {
total_letters += strlen(comment + 2);
}
line = strtok(NULL, "\n");
}
return total_letters;
}

int main() {
const char *code_example =
"// This is a comment\n"

"printf(\"Hello, World!\\n\"); // Another comment\n"


"// Third comment here\n";

printf("%d\n", count_letters_in_comments(code_example)); // Output: 48


return 0;
}

Task 2: Recognize the Types of Comments


Code:

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

void identify_comment_types(const char *code, int *inline_comments, int


*standalone_comments) {
*inline_comments = 0;

*standalone_comments = 0;
const char *line = strtok(strdup(code), "\n");
while (line != NULL) {
if (strstr(line, "//") != NULL) {
if (strstr(line, "//") == line) {

(*standalone_comments)++;
} else {
(*inline_comments)++;
}
}
line = strtok(NULL, "\n");
}
}

int main() {
const char *code_example =
"// This is a standalone comment\n"
"printf(\"Hello, World!\\n\"); // This is an inline comment\n";

int inline_comments, standalone_comments;

identify_comment_types(code_example, &inline_comments, &standalone_comments);


printf("inline: %d, standalone: %d\n", inline_comments, standalone_comments); // Output:
inline: 1, standalone: 1

return 0;
}
Task 3: Find the Number of Lines with Comments
#include <stdio.h>

#include <string.h>

int count_comment_lines(const char *code) {

int comment_lines = 0;
const char *line = strtok(strdup(code), "\n");
while (line != NULL) {

if (strstr(line, "//") != NULL) {


comment_lines++;
}
line = strtok(NULL, "\n");
}

return comment_lines;
}

int main() {
const char *code_example =
"// This is a comment\n"

"printf(\"Hello, World!\\n\"); // Another comment\n"


"// Third comment here\n";

printf("%d\n", count_comment_lines(code_example)); // Output: 3


return 0;

}
Conclusion
We successfully created programs to recognize comments, count the number of
letters in comments, identify the types of comments, and find the number of lines
with comments.

These tools help in analyzing and understanding the comment usage in C code.

Lab Report 3: String Recognition in Code


Objectives
1. Write a program to recognize strings under the rule "a+b*c+".
2. Write a program to recognize strings under the rule "a*b+c+".

Task 1: Recognize String Under Rule "a+b*c+"


Code:

#include <stdio.h>

#include <stdbool.h>

bool match_rule_a_plus_b_star_c_plus(const char *str) {


int state = 0;
for (int i = 0; str[i] != '\0'; i++) {
switch (state) {

case 0: if (str[i] == 'a') state = 1; else return false; break;


case 1: if (str[i] == 'a') state = 1; else if (str[i] == 'b') state = 2; else return false; break;
case 2: if (str[i] == 'b') state = 2; else if (str[i] == 'c') state = 3; else return false; break;
case 3: if (str[i] == 'c') state = 3; else return false; break;
}
}
return state == 3;

int main() {

const char *test_str1 = "aaabccc";


const char *test_str2 = "aabbc";

printf("%d\n", match_rule_a_plus_b_star_c_plus(test_str1)); // Output: 1 (true)

printf("%d\n", match_rule_a_plus_b_star_c_plus(test_str2)); // Output: 0 (false)


return 0;
}

Task 2: Recognize String Under Rule "a*b+c+"


Code:

#include <stdio.h>
#include <stdbool.h>

bool match_rule_a_star_b_plus_c_plus(const char *str) {


int state = 0;
for (int i = 0; str[i] != '\0'; i++) {

switch (state) {
case 0: if (str[i] == 'a') state = 0; else if (str[i] == 'b') state = 1; else return false; break;

case 1: if (str[i] == 'b') state = 1; else if (str[i] == 'c') state = 2; else return false; break;
case 2: if (str[i] == 'c') state = 2; else return false; break;

}
}
return state == 2;
}

int main() {

const char *test_str1 = "aaabbcc";


const char *test_str2 = "abbc";

printf("%d\n", match_rule_a_star_b_plus_c_plus(test_str1)); // Output: 1 (true)

printf("%d\n", match_rule_a_star_b_plus_c_plus(test_str2)); // Output: 1 (true)


return 0;

Conclusion
We successfully created programs to recognize strings under the rules "a+bc+" and
"ab+c+".

These tools help in validating strings based on specific patterns in C code

Lab Report 4: Conversion to Prefix and


Postfix Operations
Objectives
1. Write a program to convert a+(b-c) to prefix operation.

2. Write a program to convert a+(b-c) to postfix operation.

Task 1: Convert a+(b-c) to Prefix Operation


Code:

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

#define MAX 100

char stack[MAX];
int top = -1;
void push(char item) {

if (top >= MAX - 1)


return;
else {
top = top + 1;
stack[top] = item;

}
}

char pop() {
char item;
if (top < 0) {

exit(1);
} else {
item = stack[top];
top = top - 1;
return item;

}
}

int isOperator(char symbol) {

return (symbol == '+' || symbol == '-' || symbol == '*' || symbol == '/');

int precedence(char symbol) {


switch (symbol) {
case '+':
case '-':
return 1;

case '*':
case '/':
return 2;
default:
return 0;
}
}

void infixToPrefix(char infix[], char prefix[]) {


int i, j = 0;
char item, x;
strrev(infix);

for (i = 0; i < strlen(infix); i++) {

if (infix[i] == ')') {
infix[i] = '(';

} else if (infix[i] == '(')


{ infix[i] = ')';
}
}

for (i = 0; i < strlen(infix); i++) {

item = infix[i];
if (item == '(') {
push(item);
} else if (item == ')') {

x = pop();
while (x != '(') {
prefix[j++] = x;
x = pop();
}

} else if (isOperator(item)) {
x = pop();

while (isOperator(x) && precedence(x) >= precedence(item)) {


prefix[j++] = x;
x = pop();

}
push(x);
push(item);
} else {
prefix[j++] = item;

}
}

while (top != -1) {


prefix[j++] = pop();
}

prefix[j] = '\0';
strrev(prefix);
}

int main() {
char infix[] = "a+(b-c)";

char prefix[MAX];
infixToPrefix(infix, prefix);
printf("%s\n", prefix); // Output: +a-bc
return 0;
}

Task 2: Convert a+(b-c) to Postfix Operation


Code:

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

#define MAX 100

char stack[MAX];

int top = -1;

void push(char item) {


if (top >= MAX - 1)
return;
else {

top = top + 1;
stack[top] = item;
}

char pop() {

char item;
if (top < 0) {
exit(1);

} else {
item = stack[top];
top = top - 1;
return item;
}

int isOperator(char symbol) {

return (symbol == '+' || symbol == '-' || symbol == '*' || symbol == '/');

int precedence(char symbol) {

switch (symbol) {
case '+':
case '-':
return 1;
case '*':

case '/':
return 2;
default:
return 0;
}

void infixToPostfix(char infix[], char postfix[]) {

int i, j = 0;
char item, x;

for (i = 0; i < strlen(infix); i++) {


item = infix[i];
if (item == '(') {

push(item);
} else if (item == ')') {
x = pop();
while (x != '(') {
postfix[j++] = x;

x = pop();
}
} else if (isOperator(item)) {
x = pop();

while (isOperator(x) && precedence(x) >= precedence(item)) {


postfix[j++] = x;
x = pop();

}
push(x);
push(item);

} else {
postfix[j++] = item;

}
}

while (top != -1) {


postfix[j++] = pop();
}

postfix[j] = '\0';
}

int main() {
char infix[] = "a+(b-c)";
char postfix[MAX];

infixToPostfix(infix, postfix);
printf("%s\n", postfix); // Output: abc-+

return 0;
}

Conclusion
We successfully created programs to convert the infix expression a+(b-c) to
prefix and postfix operators in C.

These tools help in transforming and understanding different forms of arithmetic


expressions.

Lab Report 5: First and Follow Calculation for


Given Grammar

Objectives
1. Implement a C program to calculate the first and follow sets for a given grammar.

Code
#include <stdio.h>

#include <ctype.h>
#include <string.h>

#define MAX 10
char production[MAX][MAX], first[MAX], follow[MAX];
int count, n = 0, m = 0;

void find_first(char, int, int);

void find_follow(char);
void add_to_array(char[], char);

int main() {

int i, choice;
char c, ch;

// Example grammar count


= 6; strcpy(production[0],
"E=TR"); strcpy(production[1],
"R=+TRq"); strcpy(production[2],
"T=FY"); strcpy(production[3],
"Y=*FYq"); strcpy(production[4],
"F=(E)"); strcpy(production[5],
"F=i");

// Display First sets

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


c = production[i][0];
find_first(c, 0, 0);

printf("First(%c) = { ", c);


for (int j = 0; j < n; j++) {
printf("%c ", first[j]);
}
printf("}\n");

n = 0;
}

// Display Follow sets

find_follow(production[0][0]);
printf("Follow(%c) = { $ ", production[0][0]);
for (i = 0; i < m; i++) {

printf("%c ", follow[i]);


}
printf("}\n");

for (i = 1; i < count; i++) {


find_follow(production[i][0]);

printf("Follow(%c) = { ", production[i][0]);


for (int j = 0; j < m; j++) {
printf("%c ", follow[j]);
}
printf("}\n");

m = 0;
}

return 0;
}
void find_first(char c, int q1, int q2) {

int j;
if (!(isupper(c))) {
add_to_array(first, c);
return;
}

for (j = 0; j < count; j++) {


if (production[j][0] == c) {
if (production[j][2] == '#') {
if (production[q1][q2] == '\0')
find_follow(production[q1][0]);

else
find_first(production[q1][q2], q1, q2 + 1);

} else if (!isupper(production[j][2])) {
add_to_array(first, production[j][2]);
} else {

find_first(production[j][2], j, 3);
}
}
}
}

void find_follow(char c) {
int i, j;
if (production[0][0] == c) {
add_to_array(follow, '$');
}
for (i = 0; i < count; i++) {
for (j = 2; j < strlen(production[i]); j++) {

if (production[i][j] == c) {
if (production[i][j + 1] != '\0') {
find_first(production[i][j + 1], 0, 0);
for (int k = 0; k < n; k++) {
if (first[k] != '#') {

add_to_array(follow, first[k]);
}
}
}

if (production[i][j + 1] == '\0' && c != production[i][0]) {


find_follow(production[i][0]);
}

}
}
}

void add_to_array(char array[], char value) {


int i;
for (i = 0; i < n; i++) {
if (array[i] == value) {

return;
}
}
array[n++] = value;

}
Conclusion
We implemented a C program to calculate the first and follow sets for a given
grammar.

The program effectively computes and displays the first and follow sets for the
provided grammar rules.
Lab Report 6: LL(2) Parsing Construction

Objectives
1. Write a C program for constructing an LL(2) parser.
Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100

typedef struct {

char production[MAX][MAX];
int count;
} NonTerminal;

typedef struct {
NonTerminal nonTerminals[MAX];

int count;

} Grammar;

Grammar grammar;

void add_production(char *lhs, char *rhs) {

for (int i = 0; i < grammar.count; i++) {

if (strcmp(grammar.nonTerminals[i].production[0], lhs) == 0) {
strcpy(grammar.nonTerminals[i].production[grammar.nonTerminals[i].count], rhs);
grammar.nonTerminals[i].count++;

return;
}
}

strcpy(grammar.nonTerminals[grammar.count].production[0], lhs);
strcpy(grammar.nonTerminals[grammar.count].production[1], rhs);
grammar.nonTerminals[grammar.count].count = 2;
grammar.count++;

int is_terminal(char symbol) {

return !(symbol >= 'A' && symbol <= 'Z');


}

void parse(char *input) {

char stack[MAX];
int top = -1;
stack[++top] = '$';

stack[++top] = grammar.nonTerminals[0].production[0][0];
int i = 0;

while (stack[top] != '$') {


if (stack[top] == input[i]) {
top--;
i++;
} else if (is_terminal(stack[top])) {

printf("Error: Unexpected terminal %c\n",


stack[top]); return;

} else {
int found = 0;
for (int j = 0; j < grammar.count; j++) {

if (stack[top] == grammar.nonTerminals[j].production[0][0]) {
for (int k = 1; k < grammar.nonTerminals[j].count; k++) {

if (grammar.nonTerminals[j].production[k][0] == input[i] ||
is_terminal(grammar.nonTerminals[j].production[k][0])) {
top--;

for (int l = strlen(grammar.nonTerminals[j].production[k]) - 1; l >= 0; l--) {


stack[++top] = grammar.nonTerminals[j].production[k][l];

}
found = 1;
break;

}
}
if (found) break;
}
}

if (!found) {

printf("Error: No production found for %c\n", stack[top]);


return;
}
}
}
printf("Parsing successful\n");
}

int main() {

grammar.count = 0;

add_production("S", "aA");
add_production("A", "b");

char input[MAX];
printf("Enter the input string: ");
scanf("%s", input);
strcat(input, "$");

parse(input);

return 0;
}
Conclusion
We successfully created programs to recognize comments, count the number of
letters in comments, identify the types of comments, and find the number of lines
with comments.

These tools help in analyzing and understanding the comment usage in C code.
Lab Report 8 : Compute FIRST for the
regular expression a(alb)"a

Objectives:
1. Understand the concept of FIRST set in the context of regular expressions.
2. Implement a C program to compute the FIRST set for a given regular expression.

Code:

#include <stdio.h>

#include <stdbool.h>

#include <string.h>

void computeFirstSet(char regex[]) {

bool first['z' - 'a' + 1] = {false};

if (regex[0] == 'a') {

first['a' - 'a'] = true;

if (regex[1] == '(' && regex[2] == 'a' && regex[3] == '|' && regex[4] == 'b' && regex[5] ==
')' && regex[6] == '*') {

first['a' - 'a'] = true;

first['b' - 'a'] = true;

}
}

printf("FIRST set for regular expression %s:\n", regex);

printf("a: %s\n", first['a' - 'a'] ? "true" : "false"); printf("b:

%s\n", first['b' - 'a'] ? "true" : "false"); printf("\n");

void computeFirstSetForStar(char regex[]) {

bool first['z' - 'a' + 1] = {false};

first['a' - 'a'] = true;

first['b' - 'a'] = true;

printf("FIRST set for regular expression %s:\n", regex);

printf("a: %s\n", first['a' - 'a'] ? "true" : "false"); printf("b:

%s\n", first['b' - 'a'] ? "true" : "false"); printf("\n");

int main() {

char regex1[] = "a(a|b)*a";

char regex2[] = "(a*b*)*";

computeFirstSet(regex1);

computeFirstSetForStar(regex2);

return 0;

}
Conclusion:
In this lab exercise, we explored the concept of FIRST sets for two regular expressions. The
FIRST set helps identify the first symbols that can appear in a string derived from a given
regular expression. By implementing the FIRST set computation in C, we demonstrated how
to analyze regular expressions programmatically to determine their initial symbols. This
exercise enhances understanding of parsing and pattern recognition techniques essential in
compiler design and language processing tasks.

You might also like