State machine grammar rules

The fsm section of a grammar description consists of a list of state descriptions. Each state description defines a list of transitions that are supported for leaving that state. Each transition in turn specifies which input event and optional guard condition combination would cause that transition, any action that must be executed when that event-guard pair occur in that state, and the next state that the state machine will jump to.

As an example, we shall consider a rule from the pedestrian crossing controller state machine whose complete grammar has been seen previously here:

    // Once the lights have gone green, there is a
    // minimum interval they must remain green before
    // the controller will respond to the next button press.

    TimedGreen: 
        TIMERTICK[ButtonWasPressed] Yellow
        { SetLightYellow(); SetYellowTimer(); }
    |   BUTTONPRESS TimedGreen
        { RecordButtonPressed(); }
    |   TIMERTICK[!ButtonWasPressed] Green
    ;  

Notice the basic syntax for a state description. The name of a state that is being defined is followed by a colon. This is then followed by a list of transition descriptions, separated from each other by the vertical bar character. The state description is then ended by a semi-colon.

Each transition description consists of the name of an input event, as previously listed in the events or tokens section of the grammar. The input event name may optionally be followed by guard condition in square brackets if a guard condition should also be true for the event when it occurs as an input to the state machine. The input event and optional guard are then followed by the name of the next state to jump to.

For example, in the excerpt above, the state TimedGreen has a transition that says: if a TIMERTICK event should occur, and the guard function ButtonWasPressed returns true, jump to state Yellow.

After each transition rule there can appear an optional block of C# code enclosed in an outer set of curly braces. This indicates to the state machine generator that when this transition is recognised and takes place, that block of code should be executed as the action function. Hence in the above example, when transiting from TimedGreen to Yellow, the functions SetLightYellow followed by SetYellowTimer will be executed.

Entry and exit actions

Sometimes when designing a state machine we discover that all transitions out of a state have to execute some action code regardless of which state we are transiting to, or which event occurs. This typically might be some clean-up operation necessary before exiting the state. Rather than add this action code at the beginning of each action for every transition away from the state, we can refactor this by declaring an exit action for the state. This is written as a special rule after the state name and its colon have begun a state description. The reserved word exit or onexit is followed by the code block to be executed on leaving the state by any transition.

Similarly, an action to be taken on arriving at a new state via any transition can be introduced by using the reserved word entry or onentry.

When exit actions, actions on transitions and entry actions all are implied by a particular transition, the order of execution of these actions is clearly defined. Exit actions for the previous state are executed first. Transition actions are executed next. Lastly the entry actions of the new state to which the machine has transferred are executed.

There are no examples of these entry or exit actions in the pedestrian crossing example as it stands, but imagine there was a panic button that could be pressed to set all lights to red (the AllRed) state if something hazardous had happened on the crossing that warranted stopping the traffic for an indefinite period of time. In this case, regardless of which state we were arriving at the AllRed state from, we would want to execute the action function SetLightRed. The AllRed state description might now be rewritten as follows:

    AllRed: 
        entry
        { SetLightRed(); }
        TIMERTICK RedAndYellow
        { SetLightRedAndYellow(); SetRedAndYellowTimer(); }
    |   BUTTONPRESS AllRed
        { RecordButtonPressed(); }
    ;

Note that the Yellow state's transition to the AllRed state on a TIMERTICK event would now no longer need the SetLightRed action as it is implied by the entry action above. Moreover, the developer of the state machine should convince him/herself that it is acceptable to move the SetLightRed action along the list of actions to be executed so that it becomes the last action rather than the first.

Note that the layout used here for rules is not mandated, as white space and newlines are merely separators. It is however a common layout so that the separate rules and rule groups are easily identified.