OK, this provides a few more clues to the problem. The problem output line
is,
=nan
This is generated by the line,
void calculate()
{
while (cin)
try {
//...
cout << result << statement() << endl;
} catch (exception& e)
{
//...
}
}
So the problem is the output from statement. The function returns a double
and the value being returned is "not a number" (nan). If you have your
debugger working, you should step through the code in statement and examine
the return value. You should then step into the functions as they are called
to determine which one is causing the problem.
If you can't debug you can add debug output statements to the code to trace
the execution,
Adding debug statements to output productions,
double statement()
{
Token t = ts.get();
switch (t.kind)
{
case let:
cerr << "statement -> declaration" << endl;
return declaration();
default:
ts.putback(t);
cerr << "statement -> expression" << endl;
return expression();
}
}
double expression()
{
double left = term();
Token t = ts.get();
while (true)
{
switch (t.kind)
{
case '+':
cerr << "expression -> term + term" << endl;
left += term();
t = ts.get();
break;
case '-':
cerr << "expression -> term - term" << endl;
left -= term();
t = ts.get();
break;
default:
cerr << "expression -> term" << endl;
ts.putback(t);
return left;
}
}
}
double term()
{
double left = primary();
Token t = ts.get();
while (true)
{
switch (t.kind)
{
case '*':
{
cerr << "term -> primary * primary" << endl;
left *= primary();
t = ts.get();
break;
}
case '/':
{
cerr << "term -> primary / primary" << endl;
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}
case '%':
{
cerr << "term -> primary % primary" << endl;
double d = primary();
int i1 = int(left);
if (i1 != left) error("left-hand operand of % not int");
int i2 = int(d);
if (i2 != d) error("right-hand operand of % not int");
if (i2 == 0) error("%: divide by zero");
left = i1 % i2;
t = ts.get();
break;
}
default:
cerr << "term -> primary" << endl;
ts.putback(t); //put back into the Token stream
return left;
}
}
}
double primary()
{
Token t = ts.get();
switch (t.kind)
{
case'(':
{
cerr << "primary -> (expression)" << endl;
double d = expression();
t = ts.get();
if (t.kind != ')') error("')' expected");
return d;
}
case number:
cerr << "primary -> number" << endl;
return t.value;
case '-':
cerr << "primary -> -primary" << endl;
return -primary();
case '+':
cerr << "primary -> +primary" << endl;
return primary();
case name:
cerr << "primary -> name" << endl;
return get_value(
t.name);
default:
error("primary expected");
}
}
This produces the output,
>1+2;
statement -> expression
primary -> number
term -> primary
expression -> term + term
primary -> number
term -> primary
expression -> term
=3
>
Finally, add one more debug aide to output the tokens as they are returned
from Token_stream::get(),
void dump_token(Token token)
{
cout << "Token(" << token.kind
<< ", " << token.value
<< ", " <<
token.name
<< ")" << endl;
}
Token Token_stream::get() //read characters from cin and compose a token
{
if (full) { //remove Token from buffer
full = false;
dump_token(buffer);
return buffer;
}
char ch;
cin >> ch;
switch(ch)
{
case print://for print
case quit://for quit
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
case '%':
case '=':
dump_token(Token(ch));
return Token(ch); //let each character represnt itself
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch);//put digit back into the digit stream
double val;
cin >> val;
dump_token(Token(number,val));
return Token(number,val);
}
default:
// tfm: where does this come from?
if (isalpha(ch)) {
string s;
s += ch;
while (cin.get(ch) && (isalpha(ch) || isdigit(ch)))
s += ch;
cin.putback(ch);
if (s == declkey) return Token(let); //declaration keyword
dump_token(Token(name,s));
return Token(name,s);
}
error("Bad token");
}
}
This should give the output,
>1+2;
Token(8, 1, ) // read by calculate
Token(8, 1, ) // by statement
statement -> expression
Token(8, 1, ) // by primary
primary -> number
Token(+, 0, ) // by term
term -> primary
Token(+, 0, ) // by expression
expression -> term + term
Token(8, 2, ) // by primary
primary -> number
Token(;, 0, ) // by term
term -> primary
Token(;, 0, ) // by expression
expression -> term
=3
>Token(;, 0, ) // by calculate
q
Token(q, 0, ) // by calculate
This should point to the culprit. Since my copy of your code works, I would
suspect there is some code difference, so re-check the code. Otherwise, the
output statements should identify the problem.