/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT * Copyright 1989 Massachusetts Institute of Technology */ /*********************\ * * * WOOL_OBJECT: Fsm * * BODY * * * \*********************/ #include "EXTERN.h" #include #include #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); }