In this article, you will learn about the symbol table in C++.
Compiler Design symbol table
In order to store information on the existence of different entities , such as variable and function names, objects and classes , etc., the compiler builds and maintains a data structure. Symbol tables are one class of data structure.
C++ code for symbol table entry:
Example:
#include <iostream>
#include <unordered_map>
#include <vector>
class SymbolTableEntry {
public:
std::string name;
std::string dataType;
std::string scope;
SymbolTableEntry(const std::string& n, const std::string& dt, const std::string&sc)
: name(n), dataType(dt), scope(sc) {}
};
class SymbolTable {
public:
void insert(constSymbolTableEntry& entry) {
entries.push_back(entry);
}
SymbolTableEntry* lookup(const std::string& name) {
for (auto&entry : entries) {
if (entry.name == name) {
return &entry;
}
}
return nullptr;
}
private:
std::vector<SymbolTableEntry> entries;
};
int main() {
SymbolTablesymbolTable;
symbolTable.insert(SymbolTableEntry("A", "int", "P1"));
symbolTable.insert(SymbolTableEntry("B", "int", "P1"));
symbolTable.insert(SymbolTableEntry("C", "int", "P1 inner block"));
symbolTable.insert(SymbolTableEntry("D", "int", "P1 inner block"));
symbolTable.insert(SymbolTableEntry("E", "int", "P1"));
symbolTable.insert(SymbolTableEntry("F", "int", "P1 inner block"));
symbolTable.insert(SymbolTableEntry("G", "int", "P1 inner block"));
symbolTable.insert(SymbolTableEntry("H", "int", "P2"));
symbolTable.insert(SymbolTableEntry("I", "int", "P2"));
symbolTable.insert(SymbolTableEntry("J", "int", "P2 inner block"));
symbolTable.insert(SymbolTableEntry("K", "int", "P2 inner block"));
symbolTable.insert(SymbolTableEntry("L", "int", "P2"));
SymbolTableEntry* entryA = symbolTable.lookup("A");
if (entryA) {
std::cout<< "Found symbol A in the symbol table." <<std::endl;
} else {
std::cout<< "Symbol A not found in the symbol table." <<std::endl;
}
SymbolTableEntry* entryX = symbolTable.lookup("X");
if (entryX) {
std::cout<< "Found symbol X in the symbol table." <<std::endl;
} else {
std::cout<< "Symbol X not found in the symbol table." <<std::endl;
}
return 0;
}
Output:
Found symbol A in the symbol table.
Symbol X not found in the symbol table.
Symbol table operations
There are several symbol table operations in C++. Some main symbol table operations in C++ are as follows:
Operate on the Symbol table.
A symbol table can use the Allocate Operation to allocate a brand-new, empty symbol table.
Operation Insert on the Symbol table
A symbol table's Insert Operation can be used to insert a name and return a pointer to the entry.
Operation Set_attribute on the Symbol table
Set_attribute is a symbol table that can be operated on to associate an attribute with a specific entry.
Operation Get_attribute on the Symbol table
Get_attribute is a symbol table that can be operated on to obtain an attribute connected to a specific entry.
Operation of Lookup on the Symbol Table
Lookup An operation on a symbol table can be used to look for a name and return a pointer to its entry.
Free Operation on the Symbol table
A symbol table's storage can be freed up by performing a Free Operation to remove every entry. On the symbol table, additional actions can be carried out in a similar manner to remove operations.
Deployment of the Symbol table
It is possible to implement symbol tables using a variety of data structure methods. The following techniques are listed:
- LinkedList
- Hash Table
- Tree
Implementation of symbol tables in C++ using hashing:
// Symbol Table implementation in C++
#include <iostream>
using namespace std;
const int MAXIMUM = 200;
class Node {
string identifier, scope, type;
int Line_Number;
Node* next_Node;
public:
Node()
{
next_Node = NULL;
}
Node(string key, string value, string type, int Line_Number)
{
this->identifier = key;
this->scope = value;
this->type = type;
this->Line_Number = Line_Number;
next_Node = NULL;
}
void print()
{
cout<< "Identifier's Name:" << identifier
<< "\nType:" << type
<< "\nScope: " << scope
<< "\nLine Number: " <<Line_Number<<endl;
}
friend class SymbolTable;
};
class SymbolTable {
Node* header[MAXIMUM];
public:
SymbolTable()
{
for (int i = 0; i< MAXIMUM; i++)
header[i] = NULL;
}
int hashf(string id); // hash function
bool JavaCppTutorial_insertion(string id, string scope,
string Type, int Line_Number);
string JavaCppTutorial_search(string id);
bool deleteRecord(string id);
bool modify(string id, string scope,
string Type, int Line_Number);
};
// Identifyer modification function
bool SymbolTable::modify(string id, string s,
string t, int l)
{
int index = hashf(id);
Node* start = header[index];
if (start == NULL)
return "-1";
while (start != NULL) {
if (start->identifier == id) {
start->scope = s;
start->type = t;
start->Line_Number = l;
return true;
}
start = start->next_Node;
}
return false; // id not found
}
// Delete an identifier function
bool SymbolTable::deleteRecord(string id)
{
int index = hashf(id);
Node* JavaCppTutorial_Temporary_Variable = header[index];
Node* par = header[index];
// There is no identifier at that index.
if (JavaCppTutorial_Temporary_Variable == NULL) {
return false;
}
// There is only one identifier.
if (JavaCppTutorial_Temporary_Variable->identifier == id &&JavaCppTutorial_Temporary_Variable->next_Node == NULL) {
JavaCppTutorial_Temporary_Variable->next_Node = NULL;
delete JavaCppTutorial_Temporary_Variable;
return true;
}
while (JavaCppTutorial_Temporary_Variable->identifier != id &&JavaCppTutorial_Temporary_Variable->next_Node != NULL) {
par = JavaCppTutorial_Temporary_Variable;
JavaCppTutorial_Temporary_Variable = JavaCppTutorial_Temporary_Variable->next_Node;
}
if (JavaCppTutorial_Temporary_Variable->identifier == id &&JavaCppTutorial_Temporary_Variable->next_Node != NULL) {
par->next_Node = JavaCppTutorial_Temporary_Variable->next_Node;
JavaCppTutorial_Temporary_Variable->next_Node = NULL;
delete JavaCppTutorial_Temporary_Variable;
return true;
}
// remove the conclusion
else {
par->next_Node = NULL;
JavaCppTutorial_Temporary_Variable->next_Node = NULL;
delete JavaCppTutorial_Temporary_Variable;
return true;
}
return false;
}
// JavaCppTutorial_search identifier function
string SymbolTable::JavaCppTutorial_search(string id)
{
int index = hashf(id);
Node* start = header[index];
if (start == NULL)
return "-1";
while (start != NULL) {
if (start->identifier == id) {
start->print();
return start->scope;
}
start = start->next_Node;
}
return "-1"; // not found
}
// JavaCppTutorial_insertion function for an identifier
bool SymbolTable::JavaCppTutorial_insertion(string id, string scope,
string Type, int Line_Number)
{
int index = hashf(id);
Node* p = new Node(id, scope, Type, Line_Number);
if (header[index] == NULL) {
header[index] = p;
cout<< "\n"
<< id << " insertion";
return true;
}
else {
Node* start = header[index];
while (start->next_Node != NULL)
start = start->next_Node;
start->next_Node = p;
cout<< "\n"
<< id << " insertion";
return true;
}
return false;
}
int SymbolTable::hashf(string id)
{
int asciiSum = 0;
for (int i = 0; i<id.length(); i++) {
asciiSum = asciiSum + id[i];
}
return (asciiSum % 100);
}
int main()
{
SymbolTablest;
string check;
cout<< "**** SYMBOL_TABLE ****\n";
if (st.JavaCppTutorial_insertion("if", "local", "keyword", 4))
cout<< " -successfully";
else
cout<< "\nFailed to JavaCppTutorial_insertion.\n";
if (st.JavaCppTutorial_insertion("number", "global", "variable", 2))
cout<< " -successfully\n\n";
else
cout<< "\nFailed to JavaCppTutorial_insertion\n";
check = st.JavaCppTutorial_search("if");
if (check != "-1")
cout<< "Identifier Is present\n";
else
cout<< "\nIdentifier Not Present\n";
if (st.deleteRecord("if"))
cout<< "if Identifier is deleted\n";
else
cout<< "\nFailed to delete\n";
if (st.modify("number", "global", "variable", 3))
cout<< "\nNumber Identifier updated\n";
check = st.JavaCppTutorial_search("number");
if (check != "-1")
cout<< "Identifier Is present\n";
else
cout<< "\nIdentifier Not Present";
return 0;
}
Output:
**** SYMBOL_TABLE ****
if insertion -successfully
number insertion -successfully
Identifier's Name:if
Type:keyword
Scope: local
Line Number: 4
Identifier Is present
if Identifier is deleted
Number Identifier updated
Identifier's Name:number
Type:variable
Scope: global
Line Number: 3
Identifier Is present
Conclusion:
The symbol table is a crucial tool for language processing systems which provides the essential infrastructure to manage the complicated semantics and behavior of identifiers in C programs. It is essential to make sure the code is executed correctly and efficiently.