I'm doing the exercises in Stroustrup's new book "Programming Principles and Practice Using C++" and was wondering if anyone on Stack Overflow has done them and is willing to share the knowledge?
Specifically about the calculator that's developed in Chap 6 and 7. For example, the questions about adding the !
operator and sqrt(), pow(), etc. I have done these, but I don't know if the solution I have is the "good" way of doing things, and there are no published solutions on Bjarne's website. I'd like to know if I am going down the right track. Maybe we can make a wiki for the exercises?
Basically I have a token parser. It reads a char at a time from cin. It's meant to tokenise expressions like 5*3+1 and it works great for that. One of the exercises is to add a sqrt() function. So I modified the tokenising code to detect "sqrt(" and then return a Token object representing sqrt. In this case I use the char 's'. Is this how others would do it? What if I need to implement sin()? The case statement would get messy.
char ch;
cin >> ch; // Note that >> skips whitespace (space, newline, tab, etc.)
switch (ch) {
case ';': // For "print"
case 'q': // For "quit"
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"
}
case 's':
{
char q, r, t, br;
cin >> q >> r >> t >> br;
if (q == 'q' && r == 'r' && t == 't' && br == '(') {
cin.putback('('); // Put back the bracket
return Token('s'); // Let 's' represent sqrt
}
}
default:
error("Bad token");
}
There are a few solutions posted on Stroustrup - Programming and more will be coming over time.
Try solving exercises only with the language features and the library facilities presented so far in the book -- real novice users can't do anything else. Then return later to see how a solution can be improved.
I thought a map of strings to function pointers might be a concise way to represent things like sqrt, sin, cos, etc. that take a single double and return a double:
map<std::string, double (*)(double)> funcs;
funcs["sqrt"] = &sqrt;
funcs["sin"] = &sin;
funcs["cos"] = &cos;
Then when the parser detects a correct string (str) it can call the function with an argument (arg
) like so:
double result = funcs[str](arg);
With this method, a single call can handle all cases of functions (of that type).
Actually I'm not sure if that's the correct syntax, can anyone confirm?
Does this seem like a usable method?
It is easier to work with derived classes and virtual functions: each specialized class reading its own input...
class base {
public:
virtual double calc() = 0;
};
class get_sqrt : public base {
int useless;
public:
virtual double calc() {
cin >> number;
return sqrt(number);
}
}
get_sqrt;
Now we organize these in a map, and we will only use their pointers:
map<string,base*> func;
func["sqrt"] = &get_sqrt;
There is also a specialized method which only looks at the next character: peek();
char c = cin.peek();
You can get rid of the switch by using 1 if putting !
, +
, -
, etc. in func
; (they should operate on left_param for simplicity):
if (c>='0' && c<='9')
cin >> right_param; // Get a number, you don't have to put the
// character back as it hasn't been removed
else {
string s;
cin >> s;
right_param = func[s]->calc();
}
So basically some kind of function pointers, but without the messy syntax and in which you could store data between calculations.
I thought about the whitespace problem; it can be added before it starts to compute, I also think there could be a way to set different separators, like numbers, but I don't know how.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With