So I'm trying to generate a symbol table from an input file that contains C-style nested blocks like this in C++;
A: { int a; float b;
B: { float c; int d;
C: { int b; int c;
}
}
D: { float a;
}
}
The output should look like this.
A: a -> <int, A>
b -> <float, A>
B: a -> <int, A>
b -> <float, A>
c -> <float, B>
d -> <int, B>
C: a -> <int, A>
b -> <int, C> -> <float, A>
c -> <int C> -> <float, B>
d -> <int, local to B>
D: a -> <float D> -> <int, A>
b -> <float, A>
I'v tried so many things. Using vectors, maps and now finally I have decided to use multimaps. No matter what I do I come down to the same problem so it probably has nothing to do with the data-structure I choose.
The issue is that because I'm reading line by line I end up cout-ing more than what I need to. But if I don't have it cout/iterate the multimaps in the for loop for each line than I'd iterate after they have been erased/popped. I'm not sure what to do logic wise to get the output to display as it should or if I'm even on the right track.
Here is my .cpp file so far. Ignore comments as they were past attempts that I have opted out of using for the moment. Also in this version I'm not making use of vectors so you can ignore vector related code. I"m just using multimaps now.
#include<iostream>
#include<fstream>
#include<string>
#include <sstream>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
void ReadFromFile();
void main(){
ReadFromFile();
cin.get();
}
void ReadFromFile(){
stringstream ss;
string type = "";
string var = "";
string lable = "";
string Obraket = "";
string Cbraket = "";
int braketCount = -1;
ifstream myfile("input1.txt");
multimap<string, string> symbol;
multimap<string, multimap<string, string>> symbolL;
if (myfile.is_open())
{
for (string line; getline(myfile, line);)
{
istringstream in(line);
if (in.str().find("}") == string::npos && in.str().find("{") != string::npos){
in >> lable;
in >> Obraket;
braketCount++;
cout << Obraket << endl;
in >> type;
in >> var;
symbol.insert(pair<string, string>(var.substr(0, 1), type));
if (in.str().find("float") != string::npos || in.str().find("int") != string::npos){
var = "";
type = "";
in >> type;
in >> var;
if (type.length() > 1){
symbol.insert(pair<string, string>(var.substr(0, 1), type));
}
}
symbolL.insert( pair<string, multimap<string, string>>(lable,symbol));
for (multimap<string, multimap<string, string>>::iterator it = symbolL.begin(); it != symbolL.end(); ++it){
cout << it->first;
for (multimap<string, string>::iterator it2 = symbol.begin(); it2 != symbol.end(); ++it2){
cout << it2->first << "-> " << "<" << it2->second << ">, " << it->first.substr(0, 1) << endl;
}
}
}
else if (in.str().find("}") != string::npos){
in >> Cbraket;
//braketCount--;
cout << Cbraket << endl;
symbolL.erase(prev(symbolL.end()));
//symbol.erase(prev(symbol.end()));
}
}
myfile.close();
}
else cout << "Unable to open file";
}
This is the output I get.
{
A:a-> <int>, A
b-> <float>, A
{
A:a-> <int>, A
b-> <float>, A
c-> <float>, A
d-> <int>, A
B:a-> <int>, B
b-> <float>, B
c-> <float>, B
d-> <int>, B
{
A:a-> <int>, A
b-> <float>, A
b-> <int>, A
c-> <float>, A
c-> <int>, A
d-> <int>, A
B:a-> <int>, B
b-> <float>, B
b-> <int>, B
c-> <float>, B
c-> <int>, B
d-> <int>, B
C:a-> <int>, C
b-> <float>, C
b-> <int>, C
c-> <float>, C
c-> <int>, C
d-> <int>, C
}
}
{
A:a-> <int>, A
a-> <float>, A
b-> <float>, A
b-> <int>, A
c-> <float>, A
c-> <int>, A
d-> <int>, A
D:a-> <int>, D
a-> <float>, D
b-> <float>, D
b-> <int>, D
c-> <float>, D
c-> <int>, D
d-> <int>, D
}
}
Here it is!
If you accept an advice, start reading the main function instead of the types on the top.
I didn't need multimap. Instead of copying the parent block's variables, I only reference the parent container with its index. Just before printing there is a traversal to the top-most block, and it collects all the variables visible in the current block.
It can be optimized to avoid lookup during printing, and you can also avoid storing the symbols if you only want to print them. You can store local variables here and there, but the main idea will be the same. And yes, I'm using yet another container to manage nesting, a stack :)
Only by using multimap, your variables will be shuffled. Somehow, you have to keep track of the order.
I am using vectors to do that.
(If you can't compile C++11, just replace the range-based for loop at the very end of main)