ifstream

Pages: 12
can someone tell me why this isnt working?
a little bit of background to help. i am making a sort of language thats interpreted, not compiled down to source;

here is my if statement in main to see if thats the line:
1
2
3
4
5
6
7
8
9
10
11
12
13
					
else if(linePtr[0] == 'g' && linePtr[1] == 'o' && linePtr[2] == 't' && linePtr[3] == 'o')
{
        for(counter = 5; linePtr[counter] != ' '; counter++)
	{
	        label += linePtr[counter];
	}

	gotoLabel(parse, label, argv[1]);
}

else if(linePtr[0] == ':')
	continue;


here is the function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void gotoLabel(ifstream &parse, string label, char *filePath)
{
	string line;
	char *linePtr;

	parse.close();
	parse.open(filePath);

	while(!parse.eof())
	{
		getline(parse, line);
		linePtr = new char [line.size()+1];
		strcpy(linePtr, line.c_str());

		if(linePtr == label)
			break;
	}

}


my source file is
1
2
3
:a
print "Hello, world!"
goto :a


edit: the overall code compiles fine with no errors or warnings
it just prints Hello, world! once while it should act like a while loop
Last edited on
Why this:
1
2
3
4
		linePtr = new char [line.size()+1];
		strcpy(linePtr, line.c_str());

		if(linePtr == label)
and not this:
1
2
		std::string line2 = line;
		if(line2 == label)

Don't call open/close on fstreams. Don't test of eof on fstreams,
http://www.cplusplus.com/forum/general/77328/#msg416178
Last edited on
I suppose that you are passing a bad stream, In that case the open() will fail.
Use RAII, or better load all your file just one time.

Also, don't loop on eof() but on the reading operation
while( getline(parse, line) ){

By the way, ┬┐why the yo-yo code? there is no need for char *linePtr
im really new to pointers. i have tried to stay away from them but i need them i think to implement goto. if i post the whole source will you correct it for me?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <iostream>
#include <fstream>
#include <cmath>
#include <ctime>
#include <string>
#include <cstdlib>

using namespace std;

bool stdFile(string);
void gotoLabel(ifstream&, string, char*);

int main(int argc, char *argv[])
{
	if(argc > 2)
		cout<<"error 001: invalid number of arguements by "<< argc - 1 << endl;

	else
	{
		ifstream fileCheck, parse;

		fileCheck.open(argv[1]);

		if(fileCheck.fail())
			cout<<"error 002: invalid file path"<< endl;

		else
		{
			fileCheck.close();

			if(stdFile(argv[1]))
				cout<<"error 003: invalid file type"<< endl;

			else
			{
				string line, label;
				char *linePtr;
				int lineNum = 2;
				int counter;

				parse.open(argv[1]);

				while(!parse.eof())
				{
					label = "";
					lineNum++;

					getline(parse, line);
					linePtr = new char [line.size()+1];
					strcpy(linePtr, line.c_str());

					//if for print
					if(linePtr[0] == 'p' && linePtr[1] == 'r' && linePtr[2] == 'i' && linePtr[3] == 'n' && linePtr[4] == 't')
					{
						for(counter = 7; linePtr[counter] != '"'; counter++)
						{
							cout<< linePtr[counter];
						}

						cout<< endl;
					}

					//if for goto
					else if(linePtr[0] == 'g' && linePtr[1] == 'o' && linePtr[2] == 't' && linePtr[3] == 'o')
					{
						for(counter = 5; linePtr[counter] != ' '; counter++)
						{
							label += linePtr[counter];
						}

						gotoLabel(parse, label, argv[1]);
					}

					//if for :label
					else if(linePtr[0] == ':')
						continue;

					//if for newline
					else if(linePtr[0] == '\n')
						continue;

					//if for exit
					else if(linePtr[0] == 'e' && linePtr[1] == 'x' && linePtr[2] == 'i' && linePtr[3] == 't')
						exit(1);

					else
					{
						cout<<"error 004: line "<< lineNum <<": invalid command"<< endl;
						break;
					}
				}
			}
		}
	}
}

bool stdFile(string file)
{
	char *fileParse;
	int counter = file.size();

	fileParse = new char [file.size()+1];
	strcpy(fileParse, file.c_str());

	while(fileParse[counter] != '.')
	{
		counter -= 1;
	}

	if(fileParse[counter] == 's' && fileParse[counter + 1] == 'r' && fileParse[counter + 2] == 'c')
		return true;

	return false;
}

void gotoLabel(ifstream &parse, string label, char *filePath)
{
	string line;
    int counter;
	char *linePtr, *labelPtr;
	ifstream *parsePtr;

	parsePtr = &parse;

	parsePtr->close();
	parsePtr->open(filePath);

    labelPtr = new char [label.size() + 1];
    strcpy(labelPtr, label.c_str());

	while(!parsePtr->eof())
	{
		getline(parse, line);
		linePtr = new char [line.size()+1];

        for(counter == 0; linePtr[counter] == labelPtr[counter]; counter++) {}
	}
}
Can you describe what the program is doing?
its an interpreter for a language im trying to write.
I take it this function checks if the passed in string ends with .src.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool stdFile(string file)
{
	char *fileParse;
	int counter = file.size();

	fileParse = new char [file.size()+1];
	strcpy(fileParse, file.c_str());

	while(fileParse[counter] != '.')
	{
		counter -= 1;
	}

	if(fileParse[counter] == 's' && fileParse[counter + 1] == 'r' && fileParse[counter + 2] == 'c')
		return true;

	return false;
}
take a look at this alternative implementation:
1
2
3
4
5
6
7
8
9
bool stdFile(const string &file)
{
	if (const char* p = strrchr(file.c_str(), '.')) // find last dot
	{
		return strcmp(p, ".src") == 0;
	}

	return false;
}

As for parsing your code, I think you need a tokenizer. Stroustrup has an example of a calculator in all editions of his definitive book, The C++ Programming Language. It uses a recursive decent parser to evaluate the input. I suggest you stop coding and take a look at it before you go any further.
Last edited on
ok i have that book so ill look at it. can you explain line 3 and 5? thank you and i appreciate the help
strrchr() looks for the last occurrence of a character in a string, returns null if it's not found.
http://pubs.opengroup.org/onlinepubs/007908799/xsh/strrchr.html

strcmp() compares two strings, returns zero if they're the same.
http://pubs.opengroup.org/onlinepubs/007908799/xsh/strcmp.html

I pass the string in by const ref so there's no run-time cost in passing it.

I use strrchr to look for the last dot in the string. If it's found, I compare the string at that location with ".src". If the strings match, I return true. Otherwise I return false.
how do i test a part of string without turning it into a char array
edit: nvr mnd solved that.
Last edited on
so i have changed my code to what i think is more efficient in the form of
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include <cmath>
#include <ctime>
#include <cstdlib>

using namespace std;

bool stdFile(const string&);

int main(int argc, char* argv[])
{
	ifstream file;
	string line, label;
	int lineNum = 0, counter;

	file.open(argv[1]);

	if(file.fail())
		cerr<<"error 001: invalid file path\n";

	else
	{
		if(!stdFile(argv[1]))
			cerr<<"error 002: invalid file type\n";

		else
		{
			while(getline(file, line))
			{
				lineNum++;

				//print command
				if(line[0] == 'p' && line[1] == 'r' && line[2] == 'i' && line[3] == 'n' && line[4] == 't')
				{
					for(counter = 7; line[counter] != '"'; counter++)
					{
						cout<< line[counter];
					}

					cout<< endl;
				}

				//new line skip
				else if(line == "\n")
					continue;

				//label skip
				else if(line[0] == ':')
					continue;

				else if(line[0] == 'g' && line[1] == 'o' && line[2] == 't' && line[3] == 'o')
				{
					//get label
					for(counter = 5, label = ""; line[counter] != ' '; counter++)
					{
						label += line[counter];
					}

					file.close();
					file.open(argv[1]);

					while(getline(file, line))
					{
						if(line == label)
							break;
					}
				}

				else
					cerr<<"error "<< lineNum + 2 <<": line "<< lineNum <<": invalid command\n";
			}
		}
	}
}

bool stdFile(const string &file)
{
	if (const char* p = strrchr(file.c_str(), '.'))
	{
		return strcmp(p, ".src") == 0;
	}

	return false;
}


and the source is:
1
2
3
4
goto :a
print "This line was skipped"
:a
print "Hello, world!"


when i run it, it says Segmentation fault (core dumped). what am i doing wrong?
You're way too naive about the data present in line

On line 57: Either it contains a ' ' or crash

your permanently access indexes of line without knowing if that index is valid.

A line like
if(line[0] == 'p' && line[1] == 'r' && line[2] == 'i' && line[3] == 'n' && line[4] == 't')

should be improved like this:
if(line.substr(0, 4) == "print")

btw line 47 will never happens due to getline
ok thank you. this is really helpful. just one last question. how do i print from one " to the last "?
I've sort of hacked something together for you.

As you can see, there are clear handlers for commands goto and print, and support for labels, that is, enough to run your input script.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <string>
#include <istream>
#include <fstream>
#include <sstream>
#include <iostream>
#include <map>

struct Context
{
	typedef std::map<std::string, std::streamoff> label_type;

	Context() : tell(0) {}

	std::string line;
	std::streamoff tell;
	label_type labels;
};

bool read_token(std::istream &is, Context &ctx)
{
	ctx.tell = is.tellg();
	return std::getline(is, ctx.line) != 0;
}

int parse(std::istream& is)
{
	Context ctx;
	while (read_token(is, ctx))
	{
		std::string token;
		std::istringstream iss(ctx.line);
		if (iss >> token)
		{
			if (token == "print")
			{
				// trim quotes/spaces from text
				const char* begin = ctx.line.c_str() + token.size();
				const char* end = ctx.line.c_str() + ctx.line.size() - 1;
				while ((*end == ' ' || *end == '\"') && end > begin)
					--end;
				while ((*begin == ' '  || *begin == '\"') && begin < end)
					++begin;
				std::string str(begin, end - begin);

				// print text
				std::cout << str << std::endl;
			}
			else if (token[0] == ':')
			{
				ctx.labels.insert(std::make_pair(token, ctx.tell));
			}
			else if (token == "goto")
			{
				std::string label;
				iss >> label;

				Context::label_type::const_iterator p = ctx.labels.find(label);
				if (p != ctx.labels.end())
				{
					// we have the label, just jump to it
					is.seekg(p->second);
				}
				else
				{
					// we don't have the label, we'll have to search for it
					Context localctx;
					while (read_token(is, localctx))
					{
						std::string localtoken;
						std::istringstream iss(localctx.line);
						if (iss >> localtoken)
						{
							if (localtoken == label)
							{
								// found it
								is.seekg(localctx.tell);
								break;
							}
						}
					}

					if (!is)
					{
						// we didn't find the label
						std::cerr << "Cannot find label " << label << std::endl;
					}
				}
			}
		}
	}

	return 0;
}

int main(int argc, char* argv[])
{
	if (argc > 1)
	{
		std::ifstream script(argv[1]);
		parse(script);
	}

	return 0;
}
Last edited on
i appreciate the hack and i have some questions whats streamoff on line 10

edit: and context()?
Last edited on
when i compiled it it said that context wasnt declared
so i realized at work that i havent written a single line of code in the product so far. i have decided to scrap this for now and continue it once i have read the c++ programming language by bajarne stroustrop and have learned more. im sorry to waste your time and i appreciate your help
The goto is implemented by moving the read position of the input stream.

When a label is read, it makes a note of where it read it, the label name and the position in the stream (the streamoff). It stores these in a map<name, position>. Line 10 declares that map type, line 16 declares the variable of that type, and line 50 adds an entry to it.

When it sees a goto, it checks the labels seen so far. If it's not there, it reads forward until it finds it. When it finds it, it moves the streams' read position with seekg() to that position.
Last edited on
streamoff is this:
http://cplusplus.com/reference/iostream/streamoff/

context() doesn't exist. Be careful because C++ is case sensitive.Context() is the constructor that initializes tell to 0.

how do i print from one " to the last "?
The easiest way is the following:
1
2
3
size_t pos0 = line.find('"');
if(pos0 != string::npos)
  std::cout << line.substr(pos0, line.rfind('"'));


See:
http://cplusplus.com/reference/string/string/substr/
http://cplusplus.com/reference/string/string/find/
http://cplusplus.com/reference/string/string/rfind/

I'd suggest not to scrap this project. A book is one more source to find the required informations, but not a panacea.
If you want I'd show you a simplified version later
Pages: 12