Reputation:
I'm doing an entry level Lexical analyser here. My code is
bool DfaTab :: isAccepted(string s){
FILE *fp1;
int i;
fp1 = fopen("javalist.dat","r");
while(!(feof(fp1))){
fscanf(fp1,"%s%d%[^\n]",tkname.c_str(),&tkval);
if(strcmp(s.c_str(),tkname.c_str()) == 0){
setTkVal(tkval);
setTkName(tkname.c_str());
state = true;
return state;
break;
}
else{
//What should I do here to skip to next line
}
}
return state;
fclose(fp1);
}
which will be called from here :
while (!(feof(src))) {
fscanf(src,"%s[^\t^ ^\n]",sym.c_str());
if (d.isAccepted(sym)) {
fprintf(des,"<%s, %d>\n",d.getTkName().c_str(),d.getTkVal());
}
else{
cout << "Can not find symbol " << d.getTkName().c_str();
cout << "Rejected.\n";
break;
}
}
My problem is that the fscanf() function which is in the isAccepted() function does not skip to the new line and repeatedly printing the the first line that was read at the beginning of the is printed rest of the execution. What should I do now?
the file contains :
//javalist.dat
boolean 0
brake 1
case 2
catch 3
const 4
continue 5
default 6
....
Upvotes: 0
Views: 129
Reputation: 90493
It is incorrect to call feof
before you have performed a read operation on the file. You should probably restructure your code to be like this:
// some reasonble max size
char buf[1024];
// read in a line
while(fgets(buf, sizeof(buf), fp1)) {
// parse the contents of that line
sscanf(buf, ...); //
// the rest of your code...
}
Additionally, you have a fairly major bug in your code.
fscanf(fp1,"%s%d%[^\n]",tkname.c_str(),&tkval);
The result of tkname.c_str()
is NOT a writable string, it's a const char *
. You may not pass it to fscanf
to be written to, that is well into undefined behavior and can easily lead to crashes. Instead you need to allocate a new buffer, read into that and then assign it to the string.
Alternatively, you can use iostreams to solve this much simpler:
bool DfaTab :: isAccepted(string s){
std::ifstream file("javalist.dat");
std::string line;
std::string name;
int val;
// read a line
while(std::getline(file, line)) {
// get the data out of the line
std::stringstream ss(line);
if(ss >> name >> val) {
if(name == s) {
setTkVal(val);
setTkNamename.c_str()); // if this method takes a std::string, no need for the .c_str()
state = true;
return state;
} else{
// just ignore this line and it'll continue
}
} else {
// an invalid line, handle as you please...
}
}
return state;
}
Notice how this solution is actually simpler overall.
Upvotes: 1