Hi guys! I am reading "programming: principles and practice using c++" and I was following the exercises and I canĀ“t realy understand why when my input is, for ex: {(4+5)*6} / (3+4); I always get error:primary expected. Can anyone explain it to me?
//
// This is example code from Chapter 6.7 "Trying the second version" of
// "Software - Principles and Practice using C++" by Bjarne Stroustrup
//
#include "stdafx.h"
#include "../../std_lib_facilities.h"
//------------------------------------------------------------------------------
class Token{
public:
char kind; // what kind of token
double value; // for numbers: a value
Token(char ch) // make a Token from a char
:kind(ch), value(0) { }
Token(char ch, double val) // make a Token from a char and a double
:kind(ch), value(val) { }
};
//------------------------------------------------------------------------------
class Token_stream {
public:
Token_stream(); // make a Token_stream that reads from cin
Token get(); // get a Token (get() is defined elsewhere)
void putback(Token t); // put a Token back
private:
bool full; // is there a Token in the buffer?
Token buffer; // here is where we keep a Token put back using putback()
};
//------------------------------------------------------------------------------
// The constructor just sets full to indicate that the buffer is empty:
Token_stream::Token_stream()
:full(false), buffer(0) // no Token in buffer
{
}
//------------------------------------------------------------------------------
// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
if (full) error("putback() into a full buffer");
buffer = t; // copy t to buffer
full = true; // buffer is now full
}
//------------------------------------------------------------------------------
Token Token_stream::get()
{
if (full) { // do we already have a Token ready?
// remove token from buffer
full = false;
return buffer;
}
char ch;
cin >> ch; // note that >> skips whitespace (space, newline, tab, etc.)
switch (ch) {
case'=': // for "print"
case'x': // for "quit"
case'(': case')': case'+': case'-':
case'*': case'/': case'{': case'}':
return Token(ch); // let each character represent 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 input stream
double val;
cin >> val; // read a floating-point number
return Token('8', val); // let '8' represent "a number"
}
default:
error("Bad token");
}
}
//------------------------------------------------------------------------------
Token_stream ts; // provides get() and putback()
//------------------------------------------------------------------------------
double expression(); // declaration so that primary() can call expression()
//------------------------------------------------------------------------------
// deal with numbers and parentheses
double primary()
{
Token t = ts.get();
double d = 0;
switch (t.kind) {
case'{': // handle '{' expression '}'
d = expression();
t = ts.get();
if (t.kind != '}') error("'}' expected");
return d;
break;
case'(': // handle '(' expression ')'
d = expression();
t = ts.get();
if (t.kind != ')') error("')' expected");
return d;
break;
case'8': // we use '8' to represent a number
return t.value; // return the number's value
break;
default:
error("primary expected");
}
}
//------------------------------------------------------------------------------
// deal with *, /, and %
double term()
{
double left = primary();
Token t = ts.get(); // get the next token from token stream
while (true) {
switch (t.kind) {
case'*':
left *= primary();
t = ts.get();
case'/':
{
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}
default:
ts.putback(t); // put t back into the token stream
return left;
}
}
}
//------------------------------------------------------------------------------
// deal with + and -
double expression()
{
double left = term(); // read and evaluate a Term
Token t = ts.get(); // get the next token from token stream
while (true) {
switch (t.kind) {
case'+':
left += term(); // evaluate Term and add
t = ts.get();
break;
case'-':
left += term(); // evaluate Term and subtract
t = ts.get();
break;
default:
ts.putback(t); // put t back into the token stream
return left; // finally: no more + or -: return the answer
}
}
}
//------------------------------------------------------------------------------
int main()
try
{
double val = 0;
cout << "Welcome to our simple calculator.\nPlease enter expressions using floating - point numbers.\n";
while (cin) {
Token t = ts.get();
if (t.kind == 'x') break; // 'q' for quit
if (t.kind == '=') // ';' for "print now"
cout << "=" << val << '\n';
else
ts.putback(t);
val = expression();
}
keep_window_open();
}
catch (exception& e) {
cerr << "error: " << e.what() << '\n';
keep_window_open();
return 1;
}
catch (...) {
cerr << "Oops: unknown exception!\n";
keep_window_open();
return 2;
}
//------------------------------------------------------------------------------
You basically have two bugs that I found, and some quirks
1. After line 132, you forgot to add a break after the '*' case. Adding a break fixes your problem.
2. At line 162, you mistakenly add instead of subtract, replace += with -=
3. In the comments and the expression you posted, you use ';' for end of expression and print but in your code you use '=', similarly for 'x' and 'q'.
Not if you return in each case. In the term() function, however, you only return in the default, so you need to break for the other cases. Think of switch-case as just a bunch of labels, when you jump to a label, what happens ? You simply continue executing line-by-line, thus after you jump to the case 1, you'd go to the case 2, since it comes next, you need to explicitly 'break' out.
Some more suggestions:
1) Try writing good comments and readable code. This is a very important and difficult skill in on itself. Honestly, I had a lot of trouble understanding your calculator with a first glance even though it has a good deal of comments, but the code was small enough that I could read each line and understand what it *should* do.
It's not very clear how you are parsing, function names like "term()", "primary()" do not tell me much about what they return, what their purpose is without reading each line.
2) Try debugging yourself. Imagine you are an interpreter and run your program in your head, sequentially following the flow. This helps a lot and helps you solve most cases without even using a debugger. To isolate the region of fault try printing variables at different points and see where the internal state is corrupt.