Je me demande simplement si quelqu'un connaît de bons didacticiels sur Internet pour développer des machines d'état. Ou des ebooks?
Je commence à travailler sur des machines d'état et j'ai juste besoin de quelque chose de général pour bien démarrer.
Les machines d'état sont très simples en C si vous utilisez des pointeurs de fonction.
En principe, vous avez besoin de deux tableaux: un pour les pointeurs de fonction d'état et un pour les règles de transition d'état. Chaque fonction state renvoie le code, vous consultez la table de transition d'état par état et vous retournez le code pour rechercher l'état suivant, puis simplement l'exécuter.
int entry_state(void);
int foo_state(void);
int bar_state(void);
int exit_state(void);
/* array and enum below must be in sync! */
int (* state[])(void) = { entry_state, foo_state, bar_state, exit_state};
enum state_codes { entry, foo, bar, end};
enum ret_codes { ok, fail, repeat};
struct transition {
enum state_codes src_state;
enum ret_codes ret_code;
enum state_codes dst_state;
};
/* transitions from end state aren't needed */
struct transition state_transitions[] = {
{entry, ok, foo},
{entry, fail, end},
{foo, ok, bar},
{foo, fail, end},
{foo, repeat, foo},
{bar, ok, end},
{bar, fail, end},
{bar, repeat, foo}};
#define EXIT_STATE end
#define ENTRY_STATE entry
int main(int argc, char *argv[]) {
enum state_codes cur_state = ENTRY_STATE;
enum ret_codes rc;
int (* state_fun)(void);
for (;;) {
state_fun = state[cur_state];
rc = state_fun();
if (EXIT_STATE == cur_state)
break;
cur_state = lookup_transitions(cur_state, rc);
}
return EXIT_SUCCESS;
}
Je ne mets pas la fonction lookup_transition()
car elle est triviale.
C'est comme ça que je fais des machines à états depuis des années.
Je préfère utiliser les pointeurs de fonction que les gigantesques instructions switch
, mais contrairement à la réponse de qrdl Je n'utilise normalement pas de codes de retour explicites ni de tables de transition.
En outre, dans la plupart des cas, vous aurez besoin d’un mécanisme permettant de transmettre des données supplémentaires. Voici un exemple de machine d'état:
#include <stdio.h>
struct state;
typedef void state_fn(struct state *);
struct state
{
state_fn * next;
int i; // data
};
state_fn foo, bar;
void foo(struct state * state)
{
printf("%s %i\n", __func__, ++state->i);
state->next = bar;
}
void bar(struct state * state)
{
printf("%s %i\n", __func__, ++state->i);
state->next = state->i < 10 ? foo : 0;
}
int main(void)
{
struct state state = { foo, 0 };
while(state.next) state.next(&state);
}
Les machines à états ne nécessitent pas nécessairement un tutoriel pour être expliquées ou même utilisées. Je suggère que vous examiniez les données et la manière dont elles doivent être analysées.
Par exemple, j’ai dû analyser le protocole de données d’un ordinateur de vol ballon proche , qui stockait les données sur la carte SD dans un format spécifique (binaire) qui devait être analysé dans un fichier séparé par une virgule. . Utiliser une machine à états à cet effet est tout à fait logique car, en fonction de la prochaine information, nous devons changer ce que nous analysons.
Le code est écrit en C++ et est disponible sous la forme ParseFC . Comme vous pouvez le constater, il détecte d’abord la version que nous analysons, puis entre deux machines d’état différentes.
Il entre dans la machine à états dans un état connu, à ce stade, nous commençons l'analyse et, en fonction des caractères rencontrés, nous passons à l'état suivant ou revenons à un état précédent. Cela permet fondamentalement au code de s’adapter automatiquement à la manière dont les données sont stockées et même si certaines données existent ou non.
Dans mon exemple, la chaîne GPS n'est pas une obligation pour l'ordinateur de vol de se connecter. Par conséquent, le traitement de la chaîne GPS peut être ignoré si les octets de fin de cette écriture de journal sont trouvés.
Les machines à états sont simples à écrire, et en général, je suis la règle: elles doivent circuler. Les entrées passant par le système devraient circuler avec une certaine facilité d'un état à l'autre.
Malheureusement, la plupart des articles sur les machines à états sont écrits pour C++ ou d'autres langages prenant directement en charge le polymorphisme, car il est agréable de modéliser les états dans une implémentation FSM en tant que classes dérivées d'une classe d'états abstraite.
Cependant, il est assez facile d'implémenter des machines d'état en C en utilisant des instructions switch pour répartir des événements en états (pour les FSM simples, ils codent assez bien) ou en utilisant des tables pour mapper des événements à des transitions d'état.
Il existe quelques articles simples, mais décents, sur un cadre de base pour les machines à états en C:
Edit : Site "en cours de maintenance", liens vers les archives Web:
Les machines à états basées sur des instructions switch
utilisent souvent un ensemble de macros pour "masquer" les mécanismes de l'instruction switch
(ou utiliser un ensemble de if
/then
/else
au lieu de switch
) et donne ce qui revient à un "langage FSM" pour décrire la machine à états dans le source C. Personnellement, je préfère l’approche basée sur les tables, mais celles-ci ont certainement du mérite, sont largement utilisées et peuvent être efficaces, en particulier pour les FSM plus simples.
Steve Rabin a décrit un tel cadre dans "Chapitre 3:" Gems de programmation de jeux "(Conception d’un moteur d’intelligence artificielle robuste) .
Un ensemble similaire de macros est discuté ici:
Si vous êtes également intéressé par les implémentations de machines d'état C++, vous pouvez en trouver beaucoup plus. Je posterai des pointeurs si cela vous intéresse.
Modélisation orientée objet en temps réel était fantastique (publié en 1994 et se vend maintenant à partir de 81 centimes, plus 3,99 $ d’expédition).
Il y a beaucoup de leçons à apprendre à la fabrication manuelle de machines à états en C, mais permettez-moi également de suggérer le compilateur de machines à états Ragel:
http://www.complang.org/ragel/
Il a un moyen assez simple de définir des machines d'état et ensuite vous pouvez générer des graphiques, générer du code dans différents styles (piloté par des tables, piloté par goto), analyser ce code si vous le souhaitez, etc. Et c'est puissant, il peut être utilisé en production code pour divers protocoles.
C'est tout ce que vous devez savoir.
int state = 0;
while (state < 3)
{
switch (state)
{
case 0:
// Do State 0 Stuff
if (should_go_to_next_state)
{
state++;
}
break;
case 1:
// Do State 1 Stuff
if (should_go_back)
{
state--;
}
else if (should_go_to_next_state)
{
state++;
}
break;
case 2:
// Do State 2 Stuff
if (should_go_back_two)
{
state -= 2;
}
else if (should_go_to_next_state)
{
state++;
}
break;
default:
break;
}
}