Lab_Report
Lab_Report
: 28108/078
1. Design a DFA to simulate the following machines
a. Accepting binary string that start with 0 and ends with 1.
Theory:
A Deterministic Finite Automaton (DFA) for this language needs to:
5. Loop in q2 on '1's
6. Return to q1 on '0' in q2
7. Reject any string starting with '1' (transition to dead state q3)
States:
Program:
#include <stdio.h>
#include <string.h>
int main() {
char input[100];
// Required Output
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
return 0;
}
Output:
Sanjeet Mijar Symbol No.: 28108/078
Theory:
C variable names must:
DFA Design:
Program:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
char input[100];
if (isValidVariableName(input)) {
printf("Valid C variable name.\n");
} else {
printf("Invalid C variable name.\n");
}
// Required Output
Sanjeet Mijar Symbol No.: 28108/078
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
return 0;
}
Theory:
Valid Gmail ID format:
Program:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
char input[100];
printf("Enter a Gmail ID: ");
scanf("%s", input);
if (isValidGmail(input)) {
printf("Valid Gmail ID.\n");
} else {
printf("Invalid Gmail ID.\n");
}
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
Sanjeet Mijar Symbol No.: 28108/078
return 0;
}
Output:
Theory:
NTC (Nepal Telecom) prepaid numbers typically:
1. Start with 98 or 97
2. Are 10 digits total
3. Follow specific numbering patterns
DFA Design:
States to:
int main() {
char input[20];
if (isValidNTCPrepaid(input)) {
printf("Valid NTC prepaid number.\n");
} else {
printf("Invalid NTC prepaid number.\n");
}
// Required Output
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
return 0;
}
Output:
Sanjeet Mijar Symbol No.: 28108/078
Sanjeet Mijar Symbol No.: 28108/078
Theory:
The NFA needs to:
NFA Design:
o q0 to q0 on a
o q0 to q0 on b
o q0 to q1 on a
Program:
#include <stdio.h>
#include <string.h>
if (len == 0)
return 0; // Empty string not accepted
Sanjeet Mijar Symbol No.: 28108/078
return 0;
}
int main() {
char input[100];
if (isAcceptedByNFA(input)) {
printf("String is ACCEPTED by the NFA for (a + b)*a\n");
} else {
printf("String is REJECTED by the NFA for (a + b)*a\n");
}
// Required Output
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
return 0;
}
Output:
Sanjeet Mijar Symbol No.: 28108/078
Theory:
This accepts exactly two symbols where each can be 'a' or 'b'
NFA Design:
Program:
#include <stdio.h>
#include <string.h>
return 0;
}
int main() {
char input[100];
if (isAcceptedByNFA(input)) {
printf("String is ACCEPTED by the NFA for (a + b)(a + b)\n");
} else {
printf("String is REJECTED by the NFA for (a + b)(a + b)\n");
}
// Required Output
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
return 0;
}
Output:
Sanjeet Mijar Symbol No.: 28108/078
LAB 3. Write a program to remove left recursion from the following grammar
a. S Sab | ab | a | b (Grammar 1)
Theory:
Left recursion occurs when a non-terminal appears as the first symbol on the right-hand
side of its own production.
Steps:
Program:
#include <stdio.h>
#include <string.h>
int main() {
struct Grammar G;
G.nonTerminal = 'S';
G.productionCount = 4;
char alpha[10][20], beta[10][20]; // alpha for left recursion, beta for non-recursive
int alphaCount = 0, betaCount = 0;
// Classify productions
for (int i = 0; i < G.productionCount; i++) {
if (isLeftRecursive(G.nonTerminal, G.productions[i])) {
strcpy(alpha[alphaCount++], G.productions[i] + 1); // remove the non-terminal itself
} else {
strcpy(beta[betaCount++], G.productions[i]);
}
}
// Required Output
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
return 0;
}
Output:
Sanjeet Mijar Symbol No.: 28108/078
b. A A0 | A1 | 0 (Grammar 2)
Steps:
o A → 0A'
o A' → 0A' | 1A' | ε
Program:
#include <stdio.h>
#include <string.h>
int main() {
struct Grammar G;
G.nonTerminal = 'A';
G.productionCount = 3;
// Original grammar: A ? A0 | A1 | 0
strcpy(G.productions[0], "A0");
strcpy(G.productions[1], "A1");
strcpy(G.productions[2], "0");
char alpha[10][20], beta[10][20]; // alpha for left recursion, beta for non-recursive
int alphaCount = 0, betaCount = 0;
// Classify productions
for (int i = 0; i < G.productionCount; i++) {
if (isLeftRecursive(G.nonTerminal, G.productions[i])) {
strcpy(alpha[alphaCount++], G.productions[i] + 1); // remove the non-terminal itself
Sanjeet Mijar Symbol No.: 28108/078
} else {
strcpy(beta[betaCount++], G.productions[i]);
}
}
// Required Output
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
return 0;
}
Output:
Sanjeet Mijar Symbol No.: 28108/078
LAB 4. Write a program to create a symbol table for the variables (for data types
only)
Theory:
A symbol table stores:
1. Variable names
Sanjeet Mijar Symbol No.: 28108/078
2. Data types
3. Values
4. Memory addresses
Implementation Approach:
Example Processing:
Input: "int a = 2, float b = 3.5"
Output:
a integer 2 100
real
b 3.5 200
number
Program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Symbol {
char varName[20];
char type[20];
char value[20];
int address;
};
int main() {
char input[200];
struct Symbol table[20];
int count = 0;
int address = 100;
printf("Enter the variable declaration line (e.g., int a=2, float b=3.5):\n");
Sanjeet Mijar Symbol No.: 28108/078
fgets(input, sizeof(input), stdin);
strcpy(table[count].value, val);
table[count].address = address;
address += 100;
count++;
}
return 0;
}
Output:
Implementation Steps:
Example (3a):
Input: S → Sab | ab | a | b
Output:
Non-terminals: {S}
Terminals: {a, b}
Productions: {S → Sab, S → ab, S → a, S → b}
Start symbol: S
Program:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
Sanjeet Mijar Symbol No.: 28108/078
FILE *fp;
char line[MAX];
char nonTerminals[50], terminals[50];
char productions[50][MAX];
int ntCount = 0, tCount = 0, pCount = 0;
// Open file
fp = fopen("grammar.txt", "r");
if (fp == NULL) {
printf("Error opening file.\n");
return 1;
}
// Store production
strcpy(productions[pCount++], line);
Sanjeet Mijar Symbol No.: 28108/078
fclose(fp);
// Output results
printf("\nSet of Non-terminals = { ");
for (int i = 0; i < ntCount; i++) {
printf("%c", nonTerminals[i]);
if (i < ntCount - 1) printf(", ");
}
printf(" }\n");
// Student information
printf("\nName: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
printf("Lab No.: 6\n");
printf("Program: CFG Analyzer\n");
return 0;
}
Output:
Example:
In Program1, c = d+e and f = g+h are loop-invariant
Moving them out (Program2) reduces operations from 3×n to 2 + n
Program:
#include <stdio.h>
#include <time.h>
// Initialize arrays
for(i = 0; i < size; i++) {
b[i] = i;
c[i] = i * 2;
d[i] = i + 1;
}
int main() {
printf("==== Loop Optimization Demonstrations ====\n");
return 0;
}
Output:
b. Loop Jamming
Sanjeet Mijar Symbol No.: 28108/078
Theory:
Combine adjacent loops with same iteration space:
Program:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
void print_student_info() {
printf("\n\n--- Student Information ---\n");
printf("Name: Sanjeet Mijar\n");
printf("Symbol No.: 28108/078\n");
printf("Lab No.: 6\n");
printf("Program: Loop Jamming Optimization\n");
}
int main() {
clock_t start, end;
double time_separate, time_jammed;
int *a = malloc(SIZE * sizeof(int));
int *b = malloc(SIZE * sizeof(int));
int *c = malloc(SIZE * sizeof(int));
int *d = malloc(SIZE * sizeof(int));
if (!a || !b || !c || !d) {
printf("Memory allocation failed!\n");
return 1;
Sanjeet Mijar Symbol No.: 28108/078
}
// Initialize arrays
for (int i = 0; i < SIZE; i++) {
b[i] = i;
c[i] = i * 2;
d[i] = i + 1;
}
print_student_info();
return 0;
}
Output: