Compiler Design File New
Compiler Design File New
Design and implement a lexical analyzer for a given language using C, and the lexical
analyzer should ignore redundant spaces, tabs, and new lines.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
return 0;
int j = 0;
buffer[j++] = ch;
ungetc(ch, file);
buffer[j] = '\0';
j = 0;
buffer[j++] = ch;
while (isdigit(ch = fgetc(file))) buffer[j++] = ch;
ungetc(ch, file);
buffer[j] = '\0';
j = 0;
} else { // Operator
int main() {
lexicalAnalyzer(file);
fclose(file);
return 0;
if (x > 10) {
return x + 1;
} else {
return 0;
Sample Output:
<Keyword, if>
<Operator/Punctuation, (>
<Identifier, x>
<Operator/Punctuation, >
<Number, 10>
<Operator/Punctuation, )>
<Operator/Punctuation, {>
<Keyword, return>
<Identifier, x>
<Operator/Punctuation, +>
<Number, 1>
<Operator/Punctuation, ;>
<Operator/Punctuation, }>
<Keyword, else>
<Operator/Punctuation, {>
<Keyword, return>
<Number, 0>
<Operator/Punctuation, ;>
<Operator/Punctuation, }>
2.Implementation of Lexical Analyzer using Lex Tool.
Prerequisites
You must have Lex (or Flex) and a C compiler (like GCC) installed on your system.
%{
#include <stdio.h>
#include <string.h>
int line_num = 1;
%}
DIGIT [0-9]
ID [a-zA-Z_][a-zA-Z0-9_]*
KEYWORD if|else|while|return|int|float|char|void
OP \+|\-|\*|\/|==|!=|<=|>=|<|>
%%
";" { printf("SEMICOLON\n"); }
[\n] { line_num++; }
%%
yylex();
return 0;
int yywrap() {
return 1;
Example Input:
int main() {
int x = 10;
if (x > 5) {
x = x + 1;
return x;
Example Output:
KEYWORD: int
IDENTIFIER: main
LEFT PARENTHESIS
RIGHT PARENTHESIS
LEFT BRACE
KEYWORD: int
IDENTIFIER: x
ASSIGNMENT: =
NUMBER: 10
SEMICOLON
KEYWORD: if
LEFT PARENTHESIS
IDENTIFIER: x
OPERATOR: >
NUMBER: 5
RIGHT PARENTHESIS
LEFT BRACE
IDENTIFIER: x
ASSIGNMENT: =
IDENTIFIER: x
OPERATOR: +
NUMBER: 1
SEMICOLON
RIGHT BRACE
KEYWORD: return
IDENTIFIER: x
SEMICOLON
RIGHT BRACE
3.Generate YACC specification for a few syntactic categories:
a) Program to recognize a valid arithmetic expression that uses operators +, -, *, and /.
%{
#include <stdio.h>
%}
%token NUMBER
%%
expr: expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | NUMBER ;
%%
main() { yyparse(); }
b) Program to recognize a valid variable which starts with a letter followed by any number of
letters or digits.
%%
. { printf("INVALID\n"); }
%%
%{
#include "y.tab.h"
%}
%%
\n { return 0; }
. { /* Ignore */ }
%%
d) Convert the BNF rules into YACC form and write code to generate an abstract syntax tree.
%{
char op;
int value;
} ASTNode;
%}
%%
%%
4.Write a program to find the ε-closure of all states of any given NFA with ε-transitions.
#include <iostream>
#include <vector>
#include <stack>
#include <set>
int num_states;
vector<vector<int>> epsilon_transitions;
stack<int> stk;
set<int> closure;
stk.push(state);
closure.insert(state);
while (!stk.empty()) {
stk.pop();
if (closure.find(next) == closure.end()) {
closure.insert(next);
stk.push(next);
}
}
return closure;
int main() {
epsilon_transitions.resize(num_states);
int num_transitions;
epsilon_transitions[from].push_back(to);
}
cout << "}\n";
return 0;
Sample Input:
01
12
23
31
Sample Output:
ε-closure(0) = { 0 1 2 3 }
ε-closure(1) = { 1 2 3 }
ε-closure(2) = { 2 3 1 }
ε-closure(3) = { 3 1 2 }
5.Write a program to convert an NFA with ε-transitions to an NFA without ε-transitions.
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <string>
vector<set<int>> epsilon_closures;
set<int> closure;
stack<int> stk;
stk.push(state);
closure.insert(state);
while (!stk.empty()) {
int s = stk.top();
stk.pop();
if (closure.find(t) == closure.end()) {
closure.insert(t);
stk.push(t);
return closure;
void computeAllEpsilonClosures() {
epsilon_closures.resize(num_states);
epsilon_closures[i] = computeEpsilonClosure(i);
void convertToNFAWithoutEpsilon() {
set<int> result_set;
result_set.insert(epsilon_closures[t].begin(), epsilon_closures[t].end());
if (!result_set.empty())
new_transitions[state][symbol] = result_set;
}
void printNewNFA() {
if (new_transitions[state].count(symbol)) {
cout << "From state " << state << " on '" << symbol << "' -> { ";
int main() {
char ch;
alphabet.push_back(ch);
}
int num_transitions;
char symbol;
transitions[from][symbol].insert(to);
computeAllEpsilonClosures();
convertToNFAWithoutEpsilon();
printNewNFA();
return 0;
Sample Input:
0e1
1e2
2a2
1b1
0a0
Sample Output:
#include <iostream>
#include <sstream>
#include <string>
int main() {
string body_line;
cin.ignore();
cout << "Enter loop body using variable i (e.g., cout << i << endl;):\n";
getline(cin, body_line);
int i = start;
size_t pos;
if (remainder > 0) {
cout << "for (int i = " << (end - remainder) << "; i < " << end << "; i++) {\n";
return 0;
Sample Input:
Enter loop body using variable i (e.g., cout << i << endl;):
cout << i << endl;
Output:
}
7.Write a program to convert an NFA to a DFA.
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
vector<char> alphabet;
vector<set<int>> dfa_states;
set<int> final_states;
set<set<int>> dfa_final_states;
bool isFinalState(set<int> s) {
return false;
queue<set<int>> q;
q.push(start);
dfa_states.push_back(start);
while (!q.empty()) {
set<int> move_result;
if (nfa[state].count(symbol)) {
move_result.insert(nfa[state][symbol].begin(), nfa[state][symbol].end());
if (!move_result.empty()) {
dfa[current][symbol] = move_result;
q.push(move_result);
int main() {
alphabet.push_back(c);
int num_transitions;
char sym;
cin >> from >> sym >> to;
nfa[from][sym].insert(to);
int start_state;
int num_final;
int f;
cin >> f;
final_states.insert(f);
nfaToDfa(start_state);
if (isFinalState(s)) {
dfa_final_states.insert(s);
if (trans_map.count(sym)) {
printSet(from);
printSet(trans_map.at(sym));
printSet({start_state});
printSet(f);
return 0;
Sample Input:
0a0
0a1
1b2
2b2
Output:
DFA Transitions:
{ 0 } --a--> { 0 1 }
{ 0 1 } --a--> { 0 1 }
{ 0 1 } --b--> { 2 }
{ 2 } --b--> { 2 }
{2}
8.Write a program to minimize any given DFA.
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <iomanip>
#include <queue>
vector<char> alphabet;
vector<vector<int>> dfa_transition;
set<int> final_states;
int start_state;
bool is_final(int s) {
void minimizeDFA() {
// Step 2: Mark pairs where one is final and the other is not
if (is_final(i) != is_final(j))
distinguishable[i][j] = true;
bool changed;
do {
changed = false;
if (distinguishable[i][j]) continue;
int si = dfa_transition[i][k];
int sj = dfa_transition[j][k];
if (distinguishable[a][b]) {
distinguishable[i][j] = true;
changed = true;
break;
} while (changed);
vector<int> state_group(num_states);
for (int i = 0; i < num_states; ++i) state_group[i] = i;
if (!distinguishable[i][j]) {
break;
int new_state_id = 0;
if (group_to_state.find(grp) == group_to_state.end()) {
group_to_state[grp] = new_state_id++;
set<int> minimized_final_states;
int to = dfa_transition[i][k];
minimized_dfa[new_state][k] = new_to;
// Output
cout << i << " --" << alphabet[k] << "--> " << minimized_dfa[i][k] << "\n";
int main() {
alphabet.resize(num_symbols);
dfa_transition.resize(num_states, vector<int>(num_symbols));
char sym;
if (alphabet[k] == sym) {
dfa_transition[from][k] = to;
break;
int f;
cin >> f;
cin >> x;
final_states.insert(x);
minimizeDFA();
return 0;
Sample Input:
001
012
100
113
203
210
302
311
Sample Output:
Minimized DFA:
Number of states: 2
Start state: 0
Final states: 1
Transitions:
0 --0--> 0
0 --1--> 1
1 --0--> 1
1 --1--> 0
9.Develop an operator precedence parser for a given language.
#include <iostream>
#include <map>
#include <stack>
#include <string>
return precedence_table[row][col];
// Parsing function
stack<char> parse_stack;
parse_stack.push('#');
size_t i = 0;
while (true) {
string stack_content;
while (!temp_stack.empty()) {
temp_stack.pop();
char a = input[i];
top = temp.top();
// Shift
cout << "Shift\n";
parse_stack.push(a);
i++;
// Reduce
parse_stack.pop();
// Invalid relation
cout << "Error: No precedence relation between " << top << " and " << a << "\n";
return;
break;
int main() {
precedence_index[terminals[i]] = i;
// Precedence table
string rows[] = {
// + - * / i #
};
precedence_table[i][j] = rows[i][j];
string input;
cout << "Enter the input expression (use 'i' for id, end with #): ";
operator_precedence_parse(input);
return 0;
Sample Input:
Enter the input expression (use 'i' for id, end with #): i+i*i
Output:
#i +i*I # Reduce
#+ i*I # Shift
#+i *I # Reduce
#+* I # Shift
#+*i # Reduce
#+ # Reduce
# # Accept
10.Write a program to simulate First and Follow of any given grammar.
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <algorithm>
set<char> non_terminals;
set<char> terminals;
char start_symbol;
bool isTerminal(char c) {
if (isTerminal(symbol)) {
}
for (string prod : productions[symbol]) {
char ch = prod[i];
first[symbol].insert(subFirst.begin(), subFirst.end());
if (i == prod.size() - 1) first[symbol].insert('#');
return first[symbol];
void computeFollow() {
bool changed;
do {
changed = false;
char B = prod[i];
if (!isupper(B)) continue;
if (c != '#') follow[B].insert(c);
if (!eps) break;
if (eps || i == prod.size() - 1) {
follow[B].insert(follow[nt].begin(), follow[nt].end());
} while (changed);
if (!isupper(symbol)) continue;
cout << symbol << " : { ";
int main() {
int n;
cin >> n;
string prod;
if (i == 0) start_symbol = lhs;
non_terminals.insert(lhs);
productions[lhs].push_back(rhs);
computeFollow();
displaySets(first, "FIRST");
displaySets(follow, "FOLLOW");
return 0;
Sample Input:
E=TR
R=+TR
R=#
T=F
Output:
FIRST sets:
E:{(i}
R:{+#}
T:{(i}
FOLLOW sets:
E:{$)}
R:{$)}
T:{+$)}