C++ enum from char - c++

Ok, I'm new at C++. I got Bjarne's book, and I'm trying to follow the calculator code.
However, the compiler is spitting out an error about this section:
token_value get_token()
{
char ch;
do { // skip whitespace except '\n'
if(!std::cin.get(ch)) return curr_tok = END;
} while (ch!='\n' && isspace(ch));
switch (ch) {
case ';':
case '\n':
std::cin >> WS; // skip whitespace
return curr_tok=PRINT;
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return curr_tok=ch;
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '.':
std::cin.putback(ch);
std::cin >> number_value;
return curr_tok=NUMBER;
default: // NAME, NAME=, or error
if (isalpha(ch)) {
char* p = name_string;
*p++ = ch;
while (std::cin.get(ch) && isalnum(ch)) *p++ = ch;
std::cin.putback(ch);
*p = 0;
return curr_tok=NAME;
}
error("bad token");
return curr_tok=PRINT;
}
The error it's spitting out is this:
calc.cpp:42: error: invalid conversion from ‘char’ to ‘token_value’
token_value is an enum that looks like:
enum token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
token_value curr_tok;
My question is, how do I convert ch (from cin), to the associated enum value?

You can't implicitly cast from char to an enum - you have to do it explicitly:
return curr_tok = static_cast<token_value> (ch);
But be careful! If none of your enum values match your char, then it'll be hard to use the result :)

Note that the solutions given (i.e. telling you to use a static_cast) work correctly only because when the enum symbols were defined, the symbols (e.g. PLUS) were defined to have a physical/numeric value which happens to be equal to the underlying character value (e.g. '+').
Another way (without using a cast) would be to use the switch/case statements to specify explicitly the enum value returned for each character value, e.g.:
case '*':
return curr_tok=MUL;
case '/':
return curr_tok=DIV;

You need an explicit cast:
curr_tok = static_cast<token_value>(ch);
The reason is that it's dangerous to convert an integer type to an enum. If the value is not valid for the enum then behaviour is undefined. So the language doesn't let you do it accidentally with an implicit conversion. The explicit conversion is supposed to mean "I know what I'm doing, and I've checked that the value is valid".

I think I wouldn't try to explicitly set the values of the enum symbols and instead write a case for every symbol that in your switch statement. Doing it that way will probably be harder to debug if something goes wrong and the performance cost writing a case for every symbol is so low, that it's not even worth considering (unless you're writing for some kind of extremely low-end embedded system and probably still not worth it).

return curr_tok=(token_value)ch;

Related

How to associate an operator with a priority value?

I want to implement the Reverse Polish notation. In order to do that, I have to implement a table which stores priority for operators, as such:
operator
priority
(
0
+, -
1
*, /
2
How do I do that?
Since you have a fixed-number of key-value pairs that are known at compile time, you don't need the dynamic nature and overhead of std::unordered_map. You can use a simple switch statement, which is static and harder to get wrong:
int get_priority(char const op) {
switch (op) {
case '(':
return 0;
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return -1; // handle the error
}
}

case expression in c++ returns error

I was using this code as part of a 2 dimensional game, but when i tried compiling it, it returned the following error:
error C2051: case expression not constant.
This is my code:
switch(_getch()){
case "w":
dir = UP;
break;
case "a":
dir = LEFT;
break;
case "s":
dir = DOWN;
break;
case "d":
dir = RIGHT;
break;
default:
break;
}
You should use character literals ('w') instead of string literals ("w") in switch cases:
case 'w':
dir = UP;
break;
"w" is a string literal, which would decay to a char const* pointer. switch cases cannot be anything other than a constant integer, an enum or a class with a single non-explicit integer or enum conversion operator. A pointer to char is none of those.

In a switch case statement, it says "duplicate case value" comes up as an error. Anyone know why?

I am working on a rock paper scissors program, but this time the computer chooses rock half the time, scissors a third of the time, and paper only one sixth of the time. The way I did this was I enumerated six possible computer choice values:
enum choicec {rock1, rock2, rock3, scissors1, scissors2, paper};
choicec computer;
But then, after the computer makes its choice, I have to convert these enumerated values to either rock, paper, or scissors. I did this using a switch-case statement:
switch(computer) {
case rock1 || rock2 || rock3:
c = 1;
break;
case scissors1 || scissors2: //ERROR!
c = 3;
break;
case paper:
c = 2;
break;
}
one is rock, two is paper, and three is scissors. However, on the line where I have error written in as a comment, it gives me this error: [Error] duplicate case value.
I'm not sure why.
Any ideas?
I am not sure what you doing, but switch statement should look like this
switch(computer)
{
case rock1:
case rock2:
case rock3:
c = 1;
break;
case scissors1:
case scissors2:
c = 3;
break;
case paper:
c = 2;
break;
}
You can't use || in case branches. Sorry :(
When you use || it does a logical or on them, that says "is rock1 or rock2 or rock3 not a zero?". And the answer is yes, at least one of those is not zero. So rock1 || rock2 || rock3 is true, which is 1. And scissors1 || scissors is also true, which is 1. So you have two case branches for the 1 case.
You should simply use case fallthrough to select multiple conditions:
switch(computer) {
case rock1: case rock2: case rock3:
c = 1;
break;
case scissors1: case scissors2:
c = 3;
break;
case paper:
c = 2;
break;
default:
std::cerr << "INVALID COMPUTER MOVE";
}
Also, I always have a default in my case switches. Sometimes mistakes happen, and we definitely want to know if it doesn't hit any of the case branches. I'm also pretty paranoid about missing else statements, but about half the time it's ok if there's no else.
That switch statement does not do what you think.
Each case defines one value that the value of computer is matched against. Combining several values with logical disjunction to give the value associated with a single case label does not make the corresponding block be entered when the value of computer is equal to any of those values, but rather when it is equal to the result of their logical OR combination. Not very meaningful, indeed.
This is how you could rewrite your switch statement in order to make more sense:
switch(computer) {
case rock1: // Is it rock1?
case rock2: // Or perhaps rock2?
case rock3: // Or maybe rock3?
c = 1; // Well, if it's one of the above, do this...
break;
case scissors1: // OK, it wasn't. So is it scissors1?
case scissors2: // Or scissors2?
c = 3; // If it's one of the above, do this...
break;
case paper: // So is it paper?
c = 2;
break;
default: // Always better to be explicit about this
break;
}
Change it to:
switch(computer) {
case rock1:
case rock2:
case rock3:
c = 1;
break;
case scissors1:
case scissors2:
c = 3;
break;
case paper:
c = 2;
break;
}
rock1 || rock2 || rock3 and scissors1 || scissors2 are both expressions which evaluate to "true", hence the conflict.
The expression used in the switch statement must be integral type ( int, char and enum). In the Switch statement, all the matching case execute until a break statement is reached and Two case labels cannot have the same value.
But in the above case with logical or condition.
At first
case: rock1 || rock2 || rock3:
This will evaluate to 1 and second case scissors1 || scissors2: will also evaluate to 1. This is cause error as said Two case labels cannot have the same value.
This is the reason compiler complains and giving an error:
Compiler Error: duplicate case value
To solve this convert to
switch(computer) {
case rock1:
case rock2:
case rock3:
c = 1;
break;
case scissors1:
case scissors2: //Now will not give any error here...
c = 3;
break;
case paper:
c = 2;
break;
}

Switch statement using or

I'm creating a console app and using a switch statement to create a simple menu system. User input is in the form of a single character that displays on-screen as a capital letter. However, I do want the program to accept both lower- and upper-case characters.
I understand that switch statements are used to compare against constants, but is it possible to do something like the following?
switch(menuChoice) {
case ('q' || 'Q'):
//Some code
break;
case ('s' || 'S'):
//More code
break;
default:
break;
}
If this isn't possible, is there a workaround? I really don't want to repeat code.
This way:
switch(menuChoice) {
case 'q':
case 'Q':
//Some code
break;
case 's':
case 'S':
//More code
break;
default:
}
More on that topic:
http://en.wikipedia.org/wiki/Switch_statement#C.2C_C.2B.2B.2C_Java.2C_PHP.2C_ActionScript.2C_JavaScript
The generally accepted syntax for this is:
switch(menuChoice) {
case 'q':
case 'Q':
//Some code
break;
case 's':
case 'S':
//More code
break;
default:
break;
}
i.e.: Due the lack of a break, program execution cascades into the next block. This is often referred to as "fall through".
That said, you could of course simply normalise the case of the 'menuChoice' variable in this instance via toupper/tolower.
'q' || 'Q' results in bool type result (true) which is promoted to integral type used in switch condition (char) - giving the value 1. If compiler allowed same value (1) to be used in multiple labels, during execution of switch statement menuChoice would be compared to value of 1 in each case. If menuChoice had value 1 then code under the first case label would have been executed.
Therefore suggested answers here use character constant (which is of type char) as integral value in each case label.
Just use tolower(), here's my man:
SYNOPSIS
#include ctype.h
int toupper(int c);
int tolower(int c);
DESCRIPTION
toupper() converts the letter c to upper case, if possible.
tolower() converts the letter c to lower case, if possible.
If c is not an unsigned char value, or EOF, the behavior of these
functions is undefined.
RETURN VALUE
The value returned is that of the converted letter, or c if the
conversion was not possible.
So in your example you can switch() with:
switch(tolower(menuChoice)) {
case('q'):
// ...
break;
case('s'):
// ...
break;
}
Of course you can use both toupper() and tolower(), with capital and non-capital letters.
You could (and for reasons of redability, should) before entering switch statement use tolower fnc on your var.
switch (toupper(choice))
{
case 'Q':...
}
...or tolower.
if you do
case('s' || 'S'):
// some code
default:
// some code
both s and S will be ignored and the default code will run whenever you input these characters. So you could decide to use
case 's':
case 'S':
// some code
or
switch(toupper(choice){
case 'S':
// some code.
toupper will need you to include ctype.h.

simple cross-platform c++ GUI console -- how to?

I'm writing a game and I'm wound up in needing a console for simple text input; filenames and simple values.
Using SDL, my console looks the following at it's simplest:
class Console
{
public:
typedef std::list<String> InputList;
enum Result
{
NOTHING = 0,
ENTERED,
ESCAPED
};
static const String& GetInput() { return input; }
static Result Query(SDLKey lastKey)
{
if(lastResult == ENTERED || lastResult == ESCAPED)
{
input.clear();
}
switch (lastKey)
{
case SDLK_a:
case SDLK_b:
case SDLK_c:
case SDLK_d:
case SDLK_e:
case SDLK_f:
case SDLK_g:
case SDLK_h:
case SDLK_i:
case SDLK_j:
case SDLK_k:
case SDLK_l:
case SDLK_m:
case SDLK_n:
case SDLK_o:
case SDLK_p:
case SDLK_q:
case SDLK_r:
case SDLK_s:
case SDLK_t:
case SDLK_u:
case SDLK_v:
case SDLK_w:
case SDLK_x:
case SDLK_y:
case SDLK_z:
case SDLK_0:
case SDLK_1:
case SDLK_2:
case SDLK_3:
case SDLK_4:
case SDLK_5:
case SDLK_6:
case SDLK_7:
case SDLK_8:
case SDLK_9:
case SDLK_SLASH:
case SDLK_BACKSLASH:
case SDLK_PERIOD:
case SDLK_COMMA:
case SDLK_SPACE:
case SDLK_UNDERSCORE:
case SDLK_MINUS:
input += static_cast<char> (lastKey);
lastResult = NOTHING;
break;
case SDLK_RETURN:
lastResult = ENTERED;
break;
case SDLK_ESCAPE:
lastResult = ESCAPED;
break;
}
return lastResult;
}
protected:
static Result lastResult;
static String input;
};
This would be called from the application's main event loop, if the console is active and the last event was a keypress, then the result of the input is processed at a state where it's necessary.
Of course, it looks incredibly awkward... What's a better way to implement a simple console that can be easily rendered in my game's window? (Not going anywhere near to highly unportable solutions like having to reroute std::cout or writing code to bring up a UNIX console etc.)
One suggestion I would offer is to use if statements instead of a switch in this case:
if(lastKey == SDLK_RETURN)
lastResult = ENTERED;
else if(lastKey == SDLK_ESCAPE)
lastResult = ESCAPED;
else if(lastKey >= SDLK_SPACE && lastKey <= SDLK_z)
{
input += static_cast<char> (lastKey);
lastResult = NOTHING;
}
I took some liberties and included some characters that you didn't have in your code above, such as the ampersand, quotes, parentheses, brackets, etc. If you don't want those keys, you can add a few more if statements to break it down a bit more.
This assumes that the enum for the keys doesn't change a lot. If it does change a lot you may be better off with what you had.