reading a string in backwards

im trying to add exponents (represented by a ^) to a console calculator. i can easily get the exponent, but the base is tricky. i have to go back and get the all the digits before the ^ that arent a normal operator. i will store this in expo. (of course once i get this i will i have to flip it but i havent gotten there yet) for some reason however i keep getting 0 instead of the flipped base.
heres my code (if you dont want to read it all pay attention to lines 90-93, 107-128 and 143-148) thank you!!!
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
#include <iostream>
#include <cstdlib>
#include <cctype>
using std::cin;
using std::cout;
using std::endl;

void eatspaces(char* str);
double expr(char* str);
double exponent(char* str, int& index);
double term(char* str, int& index);
double number(char* str, int& index);
char* extract(char* str, int& index);

const int MAX = 80;

int main(void)
{
	char  buffer[MAX] = { 0 };
	
	cout << endl
		<< "Welcome to your friendly calculator."
		<< endl 
		<<"Enter an expression, or an empty line to quit."
		<< endl;

	for(;;)
	{
		cin.getline(buffer, sizeof buffer);
		eatspaces(buffer);

		if(!buffer[0])
			return 0;

		cout << "\t= " << expr(buffer) 
			<< endl << endl;
	}
}

void eatspaces(char* str)
{
	int i = 0;
	int j = 0;

	while((*(str + i) = *(str + j++)) != '\0')
		if (*(str + i) != ' ')
			i++;
	return;
}

double expr(char* str)
{
	double value = 0.0;
	int index = 0;

	value = term(str, index);

	for(;;)
	{
		switch(*(str + index++))
		{
		case '\0':
			return value;
		case '+':
			value += term(str, index);
			break;
		case '-':
			value -= term(str, index);
			break;
		default:
			cout << endl
				<< "Arrrgh!*#!! There's an error"
				<< endl;
			
			cout << str << endl;
			for (; index > 1; index--)
				cout << " ";
			cout << "^" << endl;
			exit(1);
		}
	}
}

double term(char* str, int& index)
{
	double value = 0.0;

	value = number(str, index);

	if(*(str + index) == '^')
	{
		number(str, index);
	}

	while((*(str + index) == '*') || (*(str + index) == '/'))
	{
		if(*(str + index) == '*')
			value *= number(str, ++index);

		if (*(str + index) == '/')
			value /= number(str, ++index);
	}
	
	return value;
}

double exponent(char* str, int& index, double exponentiate)
{
	double value = 0.0;
	int expo = 0;
	int copyindex = index;
	int subtractor = 1;
	while(*(str + copyindex) != '^')
	{
		copyindex--;
	}
	copyindex++;

	while(isdigit((*(str + copyindex) - subtractor)))
	{
		expo *= 10;
		expo += (*(str + copyindex) - subtractor) - '0';
		subtractor++;
	}

	cout << expo << endl;
	return value;
}

double number(char* str, int& index)
{
	double value = 0.0;

	if (*(str + index) == '(')
	{
		char* psubstr = 0;
		psubstr = extract(str, ++index);
		value = expr(psubstr);
		delete[] psubstr;
		return value;
	}

	if(*(str + index) == '^')
	{
		double exponentiate = number(str, ++index);
		double value = exponent(str, index, exponentiate);
		return value;
	}

	while(isdigit(*(str + index)))
		value = 10 * value + (*(str + index++) - '0');

	if(*(str + index) != '.')
		return value;
	
	double factor = 1.0;
	while(isdigit(*(str + (++index))))
	{
		factor *= .1;
		value = value + (*(str + index) - '0');
	}

	return value;
}

char* extract(char* str, int& index)
{
	char buffer[MAX];
	char* pstr = 0;
	int numL = 0;
	int bufindex = index;

	do
	{
		buffer[index - bufindex] = *(str + index);
		switch(buffer[index - bufindex])
		{
		case ')':
			if (numL == 0)
			{
				buffer[index - bufindex] = '\0';
				index++;
				pstr = new char[index - bufindex];
				if(!pstr)
				{
					cout << "Memory allocation failed,"
						<< " program terminated.";
					exit(1);
				}
				strcpy_s(pstr, index-bufindex, buffer);
				return pstr;
			}
			else
			{
				numL--;
				break;
			}
		case '(':
			numL++;
			break;
		}
	} while(*(str + index++) != '\0');

	cout << "Ran off the end of the expression, must be bad input."
		<< endl;
	exit(1);
	return pstr;
}
Hand-written parsers can be a real ***** to debug - I highly recommend that you step through your code with a debugger.

Alternative? Using your brain as the debugger stepping through your code (what you are asking us to do) - this is much harder (for most people - at least for me)!

Also recommended: setting up as many test cases for your parser as you can. That way, you can ensure that you have not broken anything as you modify your grammar.
I don't understand by what you mean by "flipping" it
GodPyro actually brings up an interesting point: think carefully about how term() and expr() are structured for arithmetic operators.

How is exponent the same or different?

In other words, what makes exponent so special that you need to "flip" anything? Aren't the term() and expr() parsers being done without any sort of flipping?
what i mean by flipping it is that if im reading the number from back to front i have to flip it.

if the number is 1234 im starting from the back so it is read in as 4321. i have no choice but to read it from the back because i only know i have an exponent when the ^ operator is found. however at this point the index variable will be past the base, so i store the index in copyindex and then essentially rewind copyindex to where the exponent was found. then from there i have to get the base.
But doesn't ^ use infix notation just like + - * / ?

Unless I'm mis-understanding something, you have:
A + B
A - B
A * B
A / B
A ^ B

If this is true, you should be able to use the same/similar parsing algorithms for ^ as exists for + - * /

Re-use working code as much as you can.
haha that makes far more sense than all the complicated crap i was doing, but i still wont have access to the base :o
Look at Line 88,

value = number(str, index);

Isn't value A in A + B or A - B?

Isn't A the base for A ^ B?

As I understand it, value represents the what's on the left hand side of your operator (A) while

number(str, ++index);

on lines 98 and 101 represent what's on the right hand side of your operator (B).
kfmfe04 i love you so much it is unbeliavable. works now :)
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
#include <iostream>
#include <cstdlib>
#include <cctype>
using std::cin;
using std::cout;
using std::endl;

void eatspaces(char* str);
double expr(char* str);
double findBase(char* str, int index);
double term(char* str, int& index);
double number(char* str, int& index);
char* extract(char* str, int& index);
double squareRoot(double radical);

const int MAX = 80;

int main(void)
{
	char  buffer[MAX] = { 0 };
	
	cout << "Welcome to your friendly calculator."
		<< endl 
		<<"Enter an expression, or an empty line to quit."
		<< endl;
	cout << "+ = addition" << endl
		<< "- = subtraction" << endl
		<< "* = multiplication" << endl
		<< "/ = division" << endl
		<< "^ = exponents" << endl
		<< "( ) = parantheses" << endl;

	for(;;)
	{
		cin.getline(buffer, sizeof(buffer));
		eatspaces(buffer);

		if(!buffer[0])
		{
			return 0;
		}

		cout << "\t= " << expr(buffer) 
			<< endl << endl;
	}
}

void eatspaces(char* str)
{
	int i = 0;
	int j = 0;

	while((*(str + i) = *(str + j++)) != '\0')
		if (*(str + i) != ' ')
			i++;
	return;
}

double expr(char* str)
{
	double value = 0.0;
	int index = 0;

	value = term(str, index);

	for(;;)
	{
		switch(*(str + index++))
		{
		case '\0':
			return value;
		case '+':
			value += term(str, index);
			break;
		case '-':
			value -= term(str, index);
			break;
		default:
			cout << endl
				<< "Error at index " 
				<< index << endl;
			
			cout << str << endl;
			for (; index > 1; index--)
				cout << " ";
			cout << "^" << endl;
			exit(1);
		}
	}
}

double term(char* str, int& index)
{
	double value = 0.0;

	value = number(str, index);

	if (*(str + index) == '^')
	{
		int copyindex = index - 1;
		while(isdigit(*(str + copyindex)) && copyindex != 0)
				copyindex--;
					
		double base = number(str, (copyindex == 0) ? copyindex : ++copyindex);
		double exponent = number(str, ++index);
		double exponentiated = 0.0;

		for (; exponent > 1; exponent--)
		{
			value *= base;
		}
	}

	while((*(str + index) == '*') || (*(str + index) == '/'))
	{
		if(*(str + index) == '*')
			value *= number(str, ++index);

		if (*(str + index) == '/')
			value /= number(str, ++index);
	}
	
	return value;
}

double number(char* str, int& index)
{
	double value = 0.0;

	if (*(str + index) == '(')
	{
		char* psubstr = 0;
		psubstr = extract(str, ++index);
		value = expr(psubstr);
		delete[] psubstr;
		return value;
	}

	while(isdigit(*(str + index)))
		value = 10 * value + (*(str + index++) - '0');

	if(*(str + index) != '.')
		return value;
	
	double factor = 1.0;
	while(isdigit(*(str + (++index))))
	{
		factor *= .1;
		value = value + (*(str + index) - '0');
	}

	return value;
}

double squareRoot(double radical)
{
	for (int i = 0; i < radical / 2; i++)
	{
		if (i * i == radical)
			return i;
	}
}

char* extract(char* str, int& index)
{
	char buffer[MAX];
	char* pstr = 0;
	int numL = 0;
	int bufindex = index;

	do
	{
		buffer[index - bufindex] = *(str + index);
		switch(buffer[index - bufindex])
		{
		case ')':
			if (numL == 0)
			{
				buffer[index - bufindex] = '\0';
				index++;
				pstr = new char[index - bufindex];
				if(!pstr)
				{
					cout << "Memory allocation failed,"
						<< " program terminated.";
					exit(1);
				}
				strcpy_s(pstr, index-bufindex, buffer);
				return pstr;
			}
			else
			{
				numL--; 
				break;
			}
		case '(':
			numL++;
			break;
		}
	} while(*(str + index++) != '\0');

	cout << "Ran off the end of the expression, must be bad input."
		<< endl;
	exit(1);
	return pstr;
}
Last edited on
Great! I'm happy that you learned something new.

Oh, and one other thing - I suspect when you get beyond calculators, you will eventually want to create your own language/grammars. When you do that, you should learn a little about BNF:

http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form

In the olden days, we used to use lex/yacc to write our grammars, but there are much better tools for that these days, for creating domain-specific languages (DSL):

http://en.wikipedia.org/wiki/Domain-specific_language

Or you can just use your knowledge to write your own compilers and interpreters - maybe of a language of your own design.

Good luck.

Last edited on
haha someday, but as you pointed out im still on calculators xD
Topic archived. No new replies allowed.