views:

1448

answers:

5

I'm doing the exercises in Stroustrup's new book "Programming Principles and Practice Using C++" and was wondering if anyone on SO has done them and is willing to share the knowledge? Specifically about the calculator that's developed in Chap 6 and 7. Eg 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");
}
A: 

I would move the 'sqrt' detection into another method for function detection. Essentially, I would remove the 's' detection and add something inside the default case that would read the string up to a '('.

If no '(' is detected, then error.

If you successfully read a string, pass that to a function name parser that uses string compares to generate a token that represents a call to sqrt or sin or whatever function you like. The method that checks for the function names can also error if it reads a string that it doesn't recognize.

dominic hamon
Ok I'll try and implement this. That would separate out the function stuff nicely.
20th Century Boy
+6  A: 

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 useable method?

20th Century Boy
+3  A: 

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, we will only use their pointers:

map<string,base*> func;
func["sqrt"]=&get_sqrt;

there is also a specialized method witch only looks at the next character: peek();

char c=cin.peek();

you can get rid of the switch by using 1 if and putting ! + - ... 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 sintax and in witch you could store data between calculations.

edit: 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.

csiz
Nice. I knew there would be an OOP solution in there somewhere! But...the cin>>s wouldn't work because the expression could contain no whitespace i.e. 5+sqrt(144)/2. So still need to read a char at a time to check function name like sqrt, I think.
20th Century Boy
I think it should be peek, not peak! I wonder why Stroustrup didn't use this method, it seems more logical than get() and putback().
20th Century Boy
I refrained from using peek() to avoid introducing yet another new facility this early and (more importantly) because "stream with putback()" is a very general idea that can be used in many places - peek() involves someone else doing some buffering for you. Also, think of whitespace and error handling - what if there isn't a next character to peek at? I see peek() more as a "clever trick" than as a general technique.
Bjarne Stroustrup
Good point. That makes sense. BTW thanks for taking time to check out this thread, I feel privileged to have the author himself providing input!
20th Century Boy
+69  A: 

(1) There are now a few solutions posted on www.stroustrup.com/Programming and more will be coming over the summer

(2) Try solving exercise with only the language and library facilities presented so far in the book - real novice users can't do anything else - and then return later to see how a solution can be improved.

Bjarne Stroustrup
Yes I was kind of cheating with the map...it doesn't appear till later chapters. I am really enjoying the book by the way. I think the calculator might actually be useful in the real world, which is not something you can say about the samples presented in most introductory books.
20th Century Boy
Welcome to SO Bjarne
lothar
stroustrup.rep += 10;
Daniel Earwicker
+1, I consider it my honor to upvote you. :)
missingfaktor
A: 

20th Century Boy, can you share your drills from chapter 4? I can't fix 6th drill. I'm very novice for programming and learning it with Bjarne Stroustrup's book. Very like that book, but think that it would be better to have examples for drills. I know that there are exercise examples on Bjarnes' site, but sometimes it's even difficult to do drills.

5at5ish