Recursive Descent Parser Help (Not reading a text file string) - c++

char input[100]; //Used to check grammar
char *s;
int main(int argc, char *argv[]) {
ifstream fin("input.txt"); //Open input file
while (fin>>input) { //Store text in input[]
s = input; //Point c at the input text
cout<<"String read from file: "<<input<<endl; //Show input text
if (A() && *s == '\0') { //Testing the grammar
cout<<"The string \""<<input<<"\" is in the language."<<endl;
}
else cout<<"The string \""<<input<<"\" is not in the language."<<endl;
cout<<endl; //Formatting for output in console
}
fin.close(); //Close input file
return 0;
}
Can someone tell me what i am doing wrong here. The parser is not reading string from the text file.

Let's treat this like two problems.
Problem 1: Reading in the file.
I've stripped out everything that isn't absolutely essential to reading the data in.
char input[100]; //Used to check grammar
int main(int argc, char *argv[]) {
ifstream fin("input.txt"); //Open input file
while (fin>>input) { //Store text in input[]
cout<<"String read from file: "<<input<<endl; //Show input text
}
return 0;
}
Nothing really wrong here, but you should seriously consider replacing char input[100]; with std::string input; to save you headaches with large tokens. For example, watch what happens here:
int main()
{
stringstream stream("1234567890"); // pack ten characters into stream
// note: no whitespace.
char snookums[] = "snookums";
char array[5];
cout << snookums << endl; // prove contents of snookums
stream >> array; // read up to first whitespace from stream into array
cout << array << endl; // display what we read.
cout << snookums << endl; // oh dear. Now look at poor snookums!
return 0;
}
output:
snookums
1234567890
67890
Despite array being size 5, it contains all 10. Or does it? Nope. Sadly poor snookums got run over. This won't happen with strings.
For all we know fin>>inputjust read 30000 characters from a whitespace-free file, annihilated the rest of your program's memory, and the program died before printing out anything.
Anyway, your code leaves a few questions:
Are you actually able to open the file? You don't know, really. You never checked.
Was the file empty? Also don't know. You didn't tell us. This is one of the things folks are getting on about in the comments.
None of this fixes anything, but hopefully gives you a better idea what's going wrong.
string input; // using string in case the data you're reading is incompatible
//with a 100 character char array.
int main(int argc, char *argv[]) {
ifstream fin("input.txt"); //Open input file
if (fin.is_open()
{
while (fin>>input)
{ //Store text in input
cout<<"String read from file: "<<input<<endl; //Show input text
}
}
else
{
cout << "Failed to open file." << endl;
}
return 0;
}
Once you know if you are actually reading in data, and if not, why not.
Problem 2: language parsing.
We can't help you here. No information was provided, but a few notes on coding style because they will help you ask future questions:
A() is meaningless to everyone but you. Give it a descriptive name so that someone other than you has some hints about what it does. A() takes no parameters. I assume that's because it is operating on input. OK, but why not pass input in? The cost is minimal and it provides more information to readers. Note how commenters zeroed in on A() right away? That's fear. The good kind of fear. We have no [insert expletive here] clue what it is or what it does, so it is instantly scrutinized.
A(input) reads to me as "A does something to input." I don't know what it does, but it does it to input. Unless the writer of the program has a history of doing silly stuff, it probably only does stuff to input and I don't have to fear this function nearly as much.
LanguageInterpreter() tells me that a language interpreter was run. Not much, but if I'm looking tor a bug in the file reading code, I'm not likely to find it in there. Unfortunately it also tells me that LanguageInterpreter is feasting on global data and Crom only knows what sort of side effects it could have on the rest of the program.
LanguageInterpretter(input) tells me a lot. For one thing it tells me that I can get on with my day because it has nothing to do with, or better have nothing to do with, the reading in of the data file. I'll check other places for bugs first.

string *s;
int main()
{
string input;
ifstream fin("input.txt");
if(fin.is_open())
{
while(getline(fin,input))
{
s=&input;
if (A() && *s == '\0') /* error: no match for 'operator==' in '* s == '\000''*/
{ //Testing the grammar
cout<<"The string \""<<*s<<"\" is in the language."<<endl;
}
else cout<<"The string \""<<*s<<"\" is not in the language."<<endl;
cout<<endl;
}
}
fin.close();
return 0;
}

Related

How to store specific integers from a .txt file in an array of structures?

There are numbers ranging from 1-4 in a file called "data.txt" (ex. 2 1 2 4 1 3...). I need to read these numbers and create strings of 100 numbers each. After which I need to count how many 1s, 2s 3s, and 4s there are in each string. This is what I have so far:
//structure
struct DNAnt
{
int a, c, g, t;
string strand;
};
void data2DNA();
//main
int _tmain(int argc, _TCHAR* argv[])
{
data2DNA();
cin.get();
return 0;
}
//function
void data2DNA()
{
DNAnt DNAstrand[100];
ifstream inFile;
int numbers;
inFile.open("data.txt");
if(inFile.is_open())
{
while(!inFile.eof())
{
inFile >> numbers;
}
}
else
cout << "ERROR!";
inFile.close();
}
All this program does at the moment is read all the data from the file. I don't know how to continue from here.
Very often in C++ you need to use a loop to repeat an action some number of times. In your case I believe you could benefit from a for loop. Here is an example of a loop that will read 100 integers and store each one to a location in the array that you have near the start of your main:
int i;
for(i = 0; inFile && i < 100; ++i) { //i will range from 0 to 99
inFile >> DNAstrand[i];
}
//now use DNAstrand to do stuff
The reason I say inFile && is to make sure that inFile is not at eof.
Start with a very simple program that reads numbers from a file.
Just read them. Do not interpret them because there is no point to trying to do anything with these numbers until you can prove that they are being read correctly. All additional code will do is muddy the waters of ensuring you are reading correctly and hide the location of bugs from you.
vector<int> readFile()
{
vector<int> numbers;
Why vector? Because it is the easiest way to store an unknown number of entries. Don't play around with more complicated structures at this point and don't try to roll your own. If the instructor says, "No vector" oh well. But that's for what you hand in. What you use to prove the algorithm works is another story.
ifstream inFile("data.txt");
This also opens the file so you don't have to do it later
if(inFile.is_open())
{
int number;
while(inFile >> number)
This reads into an int. If it can't read an int for any reason, it stops and leaves the loop. If the file is poorly formatted and contains data that cannot be converted, we're outta here. If it hits the end of the file, we're outta here.
{
numbers.push_pack(number);
Otherwise, we put the number we read into the vector.
}
}
else
{
cout << "ERROR opening file";
)
Don't need to close the file. When we hit the end of the function inFiles destructor will fire and do it for us.
return numbers;
And send the vector back to the caller so they can use it however they see fit. There is a whole tot of interesting stuff that can happen here to keep the vector from being copied as it is returned, so don't worry about it.
}
All together:
void data2DNA()
{
vector<int> numbers;
ifstream inFile("data.txt");
if(inFile.is_open())
{
int number;
while(inFile >> number)
{
numbers.push_pack(number);
}
}
else
{
cout << "ERROR opening file";
)
return numbers;
}
Now that you have the data in, you can get on with the real job of turning it into a string of nucleic acids.
For this part I'm going to recommend an array
const char tags[] = {'-', 'A', 'C', 'G', 'T'};
Indexes 1 though 4 are A, C, G, and T, so tags[2] will provide 'C'. This makes translating from number to tag really, really easy.
Once you have a tag, you can append it to the DNA string.

Fixing syntax of number of line reading function

I tried making a program earlier that tells the user then number of char, words, and lines in a text file. I made functions to determine the numbers of each, yet I was passing them by value. This resulted in an error since after reading the number of char it would be at the end of the file and then output zero for the other two. Now I cant seem to rewrite my functions so that the file is open and closed each time its checked for char, words, and lines. Any one see where my errors are?? Thanks! (just copied and pasted one of my functions for now).
int num_of_lines(ifstream file)
{
string myfile;
myfile = argv[1];
ifstream l;
l.open(myfile);
int cnt3 = 0;
string str;
while(getline(file, str))cnt3++;
l.close();
return(cnt3);
}
int main(int argc, char **argv)
{
int num_of_char(ifstream file);
string file;
file = argv[1];
if(argc == 1)die("usage: mywc your_file");
ifstream ifs;
ifs.open(file);
if(ifs.is_open())
{
int a, b, c;
a = num_of_lines(ifs);
cout <<"Lines: " << a << endl;
}
else
{
cerr <<"Could not open: " << file << endl;
exit(1);
}
ifs.close();
return(0);
}
There is no way to "reopen" a file other than knowing the name and creating a new ifstream, but you can use the seekg member function to set your read position in the file, and setting it to 0 will have the next read operation start from the beginning of the file.
A stream is not possible to copy, so you can't pass it "by value", but must pass it by reference.
int num_of_lines(ifstream &file)
{
int count = 0;
string str;
while (getline(file, str)) {
count++;
}
file.seekg(0);
return count;
}
For the full problem, I agree with Mats Petersson, though. Counting both characters, lines and words in one pass will be much more efficient than reading through the file three times.

Checking if one document has the contents of the other c++

I am writing a code to check to see if one document (text1.txt) contains a list of banned words (bannedwords.txt) in it.
For example, the text1 document contains lyrics to a song and i want to check whether the word pig from the banned document is included in it. I then want the out put to be similar to:
"pig" found 0 times
"ant" found 3 times
This is what I have come up with so far but cannot seem to put the array of banned words into the search. Any help would be amazing :D
Thanks Fitz
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool CheckWord(char* filename, char* search)
{
int offset;
string line;
ifstream Myfile;
Myfile.open(filename);
if (Myfile.is_open())
{
while (!Myfile.eof())
{
getline(Myfile, line);
if ((offset = line.find(search, 0)) != string::npos)
{
cout << "The Word " << search<< " was found" << endl;
return true;
}
else
{
cout << "Not found";
}
}
Myfile.close();
}
else
cout << "Unable to open this file." << endl;
return false;
}
int main()
{
ifstream file("banned.txt");
if (file.is_open())//file is opened
{
string bannedWords[8];//array is created
for (int i = 0; i < 8; ++i)
{
file >> bannedWords[i];
}
}
else //file could not be opened
{
cout << "File could not be opened." << endl;
}
ifstream text1;//file is opened
text1.open("text1.txt");
if (!text1)//if file could not be opened
{
cout << "Unable to open file" << endl;
}
CheckWord("text1.txt", "cat");
system("pause");
}
Your main() function is reading the contents of banned.txt into an array of 8 std::string named bannedWords.
The array bannedWords is not being used anywhere after that. C++ doesn't work by magic, and compilers are not psychic so cannot read your mind in order to understand what you want your code to do. If an array (or its elements) are not accessed anywhere, they will not be used to do what you want with them.
You need to pass strings from the bannedWords array to CheckWord(). For example;
CheckWord("text1.txt", bannedWords[0].c_str());
will attempt to pass the contents of the first string in bannedWords to CheckWord().
However, that will not compile either unless you make the second parameter of CheckWord() (named search) be const qualified.
Or, better yet, change the type of the second argument to be of type std::string. If you do that, you can eliminate the usage of c_str() in the above.
I don't claim that is a complete solution to your problem - because there are numerous problems in your code, some related to what you've asked about, and some not. However, my advice here will get you started.
Your question is really vague; it looks like you need to spend some time to pin down your program structure before you could ask for help here.
However, since we were all new once, here's a suggestion for a suitable structure:
(I'm leaving out the file handling bits because they're irrelevant to the essential structure)
//Populate your array of banned words
std::string bannedWords[8];
int i;
for (int i = 0; i < 8; ++i)
{
file >> bannedWords[i];
}
//Load the entire file content into memory
std::ifstream in("text1.txt");
std::string fileContents((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
So now the entire file content is in the string "fileContents", and the 8 banned words are in "bannedWords". I suggest this approach because otherwise you're opening, reading, and closing the file for every word. Hardly a good design.
Now you've got to check each word against the file content. There's some more sophisticated ways to do this, but your simplest option is a loop.
//Loop through each banned word, and check if it's in the file
for (int i = 0; i < 8; i++)
{
if (fileContents.find(bannedwords[i]) != std::string::npos)
{
//Do whatever
}
}
Obviously you'll need to do the find a little differently if you want to count the number of occurrences, but that's another question.

How do I read character by character from a text file and put it in a character array?

I'm trying to read character by character from a text file until EOF, put them into a character array, so that I can manipulate it after. Compiled with g++ without errors, and when run, I'm prompted for the input file but then it just hangs.
int main (int argc, char *argv[]) {
string filename;
ifstream infile;
char *cp, c[1024];
memset (c, 0, sizeof(c));
cp = c;
cout << "Enter file name: " << endl;
cin >> filename;
//open file
infile.open( filename.c_str() );
//if file can't open
if(!infile) {
cerr << "Error: file could not be opened" << endl;
exit(1);
}
while (!infile.eof()); {
infile.get(c, sizeof(infile));
// get character from file and store in array c[]
}
}//end main
You should try the istream::read() method rather than get(). This will help resolve any buffer overruns:
unsigned int chars_read = 0;
//...
// Read in the file.
if (!infile.read(c, sizeof(c))
{
// Handle the read error here.
// Also check for EOF here too.
}
// Obtain the number of characters actually read.
chars_read = infile.gcount();
First off, you don't want to test for eof()! Somehow I start to feel like Don Quixote having found my windmills. However, I do know that you need to check that the input was successful after trying to read it because before attempting to read the stream can't know whether it will be successful.
You program actually doesn't hang! It just waits for you to enter sizeof(infile) characters or end the input (e.g., using Ctrl-D on UNIXes and Ctrl-Z on Windows). Of course, this may look remarkable like a hanging program. You can verify that this is, indeed, the problem by using a smaller size, e.g., 4. Of course, sizeof(infile) is nearly as good as a small random number: It is the size of an object of type std::ifstream and who can tell what that is? You probably meant to use sizeof(c) to make sure that the call to get(c, n) won't write more character than can fit into c.
Try this:
int cont = 0;
while(infile.good()) {
c[cont++] = infile.get();
}

String is not printing without new line character in C++

I'm opening a file, and getting lines from it.
The first line should say how many variables there are, and what their names are.
The second line should be a logic equation using these variables.
The assignment is to have it print out a truth table for the variables and equation.
The first line the program is taking in is not printing without me inserting a new line character. I tried converting to a string and using both printf and cout.
Main file that inputs everything:
#include "truthTable2.h"
int main(int argc, const char* argv[]){
ifstream inFile;
if(argc != 2){
cout << "Enter an input file name: ";
char *inFileName = "";
cin >> inFileName;
inFile.open(inFileName);
}
else
inFile.open(argv[1]);
TruthTable tTable;
while(!inFile.eof()){
char variableLine[256];
inFile.getline(variableLine, 256);
printf("%s ", variableLine);
string variable(variableLine);
tTable.setVariables(variable);
char formulaLine[256];
inFile.getline(formulaLine, 256);
cout << formulaLine << "\n";
string formula(formulaLine);
tTable.setFormula(formula);
tTable.printTable();
}
inFile.close();
return 0;
}
Sample input:
2 x y
( \wedge x ( \not y ) )
Output from this:
( \wedge x ( \not y ) )
I think whatever is causing this is giving me problems throughout the rest of the program as well. After I tokenize the variableLine it does not print without a new line character and it does not find the second variable when evaluating the formula.
An std::ostream's output needs to be flushed. It is normally flushed automatically when a line-feed \n is written. If you want to force the stream to flush, you can use the std::flush manipulator like so:
std::cout << "foo" << std::flush;
Edit: Although my post clearly answers the question "Why does my line not show up unless I output a \n character?" You said this does not answer your question, so I will attempt some mind reading to try and answer your real question.
Since I have no idea what you really want know, I'll point out several things here that are wrong with your code and it might help you find your problem or clarify your question.
First, if you are using the file name input from std::cin, when argc<2, you will, a 100% guaranteed, cause a failure in your application. The reason is that the character buffer pointed to by inFileName contains a single byte, reserved for the terminating null character. If someone enters any text whatsoever, you will get a buffer overrun. If someone enters an empty string, your program will open no file and inFile.open(...); will return an error code that you don't check, so your program won't crash, but still won't work.
Second, the other line inputs are needlessly limited to 256 characters and are just as dangerous (i.e. lines longer that 256 characters will cause a bufer overrun). Since you eventually create std::string instances out of the content, you should just plainly use std::getline(). It is shorter to type, more general and safer.
Third, the description of your problem is that no output is generated unless you add a \n character. As I explained, this is perfectly normal. From re-reading your post, I can understand that you don't unhderstand why you should have to add one given that there was already one in the input file. The reason you need to add it is because the getline() functions discard the \n character. It is not inserted into your line's buffer.
I've cleaned up some of your code to show you some clear improvements. From this code you will be able to understand the structure of your program, which should also reflect the structure of your input.
#include "truthTable2.h"
int main(int argc, const char* argv[]){
std::ifstream inFile;
if(argc != 2){
cout << "Enter an input file name: ";
std::string inFileName;
std::getline(std::cin, inFileName);
inFile.open(inFileName.c_str());
}
else {
inFile.open(argv[1]);
}
if ( !inFile.is_open() ) {
// Did not successfully open a file. Print error message and exit!
}
TruthTable tTable;
for (std::string variables; std::getline(inFile,variables); )
{
std::cout << variables << std::endl;
tTable.setVariables(variable);
std::string formula std::getline(formula);
std::cout << formula << std::endl;
tTable.setFormula(formula);
tTable.printTable();
}
return 0;
}
From this, I have a question:how is your input structured? Is your input file only consisted of 2 lines? Are there multiple sets of these line pairs? Is there a single line with variables and a bunch of equations? These three cases will lead me to re-structure the program in one of the following fashions:
2 lines only:
ThruthTable table;
std::string variables, equation;
std::getline(file, variables);
std::getline(file, equation);
// ...
Multiple sets:
while ( !inFile.eof() )
{
ThruthTable table;
std::string variables, equation;
std::getline(file, variables);
std::getline(file, equation);
// ...
}
Multiple equations:
ThruthTable table;
std::string variables;
std::getline(variables);
for ( std::string equation; std::getline(file, equation); )
{
std::getline(file, equation);
// ...
}
If what I am seeing is right, the output from printf is the one that is not showing. In that case, either use
fflush(stdout);
Or better, just go with a std::cout for that line since you're writing it in C++ (using the std::flush technique, of course.)