read/write problem with 2d arrays

when i run the readEm and WritEm for state and action they both come back very wrong, i can't fit the whole driver program in here but the problem should be in the code below but i can't find it. Any help would be appreciated.
inputs and outputs below.

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

using namespace std;

const int maxState = 25;

enum stateType {newToken, resWord, variable, integer, real, delimiter, endState};
enum charType {letter, digit, period, delim, blank, pod, eoln, illegal, endChar};

template <typename x>
void swapEm(x& one, x& two)
{
	x temp;
	temp = one;
	one = two;
	two = temp;
}

stateType stringToState(string y)
{
	stateType ans = endState;
	if (y == "newtoken")
		ans = newToken;
	else if (y == "resword")
		ans = resWord;
	else if (y == "variable")
		ans = variable;
	else if (y == "integer")
		ans = integer;
	else if (y == "real")
		ans = real;
	else if (y == "delimiter")
		ans = delimiter;
	else
		ans = endState;
	return ans;
}

string stateToString(stateType state)
{
	string ans = "";
	if (state == newToken)
		ans = "newtoken";
	else if (state == resWord)
		ans = "resword";
	else if (state == variable)
		ans = "variable";
	else if (state == integer)
		ans = "integer";
	else if (state == real)
		ans = "real";
	else if (state == delimiter)
		ans = "delimiter";
	else
		ans = "Error Not valid";
	return ans;
}

charType StringtoCharType(string y)
{
	charType ans = endChar;
	if (y == "letter")
		ans = letter;
	else if (y == "digit")
		ans = digit;
	else if (y == "period")
		ans = period;
	else if (y == "delimiter")
		ans = delim;
	else if (y == "blank")
		ans = blank;
	else if (y == "pod")
		ans = pod;
	else if (y == "eoln")
		ans = eoln;
	else if (y == "illegal")
		ans = illegal;
	else
		ans = endChar;
	return ans;
}

string charTypeToString(charType c) {
	string ans = "";
	if (c == letter)
		ans = "Letter";
	else if (c == digit)
		ans = "Digit";
	else if (c == period)
		ans = "Period";
	else if (c == delim)
		ans = "Delimiter";
	else if (c == blank)
		ans = "Blank";
	else if (c == pod)
		ans = "POD";
	else if (c == eoln)
		ans = "EOLN";
	else if (c == illegal)
		ans = "Illegal";
	else
		ans = "Error Not Valid";
	return ans;
}

charType getChar(char ch)
{
	charType ct = endChar;
	char delimiter[] = { '+', '-', '*', '/', '=', '<', '>', '(', ')', ',', '.', '&', '^', '"' };
	if (ch >= 'a' && ch <= 'z')
		ct = letter;
	else if (ch >= '0' && ch <= '9')
		ct = digit;
	else if (ch == '.')
		ct = period;
	else if (ch == ' ')
		ct = blank;
	else if (ch == '$' || ch == '%')
		ct = pod;
	else if (ch == '|')
		ct = eoln;
	else 
	{
		for (int i = 0; i < 14; i++)
			if (ch == delimiter[i])
				ct = delim;
	}
	if (ct == endChar)
		ct = illegal;
	return ct;
}

void readEmAction(int action[endState][endChar]) 
{
	ifstream inf("action.dat");
	for (int i = newToken; i < endState; i++) 
	{
		for (int j = letter; j < endChar; j++) 
		{
			inf >> action[i][j];
		}
	}
}

void writeEmAction(ofstream& outf, int action[endState][endChar]) 
{
	outf << endl;
	outf << setw(50) << "Action Table" << endl;
	outf << setw(50) << "Character Classification" << endl;
	outf << setw(15) << " ";
	for (int j = letter; j < endChar; j++)
		outf << setw(10) << left << charTypeToString((charType)j);
	outf << endl;
	for (int i = 0; i < 150; i++)
		outf << "-";
	outf << endl;
	for (int i = newToken; i < endState; i++) 
	{
		if (i > 0)
			outf << endl << setw(10) << stateToString((stateType)i) << " |";
		else
			outf << setw(10) << stateToString((stateType)i) << " |";
		for (int j = letter; j < endChar; j++)
			outf << right << setw(9) << action[i][j];
	}
	outf << endl;
	for (int i = 0; i < 150; i++)
		outf << "-";
	outf << right << endl;

}

void readEmState(stateType FSM[endState][endChar]) 
{
	ifstream inf("state.dat");
	string st;
	for (int i = newToken; i < endState; i++) 
	{
		for (int j = letter; j < endChar; j++) 
		{
			inf >> st;
			FSM[i][j] = stringToState(st);
		}
	}
}

void writeEmState(ofstream& outf, stateType FSM[endState][endChar]) 
{
	outf << endl;
	outf << setw(45) << "State Table" << endl;
	outf << setw(51) << "Character Classification" << endl;
	outf << setw(13) << " ";
	for (int j = letter; j < endChar; j++)
		outf << setw(10) << left << charTypeToString((charType)j);
	outf << endl;
	for (int i = 0; i < 150; i++)
		outf << "-";
	outf << endl;
	for (int i = newToken; i < endState; i++) 
	{
		if (i > 0)
			outf << endl << setw(10) << left << stateToString((stateType)i) << " | ";
		else
			outf << setw(10) << stateToString(stateType(i)) << " | ";
		for (int j = letter; j < endChar; j++)
			outf << setw(10) << right << stateToString(FSM[i][j]);
	}
	outf << endl;
	for (int i = 0; i < 150; i++)
		outf << "-";
	outf << right << endl;
	outf << right;
}


}


state.dat
1
2
3
4
5
6
Reserved Word   integer    New Token   Delimiter   New Token   New Token   New Token   New Token
Reserved word   variable   New Token   Delimiter   New Token   New Token   New Token   New Token
Variable        Variable   New Token   Delimiter   New Token   New Token   New Token   New Token
Reserved Word   Integer    Real        Delimiter   New Token   New Token   New Token   New Token
Reserved Word   Real       New Token   Delimiter   New Token   New Token   New Token   New Token
Reserved Word   Integer    New Token   New Token   New Token   New Token   New Token   New token


action.dat
1
2
3
4
5
6
1 1 5 1  6 5  6 7
1 1 4 8  2 10 2 11
1 1 4 9  3 12 3 13
9 1 1 9  3 4  3 13
9 1 4 9  3 4  3 13
9 9 4 12 3 4  3 13


output.ot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
                                  State Table
                           Character Classification
             Letter    Digit     Period    Delimiter Blank     POD       EOLN      Illegal   
newtoken   | Error Not validError Not valid   integerError Not validError Not validError Not validError Not validError Not valid
resword    | Error Not validError Not validError Not validError Not validError Not validError Not validError Not validError Not valid
variable   |   variableError Not validError Not validError Not validError Not validError Not validError Not validError Not valid
integer    | Error Not validError Not validError Not validError Not validError Not validError Not validError Not validError Not valid
real       | Error Not validError Not validError Not validError Not validError Not validError Not validError Not validError Not valid
delimiter  | Error Not validError Not validError Not validError Not validError Not validError Not validError Not validError Not valid
------------------------------------------------------------------------------------------------------------------------------------------------------

                                      Action Table
                          Character Classification
               Letter    Digit     Period    Delimiter Blank     POD       EOLN      Illegal   
------------------------------------------------------------------------------------------------------------------------------------------------------
newtoken   |-858993460-858993460-858993460-858993460-858993460-858993460-858993460-858993460
   resword |-858993460-858993460-858993460-858993460-858993460-858993460-858993460-858993460
  variable |-858993460-858993460-858993460-858993460-858993460-858993460-858993460-858993460
   integer |-858993460-858993460-858993460-858993460-858993460-858993460-858993460-858993460
      real |-858993460-858993460-858993460-858993460-858993460-858993460-858993460-858993460
 delimiter |-858993460-858993460-858993460-858993460-858993460-858993460-858993460-858993460
------------------------------------------------------------------------------------------------------------------------------------------------------
Without the chance to test I would say that the code you provide looks ok. It rather seems that something goes wrong when the data is transported. I.e. it looks like that you don't pass the read data to the write functions. Instead it seems you pass uninitialized/invalid data.
Hello TheJast,

but the problem should be in the code below but i can't find it.
It is very possible the the problem starts in the code that you have not shown.

With out "main" the program can not be compiled or run. Now is the time to run the program to see what it is doing.

I do have one question. On lines 138 and 178 you define a file stream and open a file, but how do you know it is open and ready to use. The open can fail, but the rest of the function would continue just not being able to read anything.

Most times it is best to post a complete program that can be compiled and run.

Hope that helps,

Andy
Hello TheJast,

Sorry this took me longer than I expected.

Working with the program I did change some things around.

To start with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <iomanip>
#include <string>

#include <fstream>
#include <chrono> // <--- Optional.
#include <thread> // <--- Optional.

using namespace std;  // <--- Best not to use.
// A recent post that is worth reading. http://www.cplusplus.com/forum/beginner/258335/

enum stateType { newToken, resWord, variable, integer, real, delimiter, endState };
enum charType { letter, digit, period, delim, blank, pod, eoln, illegal, endChar };

constexpr int ROW{ 6 };  // Or constexpr int ROW{ endState };
constexpr int COL{ 8 };  // Or constexpr int COL{ endChar};
// <--- I would suggest using the uncommented part.

const std::string ACTION_HEADINGS{ "  Letter    Digit   Period  Delimiter  Blank     POD     EOLN    Illegal" };
const std::string STATE_HEADINGS{ "    Letter    Digit    Period  Delimiter    Blank     POD       EOLN    Illegal" };

template <typename x>

At the moment I do not see any problem with "enum"s, but I am not making use of all the functions.

I would prefer using lines 15 and 16 when dealing with arrays. If anything in the "enum"s change it will affect the arrays and other parts of the program,

Lines 19 and 20 Your program uses a for loop and the loop counter to call a function to change a number into a word. This is nice, but the "setw" in the for loop does not allow for the best positioning of the heading. These lines allow the adjustment of the headings as needed by varying the spaces between words.

The "readEmAction" function for the most part works fine as best as I can tell although I did change some of it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void readEmAction(int action[ROW][COL])
{
	const std::string inFileName{ "action.dat" };

	std::ifstream inFile(inFileName);

	if (!inFile)
	{
		std::cout << "\n File " << std::quoted(inFileName) << " did not open" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(3));  // <--- Needs header files chrono" and "thread". Optional as is the header files.
		/*return 1;*/  exit(1);  // If not in "main".
	}

	for (int row = 0; row < ROW; row++)
	{
		for (int col = 0; col < COL; col++)
		{
			inFile >> action[row][col];
		}
	}
}

Lines 3 - 12 I added. When dealing with an input file you need to check that the file stream is open and usable before you proceed. Otherwise you could reach the for loops and it would not be able to read from the file, but still store something in the array. Depending on which C++ standard you are using will determine what is stored in the array. Either way it would be something that you do not want.

Notice how I used "row", "ROW", "col" and "COL" in the function. What you started with works, but this makes it easier to read and understand. You do not have to change what you have since it works, but keep this in mind for the future.

I set "row" and "col" to (0) zero because if the "enum" changes this could be off and not what you want. I do give you credit for what you were thinking about.

One last note: Line 11. Notice how there are two choices. Use "return" if this is used in "main" and "exit" if used in a function since "return" would return from the function back to where the function was called from. Also (0) zero means that there was no problem and it is a normal return. Any number greater than (0)zero means that there is a problem. Using different numbers greater than (0) zero can help to track down where the problem is.

"std::quoted" is from the "<iomanip>" header file. This is a function that is not mentioned very often and you only learn about it when someone uses it or tells you about it. All it does is put double quotes around whatever is in the (). This could be a variable or a string in quotes.

The "writeEmAction" function I did this way:
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
void writeEmAction(int action[ROW][COL])
{
	std::string outFileName{ "Action Out.txt" };

	std::ofstream outFile(outFileName);

	if (!outFile)
	{
		std::cout << "\n File " << std::quoted(outFileName) << " did not open" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(3));  // <--- Needs header files chrono" and "thread". Optional as is the header files.
		/*return 1;*/  exit(3);  // If not in "main".
	}

	outFile << endl;
	outFile << std::string(46 - 6, ' ') << "Action Table\n";
	outFile << std::string(46 - 12, ' ') << "Character Classification\n";
	outFile << std::string(92, '-') << '\n' << std::endl; 

	outFile << setw(15) << " ";
	outFile << ACTION_HEADINGS;

	outFile << right << endl; // <--- "right" only needs done once.
	//std::cout << right << endl; // <--- Used for testing. Comment or remove when finished.

	outFile << std::string(92,'-') << endl;

	for (int row = 0; row < ROW; row++)
	{
		if (row > 0)
		{
			outFile << endl << setw(10) << stateToString((stateType)row) << " |";
			//std::cout << endl << setw(10) << stateToString((stateType)i) << " |"; // <--- Used for testing. Comment or remove when finished.
		}
		else
		{
			outFile << setw(10) << stateToString((stateType)row) << " |";
			//std::cout << setw(10) << stateToString((stateType)i) << " |"; // <--- Used for testing. Comment or remove when finished.
		}

		for (int col = 0; col < COL; col++)
		{
			outFile << /*right <<*/ setw(9) << action[row][col];
			//std::cout << right << setw(9) << action[i][j]; // <--- Used for testing. Comment or remove when finished.
		}
	}

	outFile << endl;

	outFile << std::string(92, '-') << /*right <<*/ endl;
}

The lines 3 - 12 are not as necessary for the output file stream as it is for the input file stream. When opening an output stream if the file does not exist it will be created. Should you use a path to the file then these line have more use.

In lines 15 and 16 the "std::string(46 - 6, ' ')" is a way to center the string that follows. the 46 is based on using a width or line length of 92 and dividing this by 2. The 6 is the length of the string divided by 2. In the end the first parameter is how many characters to put in the string and the second parameter is what character to print. I have found this to be the easiest way to print spaces to position something on the screen.

Line 17 replaces your for loop and prints 92 "-" on the screen.

Line 20 replaces your for loop which is not adjustable with a string that you can adjust as needed.

Lines 32, 37 and 43 as the comment says I used when first testing the program. You can comment the lines as I did or delete them if you do not need them. to the compiles a commented line is not included in the object code that is generated.

Line 22 I used "right" here. You only need to do this once and it affects every "setw()" until it is changes. No need to do "left" or "right" every time you think that you need it.

There is something to get you started. Understand this is only a suggestion and not something that you have to do. Some of the concepts are worth understanding.

I will deal with the "readEmState" next as I am running out of room here.

Hope that helps,

Andy
Hello TheJast,

For your function "readEmState" this is where you have problems.

Given the first line of the file:

Reserved Word integer New Token Delimiter New Token New Token New Token New Token


And given your for loops:
1
2
3
4
5
6
7
8
for (int i = newToken; i < endState; i++) 
	{
		for (int j = letter; j < endChar; j++) 
		{
			inf >> st;
			FSM[i][j] = stringToState(st);
		}
	}

This is what it is doing.

The formatted input of "inf >> st;" will read until it finds a white space, and this could be something other than a space bar press, or a new line whichever comes first. So "inf >> st;" reads "Reserved " and discards the space then you call the "stringToState" function where your next problem starts.

In "stringToState" you are trying to compare "Reserved" to "resword". This will never match and always return false. So when you return to the "readEmState" function you will be storing the wrong number in the array.

On the next iteration of the loop you read "Word" and then try to process it storing the wrong number in the array.

On the third iteration of the loop you read "integer" which does have a match in the "stringToState" function and stores the correct value in the array.

I could go on, but you should get the idea.

The other thing the inner for loop is doing is this:
Reserved Word integer New Token Delimiter New Token / New Token New Token New Token
It is reading each word up to the "/", (only there for reference), then the outer loop increases by one and the inner loop is repeated. reading from what follows the "/". This is not what you want.

The questions I have is if "Reserved" and "Word" along with "new" and "token" are to be considered as one word or two? And is the input file set and unchangeable or can you change it?

For the moment I solved the problem by reading the file and if the word read is "Reserved" or "New" then read another word and add it to the original. This way you are sending "Reserved Word" or New Token" to the "stringToState" function and then by changing the "stringToState" function it will return the correct answer to store in the array.

With the "stringToState" function I did this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
stateType stringToState(string word)
{
	stateType ans = endState;

	if (word == "New Token")
		ans = newToken;
	else if (word == "Reserved Word")
		ans = resWord;
	else if (word == "Variable")
		ans = variable;
	else if (word == "Integer")
		ans = integer;
	else if (word == "Real")
		ans = real;
	else if (word == "Delimiter")
		ans = delimiter;
	else
		ans = endState;

	return ans;
}

Changing "y" to "word" makes more sense when reading the code.

And in the read function I did this:
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
void readEmState(stateType FSM[ROW][COL])
{
	string word, word2;
	std::string inFileName{ "state.dat" };

	std::ifstream inFile(inFileName);

	if (!inFile)
	{
		std::cout << "\n File " << std::quoted(inFileName) << " did not open" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(3));  // <--- Needs header files chrono" and "thread".
		/*return 1;*/  exit(2);  // If not in "main".
	}

	for (int i = newToken; i < ROW; i++)
	{
		for (int j = letter; j < COL; j++)
		{
			inFile >> word;

			if (word == "Reserved" || word == "New")
			{
				inFile >> word2;

				word += ' ' + word2;
			}

			FSM[i][j] = stringToState(word);
		}
	}
}

By changing "st" to "word" it helps to comprehend what is happening. Reading a "word" makes more sense than reading a "st".

When I read and combines the words "Reserved" and "Word" into one word and the same with "New" and "Token" the function filled the array properly. I say properly based on if I understand things correctly.

If I have this correct the write functions produced these files:


                                        Action Table
                                  Character Classification
--------------------------------------------------------------------------------------------

                 Letter    Digit   Period  Delimiter  Blank     POD     EOLN    Illegal
--------------------------------------------------------------------------------------------
  newtoken |        1        1        5        1        6        5        6        7
   resword |        1        1        4        8        2       10        2       11
  variable |        1        1        4        9        3       12        3       13
   integer |        9        1        1        9        3        4        3       13
      real |        9        1        4        9        3        4        3       13
 delimiter |        9        9        4       12        3        4        3       13
--------------------------------------------------------------------------------------------



                                        State Table
                                  Character Classification
---------------------------------------------------------------------------------------------

                 Letter    Digit    Period  Delimiter    Blank     POD       EOLN    Illegal
---------------------------------------------------------------------------------------------
  newtoken |    resword   integer  newtoken delimiter  newtoken  newtoken  newtoken  newtoken
   resword |    resword  variable  newtoken delimiter  newtoken  newtoken  newtoken  newtoken
  variable |   variable  variable  newtoken delimiter  newtoken  newtoken  newtoken  newtoken
   integer |    resword   integer      real delimiter  newtoken  newtoken  newtoken  newtoken
      real |    resword      real  newtoken delimiter  newtoken  newtoken  newtoken  newtoken
 delimiter |    resword   integer  newtoken  newtoken  newtoken  newtoken  newtoken  newtoken
---------------------------------------------------------------------------------------------



I have the feeling that I missed something. Any questions let me know.

Hope that helps,

Andy
Andy Notice my pm
Topic archived. No new replies allowed.