Reputation: 63
I have the following code to define my FSM states:
enum states
{
START, // Send request to remote IP or wait for a request (WAIT_CONN_REQ)
WAIT_RESP, // Chat request sent to remote IP. Waiting for a response from the target machine
SEND_CONN_RESP, // Chat request received from remote IP. ACCEPT or REJECT
ACCEPTED // Both parties agreed to exchange datagrams. Begin application data (MESSAGES) exchange
};
typedef enum states states;
states state;
My thought process was this: My chat program will have the aforementioned four states. What's the best way to do this neatly? Using a switch statement, of course. So how can I do it? Like this: (code is simplified & replaced with printf
functions"
int main(int argc, char *argv[])
{
state = START;
switch (state)
{
case START:
printf("Simple Chat Client - START state\n");
if (argv[1] != NULL)
{
SEND_CONN_REQ();
} else {
WAIT_CONN_REQ();
}
break;
case WAIT_RESP:
printf("WAIT_RESP STATE!");
break;
case SEND_CONN_RESP:
printf("SEND_CONN_RESP state!");
break;
case ACCEPTED:
printf("ACCEPTED state!");
break;
}
}
But this does not do what I want. I want it to jump to another case when a condition is met. Like so:
if (argv[1] != NULL)
{
SEND_CONN_REQ();
goto case WAIT_RESP;
} else {
WAIT_CONN_REQ();
}
break;
case WAIT_RESP:
printf("WAIT_RESP STATE!");
break;
My logic tells me that the way to do this would be to change the state
variable, assuming the whole switch
would be executed again with the new variable. But what happens is that I have to either use break
and quit the switch
, or not use it and let the program execute the next case
.
So I looked at other options, like do
statements and continue
. But everywhere I look, using case
seems to be the way to go with an FSM.
I would appreciate any help on how to do this properly. Is a switch
statement even the best way to go?
Upvotes: 3
Views: 7325
Reputation: 753585
The normal way to code a state machine like that is using a loop and a switch:
state = START;
while (state != STOP)
{
switch (state)
{
case START:
printf("Simple Chat Client - START state\n");
if (argv[1] != NULL)
{
SEND_CONN_REQ();
} else {
WAIT_CONN_REQ();
}
break;
case WAIT_RESP:
printf("WAIT_RESP STATE!");
break;
case SEND_CONN_RESP:
printf("SEND_CONN_RESP state!");
break;
case ACCEPTED:
printf("ACCEPTED state!");
break;
}
}
Each action can optionally set the new state so that the next iteration will do the appropriate actions. Don't forget to output newlines at the ends of printf()
statements if you want to see the output in a timely manner. It may not matter on Windows; it does on other platforms.
Upvotes: 3
Reputation: 6665
If you will always just want to execute the state right below where you are, you could remove the break
statement. I would put a comment in it's place like /* fall through */
so that it is clear that it is intentionally missing for people who follow, as well as your future-forgetting self. I personally don't like this method.
Why not change the state
variable, and then just execute a goto
that is right above the switch statement? Like this maybe:
switchStart:
switch (state)
{
case START:
printf("Simple Chat Client - START state\n");
if (argv[1] != NULL)
{
SEND_CONN_REQ();
state = STATE_HERE; // change your state
goto switchStart; // jump to the top of the switch
} else {
WAIT_CONN_REQ();
}
break;
case WAIT_RESP:
printf("WAIT_RESP STATE!");
break;
case SEND_CONN_RESP:
printf("SEND_CONN_RESP state!");
break;
case ACCEPTED:
printf("ACCEPTED state!");
break;
}
Upvotes: 2