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

compiler_design

The document outlines a Bachelor of Technology (B.Tech) program in Compiler Design Lab at SRM University, detailing the work of a student named Saurav Kumar. It includes code implementations for a one-pass and two-pass assembler, a symbol table, and a lexical analyzer for C programming. Additionally, it features a Lex tool implementation for lexical analysis.

Uploaded by

ft.saurav17
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)
2 views

compiler_design

The document outlines a Bachelor of Technology (B.Tech) program in Compiler Design Lab at SRM University, detailing the work of a student named Saurav Kumar. It includes code implementations for a one-pass and two-pass assembler, a symbol table, and a lexical analyzer for C programming. Additionally, it features a Lex tool implementation for lexical analysis.

Uploaded by

ft.saurav17
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/ 62

SRM UNIVERSITY DELHI-NCR, SONEPAT, HARYANA

DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING

Bachelor of Technology(B.Tech)

Compiler Design Lab


(21CS3117)

NAME : SAURAV KUMAR

REGISTER NO : 10322210041

SEMESTER : 5th

YEAR : 3rd

SRM University Delhi-NCR, Sonepat, Haryana, Rajiv Gandhi Education City, Delhi-NCR, Sonepat-131029,
Haryana (India)
SRM UNIVERSITY DELHI-NCR, SONEPAT, HARYANA

DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING

BONAFIDE CERTIFICATE

This is to certify that is a bonafide work done by Mr. Saurav Kumar For
the 2 1 CS 3 1 1 7 Compiler Design L AB as a part of the B.Tech (Core), course
in SRM University Delhi-NCR, Sonepat, Haryana during the year of 2023-24.
The record was found to be completed and satisfactory.

HOD/Coordinator Subject In-Charge

Submitted for the Practical Examination held on

Internal Examiner External Examiner


1.Write a program to implement a one-pass and two-pass
assembler.

i)One-Pass Assembler

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

#define MAX_LINES 100


#define MAX_LABELS 50

typedef struct {
char label[20];
int address;
} Symbol;

Symbol symbol_table[MAX_LABELS];
int symbol_count = 0;

void add_to_symbol_table(char *label, int address) {


strcpy(symbol_table[symbol_count].label, label);
symbol_table[symbol_count].address = address;
symbol_count++;
}

int get_symbol_address(char *label) {


for (int i = 0; i < symbol_count; i++) {
if (strcmp(symbol_table[i].label, label) == 0) {
return symbol_table[i].address;
}
}
return -1; // Symbol not found
}
Machine Code:
0: START
1: LOAD A
2: ADD B
3: STORE C
4: END

Symbol Table:
START -> 0
void one_pass_assembler(char *assembly_code[], int line_count) {
int location_counter = 0;

printf("Machine Code:\n");
for (int i = 0; i < line_count; i++) {
char line[100];
strcpy(line, assembly_code[i]);
char *token = strtok(line, " ");

if (token[strlen(token) - 1] == ':') {
// Label definition
token[strlen(token) - 1] = '\0'; // Remove colon
add_to_symbol_table(token, location_counter);
token = strtok(NULL, " ");
}

printf("%d: %s\n", location_counter, token ? token : "");


location_counter++;
}
printf("\nSymbol Table:\n");
for (int i = 0; i < symbol_count; i++) {
printf("%s -> %d\n", symbol_table[i].label, symbol_table[i].address);
}
}
int main() {
char *assembly_code[] = {
"START:",
"LOAD A",
"ADD B",
"STORE C",
"END:"
};
int line_count = sizeof(assembly_code) / sizeof(assembly_code[0]);
one_pass_assembler(assembly_code, line_count);
return 0;
}
ii)Two-Pass Assembler

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

#define MAX_LINES 100


#define MAX_LABELS 50

typedef struct {
char label[20];
int address;
} Symbol;

Symbol symbol_table[MAX_LABELS];
int symbol_count = 0;

void add_to_symbol_table(char *label, int address) {


strcpy(symbol_table[symbol_count].label, label);
symbol_table[symbol_count].address = address;
symbol_count++;
}

int get_symbol_address(char *label) {


for (int i = 0; i < symbol_count; i++) {
if (strcmp(symbol_table[i].label, label) == 0) {
return symbol_table[i].address;
}
}
return -1; // Symbol not found
}

void two_pass_assembler(char *assembly_code[], int line_count) {


int location_counter = 0;
Machine Code:
0: LOAD A
1: ADD B
2: STORE C
3: END

Symbol Table:
START -> 0
// First Pass: Build Symbol Table
for (int i = 0; i < line_count; i++) {
char line[100];
strcpy(line, assembly_code[i]);
char *token = strtok(line, " ");

if (token[strlen(token) - 1] == ':') {
// Label definition
token[strlen(token) - 1] = '\0'; // Remove colon
add_to_symbol_table(token, location_counter);
}
location_counter++;
}

// Second Pass: Generate Machine Code


location_counter = 0;
printf("Machine Code:\n");
for (int i = 0; i < line_count; i++) {
char line[100];
strcpy(line, assembly_code[i]);
char *token = strtok(line, " ");

if (token[strlen(token) - 1] == ':') {
token = strtok(NULL, " "); // Skip label
}

printf("%d: %s\n", location_counter, token ? token : "");


location_counter++;
}

printf("\nSymbol Table:\n");
for (int i = 0; i < symbol_count; i++) {
printf("%s -> %d\n", symbol_table[i].label, symbol_table[i].address);
}
}
int main() {
char *assembly_code[] = {
"START:",
"LOAD A",
"ADD B",
"STORE C",
"END:"
};
int line_count = sizeof(assembly_code) / sizeof(assembly_code[0]);

two_pass_assembler(assembly_code, line_count);

return 0;
}
2. Write a program to implement a symbol table.

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

#define MAX_SYMBOLS 100


#define MAX_NAME_LENGTH 50

typedef struct {
char name[MAX_NAME_LENGTH];
char type[20]; // e.g., "int", "float", "char"
int address;
} Symbol;

Symbol symbol_table[MAX_SYMBOLS];
int symbol_count = 0;

// Function to add a symbol to the table


void add_symbol(char *name, char *type, int address) {
// Check if the symbol already exists
for (int i = 0; i < symbol_count; i++) {
if (strcmp(symbol_table[i].name, name) == 0) {
printf("Error: Symbol '%s' already exists in the table.\n", name);
return;
}
}

// Add new symbol


strcpy(symbol_table[symbol_count].name, name);
strcpy(symbol_table[symbol_count].type, type);
symbol_table[symbol_count].address = address;
symbol_count++;
printf("Symbol '%s' added successfully.\n", name);
}
Symbol Table Menu:
1. Add Symbol
2. Search Symbol
3. Display Symbol Table
4. Exit
Enter your choice: 1
Enter symbol name: x
Enter symbol type: int
Enter symbol address: 100
Symbol 'x' added successfully.

Symbol Table Menu:


1. Add Symbol
2. Search Symbol
3. Display Symbol Table
4. Exit
Enter your choice: 3

Symbol Table:
--------------------------------------------------
| Name | Type | Address |
--------------------------------------------------
|x | int | 100 |
--------------------------------------------------

Symbol Table Menu:


1. Add Symbol
2. Search Symbol
3. Display Symbol Table
4. Exit
Enter your choice: 2
Enter symbol name to search: x
Symbol found: Name = x, Type = int, Address = 100

Symbol Table Menu:


1. Add Symbol
2. Search Symbol
3. Display Symbol Table
4. Exit
Enter your choice: 4
Exiting...
// Function to search for a symbol by name
int search_symbol(char *name) {
for (int i = 0; i < symbol_count; i++) {
if (strcmp(symbol_table[i].name, name) == 0) {
return i; // Return index of the symbol
}
}
return -1; // Symbol not found
}

// Function to display the symbol table


void display_symbol_table() {
printf("\nSymbol Table:\n");
printf("--------------------------------------------------\n");
printf("| %-20s | %-10s | %-10s |\n", "Name", "Type", "Address");
printf("--------------------------------------------------\n");
for (int i = 0; i < symbol_count; i++) {
printf("| %-20s | %-10s | %-10d |\n",
symbol_table[i].name,
symbol_table[i].type,
symbol_table[i].address);
}
printf("--------------------------------------------------\n");
}

int main() {
int choice;
char name[MAX_NAME_LENGTH], type[20];
int address;

do {
printf("\nSymbol Table Menu:\n");
printf("1. Add Symbol\n");
printf("2. Search Symbol\n");
printf("3. Display Symbol Table\n");
printf("4. Exit\n");

printf("Enter your choice: ");


scanf("%d", &choice);

switch (choice) {
case 1:
printf("Enter symbol name: ");
scanf("%s", name);
printf("Enter symbol type: ");
scanf("%s", type);
printf("Enter symbol address: ");
scanf("%d", &address);
add_symbol(name, type, address);
break;

case 2:
printf("Enter symbol name to search: ");
scanf("%s", name);
int index = search_symbol(name);
if (index != -1) {
printf("Symbol found: Name = %s, Type = %s, Address = %d\n",
symbol_table[index].name,
symbol_table[index].type,
symbol_table[index].address);
} else
{
printf("Symbol '%s' not found in the table.\n", name);
}
break;

case 3:
display_symbol_table();
break;

case 4:
printf("Exiting...\n");
break;

default:
printf("Invalid choice. Please try again.\n");
}
} while (choice != 4);

return 0;
}
3. Develop a lexical analyzer to recognize a few patterns in C. (Ex.
identifiers, constants, comments, operators etc.)

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

#define MAX 100

// List of keywords
const char *keywords[] = {
"int", "float", "if", "else", "while", "return", "void", "char", "for", "do", "break"
};
const int num_keywords = sizeof(keywords) / sizeof(keywords[0]);

// Function to check if a string is a keyword


int is_keyword(const char *word) {
for (int i = 0; i < num_keywords; i++) {
if (strcmp(word, keywords[i]) == 0) {
return 1;
}
}
return 0;
}
// Function to recognize operators
int is_operator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=' ||
ch == '<' || ch == '>' || ch == '&' || ch == '|' || ch == '%';
}
// Function to recognize delimiters
int is_delimiter(char ch) {
return ch == ' ' || ch == ',' || ch == ';' || ch == '(' || ch == ')' ||
ch == '{' || ch == '}' || ch == '[' || ch == ']';
}
// Function to recognize digits
Input Code:
int main() {
int x = 10; // This is a comment
float y = 20.5;
if (x < y) {
x = x + y;
}
/* Multi-line comment
Example */

Lexical Analysis:
-------------------------------
| Token | Type |
-------------------------------
| int | Keyword |
| main | Identifier |
|( | Delimiter |
|) | Delimiter |
|{ | Delimiter |
| int | Keyword |
|x | Identifier |
|= | Operator |
| 10 | Constant |
|; | Delimiter |
| //... | Comment |
| float | Keyword |
|y | Identifier |
|= | Operator |
| 20 | Constant |
|. | Unknown |
|5 | Constant |
|; | Delimiter |
| if | Keyword |
|( | Delimiter |
|x | Identifier |
|< | Operator |
|y | Identifier |
|) | Delimiter |
|{ | Delimiter |
|x | Identifier |
|= | Operator |
|x | Identifier |
|+ | Operator |
|y | Identifier |
|; | Delimiter |
|} | Delimiter |
| /*...*/ | Comment |
|} | Delimiter |
-------------------------------
int is_constant(char *word) {
for (int i = 0; word[i] != '\0'; i++) {
if (!isdigit(word[i])) {
return 0;
}
}
return 1;
}

// Function to analyze the input


void lexical_analyzer(const char *code) {
int i = 0;
char buffer[MAX];
printf("Lexical Analysis:\n");
printf("-------------------------------\n");
printf("| Token | Type |\n");
printf("-------------------------------\n");

while (code[i] != '\0') {


// Skip whitespace
if (isspace(code[i])) {
i++;
continue;
}

// Handle comments
if (code[i] == '/' && code[i + 1] == '/') {
printf("| %-12s | %-14s |\n", "//...", "Comment");
while (code[i] != '\0' && code[i] != '\n') {
i++;
}
continue;
}

// Handle multi-line comments


if (code[i] == '/' && code[i + 1] == '*') {
printf("| %-12s | %-14s |\n", "/*...*/", "Comment");
i += 2;
while (code[i] != '\0' && !(code[i] == '*' && code[i + 1] == '/')) {
i++;
}
i += 2; // Skip "*/"
continue;
}

// Handle identifiers and keywords


if (isalpha(code[i])) {
int j = 0;
while (isalnum(code[i]) || code[i] == '_') {
buffer[j++] = code[i++];
}
buffer[j] = '\0';

if (is_keyword(buffer)) {
printf("| %-12s | %-14s |\n", buffer, "Keyword");
} else {
printf("| %-12s | %-14s |\n", buffer, "Identifier");
}
continue;
}

// Handle constants
if (isdigit(code[i])) {
int j = 0;
while (isdigit(code[i])) {
buffer[j++] = code[i++];
}
buffer[j] = '\0';

printf("| %-12s | %-14s |\n", buffer, "Constant");


continue;
}
// Handle operators
if (is_operator(code[i])) {
printf("| %-12c | %-14s |\n", code[i], "Operator");
i++;
continue;
}

// Handle delimiters
if (is_delimiter(code[i])) {
printf("| %-12c | %-14s |\n", code[i], "Delimiter");
i++;
continue;
}

// Unknown token
printf("| %-12c | %-14s |\n", code[i], "Unknown");
i++;
}

printf("-------------------------------\n");
}

int main() {
const char *code = "int main() {\n"
" int x = 10; // This is a comment\n"
" float y = 20.5;\n"
" if (x < y) {\n"
" x = x + y;\n"
" }\n"
" /* Multi-line comment\n"
" Example */\n"
"}";
printf("Input Code:\n%s\n\n", code);
lexical_analyzer(code);
return 0;
}
4.Write a program to implement a lexical analyzer using Lex
Tool.

%{
#include <stdio.h>
%}

%%

"int"|"float"|"char"|"if"|"else"|"while"|"for"|"return" { printf("Keyword: %s\n",


yytext); }
[a-zA-Z_][a-zA-Z0-9_]* { printf("Identifier: %s\n", yytext); }
[0-9]+ { printf("Constant: %s\n", yytext); }
"//".* { printf("Single-line Comment: %s\n", yytext); }
"/*"([^*]|[\r\n]|"*"[^/])*"*/" { printf("Multi-line Comment: %s\n",
yytext); }
"+"|"-"|"*"|"/"|"="|"<"|">" { printf("Operator: %s\n", yytext); }
"(" | ")" | "{" | "}" | ";" | "," | "[" | "]" { printf("Delimiter: %s\n", yytext); }
[ \t\n]+ { /* Ignore whitespace */ }
. { printf("Unknown Token: %s\n", yytext); }

%%

int main() {
yylex();
return 0;
}

int yywrap() {
return 1;
}
Keyword: int
Identifier: main
Delimiter: (
Delimiter: )
Delimiter: {
Keyword: int
Identifier: a
Operator: =
Constant: 10
Delimiter: ;
Single-line Comment: // This is a single-line comment
Keyword: float
Identifier: b
Operator: =
Constant: 20
Operator: .
Constant: 5
Delimiter: ;
Keyword: char
Identifier: c
Operator: =
Unknown Token: '
Identifier: z
Unknown Token: '
Delimiter: ;
Keyword: if
Delimiter: (
Identifier: a
Operator: <
Identifier: b
Delimiter: )
Delimiter: {
Identifier: a
Operator: =
Identifier: a
Operator: +
Identifier: b
Delimiter: ;
Delimiter: }
Multi-line Comment: /* Multi-line comment
Example */
Keyword: return
Constant: 0
Delimiter: ;
Delimiter: }
Input C file:
int main() {
int a = 10; // This is a single-line comment
float b = 20.5;
char c = 'z';
if (a < b) {
a = a + b;
}
/* Multi-line comment
Example */
return 0;
}
5.Write a program to design a lexical analyzer for a given
language, and the lexical analyzer should ignore redundant
spaces, tabs, and newlines.

%{
#include <stdio.h>
%}

%%

"int"|"float"|"char"|"if"|"else"|"while"|"for"|"return" { printf("Keyword: %s\n",


yytext); }
[a-zA-Z_][a-zA-Z0-9_]* { printf("Identifier: %s\n", yytext); }
[0-9]+ { printf("Constant: %s\n", yytext); }
"//".* { printf("Single-line Comment: %s\n", yytext); }
"/*"([^*]|[\r\n]|"*"[^/])*"*/" { printf("Multi-line Comment: %s\n",
yytext); }
"+"|"-"|"*"|"/"|"="|"<"|">" { printf("Operator: %s\n", yytext); }
"(" | ")" | "{" | "}" | ";" | "," | "[" | "]" { printf("Delimiter: %s\n", yytext); }
[ \t\n]+ { /* Ignore whitespace */ }
. { printf("Unknown Token: %s\n", yytext); }

%%

int main() {
printf("Lexical Analysis:\n");
printf("-------------------------------\n");
yylex();
return 0;
}

int yywrap() {
return 1;
}
Lexical Analysis:
-------------------------------
Keyword: int
Identifier: main
Delimiter: (
Delimiter: )
Delimiter: {
Keyword: int
Identifier: a
Operator: =
Constant: 10
Delimiter: ;
Single-line Comment: // This is a comment
Keyword: float
Identifier: b
Operator: =
Constant: 20
Operator: .
Constant: 5
Delimiter: ;
Keyword: char
Identifier: c
Operator: =
Unknown Token: '
Identifier: z
Unknown Token: '
Delimiter: ;
Keyword: if
Delimiter: (
Identifier: a
Operator: <
Identifier: b
Delimiter: )
Delimiter: {
Identifier: a
Operator: =
Identifier: a
Operator: +
Identifier: b
Delimiter: ;
Delimiter: }

Keyword: return
Constant: 0
Delimiter: ;
Delimiter: }
Input File:

int main() {
int a = 10; // This is a comment
float b = 20.5;
char c = 'z';

if (a < b) {
a = a + b;
}

/* Multi-line comment
example */
return 0;
}
6. Write a program to implement the First and Follow of the
following Grammar:
E→ T E’
E’ → +T E’| Є
T → F T’
T’ → *FT’| Є
F → (E)|id
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAX 10

// Define grammar rules


char productions[MAX][MAX] = {
"E->TE'",
"E'->+TE'|ε",
"T->FT'",
"T'->*FT'|ε",
"F->(E)|id"
};

char first[MAX][MAX], follow[MAX][MAX];


int prodCount = 5;

// Function to check if a symbol is a non-terminal


int isNonTerminal(char symbol) {
return (symbol >= 'A' && symbol <= 'Z');
}

// Function to compute FIRST of a symbol


void computeFirst(char symbol, int index) {
for (int i = 0; i < prodCount; i++) {
Non-Terminal FIRST FOLLOW
E (id $
E' +ε $
T (id +$
T' *ε +$
F (id *+$
if (productions[i][0] == symbol) {
char *body = strchr(productions[i], '>') + 1;
for (int j = 0; body[j] != '\0'; j++) {
if (!isNonTerminal(body[j])) {
strncat(first[index], &body[j], 1); // Add terminal
break;
} else {
computeFirst(body[j], body[j] - 'A');
strcat(first[index], first[body[j] - 'A']); // Add FIRST of non-terminal
if (!strchr(first[body[j] - 'A'], 'ε')) break;
}
}
}
}
}

// Function to compute FOLLOW of a symbol


void computeFollow(char symbol, int index) {
if (index == 0) strcat(follow[index], "$"); // Add $ for the start symbol

for (int i = 0; i < prodCount; i++) {


char *body = strchr(productions[i], '>') + 1;
for (int j = 0; body[j] != '\0'; j++) {
if (body[j] == symbol) {
if (body[j + 1] == '\0') {
// Add FOLLOW of LHS
strcat(follow[index], follow[productions[i][0] - 'A']);
} else if (!isNonTerminal(body[j + 1])) {
// Add terminal in FOLLOW
strncat(follow[index], &body[j + 1], 1);
} else {
// Add FIRST of next symbol
strcat(follow[index], first[body[j + 1] - 'A']);
if (strchr(first[body[j + 1] - 'A'], 'ε')) {
strcat(follow[index], follow[productions[i][0] - 'A']);
}
}
}
}
}
}

// Function to remove duplicates in FIRST or FOLLOW sets


void removeDuplicates(char *set) {
int len = strlen(set);
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; ) {
if (set[i] == set[j]) {
memmove(&set[j], &set[j + 1], len - j);
len--;
} else {
j++;
}
}
}
}

int main() {
// Initialize FIRST and FOLLOW arrays
for (int i = 0; i < MAX; i++) {
first[i][0] = '\0';
follow[i][0] = '\0';
}

// Compute FIRST for all non-terminals


for (int i = 0; i < prodCount; i++) {
computeFirst(productions[i][0], productions[i][0] - 'A');
}

// Compute FOLLOW for all non-terminals


for (int i = 0; i < prodCount; i++) {
computeFollow(productions[i][0], productions[i][0] - 'A');
}

// Remove duplicates in FIRST and FOLLOW sets


for (int i = 0; i < prodCount; i++) {
removeDuplicates(first[productions[i][0] - 'A']);
removeDuplicates(follow[productions[i][0] - 'A']);
}

// Display results
printf("Non-Terminal\tFIRST\tFOLLOW\n");
for (int i = 0; i < prodCount; i++) {
printf("%c\t\t%s\t%s\n", productions[i][0], first[productions[i][0] - 'A'],
follow[productions[i][0] - 'A']);
}

return 0;
}
7.Write a program to Develop an operator precedence parser
for a given language.

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

#define MAX 10
#define EMPTY ' '

char operators[] = {'+', '*', '(', ')', 'i', '$'}; // Operator set including terminals
char precedenceTable[MAX][MAX];
char stack[MAX];
int top = -1;

// Function to return precedence table index


int getIndex(char symbol) {
for (int i = 0; i < sizeof(operators); i++) {
if (operators[i] == symbol) return i;
}
return -1; // Not found
}

// Function to initialize precedence table


void initializePrecedenceTable() {
for (int i = 0; i < MAX; i++) {
for (int j = 0; j < MAX; j++) {
precedenceTable[i][j] = EMPTY;
}
}

// Fill precedence table manually based on the grammar


precedenceTable[getIndex('+')][getIndex('+')] = '>';
precedenceTable[getIndex('+')][getIndex('*')] = '<';
precedenceTable[getIndex('+')][getIndex('(')] = '<';
precedenceTable[getIndex('+')][getIndex(')')] = '>';
Enter input string ending with $: i+i*i$

Operator Precedence Table:


+ * ( ) i $
+ > < < > < >
* > > < > < >
( < < < = <
) > > > >
i > > > >
$ < < < < =

Stack Input Action


$ i+i*i$ Shift i
$i +i*i$ Reduce
$ +i*i$ Shift +
$+ i*i$ Shift i
$+i *i$ Reduce
$+ *i$ Shift *
$+* i$ Shift i
$+*i $ Reduce
$+* $ Reduce
$+ $ Reduce
$ $ Accept

The string is accepted by the grammar.


precedenceTable[getIndex('+')][getIndex('i')] = '<';
precedenceTable[getIndex('+')][getIndex('$')] = '>';

precedenceTable[getIndex('*')][getIndex('+')] = '>';
precedenceTable[getIndex('*')][getIndex('*')] = '>';
precedenceTable[getIndex('*')][getIndex('(')] = '<';
precedenceTable[getIndex('*')][getIndex(')')] = '>';
precedenceTable[getIndex('*')][getIndex('i')] = '<';
precedenceTable[getIndex('*')][getIndex('$')] = '>';

precedenceTable[getIndex('(')][getIndex('+')] = '<';
precedenceTable[getIndex('(')][getIndex('*')] = '<';
precedenceTable[getIndex('(')][getIndex('(')] = '<';
precedenceTable[getIndex('(')][getIndex(')')] = '=';
precedenceTable[getIndex('(')][getIndex('i')] = '<';

precedenceTable[getIndex(')')][getIndex('+')] = '>';
precedenceTable[getIndex(')')][getIndex('*')] = '>';
precedenceTable[getIndex(')')][getIndex(')')] = '>';
precedenceTable[getIndex(')')][getIndex('$')] = '>';

precedenceTable[getIndex('i')][getIndex('+')] = '>';
precedenceTable[getIndex('i')][getIndex('*')] = '>';
precedenceTable[getIndex('i')][getIndex(')')] = '>';
precedenceTable[getIndex('i')][getIndex('$')] = '>';

precedenceTable[getIndex('$')][getIndex('+')] = '<';
precedenceTable[getIndex('$')][getIndex('*')] = '<';
precedenceTable[getIndex('$')][getIndex('(')] = '<';
precedenceTable[getIndex('$')][getIndex('i')] = '<';
precedenceTable[getIndex('$')][getIndex('$')] = '=';
}

// Function to print precedence table


void printPrecedenceTable() {
printf("Operator Precedence Table:\n");
printf(" ");
for (int i = 0; i < sizeof(operators); i++) {
printf(" %c", operators[i]);
}
printf("\n");
for (int i = 0; i < sizeof(operators); i++) {
printf(" %c ", operators[i]);
for (int j = 0; j < sizeof(operators); j++) {
printf(" %c", precedenceTable[i][j]);
}
printf("\n");
}
}

// Function to push onto stack


void push(char symbol) {
stack[++top] = symbol;
}

// Function to pop from stack


char pop() {
return stack[top--];
}

// Function to peek at the top of the stack


char peek() {
return stack[top];
}

// Function to parse the input string


int parseInput(char *input) {
char *ptr = input;
push('$'); // Push initial symbol onto the stack

printf("\nStack\t\tInput\t\tAction\n");
while (*ptr != '\0') {
char topSymbol = peek();
int topIndex = getIndex(topSymbol);
int inputIndex = getIndex(*ptr);

if (topIndex == -1 || inputIndex == -1) {


printf("Invalid symbol in input.\n");
return 0;
}

printf("%s\t\t%s\t\t", stack, ptr);

char precedence = precedenceTable[topIndex][inputIndex];


if (precedence == '<' || precedence == '=') {
printf("Shift %c\n", *ptr);
push(*ptr);
ptr++;
} else if (precedence == '>') {
printf("Reduce\n");
while (precedenceTable[getIndex(peek())][inputIndex] == '>') {
pop();
}
} else {
printf("Error: Invalid precedence.\n");
return 0;
}
}

while (peek() != '$') {


char topSymbol = peek();
char precedence = precedenceTable[getIndex(topSymbol)][getIndex('$')];
printf("%s\t\t%s\t\t", stack, ptr);

if (precedence == '>') {
printf("Reduce\n");
pop();
} else {
printf("Error: Invalid precedence.\n");
return 0;
}
}

printf("Accept\n");
return 1;
}

int main() {
char input[MAX];

// Initialize operator precedence table


initializePrecedenceTable();

// Print precedence table


printPrecedenceTable();

// Input string
printf("\nEnter input string ending with $: ");
scanf("%s", input);

// Parse input string


if (!parseInput(input)) {
printf("\nThe string is not accepted by the grammar.\n");
} else {
printf("\nThe string is accepted by the grammar.\n");
}

return 0;
}
8.Write a program to construct a recursive descent parser for
an expression: E –> E + T | T
T –> T * F | F
F –> ( E ) | id
#include <stdio.h>
#include <string.h>
#include <ctype.h>

// Global variables
char input[100];
int position = 0;

// Function prototypes
int E();
int T();
int F();

// Function to match and consume a token


int match(char expected) {
if (input[position] == expected) {
position++;
return 1;
}
return 0;
}

// Recursive function for E -> E + T | T


int E() {
printf("Entering E\n");
if (T()) {
if (input[position] == '+') {
match('+'); // Consume '+'
if (E()) return 1;
return 0; // Invalid after '+'
Enter the input expression: id+id*id

Entering E
Entering T
Entering F
Entering T
Entering F
Entering E
Entering T
Entering F

The input expression is valid.


}
return 1; // Valid if it matches T
}
return 0; // Invalid if T fails
}

// Recursive function for T -> T * F | F


int T() {
printf("Entering T\n");
if (F()) {
if (input[position] == '*') {
match('*'); // Consume '*'
if (T()) return 1;
return 0; // Invalid after '*'
}
return 1; // Valid if it matches F
}
return 0; // Invalid if F fails
}

// Recursive function for F -> ( E ) | id


int F() {
printf("Entering F\n");
if (input[position] == '(') {
match('('); // Consume '('
if (E()) {
if (match(')')) return 1; // Consume ')'
return 0; // Invalid if ')' is missing
}
return 0; // Invalid if E fails
} else if (isalnum(input[position])) {
match(input[position]); // Consume id (single letter/digit)
return 1;
}
return 0; // Invalid if neither '(' nor id
}
// Main function
int main() {
printf("Enter the input expression: ");
scanf("%s", input);

// Add end marker to the input


strcat(input, "$");

// Start parsing from E and check if input is fully consumed


if (E() && input[position] == '$') {
printf("\nThe input expression is valid.\n");
} else {
printf("\nThe input expression is invalid.\n");
}

return 0;
}
9.Write a program to construct an LL(1) parser for an
expression.
E -> T E'
E' -> + T E' | ε
T -> F T'
T' -> * F T' | ε
F -> ( E ) | id

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

#define MAX 10

// Parsing table
char parsingTable[MAX][MAX][MAX] = {
/* id + * ( ) $ */
/* E */ {"TE'", "", "", "TE'", "", ""},
/* E' */ {"", "+TE'", "", "", "ε", "ε"},
/* T */ {"FT'", "", "", "FT'", "", ""},
/* T' */ {"", "ε", "*FT'", "", "ε", "ε"},
/* F */ {"id", "", "", "(E)", "", ""}
};

char stack[MAX];
int top = -1;

// Push onto the stack


void push(char *str) {
for (int i = strlen(str) - 1; i >= 0; i--) {
stack[++top] = str[i];
}
Enter input string ending with $: id+id*id$

Expand: E -> TE'


Expand: T -> FT'
Expand: F -> id
Match: i
Expand: E' -> +TE'
Match: +
Expand: T -> FT'
Expand: F -> id
Match: i
Expand: T' -> *FT'
Match: *
Expand: F -> id
Match: i
Expand: T' -> ε
Expand: E' -> ε
The input string is valid.
}

// Pop from the stack


char pop() {
return (top == -1) ? '\0' : stack[top--];
}

// Peek at the top of the stack


char peek() {
return (top == -1) ? '\0' : stack[top];
}

// Function to return column index for a terminal


int getColumnIndex(char terminal) {
switch (terminal) {
case 'i': return 0; // id
case '+': return 1;
case '*': return 2;
case '(': return 3;
case ')': return 4;
case '$': return 5;
default: return -1;
}
}

// Function to return row index for a non-terminal


int getRowIndex(char nonTerminal) {
switch (nonTerminal) {
case 'E': return 0;
case 'E': return 1;
case 'T': return 2;
case 'T': return 2;
case 'T': return 3;
case 'F': return 4;
default: return -1;
}
}

// Function to parse input


int parse(char *input) {
stack[++top] = '$'; // Push end marker
stack[++top] = 'E'; // Start symbol

int idx = 0;
char currentInput = input[idx];
while (top != -1) {
char topSymbol = pop();

// Match terminal symbols


if (topSymbol == currentInput) {
printf("Match: %c\n", currentInput);
idx++;
currentInput = input[idx];
} else if (topSymbol >= 'A' && topSymbol <= 'Z') {
// Non-terminal
int row = getRowIndex(topSymbol);
int col = getColumnIndex(currentInput);

if (row == -1 || col == -1 || strcmp(parsingTable[row][col], "") == 0) {


printf("Error: No rule for %c -> %c\n", topSymbol, currentInput);
return 0;
}

printf("Expand: %c -> %s\n", topSymbol, parsingTable[row][col]);


if (strcmp(parsingTable[row][col], "ε") != 0) {
push(parsingTable[row][col]);
}
} else {
// Error case
printf("Error: Unexpected symbol %c\n", topSymbol);
return 0;
}
}

return (currentInput == '$');


}

// Main function
int main() {
char input[MAX];

printf("Enter input string ending with $: ");


scanf("%s", input);

if (parse(input)) {
printf("The input string is valid.\n");
} else {
printf("The input string is invalid.\n");
}

return 0;
}
10.Write a program to design a predictive parser for the
given language:
E->E+T|T
T->T*F|F
F->(E)|id
#include <stdio.h>
#include <string.h>

#define MAX 100

char stack[MAX];
int top = -1;

// Parsing table
char parsingTable[5][6][MAX] = {
// id + * ( ) $
{ "TE'", "", "", "TE'", "", "" }, // E
{ "", "+TE'", "", "", "ε", "ε" }, // E'
{ "FT'", "", "", "FT'", "", "" }, // T
{ "", "ε", "*FT'", "", "ε", "ε" }, // T'
{ "id", "", "", "(E)", "", "" } // F
};

// Function to get row index for non-terminal


int getNonTerminalIndex(char nonTerminal) {
switch (nonTerminal) {
case 'E': return 0;
case 'E': return 1;
case 'T': return 2;
case 'T': return 2;
case 'T': return 3;
case 'F': return 4;
default: return -1;
Enter input string ending with $: id+id*id$

Expand: E -> TE'


Expand: T -> FT'
Expand: F -> id
Match: i
Expand: E' -> +TE'
Match: +
Expand: T -> FT'
Expand: F -> id
Match: i
Expand: T' -> *FT'
Match: *
Expand: F -> id
Match: i
Expand: T' -> ε
Expand: E' -> ε
The input string is valid.
}
}

// Function to get column index for terminal


int getTerminalIndex(char terminal) {
switch (terminal) {
case 'i': return 0; // id
case '+': return 1;
case '*': return 2;
case '(': return 3;
case ')': return 4;
case '$': return 5;
default: return -1;
}
}

// Function to push a string onto the stack in reverse


void push(char *str) {
for (int i = strlen(str) - 1; i >= 0; i--) {
stack[++top] = str[i];
}
}

// Function to pop the top of the stack


char pop() {
return (top == -1) ? '\0' : stack[top--];
}

// Peek the top of the stack


char peek() {
return (top == -1) ? '\0' : stack[top];
}

// Function to parse the input


int parse(char *input) {
stack[++top] = '$'; // End marker
stack[++top] = 'E'; // Start symbol

int idx = 0;
char currentInput = input[idx];

while (top != -1) {


char topSymbol = pop();

// Match terminal
if (topSymbol == currentInput) {
printf("Match: %c\n", currentInput);
idx++;
currentInput = input[idx];
} else if (topSymbol >= 'A' && topSymbol <= 'Z') {
// Non-terminal
int row = getNonTerminalIndex(topSymbol);
int col = getTerminalIndex(currentInput);

if (row == -1 || col == -1 || strcmp(parsingTable[row][col], "") == 0) {


printf("Error: No rule for %c -> %c\n", topSymbol, currentInput);
return 0;
}

printf("Expand: %c -> %s\n", topSymbol, parsingTable[row][col]);


if (strcmp(parsingTable[row][col], "ε") != 0) {
push(parsingTable[row][col]);
}
} else {
// Error: unexpected symbol
printf("Error: Unexpected symbol %c\n", currentInput);
return 0;
}
}

return (currentInput == '$');


}
// Main function
int main() {
char input[MAX];

printf("Enter input string ending with $: ");


scanf("%s", input);

if (parse(input)) {
printf("The input string is valid.\n");
} else {
printf("The input string is invalid.\n");
}

return 0;
}
11.Write a program to implement shift- reduce parsing
algorithm for the following grammar:
S→(L)|a
L→ L,S|S
and input string is (a,a).

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

#define MAX 100

// Grammar rules
char *rules[] = {
"S -> (L)",
"S -> a",
"L -> L,S",
"L -> S"
};

// Function to check if a reduction is possible


int reduce(char stack[], int *top) {
// Check for possible reductions
if (*top >= 2 && stack[*top - 2] == '(' && stack[*top] == ')' && stack[*top - 1] ==
'L') {
// Reduce (L) -> S
stack[*top - 2] = 'S';
*top -= 2;
printf("Reduce: S -> (L)\n");
return 1;
}
if (*top >= 0 && stack[*top] == 'a') {
// Reduce a -> S
stack[*top] = 'S';
printf("Reduce: S -> a\n");
Input: (a,a)$
Stack Action
( Shift: (
(a Shift: a
(a Reduce: S -> a
(aS Reduce: L -> S
(aS, Shift: ,
(aS,a Shift: a
(aS,a Reduce: S -> a
(aL Reduce: L -> L,S
S Reduce: S -> (L)
Input string is successfully parsed.
return 1;
}
if (*top >= 2 && stack[*top - 1] == ',' && stack[*top] == 'S' && stack[*top - 2] ==
'L') {
// Reduce L,S -> L
stack[*top - 2] = 'L';
*top -= 2;
printf("Reduce: L -> L,S\n");
return 1;
}
if (*top >= 0 && stack[*top] == 'S') {
// Reduce S -> L
stack[*top] = 'L';
printf("Reduce: L -> S\n");
return 1;
}
return 0; // No reduction possible
}

// Function to parse the input string


void shiftReduceParse(char input[]) {
char stack[MAX] = {0};
int top = -1;
int idx = 0;
int length = strlen(input);

printf("Input: %s\n", input);


printf("Stack\t\tAction\n");

while (idx < length || top >= 0) {


// Print the stack and input
for (int i = 0; i <= top; i++) {
printf("%c", stack[i]);
}
printf("\t\t");
if (idx < length) {
// Shift the next input symbol onto the stack
stack[++top] = input[idx++];
printf("Shift: %c\n", stack[top]);
} else {
printf("Reduce\n");
}

// Try to reduce
while (reduce(stack, &top)) {
// Keep reducing until no further reduction is possible
}
}

// Final check
if (top == 0 && stack[top] == 'S') {
printf("Input string is successfully parsed.\n");
} else {
printf("Error: Input string is invalid.\n");
}
}

// Main function
int main() {
char input[] = "(a,a)$";

shiftReduceParse(input);

return 0;
}
12.Write a program to design a LALR bottom-up parser for
the given language:
E→E+T | T
T→T*F | F
F→(E) | id for the input string id+id*id
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX 100

typedef struct {
char action[10];
int state;
} ParsingTableEntry;

// Parsing table for the grammar


ParsingTableEntry actionTable[12][6]; // Action table
int gotoTable[12][3]; // Goto table

// Grammar rules
char *rules[] = {
"E -> E+T",
"E -> T",
"T -> T*F",
"T -> F",
"F -> (E)",
"F -> id"
};

// Helper function to initialize the parsing table


void initializeParsingTable() {
// Fill in actionTable
Stack Input Action
0 i+i*i$ s5
5 +i*i$ r6
...
Input string is valid.
strcpy(actionTable[0][0].action, "s5"); // Shift state 5 on "id"
strcpy(actionTable[0][3].action, "s4"); // Shift state 4 on "("

strcpy(actionTable[1][1].action, "s6"); // Shift state 6 on "+"


strcpy(actionTable[1][5].action, "acc"); // Accept

strcpy(actionTable[2][2].action, "s7"); // Shift state 7 on "*"


strcpy(actionTable[2][1].action, "r2"); // Reduce T -> F
strcpy(actionTable[2][5].action, "r2");

strcpy(actionTable[3][1].action, "r4"); // Reduce F -> (E)


strcpy(actionTable[3][2].action, "r4");
strcpy(actionTable[3][5].action, "r4");

strcpy(actionTable[4][0].action, "s5");
strcpy(actionTable[4][3].action, "s4");

strcpy(actionTable[5][1].action, "r6"); // Reduce F -> id


strcpy(actionTable[5][2].action, "r6");
strcpy(actionTable[5][5].action, "r6");

// Fill in gotoTable
gotoTable[0][0] = 1; // Goto E
gotoTable[0][1] = 2; // Goto T
gotoTable[0][2] = 3; // Goto F

gotoTable[4][0] = 8;
gotoTable[4][1] = 2;
gotoTable[4][2] = 3;
}

// Function to parse input


void parseInput(char *input) {
int stack[MAX];
char symbols[MAX];
int top = 0;
stack[top] = 0; // Start state
int idx = 0;

printf("Stack\t\tInput\t\tAction\n");
while (1) {
int state = stack[top];
char symbol = input[idx];

// Determine the column in the action table


int col = -1;
if (symbol == 'i') col = 0; // "id"
else if (symbol == '+') col = 1; // "+"
else if (symbol == '*') col = 2; // "*"
else if (symbol == '(') col = 3; // "("
else if (symbol == ')') col = 4; // ")"
else if (symbol == '$') col = 5; // End marker

// Get action
ParsingTableEntry action = actionTable[state][col];

printf("%d\t\t%s\t\t%s\n", stack[top], &input[idx], action.action);

if (action.action[0] == 's') { // Shift


stack[++top] = atoi(&action.action[1]); // Push next state
idx++; // Move to the next input symbol
} else if (action.action[0] == 'r') { // Reduce
int rule = atoi(&action.action[1]) - 1;
char *ruleBody = strchr(rules[rule], '>') + 2;
int len = strlen(ruleBody);

// Pop the stack for each symbol in the rule


for (int i = 0; i < len; i++) {
top--;
}
// Push the LHS of the rule
char lhs = rules[rule][0];
stack[++top] = gotoTable[stack[top - 1]][lhs - 'E'];
} else if (strcmp(action.action, "acc") == 0) { // Accept
printf("Input string is valid.\n");
break;
} else { // Error
printf("Error: Invalid input.\n");
break;
}
}
}

int main() {
initializeParsingTable();

char input[MAX] = "i+i*i$"; // Input string (id = i)

parseInput(input);

return 0;
}
13.Write a program to perform loop unrolling.

#include <stdio.h>

// Function to perform a regular loop


void regularLoop(int *arr, int size) {
for (int i = 0; i < size; i++) {
arr[i] += 1;
}
}

// Function to perform loop unrolling


void unrolledLoop(int *arr, int size, int unrollFactor) {
int i;
for (i = 0; i <= size - unrollFactor; i += unrollFactor) {
// Unrolled loop body
for (int j = 0; j < unrollFactor; j++) {
arr[i + j] += 1;
}
}
// Handle the remainder
for (; i < size; i++) {
arr[i] += 1;
}
}

int main() {
int size = 10;
int unrollFactor = 2; // Factor of unrolling
int arr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int arr2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

printf("Original Array: ");


Array: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Unroll Factor: 2

Original Array: 0 1 2 3 4 5 6 7 8 9
After Regular Loop: 1 2 3 4 5 6 7 8 9 10
After Unrolled Loop: 1 2 3 4 5 6 7 8 9 10
for (int i = 0; i < size; i++) {
printf("%d ", arr1[i]);
}
printf("\n");

// Regular loop
regularLoop(arr1, size);
printf("After Regular Loop: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr1[i]);
}
printf("\n");

// Loop unrolling
unrolledLoop(arr2, size, unrollFactor);
printf("After Unrolled Loop: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr2[i]);
}
printf("\n");

return 0;
}

You might also like