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

CD File

Practical file

Uploaded by

pankajadarsh2311
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

CD File

Practical file

Uploaded by

pankajadarsh2311
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

Q1. Study of LEX tool.

Study of LEX Tool


Introduction
LEX (Lexical Analyzer Generator) is a powerful tool used in compiler design and text processing. It
generates lexical analyzers, also known as scanners or tokenizers, which are crucial components in
the front-end of compilers. LEX was originally developed by Mike Lesk and Eric Schmidt at Bell Labs
in the 1970s.

Purpose and Function


The primary purpose of LEX is to simplify the creation of lexical analyzers. It takes a set of regular
expressions and associated actions as input and generates C code for a lexical analyzer that can
recognize these patterns in an input stream.

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.

Structure of a LEX Program


A typical LEX program consists of three sections:

1. Definitions: For declaring variables, constants, and regular definitions.


2. Rules: Contains pattern-action pairs.
3. User Subroutines: Additional C functions used by the actions.

These sections are separated by %% delimiters.


Q2. Write a program to find First of a Non-terminal/string.
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>

using namespace std;

map<char, vector<string>> grammar;


map<char, set<char>> first_sets;

void computeFirst(char non_terminal) {


if (first_sets.find(non_terminal) != first_sets.end()) {
return;
}

first_sets[non_terminal] = set<char>();

for (const string& production : grammar[non_terminal]) {


for (char symbol : production) {
if (isupper(symbol)) {
computeFirst(symbol);
first_sets[non_terminal].insert(first_sets[symbol].begin(), first_sets[symbol].end());
if (first_sets[symbol].find('$') == first_sets[symbol].end()) {
break;
}
} else if (symbol != '$') {
first_sets[non_terminal].insert(symbol);
break;
} else {
first_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);
}

cout << "\nFIRST sets:" << endl;


for (const auto& entry : first_sets) {
cout << "FIRST(" << entry.first << ") = { ";
for (char symbol : entry.second) {
cout << symbol << " ";
}
cout << "}" << endl;
}

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>

using namespace std;

map<char, vector<string>> grammar;


map<char, set<char>> first_sets;
map<char, set<char>> follow_sets;

void computeFirst(char non_terminal) {


if (first_sets.find(non_terminal) != first_sets.end()) {
return;
}

first_sets[non_terminal] = set<char>();

for (const string& production : grammar[non_terminal]) {


for (char symbol : production) {
if (isupper(symbol)) {
computeFirst(symbol);
first_sets[non_terminal].insert(first_sets[symbol].begin(), first_sets[symbol].end());
if (first_sets[symbol].find('$') == first_sets[symbol].end()) {
break;
}
} else if (symbol != '$') {
first_sets[non_terminal].insert(symbol);
break;
} else {
first_sets[non_terminal].insert('$');
}
}
}
}

void computeFollow(char non_terminal) {


if (follow_sets.find(non_terminal) != follow_sets.end()) {
return;
}
follow_sets[non_terminal] = set<char>();

if (non_terminal == grammar.begin()->first) {
follow_sets[non_terminal].insert('$');
}

for (const auto& entry : grammar) {


for (const string& production : entry.second) {
for (size_t i = 0; i < production.length(); i++) {
if (production[i] == non_terminal) {
if (i == production.length() - 1) {
computeFollow(entry.first);
follow_sets[non_terminal].insert(follow_sets[entry.first].begin(),
follow_sets[entry.first].end());
} else {
set<char> first_of_next;
for (size_t j = i + 1; j < production.length(); j++) {
if (isupper(production[j])) {
first_of_next.insert(first_sets[production[j]].begin(),
first_sets[production[j]].end());
if (first_sets[production[j]].find('$') == first_sets[production[j]].end()) {
break;
}
} else {
first_of_next.insert(production[j]);
break;
}
}
follow_sets[non_terminal].insert(first_of_next.begin(), first_of_next.end());
if (first_of_next.find('$') != first_of_next.end()) {
computeFollow(entry.first);
follow_sets[non_terminal].insert(follow_sets[entry.first].begin(),
follow_sets[entry.first].end());
}
}
}
}
}
}
follow_sets[non_terminal].erase('$');
}

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;

// Function to get precedence of operators


int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
if (op == '^') return 3;
return 0;
}

// Function to perform infix to postfix conversion


string infixToPostfix(string infix) {
stack<char> s;
string postfix;

for (char ch : infix) {


if (isalnum(ch)) {
postfix += ch;
} else if (ch == '(') {
s.push(ch);
} else if (ch == ')') {
while (!s.empty() && s.top() != '(') {
postfix += s.top();
s.pop();
}
s.pop(); // Remove '('
} else {
while (!s.empty() && precedence(ch) <= precedence(s.top())) {
postfix += s.top();
s.pop();
}
s.push(ch);
}
}

while (!s.empty()) {
postfix += s.top();
s.pop();
}
return postfix;
}

// Function to reverse the infix expression for prefix conversion


string infixToPrefix(string infix) {
reverse(infix.begin(), infix.end());

for (int i = 0; i < infix.length(); i++) {


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

string prefix = infixToPostfix(infix);


reverse(prefix.begin(), prefix.end());
return prefix;
}

int main() {
string infix;
cout << "Enter an infix expression: ";
cin >> infix;

cout << "Postfix: " << infixToPostfix(infix) << endl;


cout << "Prefix: " << infixToPrefix(infix) << endl;

return 0;
}
Q5. Write a program to check whether a string is an identifier or not.

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

bool isValidIdentifier(const string& str) {


if (str.empty() || isdigit(str[0])) {
return false;
}

for (char c : str) {


if (!isalnum(c) && c != '_') {
return false;
}
}

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>

using namespace std;

map<char, vector<string>> grammar;

void removeLeftRecursion() {
for (auto& entry : grammar) {
char A = entry.first;
vector<string> alpha, beta;

for (const string& production : entry.second) {


if (production[0] == A) {
alpha.push_back(production.substr(1));
} else {
beta.push_back(production);
}
}

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);
}

cout << "\nOriginal Grammar:" << endl;


for (const auto& entry : grammar) {
cout << entry.first << " -> ";
for (size_t i = 0; i < entry.second.size(); i++) {
cout << entry.second[i];
if (i < entry.second.size() - 1) cout << " | ";
}
cout << endl;
}

removeLeftRecursion();

cout << "\nGrammar after removing left recursion:" << endl;


for (const auto& entry : grammar) {
cout << entry.first << " -> ";
for (size_t i = 0; i < entry.second.size(); i++) {
cout << entry.second[i];
if (i < entry.second.size() - 1) cout << " | ";
}
cout << endl;
}

return 0;
}
Q8. Write a program to remove left factoring from a grammar.

#include <iostream>
#include <vector>
#include <string>
using namespace std;

void removeLeftFactoring(string nonTerminal, vector<string> productions) {


string prefix = productions[0];
for (string prod : productions) {
int j = 0;
while (j < prefix.length() && j < prod.length() && prefix[j] == prod[j]) {
j++;
}
prefix = prefix.substr(0, j);
}

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>

using namespace std;

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);

size_t actionStart = input.find('{');


string rhsAndAction = input.substr(arrowPos + 2, actionStart - arrowPos - 3);
size_t pos = 0;
string token;
while ((pos = rhsAndAction.find(' ')) != string::npos) {
token = rhsAndAction.substr(0, pos);
p.rhs.push_back(token);
rhsAndAction.erase(0, pos + 1);
}
p.rhs.push_back(rhsAndAction);

p.action = input.substr(actionStart + 1, input.length() - actionStart - 2);

grammar.push_back(p);
}

generateSDT();

return 0;
}
Q10. Program to generate a parse tree.

#include <iostream>
#include <string>
#include <vector>
#include <memory>

using namespace std;

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;

char peek() { return pos < input.length() ? input[pos] : '\0'; }


char consume() { return pos < input.length() ? input[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;

prefix += isLast ? " " : "│ ";

for (size_t i = 0; i < node->children.size(); ++i) {


printTree(node->children[i].get(), prefix, i == node->children.size() - 1);
}
}
int main() {
string expression;
cout << "Enter an arithmetic expression: ";
getline(cin, expression);

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;

template <typename T>


class Stack {
private:
stack<T> s;
public:
void push(T value) {
s.push(value);
cout << "Pushed: " << value << endl;
}
T pop() {
if (s.empty()) {
throw runtime_error("Stack is empty");
}
T value = s.top();
s.pop();
cout << "Popped: " << value << endl;
return value;
}
T top() {
if (s.empty()) {
throw runtime_error("Stack is empty");
}
return s.top();
}
bool isEmpty() {
return s.empty();
}
size_t size() {
return s.size();
}
void display() {
if (s.empty()) {
cout << "Stack is empty" << endl;
return;
}
cout << "Stack contents (top to bottom): ";
stack<T> temp = s;
while (!temp.empty()) {
cout << temp.top() << " ";
temp.pop();
}
cout << endl;
}
};
int main() {
Stack<int> stack;

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>

using namespace std;

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>

using namespace std;

class DAG {
private:
map<string, set<string>> graph;
set<string> vertices;

bool hasCycle(const string& start, set<string>& visited, set<string>& recursionStack) {


visited.insert(start);
recursionStack.insert(start);

for (const auto& neighbor : graph[start]) {


if (visited.find(neighbor) == visited.end()) {
if (hasCycle(neighbor, visited, recursionStack)) {
return true;
}
} else if (recursionStack.find(neighbor) != recursionStack.end()) {
return true;
}
}

recursionStack.erase(start);
return false;
}

public:
bool addEdge(const string& from, const string& to) {
vertices.insert(from);
vertices.insert(to);
graph[from].insert(to);

set<string> visited, recursionStack;


for (const auto& vertex : vertices) {
if (visited.find(vertex) == visited.end()) {
if (hasCycle(vertex, visited, recursionStack)) {
graph[from].erase(to);
return false;
}
}
}
return true;
}

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>

using namespace std;

enum class SymbolType { VARIABLE, FUNCTION, CONSTANT };

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;
}

bool lookup(const string& name, SymbolInfo& info) {


if (table.find(name) != table.end()) {
info = table[name];
return true;
}
return false;
}

void display() {
cout << setw(15) << "Name" << setw(15) << "Type" << setw(15) << "Data Type"
<< setw(10) << "Scope" << setw(15) << "Value" << endl;
cout << string(70, '-') << endl;

for (const auto& entry : table) {


const SymbolInfo& info = entry.second;
cout << setw(15) << info.name
<< setw(15) << (info.type == SymbolType::VARIABLE ? "Variable" :
info.type == SymbolType::FUNCTION ? "Function" : "Constant")
<< setw(15) << info.dataType
<< setw(10) << info.scope
<< setw(15) << info.value << 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);

cout << "Enter data type: ";


getline(cin, symbol.dataType);

cout << "Enter scope: ";


cin >> symbol.scope;
clearInputBuffer();

cout << "Enter value: ";


getline(cin, symbol.value);

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>

using namespace std;

enum class SymbolType { VARIABLE, FUNCTION, CONSTANT };

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;
}

bool lookup(const string& name, SymbolInfo& info) {


if (table.find(name) != table.end()) {
info = table[name];
return true;
}
return false;
}

void display() {
cout << setw(15) << "Name" << setw(15) << "Type" << setw(15) << "Data Type"
<< setw(10) << "Scope" << setw(15) << "Value" << endl;
cout << string(70, '-') << endl;

for (const auto& entry : table) {


const SymbolInfo& info = entry.second;
cout << setw(15) << info.name
<< setw(15) << (info.type == SymbolType::VARIABLE ? "Variable" :
info.type == SymbolType::FUNCTION ? "Function" : "Constant")
<< setw(15) << info.dataType
<< setw(10) << info.scope
<< setw(15) << info.value << 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);

cout << "Enter data type: ";


getline(cin, symbol.dataType);

cout << "Enter scope: ";


cin >> symbol.scope;
clearInputBuffer();

cout << "Enter value: ";


getline(cin, symbol.value);

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;
}

You might also like