CD File
CD File
Key Features
1. Pattern Matching: LEX uses regular expressions to define patterns for tokens.
2. Action Association: Each pattern can be associated with a C code snippet to be executed
when the pattern is matched.
3. Automatic DFA Generation: LEX converts the regular expressions into a Deterministic Finite
Automaton (DFA) for efficient pattern matching.
4. Integration with YACC: LEX is often used in conjunction with YACC (Yet Another Compiler
Compiler) for parser generation.
first_sets[non_terminal] = set<char>();
int main() {
int num_productions;
cout << "Enter the number of productions: ";
cin >> num_productions;
cin.ignore();
cout << "Enter the productions in the format 'S->aAb|b' (use '$' for epsilon):" << endl;
for (int i = 0; i < num_productions; i++) {
string production;
getline(cin, production);
char non_terminal = production[0];
string rhs = production.substr(3);
size_t pos = 0;
while ((pos = rhs.find('|')) != string::npos) {
grammar[non_terminal].push_back(rhs.substr(0, pos));
rhs.erase(0, pos + 1);
}
grammar[non_terminal].push_back(rhs);
}
return 0;
}
Q3. Write a program to find the Follow of a Non terminal/string.
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
first_sets[non_terminal] = set<char>();
if (non_terminal == grammar.begin()->first) {
follow_sets[non_terminal].insert('$');
}
int main() {
int num_productions;
cout << "Enter the number of productions: ";
cin >> num_productions;
cin.ignore();
cout << "Enter the productions in the format 'S->aAb|b' (use '$' for epsilon):" << endl;
for (int i = 0; i < num_productions; i++) {
string production;
getline(cin, production);
char non_terminal = production[0];
string rhs = production.substr(3);
size_t pos = 0;
while ((pos = rhs.find('|')) != string::npos) {
grammar[non_terminal].push_back(rhs.substr(0, pos));
rhs.erase(0, pos + 1);
}
grammar[non_terminal].push_back(rhs);
}
for (const auto& entry : grammar) {
computeFirst(entry.first);
}
for (const auto& entry : grammar) {
computeFollow(entry.first);
}
cout << "\nFOLLOW sets:" << endl;
for (const auto& entry : follow_sets) {
cout << "FOLLOW(" << entry.first << ") = { ";
for (char symbol : entry.second) {
cout << symbol << " ";
}
cout << "}" << endl;
}
return 0;
}
Q4. Write a program to convert INFIX notation to POSTFIX and PREFIX notation.
#include <iostream>
#include <stack>
#include <algorithm>
using namespace std;
while (!s.empty()) {
postfix += s.top();
s.pop();
}
return postfix;
}
int main() {
string infix;
cout << "Enter an infix expression: ";
cin >> infix;
return 0;
}
Q5. Write a program to check whether a string is an identifier or not.
#include <iostream>
#include <string>
#include <cctype>
return true;
}
int main() {
string input;
cout << "Enter a string to check if it's a valid identifier: ";
cin >> input;
if (isValidIdentifier(input)) {
cout << "'" << input << "' is a valid identifier." << endl;
} else {
cout << "'" << input << "' is not a valid identifier." << endl;
}
return 0;
}
Q6. Program to Check Whether a String Belongs to a Grammar.
#include <iostream>
#include <map>
#include <vector>
using namespace std;
map<char, vector<string>> grammar;
bool isValid(string input, char start) {
if (input.empty()) return false;
vector<string> productions = grammar[start];
for (string prod : productions) {
if (input == prod) {
return true;
}
}
return false;
}
int main() {
int n;
cout << "Enter number of productions: ";
cin >> n;
cout << "Enter productions (e.g., A->a):\n";
for (int i = 0; i < n; i++) {
char nonTerminal;
string arrow, production;
cin >> nonTerminal >> arrow >> production;
grammar[nonTerminal].push_back(production);
}
char start;
cout << "Enter start symbol: ";
cin >> start;
string input;
cout << "Enter string to check: ";
cin >> input;
if (isValid(input, start)) {
cout << "The string belongs to the grammar.\n";
} else {
cout << "The string does NOT belong to the grammar.\n";
}
return 0;
}
Q7. Write a program to remove left recursion from a grammar.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
void removeLeftRecursion() {
for (auto& entry : grammar) {
char A = entry.first;
vector<string> alpha, beta;
if (!alpha.empty()) {
char newNonTerminal = A + 1;
while (grammar.find(newNonTerminal) != grammar.end()) {
newNonTerminal++;
}
grammar[A].clear();
for (const string& b : beta) {
grammar[A].push_back(b + newNonTerminal);
}
grammar[newNonTerminal] = vector<string>();
for (const string& a : alpha) {
grammar[newNonTerminal].push_back(a + newNonTerminal);
}
grammar[newNonTerminal].push_back("ε");
}
}
}
int main() {
int numProductions;
cout << "Enter the number of productions: ";
cin >> numProductions;
cin.ignore();
cout << "Enter the productions in the format 'S->aA|b':" << endl;
for (int i = 0; i < numProductions; i++) {
string production;
getline(cin, production);
char nonTerminal = production[0];
string rhs = production.substr(3);
size_t pos = 0;
while ((pos = rhs.find('|')) != string::npos) {
grammar[nonTerminal].push_back(rhs.substr(0, pos));
rhs.erase(0, pos + 1);
}
grammar[nonTerminal].push_back(rhs);
}
removeLeftRecursion();
return 0;
}
Q8. Write a program to remove left factoring from a grammar.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
if (prefix.empty()) {
cout << "No left factoring found.\n";
return;
}
cout << nonTerminal << " -> " << prefix << nonTerminal << "'\n";
cout << nonTerminal << "' -> ";
for (string prod : productions) {
if (prod != prefix) {
cout << prod.substr(prefix.length()) << " | ";
}
}
cout << "ε\n";
}
int main() {
int n;
cout << "Enter the number of productions: ";
cin >> n;
string nonTerminal;
cout << "Enter the non-terminal: ";
cin >> nonTerminal;
vector<string> productions(n);
cout << "Enter the productions:\n";
for (int i = 0; i < n; i++) {
cin >> productions[i];
}
removeLeftFactoring(nonTerminal, productions);
return 0;
}
Q9. Program to generate SDT for a given graph
#include <iostream>
#include <map>
#include <vector>
#include <string>
struct Production {
string lhs;
vector<string> rhs;
string action;
};
vector<Production> grammar;
void generateSDT() {
cout << "Syntax-Directed Translation (SDT) for the given grammar:\n\n";
for (const auto& prod : grammar) {
cout << prod.lhs << " -> ";
for (const auto& symbol : prod.rhs) {
cout << symbol << " ";
}
cout << "{ " << prod.action << " }" << endl;
}
}
int main() {
int numProductions;
cout << "Enter the number of productions: ";
cin >> numProductions;
cin.ignore();
cout << "Enter productions in the format 'E -> E + T { E.val = E1.val + T.val }'\n";
for (int i = 0; i < numProductions; i++) {
string input;
getline(cin, input);
Production p;
size_t arrowPos = input.find("->");
p.lhs = input.substr(0, arrowPos - 1);
grammar.push_back(p);
}
generateSDT();
return 0;
}
Q10. Program to generate a parse tree.
#include <iostream>
#include <string>
#include <vector>
#include <memory>
struct Node {
string value;
vector<unique_ptr<Node>> children;
Node(string v) : value(v) {}
void addChild(unique_ptr<Node> child) {
children.push_back(move(child));
}
};
class Parser {
string input;
size_t pos = 0;
unique_ptr<Node> parseExpression() {
auto node = parseterm();
while (peek() == '+' || peek() == '-') {
auto op = make_unique<Node>(string(1, consume()));
op->addChild(move(node));
op->addChild(parseterm());
node = move(op);
}
return node;
}
unique_ptr<Node> parseterm() {
auto node = parseFactor();
while (peek() == '*' || peek() == '/') {
auto op = make_unique<Node>(string(1, consume()));
op->addChild(move(node));
op->addChild(parseFactor());
node = move(op);
}
return node;
}
unique_ptr<Node> parseFactor() {
if (isdigit(peek())) {
string num;
while (isdigit(peek())) num += consume();
return make_unique<Node>(num);
} else if (peek() == '(') {
consume(); // '('
auto node = parseExpression();
consume(); // ')'
return node;
}
throw runtime_error("Unexpected character: " + string(1, peek()));
}
public:
unique_ptr<Node> parse(const string& expr) {
input = expr;
pos = 0;
return parseExpression();
}
};
void printTree(const Node* node, string prefix = "", bool isLast = true) {
cout << prefix;
cout << (isLast ? "└── " : "├── ");
cout << node->value << endl;
Parser parser;
try {
auto root = parser.parse(expression);
cout << "Parse Tree:" << endl;
printTree(root.get());
} catch (const exception& e) {
cout << "Error: " << e.what() << endl;
}
return 0;
}
Q11 Program to draw the dependency graph.
#include <iostream>
#include <stack>
#include <stdexcept>
using namespace std;
while (true) {
cout << "\nStack Operations:" << endl;
cout << "1. Push" << endl;
cout << "2. Pop" << endl;
cout << "3. Top" << endl;
cout << "4. IsEmpty" << endl;
cout << "5. Size" << endl;
cout << "6. Display" << endl;
cout << "7. Exit" << endl;
cout << "Enter your choice: ";
int choice;
cin >> choice;
try {
switch (choice) {
case 1: {
int value;
cout << "Enter value to push: ";
cin >> value;
stack.push(value);
break;
}
case 2: {
stack.pop();
break;
}
case 3: {
cout << "Top element: " << stack.top() << endl;
break;
}
case 4: {
cout << "Is empty: " << (stack.isEmpty() ? "Yes" : "No") << endl;
break;
}
case 5: {
cout << "Size: " << stack.size() << endl;
break;
}
case 6: {
stack.display();
break;
}
case 7: {
cout << "Exiting program." << endl;
return 0;
}
default: {
cout << "Invalid choice. Please try again." << endl;
}
}
} catch (const exception& e) {
cout << "Error: " << e.what() << endl;
}
}
return 0;
}
Q12. Write a program to draw the dependency graph.
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
class DependencyGraph {
private:
map<string, set<string>> graph;
public:
void addDependency(const string& from, const string& to) {
graph[from].insert(to);
}
void generateDOT() {
cout << "digraph DependencyGraph {" << endl;
for (const auto& node : graph) {
for (const auto& dependency : node.second) {
cout << " \"" << node.first << "\" -> \"" << dependency << "\";" << endl;
}
}
cout << "}" << endl;
}
};
int main() {
DependencyGraph graph;
cout << "Enter dependencies (format: 'from to', enter 'done' when finished):" << endl;
while (true) {
string from, to;
cin >> from;
if (from == "done") break;
cin >> to;
graph.addDependency(from, to);
}
cout << "\nGenerating DOT format for the dependency graph:" << endl;
graph.generateDOT();
cout << "\nTo visualize the graph, copy the above DOT format and use a tool like Graphviz." <<
endl;
return 0;
}
Q14. Write a program to draw the DAG.
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <stack>
class DAG {
private:
map<string, set<string>> graph;
set<string> vertices;
recursionStack.erase(start);
return false;
}
public:
bool addEdge(const string& from, const string& to) {
vertices.insert(from);
vertices.insert(to);
graph[from].insert(to);
void generateDOT() {
cout << "digraph DAG {" << endl;
for (const auto& node : graph) {
for (const auto& edge : node.second) {
cout << " \"" << node.first << "\" -> \"" << edge << "\";" << endl;
}
}
cout << "}" << endl;
}
};
int main() {
DAG dag;
cout << "Enter edges for the DAG (format: 'from to', enter 'done' when finished):" << endl;
while (true) {
string from, to;
cin >> from;
if (from == "done") break;
cin >> to;
if (!dag.addEdge(from, to)) {
cout << "Adding edge " << from << " -> " << to << " would create a cycle. Edge not added." <<
endl;
}
}
cout << "\nGenerating DOT format for the DAG:" << endl;
dag.generateDOT();
cout << "\nTo visualize the graph, copy the above DOT format and use a tool like Graphviz." <<
endl;
return 0;
}
Q14. Write a program to show the symbol table entries.
#include <iostream>
#include <string>
#include <map>
#include <iomanip>
#include <limits>
struct SymbolInfo {
string name;
SymbolType type;
string dataType;
int scope;
string value;
};
class SymbolTable {
private:
map<string, SymbolInfo> table;
public:
void insert(const SymbolInfo& symbol) {
table[symbol.name] = symbol;
}
void display() {
cout << setw(15) << "Name" << setw(15) << "Type" << setw(15) << "Data Type"
<< setw(10) << "Scope" << setw(15) << "Value" << endl;
cout << string(70, '-') << endl;
void clearInputBuffer() {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
int main() {
SymbolTable symbolTable;
while (true) {
cout << "\nSymbol Table Operations:" << endl;
cout << "1. Insert Symbol" << endl;
cout << "2. Lookup Symbol" << endl;
cout << "3. Display Symbol Table" << endl;
cout << "4. Exit" << endl;
cout << "Enter your choice: ";
int choice;
cin >> choice;
clearInputBuffer();
switch (choice) {
case 1: {
SymbolInfo symbol;
cout << "Enter symbol name: ";
getline(cin, symbol.name);
int typeChoice;
cout << "Enter symbol type (0: VARIABLE, 1: FUNCTION, 2: CONSTANT): ";
cin >> typeChoice;
clearInputBuffer();
symbol.type = static_cast<SymbolType>(typeChoice);
symbolTable.insert(symbol);
cout << "Symbol inserted successfully." << endl;
break;
}
case 2: {
string name;
cout << "Enter symbol name to lookup: ";
getline(cin, name);
SymbolInfo info;
if (symbolTable.lookup(name, info)) {
cout << "Symbol found:" << endl;
cout << "Name: " << info.name << endl;
cout << "Type: " << (info.type == SymbolType::VARIABLE ? "Variable" :
info.type == SymbolType::FUNCTION ? "Function" : "Constant")
<< endl;
cout << "Data Type: " << info.dataType << endl;
cout << "Scope: " << info.scope << endl;
cout << "Value: " << info.value << endl;
} else {
cout << "Symbol not found." << endl;
}
break;
}
case 3:
symbolTable.display();
break;
case 4:
cout << "Exiting program." << endl;
return 0;
default:
cout << "Invalid choice. Please try again." << endl;
}
}
return 0;
}
Q14. Program to show the symbol table entries
#include <iostream>
#include <string>
#include <map>
#include <iomanip>
#include <limits>
struct SymbolInfo {
string name;
SymbolType type;
string dataType;
int scope;
string value;
};
class SymbolTable {
private:
map<string, SymbolInfo> table;
public:
void insert(const SymbolInfo& symbol) {
table[symbol.name] = symbol;
}
void display() {
cout << setw(15) << "Name" << setw(15) << "Type" << setw(15) << "Data Type"
<< setw(10) << "Scope" << setw(15) << "Value" << endl;
cout << string(70, '-') << endl;
void clearInputBuffer() {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
int main() {
SymbolTable symbolTable;
while (true) {
cout << "\nSymbol Table Operations:" << endl;
cout << "1. Insert Symbol" << endl;
cout << "2. Lookup Symbol" << endl;
cout << "3. Display Symbol Table" << endl;
cout << "4. Exit" << endl;
cout << "Enter your choice: ";
int choice;
cin >> choice;
clearInputBuffer();
switch (choice) {
case 1: {
SymbolInfo symbol;
cout << "Enter symbol name: ";
getline(cin, symbol.name);
int typeChoice;
cout << "Enter symbol type (0: VARIABLE, 1: FUNCTION, 2: CONSTANT): ";
cin >> typeChoice;
clearInputBuffer();
symbol.type = static_cast<SymbolType>(typeChoice);
symbolTable.insert(symbol);
cout << "Symbol inserted successfully." << endl;
break;
}
case 2: {
string name;
cout << "Enter symbol name to lookup: ";
getline(cin, name);
SymbolInfo info;
if (symbolTable.lookup(name, info)) {
cout << "Symbol found:" << endl;
cout << "Name: " << info.name << endl;
cout << "Type: " << (info.type == SymbolType::VARIABLE ? "Variable" :
info.type == SymbolType::FUNCTION ? "Function" : "Constant") << endl;
cout << "Data Type: " << info.dataType << endl;
cout << "Scope: " << info.scope << endl;
cout << "Value: " << info.value << endl;
} else {
cout << "Symbol not found." << endl;
}
break;
}
case 3:
symbolTable.display();
break;
case 4:
cout << "Exiting program." << endl;
return 0;
default:
cout << "Invalid choice. Please try again." << endl;
}
}
return 0;
}