Feed a few such “problematic” expressions to the calculator and try to figure out in how many ways you can get it to misbehave. Can you get it to crash, that is, to get it past our error handling and give a machine error? We don’t think you can. Can you get it to exit without a useful error message? You can.
Starting from the file calculator08buggy.cpp, get the calculator to compile.
Go through the entire program and add appropriate comments.
As you commented, you found errors (deviously inserted especially for you to find). Fix them; they are not in the text of the book.
Testing: prepare a set of inputs and use them to test the calculator. Is your list pretty complete? What should you look for? Include negative values, 0, very small, very large, and “silly” inputs.
Do the testing and fix any bugs that you missed when you commented.
Add a predefined name k meaning 1000.
Give the user a square root function sqrt(), for example, sqrt(2+6.7). Naturally, the value of sqrt(x) is the square root of x; for example, sqrt(9) is 3. Use the standard-library sqrt() function to implement that calculator sqrt(). Remember to update the comments, including the grammar.
Catch attempts to take the square root of a negative number and print an appropriate error message.
Allow the user to use pow(x,i) to mean “Multiply x with itself i times”; for example, pow(2.5,3) is 2.5*2.5*2.5. Require i to be an integer using the technique we used for % (§6.5).
Change the “declaration keyword” from let to #.
Change the “quit keyword” from quit to exit. That will involve defining a string for quit just as we did for let in §6.8.2.
What is the purpose of working on the program after the first version works? Give a list of reasons.
Why does 1+2; q typed into the calculator not quit after it receives an error?
Why did we choose to make a constant character called number?
We split main() into two separate functions. What does the new function do and why did we split main()?
Why do we split code into multiple functions? State principles.
What is the purpose of commenting?
What is the use of symbolic constants?
Why do we care about code layout?
How do we handle % (remainder) of floating-point numbers?
What does is_declared() do and how does it work?
The input representation for let is more than one character. How is it accepted as a single token in the modified code?
What are the rules for what names can and cannot be in a calculator program?
Why is it a good idea to build a program incrementally?
When do you start to test?
When do you retest?
How do you decide what should be a separate function?
How do you choose names for variables and functions? List possible reasons.
What should be in comments and what should not?
When do we consider a program finished?
Allow underscores in the calculator’s variable names.
Provide an assignment operator, =, so that you can change the value of a variable after you have introduced it using let. Discuss why that can be useful and how it can be a source of problems.
Provide named constants that you really can’t change the value of. Hint: You have to add a member to Variable that distinguishes between constants and variables and check for it in set_value(). If you want to let the user define constants (rather than just having pi and e defined as constants), you’ll have to add a notation to let the user express that, for example, const pi = 3.14;.
The get_value(), set_value(), is_declared(), and define_name() functions all operate on the variable var_table. Define a class called Symbol_table with a member var_table of type vector<Variable> and member functions get(), set(), is_declared(), and declare(). Rewrite the calculator to use a variable of type Symbol_table.
Modify Token_stream::get() to return Token(print) when it sees a newline. This implies looking for whitespace characters and treating newline ('\n') specially. You might find the standard-library function isspace(ch), which returns true if ch is a whitespace character, useful.
Part of what every program should do is to provide some way of helping its user. Have the calculator print out some instructions for how to use the calculator if the user presses the H key (both upper- and lowercase).
Change the q and h commands to be quit and help, respectively.
The grammar in §6.6.4 is incomplete (we did warn you against overreliance on comments); it does not define sequences of statements, such as 4+4; 5−6;, and it does not incorporate the grammar changes outlined in §6.8. Fix that grammar. Also add whatever you feel is needed for that comment as the first comment of the calculator program and its overall comment.
Suggest three improvements (not mentioned in this chapter) to the calculator. Implement one of them.
Modify the calculator to operate on ints (only); give errors for overflow and underflow. Hint: Use narrow (§6.5).
Revisit two programs you wrote for the exercises in §3 or Chapter 4. Clean up that code according to the rules outlined in this chapter. See if you find any bugs in the process.
Modify the calculator to accept input from any istream.