As I wrote the post below, it occurred to me that running a program from the command line is different from running it in an IDE. Is there a way to run a program from the command line and exit it if the program itself doesn't supply a way to exit while still retaining the return value of main()? If so, please tell me and disregard the rest of this message.
One of the exercises in TC++PL is to copy a desk calculator program in the book that demonstrates basic parsing. I copied it by hand, obviously, and when I compiled it it works well except I can't get it to exit. (I made extra sure I copied it exactly, and I found the exact exercise online and compared it and found no difference.) Here's the code in question:
curr_tok being of enum type Token_value. Here's the bulk of main():
1 2 3 4 5 6
while (cin) {
get_token();
if (curr_tok == END) break;
if (curr_tok == PRINT) continue;
cout << expr(false) << '\n';
}
I'm assuming I'm just misunderstanding something. Entering 0 obviously doesn't work because it's used as the character 0, so I guess nothing will exit the program? (Nothing in the rest of the code has any favility for exiting the program. I at least made sure of that.)
By default, operator >> skips whitespace (that is, spaces, tabs, newlines, etc.) and leaves the value
of ch unchanged if the input operation failed. Consequently, ch==0 indicates end of input.
To give eof to cin, enter Ctrl+D or Ctrl+Z ( depending on the system )
I have a related question that I don't want to make a new topic for:
I'm using GDB to follow the flow of the parser and get a better understanding for it. I have a decent grasp of it, except for entering an identifier. In get_token(), it takes a char ch and uses that to determine the token. When I say var = 10, it takes var in with this:
string_value being a string. I don't understand how ch can hold a multi-letter identifier like var to put into string_value. If chars can only hold one character, then how does this code work?
Okay that taught me a LOT. I wasn't aware that cin would hold everything entered like that. So if the first thing entered is a letter, it'll read everything up until the next whitespace as an identifier. I understand it much better now, thanks!
While still on the topic of this, I'm a little confused about this part of the code:
1 2 3 4 5 6 7 8 9
double prim(bool get) {
if (get) get_token();
switch (curr_tok) {
case NUMBER:
{ double v = number_value;
get_token();
return v;
}
The beginning of prim(). If I put in var = 10; , it goes through parsing the identifier, = operator, and number as I expect it to. Then it enters prim() and goes to that section of the switch. When it gets to get_token(), it then gets the token as the = operator again. Why does this happen?
The purpose of that get_token call, is visible in the previous function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
double term(bool get )
{
double left = prim(get); // calls prim to get a number, which calls get_token again
for (;;)
switch (curr_tok) { // here is switching the result of the second get_token call
case MUL:
left *= prim(true);
break;
case DIV:
if (double d = prim(true)) {
left /= d;
break;
}
return error("divide by 0");
default:
return left;
}
}
So, the first get_token says that there's a NUMBER, then you get that number, and the last get_token is to provide the operation
Why separate expr() and term()? I understand why prim() is its own function, but the other two seem like they would all be one function (i.e. one function for all arithmetic operators).