394 lines
9.0 KiB
C
394 lines
9.0 KiB
C
/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
|
|
* Copyright 1989 Massachusetts Institute of Technology
|
|
*/
|
|
/*********************\
|
|
* *
|
|
* WOOL_OBJECT: Fsm *
|
|
* BODY *
|
|
* *
|
|
\*********************/
|
|
|
|
#include "EXTERN.h"
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include "wool.h"
|
|
#include "wl_number.h"
|
|
#include "wl_atom.h"
|
|
#include "wl_list.h"
|
|
#include "wl_func.h"
|
|
#include "gwm.h"
|
|
#include "wl_event.h"
|
|
#include "INTERN.h"
|
|
#include "wl_fsm.h"
|
|
|
|
WOOL_FsmState WLFsmState_copy();
|
|
WOOL_FsmState WLState_fp();
|
|
WOOL_StateArc WLArc_fp();
|
|
|
|
#define SAME_STATE ((WOOL_Atom) -1)
|
|
|
|
/*
|
|
* Constructor: wool_fsm_make callable from wool
|
|
*/
|
|
|
|
WOOL_Fsm
|
|
wool_fsm_make(argc, argv)
|
|
int argc;
|
|
WOOL_FsmState *argv;
|
|
{
|
|
WOOL_Fsm fsm;
|
|
int i;
|
|
|
|
for (i = 0; i < argc; i++) /* check args are all states */
|
|
must_be(WLFsmState, argv[i], i);
|
|
fsm = (WOOL_Fsm) Malloc(sizeof(struct _WOOL_Fsm) + Max(0,argc - 1) *
|
|
sizeof(WOOL_OBJECT));
|
|
zrt_put(fsm);
|
|
fsm -> type = WLFsm;
|
|
fsm -> mask = 0;
|
|
fsm -> user_mask = 0;
|
|
fsm -> states_size = argc;
|
|
for (i = 0; i < argc; i++) {
|
|
fsm -> mask |= argv[i] -> mask;
|
|
fsm -> user_mask |= argv[i] -> user_mask;
|
|
increase_reference(fsm -> states[i] = WLFsmState_copy(argv[i]));
|
|
}
|
|
WLFsm_fix(fsm, argc, argv);
|
|
return fsm;
|
|
}
|
|
|
|
/*
|
|
* fixes the states to go to in the fsm
|
|
*/
|
|
|
|
WLFsm_fix(fsm, argc, argv)
|
|
WOOL_Fsm fsm;
|
|
int argc;
|
|
WOOL_FsmState argv[];
|
|
{
|
|
int nstate, narc, i;
|
|
|
|
for (nstate = 0; nstate < fsm -> states_size; nstate++)
|
|
for (narc = 0; narc < fsm -> states[nstate] -> arcs_size; narc++)
|
|
if (fsm -> states[nstate] -> arcs[narc] -> state != SAME_STATE) {
|
|
for (i = 0; i < argc; i++)
|
|
if (fsm -> states[nstate] -> arcs[narc] -> state -> c_val
|
|
== (WOOL_OBJECT) ((argv[i]) -> copy_of)) {
|
|
fsm -> states[nstate] -> arcs[narc] -> state =
|
|
(WOOL_Atom) i;
|
|
break;
|
|
}
|
|
if (i == argc)
|
|
wool_error("State %s not found!", fsm -> states[nstate]
|
|
-> arcs[narc] -> state -> p_name);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* WLFsm_print prints any object of this package.
|
|
*/
|
|
|
|
WOOL_OBJECT
|
|
WLFsm_print(obj)
|
|
WOOL_Fsm obj;
|
|
{
|
|
wool_printf("{%s", WOOL_TYPE_P_NAME(obj -> type));
|
|
wool_printf(" 0x%x}", obj);
|
|
return (WOOL_OBJECT) obj;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
WOOL_Fsm
|
|
WLFsm_fp(obj)
|
|
WOOL_Fsm obj;
|
|
{
|
|
int nstate;
|
|
|
|
wool_printf("{%s", WOOL_TYPE_P_NAME(obj -> type));
|
|
wool_printf(" 0x%x:\n", obj);
|
|
for (nstate = 0; nstate < obj -> states_size; nstate++) {
|
|
wool_printf("State %d:\n", nstate);
|
|
WLState_fp(obj->states[nstate]);
|
|
}
|
|
wool_printf("}\n");
|
|
return obj;
|
|
}
|
|
|
|
WOOL_FsmState
|
|
WLState_fp(obj)
|
|
WOOL_FsmState obj;
|
|
{
|
|
int narc;
|
|
for (narc = 0; narc < obj-> arcs_size; narc++) {
|
|
wool_puts(" * ");
|
|
WLArc_fp(obj->arcs[narc]);
|
|
wool_puts("\n");
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
WOOL_StateArc
|
|
WLArc_fp(obj)
|
|
WOOL_StateArc obj;
|
|
{
|
|
wool_print(obj->event);
|
|
wool_puts(" ");
|
|
wool_print(obj->action);
|
|
return obj;
|
|
}
|
|
|
|
#endif /*DEBUG*/
|
|
|
|
|
|
/* the main routine:
|
|
* check the incoming event against all transitions of the current
|
|
* state of the fsm, and triggers the action if necessary
|
|
*/
|
|
|
|
WOOL_OBJECT
|
|
WLFsm_action(fsm, wob, evt)
|
|
WOOL_Fsm fsm;
|
|
Wob wob;
|
|
Event evt;
|
|
{
|
|
int i;
|
|
WOOL_FsmState state;
|
|
WOOL_StateArc arc;
|
|
WOOL_List l;
|
|
int local_zrt_size = zrt_size;
|
|
|
|
TargetWob = wob;
|
|
GWM_invalid_context = 1;
|
|
state = fsm -> states[wob -> curstate];
|
|
for (i = 0; i < state -> arcs_size; i++) {
|
|
arc = state -> arcs[i];
|
|
ASSERT(arc -> event -> match);
|
|
if (evt -> type == arc -> event -> x_type &&
|
|
((*(arc -> event -> match)) (arc -> event, evt))) {
|
|
|
|
TraceDo('f',
|
|
GWM_prettyprint_fsm_event(wob, evt, "MATCH",
|
|
wob -> curstate,
|
|
arc -> state));
|
|
if (l = arc -> action) {
|
|
save_wool_error_resume_point();
|
|
if (GWM_invalid_context)
|
|
SetTarget(wob);
|
|
TriggeringEvent = evt;
|
|
if (set_wool_error_resume_point()) {
|
|
} else {
|
|
WOOL_send(WOOL_execute, (*(l -> list)), (*(l -> list), l));
|
|
zrt_gc(local_zrt_size);
|
|
}
|
|
restore_wool_error_resume_point();
|
|
}
|
|
|
|
if (arc -> event -> release)
|
|
(*(arc -> event -> release)) (arc -> event, evt);
|
|
if (arc -> state != SAME_STATE)
|
|
wob -> curstate = (int) arc -> state;
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
TraceDo('f',
|
|
GWM_prettyprint_fsm_event(wob, evt, "REJECT",
|
|
wob -> curstate,
|
|
arc -> state));
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Routine used to construct a state
|
|
* USAGE:
|
|
* (state-make arc1 arc2 ... arcn)
|
|
*/
|
|
|
|
WOOL_FsmState
|
|
wool_fsm_state_make(argc, argv)
|
|
int argc;
|
|
WOOL_StateArc argv[];
|
|
{
|
|
WOOL_FsmState state;
|
|
int i, j, narc = argc;
|
|
WOOL_FsmState inc_state;
|
|
|
|
for (i = 0; i < argc; i++)
|
|
if (argv[i] -> type == WLFsmState)
|
|
narc += ((WOOL_FsmState) argv[i]) -> arcs_size - 1;
|
|
else if (argv[i] == (WOOL_StateArc) NIL)
|
|
narc--;
|
|
state = (WOOL_FsmState)
|
|
Malloc(sizeof(struct _WOOL_FsmState) +
|
|
Max(0, narc - 1) * sizeof(WOOL_OBJECT));
|
|
state -> type = WLFsmState;
|
|
state -> mask = state -> user_mask = 0;
|
|
zrt_put(state);
|
|
state -> arcs_size = narc;
|
|
state -> copy_of = state;
|
|
narc = 0;
|
|
for (i = 0; i < argc; i++) {
|
|
if (argv[i] -> type == WLStateArc) {
|
|
increase_reference(state -> arcs[narc++] = argv[i]);
|
|
state -> mask |= argv[i] -> event -> mask;
|
|
state -> user_mask |= argv[i] -> event -> user_mask;
|
|
} else if (argv[i] -> type == WLFsmState) {
|
|
inc_state = (WOOL_FsmState) argv[i];
|
|
for (j = 0; j < inc_state -> arcs_size; j++) {
|
|
increase_reference(state -> arcs[narc++]
|
|
= inc_state -> arcs[j]);
|
|
state -> mask |= inc_state -> arcs[j] -> event -> mask;
|
|
state -> user_mask |=
|
|
inc_state -> arcs[j] -> event -> user_mask;
|
|
}
|
|
} else if (argv[i] == (WOOL_StateArc) NIL)
|
|
; /* skip () */
|
|
else
|
|
bad_argument(argv[i], i, "fsm state");
|
|
}
|
|
return state;
|
|
}
|
|
|
|
|
|
/*
|
|
* make an arc: (FSUBR)
|
|
* syntax: (on event [action [state]])
|
|
* action (list) and state (atom) MUST NOT BE QUOTED!
|
|
*/
|
|
|
|
WOOL_StateArc
|
|
wool_state_arc_make(argc, argv)
|
|
int argc;
|
|
WOOL_OBJECT argv[];
|
|
{
|
|
WOOL_StateArc arc = (WOOL_StateArc)
|
|
Calloc(sizeof(struct _WOOL_StateArc),1);
|
|
|
|
arc -> type = WLStateArc;
|
|
zrt_put(arc);
|
|
if (argc == 0 || argc > 3)
|
|
wool_error(BAD_NUMBER_OF_ARGS, argc);
|
|
arc -> state = SAME_STATE;
|
|
arc -> action = NULL;
|
|
increase_reference(arc -> event = (WOOL_Event)
|
|
wool_type_or_evaluate(argv[0], WLEvent));
|
|
if (arc -> event == (WOOL_Event) NIL)
|
|
bad_argument(argv[0], 0, "event");
|
|
switch (argc) {
|
|
case 3:
|
|
must_be_atom(argv[2], 2);
|
|
arc -> state = (WOOL_Atom) argv[2];
|
|
case 2:
|
|
must_be_or_nil(WLList, argv[1], 1);
|
|
if (argv[1] != (WOOL_OBJECT) NIL)
|
|
increase_reference(arc -> action = (WOOL_List) argv[1]);
|
|
}
|
|
return arc;
|
|
}
|
|
|
|
WOOL_OBJECT
|
|
WLFsm_free(obj)
|
|
WOOL_Fsm obj;
|
|
{
|
|
decrease_reference_in_list(obj -> states_size, obj -> states);
|
|
Free(obj);
|
|
return NULL;
|
|
}
|
|
|
|
WOOL_OBJECT
|
|
WLFsmState_free(obj)
|
|
WOOL_FsmState obj;
|
|
{
|
|
decrease_reference_in_list(obj -> arcs_size, obj -> arcs);
|
|
Free(obj);
|
|
return NULL;
|
|
}
|
|
|
|
WOOL_OBJECT
|
|
WLStateArc_free(obj)
|
|
WOOL_StateArc obj;
|
|
{
|
|
decrease_reference(obj -> event);
|
|
decrease_reference(obj -> action);
|
|
Free(obj);
|
|
return NULL;
|
|
}
|
|
|
|
WOOL_OBJECT
|
|
WLFsm_open(fsm)
|
|
WOOL_Fsm fsm;
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
WOOL_StateArc
|
|
WLStateArc_copy(oldarc)
|
|
WOOL_StateArc oldarc;
|
|
{
|
|
WOOL_StateArc arc =
|
|
(WOOL_StateArc) Malloc(sizeof(struct _WOOL_StateArc));
|
|
|
|
arc -> type = WLStateArc;
|
|
zrt_put(arc);
|
|
increase_reference(arc -> event = oldarc -> event);
|
|
if(arc -> action = oldarc -> action)
|
|
increase_reference(arc -> action);
|
|
if((arc -> state = oldarc -> state) != (WOOL_Atom) ANY)
|
|
increase_reference(arc -> state);
|
|
return arc;
|
|
}
|
|
|
|
WOOL_FsmState
|
|
WLFsmState_copy(oldstate)
|
|
WOOL_FsmState oldstate;
|
|
{
|
|
WOOL_FsmState state = (WOOL_FsmState)
|
|
Malloc(sizeof(struct _WOOL_FsmState) + Max(0,oldstate -> arcs_size - 1)
|
|
* sizeof(WOOL_OBJECT));
|
|
int i;
|
|
|
|
state -> type = WLFsmState;
|
|
zrt_put(state);
|
|
state -> mask = oldstate -> mask;
|
|
state -> user_mask = oldstate -> user_mask;
|
|
state -> arcs_size = oldstate -> arcs_size;
|
|
state -> copy_of = oldstate -> copy_of;
|
|
for (i = 0; i < state -> arcs_size; i++)
|
|
increase_reference(state -> arcs[i] =
|
|
WLStateArc_copy(oldstate -> arcs[i]));
|
|
return state;
|
|
}
|
|
|
|
/*
|
|
* NIL_FSM_make:
|
|
* used to build the nil fsm on startup
|
|
*/
|
|
|
|
NIL_FSM_make()
|
|
{
|
|
WOOL_FsmState state = (WOOL_FsmState)
|
|
Malloc(sizeof(struct _WOOL_FsmState));
|
|
|
|
NIL_FSM = (WOOL_Fsm) Malloc(sizeof(struct _WOOL_Fsm));
|
|
state -> type = WLFsmState;
|
|
state -> mask = state -> user_mask = 0;
|
|
zrt_put(state);
|
|
increase_reference(state);
|
|
state -> arcs_size = 0;
|
|
zrt_put(NIL_FSM);
|
|
NIL_FSM -> type = WLFsm;
|
|
NIL_FSM -> mask = 0;
|
|
NIL_FSM -> user_mask = 0;
|
|
NIL_FSM -> states_size = 1;
|
|
NIL_FSM -> states[0] = state;
|
|
increase_reference(NIL_FSM);
|
|
}
|
|
|
|
void
|
|
fix_fsm(ptr)
|
|
WOOL_Fsm *ptr;
|
|
{
|
|
if (*ptr == (WOOL_Fsm) NIL)
|
|
increase_reference(*ptr = (WOOL_Fsm) NIL_FSM);
|
|
}
|