D
Donald Canton
Hi,
I'm using Bjarne's book to learn C++ and am stuck on the Calc program
in Section 6. Everything works fine except when I try to use
istringstream to parse a token from the command line. I thought I
followed his instructions on page 118 correctly, but I can't get it to
compile without syntax errors in the get_token() function. The whole
program follows with the four syntax errors flagged with the text "//
SYNTAX ERROR". Thanks in advance.
#include <iostream> // I/O
#include <string> // strings
#include <map> // map
#include <cctype> // isalpha(), etc.
#include <sstream> // so that we can use "istringstream"
using namespace std;
istream* input; //pointer to input stream
enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
Token_value curr_tok = PRINT;
//function prototypes
map<string, double> table;
double expr(bool);
double term(bool);
double prim (bool);
Token_value get_token();
double error(const string&);
double expr(bool get) //add and subtract
{
double left = term(get);
for (; //"forever"
switch (curr_tok) {
case PLUS:
left += term(true);
break;
case MINUS:
left -= term(true);
break;
default:
return left;
}
}
double term(bool get) //multiply and divide
{
double left = prim(get);
for (;
switch (curr_tok) {
case MUL:
left *= prim(true);
break;
case DIV:
if (double d = prim(true)) {
left /= d;
break;
}
return error("divide by 0");
default:
return left;
}
}
double number_value;
string string_value;
double prim (bool get) //handle primaries
{
if (get) get_token();
switch (curr_tok) {
case NUMBER:
{ double v = number_value;
get_token();
return v;
}
case NAME:
{ double& v = table[string_value];
if (get_token() == ASSIGN) v = expr(true);
return v;
}
case MINUS: //unary minus
return -prim(true);
case LP:
{ double e = expr(true);
if (curr_tok != RP) return error("')' expected");
get_token(); //eat ')'
return e;
}
default:
return error("primary expected");
}
}
Token_value get_token()
{
char ch;
do { //skip whitespace except '\n'
if (!*input.get(ch)) return curr_tok=END; // SYNTAX ERROR
} while (ch != '\n' && isspace(ch));
switch (ch) {
case ';':
case '\n':
return curr_tok=PRINT;
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return curr_tok=Token_value(ch);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
*input.putback(ch); // SYNTAX ERROR
*input >> number_value;
return curr_tok=NUMBER;
default: //NAME, NAME=, or error
if (isalpha(ch)) {
string_value = ch;
while (*input.get(ch) && isalnum(ch)) // SYNTAX ERROR
string_value.push_back(ch);
*input.putback(ch); // SYNTAX ERROR
return curr_tok=NAME;
}
error("bad token");
return curr_tok=PRINT;
}
}
int no_of_errors;
double error(const string& s)
{
no_of_errors++;
cerr << "error:" << s << '\n';
return 1;
}
int main(int argc, char* argv[])
{
switch (argc) {
case 1:
input = &cin;
break;
case 2:
input = new istringstream(argv[1]);
break;
default:
error("too many arguments");
return 1;
}
table["pi"] = 3.1415926535897932384626433832795; //insert
predefined names
table["e"] = 2.7182818284590452353602874713527;
while (*input) {
get_token();
if (curr_tok==END) break;
if (curr_tok==PRINT) continue;
cout << expr(false) << '\n';
}
if (input != &cin) delete input;
return no_of_errors;
}
I'm using Bjarne's book to learn C++ and am stuck on the Calc program
in Section 6. Everything works fine except when I try to use
istringstream to parse a token from the command line. I thought I
followed his instructions on page 118 correctly, but I can't get it to
compile without syntax errors in the get_token() function. The whole
program follows with the four syntax errors flagged with the text "//
SYNTAX ERROR". Thanks in advance.
#include <iostream> // I/O
#include <string> // strings
#include <map> // map
#include <cctype> // isalpha(), etc.
#include <sstream> // so that we can use "istringstream"
using namespace std;
istream* input; //pointer to input stream
enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
Token_value curr_tok = PRINT;
//function prototypes
map<string, double> table;
double expr(bool);
double term(bool);
double prim (bool);
Token_value get_token();
double error(const string&);
double expr(bool get) //add and subtract
{
double left = term(get);
for (; //"forever"
switch (curr_tok) {
case PLUS:
left += term(true);
break;
case MINUS:
left -= term(true);
break;
default:
return left;
}
}
double term(bool get) //multiply and divide
{
double left = prim(get);
for (;
switch (curr_tok) {
case MUL:
left *= prim(true);
break;
case DIV:
if (double d = prim(true)) {
left /= d;
break;
}
return error("divide by 0");
default:
return left;
}
}
double number_value;
string string_value;
double prim (bool get) //handle primaries
{
if (get) get_token();
switch (curr_tok) {
case NUMBER:
{ double v = number_value;
get_token();
return v;
}
case NAME:
{ double& v = table[string_value];
if (get_token() == ASSIGN) v = expr(true);
return v;
}
case MINUS: //unary minus
return -prim(true);
case LP:
{ double e = expr(true);
if (curr_tok != RP) return error("')' expected");
get_token(); //eat ')'
return e;
}
default:
return error("primary expected");
}
}
Token_value get_token()
{
char ch;
do { //skip whitespace except '\n'
if (!*input.get(ch)) return curr_tok=END; // SYNTAX ERROR
} while (ch != '\n' && isspace(ch));
switch (ch) {
case ';':
case '\n':
return curr_tok=PRINT;
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return curr_tok=Token_value(ch);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
*input.putback(ch); // SYNTAX ERROR
*input >> number_value;
return curr_tok=NUMBER;
default: //NAME, NAME=, or error
if (isalpha(ch)) {
string_value = ch;
while (*input.get(ch) && isalnum(ch)) // SYNTAX ERROR
string_value.push_back(ch);
*input.putback(ch); // SYNTAX ERROR
return curr_tok=NAME;
}
error("bad token");
return curr_tok=PRINT;
}
}
int no_of_errors;
double error(const string& s)
{
no_of_errors++;
cerr << "error:" << s << '\n';
return 1;
}
int main(int argc, char* argv[])
{
switch (argc) {
case 1:
input = &cin;
break;
case 2:
input = new istringstream(argv[1]);
break;
default:
error("too many arguments");
return 1;
}
table["pi"] = 3.1415926535897932384626433832795; //insert
predefined names
table["e"] = 2.7182818284590452353602874713527;
while (*input) {
get_token();
if (curr_tok==END) break;
if (curr_tok==PRINT) continue;
cout << expr(false) << '\n';
}
if (input != &cin) delete input;
return no_of_errors;
}