Statechart language reference

itemis CREATE provides a formal definition of statecharts which allows execution and code generation. This formalization is provided by the statechart language, which is used to describe statecharts. It consists both of graphical and of textual elements.

State machine basics

This is a short overview over basic state machine concepts. For a more thorough explanation, see What are State Machines?

Words and definitions

A finite-state machine (FSM) or finite-state automaton (FSA, plural: automata), finite automaton, or simply a state machine as a mathematical model of computation. It is an abstract machine that can be in exactly one of a finite number of states at any given time. The FSM can change from one state to another in response to some external inputs; the change from one state to another is called a transition. An FSM is defined by a list of its states, its initial state, and the conditions for each transition.

A state diagram is one of many possible representations of an FSM. A state transition table would be different way to describe an FSM.

A statechart or Harel statechart is an extended form of the classic state diagram. The basic principles are the same, however. In this documentation, the term statechart usually denotes the graphical representation of an FSM.

The term state machine is a short form of finite-state machine. In this documentation, the term state machine usually pertains to the dynamic aspects of an FSM, i.e., it is more thought of as being executed, simulated etc. than being depicted.

Automata theory

itemis CREATE was designed to create statecharts according to David Harel’s statechart theory. Harel statecharts have become part of the Unified Modeling Language (UML). Harel introduced a couple of extensions to conventional state diagrams, making them more concise and more readable.

Classic state diagrams

Classic state diagrams describe finite-state machines and consist of the following things only:

These parameters describe a finite-state machine completely.

Moore and Mealy machines

In classic automata theory, two distinct types of finite-state machines exist:

It is possible to transform these types of machine into each other, however, states, transitions and the output function need to be changed to achieve this.

Harel statecharts

Harel statecharts extend the classic state diagrams by a couple of additional aspects, resulting in representations that need much less states and transitions, making them much more compact, expressive, manageable and comprehensible – though not as mathematically concise as Moore or Mealy machines.

Harel added the following notations, dealing with hierarchy, concurrency, and communication:

Since Harel statecharts are a superset of Mealy and Moore machines, it is possible to model all of these types in itemis CREATE.

Statechart model

A statechart or statechart model consists of several components.

The most important part is the canvas, comprising one or more top-level regions. Regions in turn are containing states and transitions. For hints on how to use the statechart editor to modify a statechart, see section "Editing statecharts".

The definition section is a textual statechart model component. It contains definitions of namespaces, interfaces, variables, events, operations, etc.

Most objects defined in the definition section have a type. For example, a variable could be of the integer type. Another example is the type of the return value (if any) of an operation. Events can be typed as well.

A type system or domain specifies which types are available. itemis CREATE has a built-in type system. Section "Types" lists the types that are available in itemis CREATE’s standard domain.

itemis CREATE provides additional domains. These domains allow a deeper integration with different target languages and environments:

Please be aware that these domains require a Professional Edition License.

Statechart elements

Regions

CREATE Statecharts are organized in regions. Hence it is possible to organize multiple state machines in different regions and to run them virtually concurrently.

Orthogonal regions

Orthogonal regions

Regions typically contain states and transitions. A state in turn can contain one or more regions, turning it into a composite state (contains one region) or an orthogonal state (contains two or more regions).

States

States are the central elements of a state machine. A state has to be placed inside a region and must have a name that is unique within this region. During state machine execution, a state is either active or passive.

A state can have behavior. The behavior specifies which actions are executed on which conditions. Such actions can be triggered by entering the state, leaving the state, occurrence of events, conditions becoming true, or time passing. The behavior specification is a text in a state’s box and consists of a sequence of local reactions .

The state Countdown in the sample statechart below has three local reactions:


State example

State example: A simple state machine to launch a rocket.

When the Countdown state is entered, it sets the counting variable t to 10. As long as that variable’s value is greater than 0, each second it gets counted down by 1. The operation speak provides audible information on how many seconds to go until the rocket is launched. If t has been counted down to 0 – checked by a transition’s guard condition –, the Countdown state will become inactive and launch the rocket upon exiting. The countdown can be aborted anytime before launch by a cancel event. (See figure "Transition example" for a different state machine which solves the same task but puts more emphasis on transitions.)

The state’s behavior contains a subtle error. Can you spot it?

Transitions

A transition is the transfer of one state to another. A transition is diagrammed as an arrow leading from a source state to a target state. When a transition is taken, the source state ceases to be active, and the target state becomes active instead.

A transition should have a reaction . A transition’s reaction specifies

The occurrence of an event, a condition becoming true, or time passing can trigger a transition. The transition’s reaction is attached to the transition’s arrow as a text. Its syntax can be found in the section on reactions.

Please note: Transitions without a reaction are possible, but useless. They will never be taken.

Here’s an example:


Transition example

Transition example: A simple state machine to launch a rocket.

The initial transition’s effect sets the counting variable t to 10. As long as that variable’s value is greater than 0, every second it gets counted down by 1. The operation speak – executed as one of a transition’s actions – cares for audible information on how many seconds to go until the rocket is launched. If t has been counted down to 0 – checked by a transition’s guard condition –, the rocket is launched. The countdown can be aborted anytime before launch by a cancel event which triggers the appropriate transition to fire. (See figure "State example" for a different state machine which solves the same task, but puts more emphasis on states.)

Figure "Transition syntax overview" shows how the syntax of a transition reaction is defined.


Transition syntax overview

Transition syntax overview

Transition priorities

If a state has several outgoing transitions, several of these transitions could in principle fire at the same time, dependent on the events that occured and on guard conditions.

Consider this example:


Transition priorities [1]

Transition priorities [1]

Which transition will be taken if the state machine is in state A and event e1 occurs?

Fortunately, itemis CREATE state machines behave deterministically, so this question can be answered unambiguously. Outgoing transitions of a state have a definite order and are prioritized by that order. The state machine checks the transitions one by one in this order and executes the first transition that fulfills all prerequisites for firing.

As you can see in figure "Transition priorities [1]", little numbers at the transition arrows indicate their priorities. This numbering is shown only if the option Show transition priority in Window → Preferences → itemis CREATE → Diagram appearance has been activated. By default, this option is not activated.

The order of transitions is a property of their source state. In the example above, the transition priorities of state A appear like this in the properties view:


Transition priorities [2]

Transition priorities [2]

To change priorities, select a transition in the properties view and click on the up or down button as appropriate.

Choices

A choice is a pseudo state. It is used to model a conditional path. If a choice’s incoming transition is taken, its outgoing transitions are immediately evaluated to decide which path to take. To ensure there is always a valid path, a default transition can be defined with the trigger else or default.

Example with a choice node and else-transition

Example with a choice node and else-transition

Composite states

itemis CREATE allows to express state hierarchies by the means of composite states and subdiagrams.

A composite state is a state that contains a region with further substates. It can be used to group states into logical compounds and thus make the statechart more comprehensible.

When a composite state is entered, its entry node denotes the substate to be activated. A composite state can specify multiple entry nodes with unique names. Incoming transitions of the composite state can specify the desired entry node to take for entering the composite state.

When a composite state is left, all active substates are also left. A composite state can specify multiple exit nodes with unique names. Outgoing transitions of the composite state can specify the relevant exit node for them.

See the sections on Entry and exit points for further information and examples.

Entry and exit points

A standard UML composite state is always entered via its initial state. The latter denotes the inner state that is to be activated, unless a history state tells otherwise. Since there can be only a single initial state per region, a standard UML composite state always starts at the same inner state (history states aside).

Unlike UML composite states, however, composite states in CREATE Statecharts can additionally denote specific named entry points. A transition leading to a composite state can specify the entry point to be used instead of the initial state.

Analogously, a composite state can have named exit points. Outgoing transitions of that composite state may specify which exit point to react to, and thus lead to different target states, depending on which of the source composite state’s exit points has been taken. A blank transition with no trigger or guard reacts to all exit points, and is needed when a composite state contains a default exit point.


Entry and exit points overview

Entry and exit points overview

The syntax to connect a transition to an entry point with the name entry-point-1 of a target composite state is as follows:

# >entry-point-1

A named exit point can be used as follows:

# exit-point-1> [ exit-point-2> ]…

It is also possible to specify both entry and exit points in a single transition specification. The order of exit and entry points is irrelevant. Instead, the position of the > character is decisive:

The sample statechart in figure "Entry and exit points" contains two composite states:

The question is how to connect the exit points of Process to the corresponding entry points of Handle result. This is done by two transitions leading from Process to Handle result and appropriate specifications.

The transition shown on the left specifies # no_problem> >success. This means: If the source composite state is left via the no_problem exit point, then enter the target composite state at the success entry point. The specification of the transition on the right is analogous: If the source state is left via the problem exit point, then enter the target state at the failure entry point.

Alternatively, Process could have been modeled with two different error exit points, say error_1 and error_2. This would allow to respond differently to different error conditions, while still enabling to catch them both with a single flow. A transition with # >error_1 >error_2 problem> would do so.


Entry and exit points

Entry and exit points by example

The entry or exit points to take have to be specified at the right-hand side of a transition specification. The corresponding syntax element is the TransitionProperties non-terminal symbol that is shown in figure "Transition syntax overview". It is part of the TransitionReaction.

More on entry and exit points can be found in sections "Entry points" and "Exit points".

Entry points

When a state machine starts or when the control flow enters a region, an entry point, or simply entry, defines which state is to be activated first. The flow passes through the state machine’s or the region’s entry point and transitions to the target state the entry point’s transition is pointing to. This state becomes active.

An entry point has a single outgoing transition and no incoming ones. Its outgoing transition has neither a trigger nor a guard condition. It is always taken immediately.

An entry point is depicted as a filled circle, see figure "Entry and exit points overview".

Default entry point and initial state

An entry point without a name is called the default entry point. It is similar to the UML’s initial state. However, while the transition from the initial state to an ordinary state may specify a guard, the transition sourced at an entry point cannot.

A region may have at most one default entry point.

Named entry points

The default entry point specifies a single entry point into a region. A region can provide a multitude of additional or alternative entry points, thus implementing different kinds of behavior, depending on which entry point has been taken. If a region comprises multiple entry points, these entry points must have names. An entry point’s name must be unique within its region.

The default entry point implicitly has the name default. Alternatively, it is possible to explicitly give the name default to the default entry point. Semantically both variants are equivalent. Whether an entry point has no name or has the name default, in both cases this entry point is called the default entry point.

An incoming transition to a composite state can specify the named entry point it shall lead to. For details, see section "Entry and Exit points".

Named entry points have no equivalent in the UML.

Exit points

An exit point, or simply exit, is a pseudo state that is used to leave and deactivate a composite state. Exit points are counterpart to entry point. See section "Final state" for a different way to terminate a region or state machine.

An exit point may have multiple incoming transitions and has no outgoing one.

An exit point is depicted as an unfilled circle with an X-shaped cross, see figure "Entry and exit points overview".

Within a region, multiple exit points are allowed. Each exit point must either have a name that is unique within its region or be the default exit point. The default exit point is either unnamed or has the name default, which is semantically equivalent. A region may have at most one default exit point. For details on how to connect named exit points to transitions, see section "Entry and exit points".


Exit points

The event e leads to the unnamed (default) exit point, which is connected to the blank transition. The event g activates the transition to the exit point named g, for which no specific transition exists, so the blank transition to state E is taken. The event f leads to the named exit f. The lower outgoing transition is connected to this exit point via # f > and takes precedence over the blank transition, thus state F becomes active. Named exit points take precedence over the actual transition priority.

When the control flow of a composite state reaches an exit point in any of its regions, all states in other regions of that composite state, if any, are deactivated immediately. The composite state will be left and be deactivated. It maintains no status information that could be probed from the outside. In other words, reaching an exit point in one of a composite state’s regions has severe consequences for all the other regions, since they are exited and disposed immediately. After that, the containing composite state is also exited. There must be an unguarded transition that catches the exit and leads to another state outside of the composite state. The semantics of an exit point is different from that of a final state; please see section "Final state" for details.

Named exit points have no equivalent in the UML.

Final state

A final state denotes the end of the execution flow of a state machine or region. See section "Exit point" for a different way to terminate a composite state.

A final state is depicted as an unfilled circle with a smaller filled black circle inside.

Like a regular state, A final state can have multiple incoming transitions.

Within a region, only a single final state is allowed, but each region may have its own final state.

When a region reaches its final state, control stops there and waits until all other orthogonal regions, if any, have reached their respective final states, too. The semantics of final states is different from that of exits; please see section "Exit point" for details.

Please note: In itemis CREATE, final states are proper states. This is different from the UML, where a final state is a pseudo state, i.e., in the UML a final state cannot have any properties that normal states can have, except for a name.

Orthogonal states

An orthogonal state is basically a composite state with more than one region. These regions are executed virtually concurrently. Please note the word virtually! itemis CREATE does not guarantee in any way that orthogonal regions are really executed concurrently. At the moment, no code generator utilizes threads to achieve this. Orthogonal states should rather be understood as a manner to have two or more sub-statecharts working together, however, they are executed one after the other in every cycle, and in a defined order: top to bottom, left to right. The same applies to multiple regions in the statechart itself. Please consult section "Raising and processing an event" for further information on region priorities and their meanings for the statechart execution.


Overview of a orthogonal state with fork and join nodes

Orthogonal state and synchronization nodes

Synchronizations

A synchronization is a means to either split a flow into several parallel regions of a substate or to join several parallel flows from orthogonal regions into a single flow.

The synchronization state corresponds to the UML’s concepts of fork and join. Whether a synchronization state behaves as a fork or as a join depends on its usage.

A synchronization state is shown as a thick horizontal or vertical line, as can be seen in figure "Orthogonal state and synchronization nodes".

For a synchronization to actually join the incoming transitions and execute the outgoing one, all of the following conditions must be met:

Figure "Orthogonal state and synchronization nodes" shows a sample statechart containing a forking and a joining synchronization. After having left the Start state, the synchronization state forks the execution flow into two regions r1 and r2. Both are part of the Orthogonal State and both are executed virtually concurrently. That is, when activating Orthogonal State, the substates A1 and B1 also become active. When the flows continues and both A2 and B2 have been reached, the synchronization state on the right-hand side joins the flows and transitions to substates End, making it the active state. However, as long as only one of A2 and B2 is active, the synchronization will wait for the other one to also become active, before proceeding to End. In case events and/or guards are used on the incoming transitions of a joining synchronization, all conditions need to be satisfied at the same run-to-completion cycle in order to join the flows.

Shallow history states

A shallow history state is a pseudo state that is placed inside the region of a composite state. It is used to remember the last active state inside a composite state. This makes it possible to jump back to the remembered state instead of starting at the inner initial state again.

A history state saves the current state exactly when its containing region is left. A shallow history state saves the state of the current level only. If you need to save the status of multiple nested composite states, use a deep history state.

The following example, showing the answering of a questionaire, explains this:

Shallow history [1]
Shallow history [2]
Shallow history [3]

Inside the answeringQuestions composite state, it is always possible to send a pause event, which will return to the init state. At this point, the previous state, i.e., the last-answered question, is saved to the shallow history state.

Shallow history [4]

When the continue event is triggered, the most recent active state inside of the composite state answeringQuestions is activated again. The respondent doesn’t have to answer the previous questions again, he can simply resume.

Shallow history [5]

Deep history states

A deep history state is similar to a shallow history state, but more complex. With a deep history state, the latest status of multiple nested states is remembered.

A history state saves the current state exactly when its containing region is left. A deep history state saves the status of multiple nested composite states. If saving the state of the current level only is sufficient, consider using a shallow history state instead.

Definition section

The definition section is a text area. Per default, it is located to the left of the canvas. You can move or resize it like other elements on the canvas.

In the definition section, you have to define entities you want to use in your statechart. This includes variables, events, and operations. Variables and events have to be defined in the scope of a named interface or the internal interface. Especially useful for larger parts of a statechart model is the possibility to use namespaces.

When it comes to code generation all these elements are properly reflected in the generated source code as far as the respective target language supports it.

Scopes

Namespaces

The statechart language allows to define unique namespaces. They can be used to qualify references to statechart elements.

namespace trafficlights

Imports

Imports can be used to make elements visible that are defined in another file. In the default domain it is possible to import other statechart types (see also multi state machine modeling ).

Different statechart domains allow to import different file types. For example, the C/C++ domain allows to import header files.

// multi state machine modeling (default domain)
import: "LED.sct"
// header import in C/C++ domain
import: "MyHeader.h"

Interface scopes

Declarations in the interface scope are externally visible. They can be shared within the environment, e.g., client code that uses the state machine.

interface NamedInterface:
  in event event1
  out event event3 : integer
  var variable1 : integer

Please note: All elements defined in a named interface must be referenced using that interface’s name, such as NamedInterface.event1, NamedInterface.event3, or NamedInterface.variable1.

It is also possible to have a single unnamed interface, which is externally visible as well:

interface:
  in event event1

It behaves exactly as a named interface.

Internal scope

Definitions made in the internal scope are visible within the statechart only, but not to the outside. It is not possible to access them from client code.

internal:
  var localVariable1: integer
  event localEvent: integer
  operation localOperation (int1 : integer, int2 : integer): integer
  localEvent2 / raise NamedInterface.event3 :
  localOperation(valueof(localEvent) , NamedInterface.variable1)

Variables

Variables have to be defined in an internal or external interface. Variables in the internal scope are not visible to any client code.

var variable1: real = 2.5

Variables that are defined in a named interface have to be referenced using the interface name, see section "Interfaces".

Variables are always typed, see section "Types".

Variables may have an initial value.

var variable1: real = 2.5

The variable type may be omitted and inferred from the specified initial value.

var variable1 = 2.5

Variables can be marked by the readonly keyword, which has the effect that client code can only read them. Please note that this restriction is imposed on the client code only. Readonly variables can still be modified from within the statechart.

var readonly pi: real = 3.1415

Constants

A variable can be immutable, i.e., constant. Such variables are marked by the const keyword. They can neither be modified by the client code nor from within the statechart.

const variable1: real

Events

An event is something of importance that happens at a certain point in time in the context of a state machine. For example, a user pushes a button, a temperature sensor delivers a value, a period of time has passed, etc. An event can be of one of three basic types:

Events that are defined in a named interface need to be referenced using the interface’s name, see section "Interfaces".

Events can be processed in triggers, see section "Trigger specification". As events are treated as booleans, they can also be used in guards, see section "Guard conditions". In order to raise an event in the state machine, see section "Raising an event". For details on the processing of events see section "Raising and processing an event".

Incoming and outgoing events

An event in an interface scope has a direction. It is either incoming or outgoing.

In an event declaration, the corresponding keywords are in and out, followed by the keyword event, followed by the event’s name.

interface NamedInterface:
  in event event1
  out event event2

Events in the internal scope do neither enter nor leave the state machine, thus they don’t have a direction.

internal:
  event ev1

Events with values

An event can be typed and can carry a value:

internal:
  event event1 : integer

Read access to an event’s value is possible in the statechart using the valueof() built-in method, see section "Built-in methods" for details.

Please note: Reading an event’s value is possible only when the event actually occurs, for example in a guard condition.

Example (reading an event’s value in a transition’s guard condition):

event1 [valueof(event1) == 6]

An event parameter can be specified when raising an event, as in the following example:

raise event1 : 3+3

Regarding the syntax of raising an event, see section "Raising an event". Regarding the more complicated details of processing an event, see section "Raising and processing an event".

Operations

An operation connects a state machine to the outside world by making external behaviour accessible to the state machine.

A state machine typically interacts with the outside world, in order, for example, to read data from a sensor, engage an actuator, etc. The client software has to provide such behaviour as functions or methods in a programming language the state machine can interact with. An operation is the statechart language’s means to call such an external procedure from the state machine.

Consider, for example, a C function float read_sensor() that should be called by the state machine. To interface with that function, an operation read_sensor must first be defined in the state machine, and can then be called from, e.g., a state or transition. At execution time, a call to the read_sensor operation is mapped to an actual call of the external C function with the same name. To make this work, the statechart must have been generated as source code of the respective target language, of course.

It is the purpose of a code generator to create a suitable construct in the respective target language for the procedure call. For details on code generation, please see section "Generating state machine code".

Operations can have none, one, or multiple parameters. A parameter is declared with a name and a type. An operation may have a single or no return type similar to usual programming languages. Please see section "Types" for details.

operation myOperation (xValue: integer, yValue: integer): integer

You can call myOperation by using positional parameters:

myOperation(27, 42)

This call assigns the value 27 to the operation’s xValue parameter and 42 to yValue.

Alternatively, you can use named parameters, like in the following example:

myOperation(xValue = 27, yValue = 42)

Named parameters make their order irrelevant. The following call is semantically equivalent to the one above:

myOperation(yValue = 42, xValue = 27)

While an operation call with named parameters is longer than the equivalent call with positional parameters, named parameters are a great means for self-documenting code (especially if the parameter names are more telling than in the example above).

Operations with a variable number of parameters are supported, too. To be more exact, it is possible to specify an operation’s last parameter as being allowed to occur an arbitrary number of times. This feature is usually called “varargs”, short for “variable number of arguments”. Compared to a “regular” operation parameter declaration, the varargs parameter name is followed by three dots ( ...) to indicate it may occur zero or more times.

For example, an operation sum adding a variable number of summands and returning their sum could be defined as follows:

operation sum(count: integer, summand...: integer): integer

Sample calls of this operation are sum(1, 42), sum(2, 4711, 815), sum(7, 555, 338, 881, 192, 69, 999, 610), or even sum(0). In this example the first parameter advises the called function or method of how many instances of the last parameter it should expect. Whether such information is needed or not depends on the target language. For example, a C function needs to receive this information while a Java method does not.

Specifying semantic variants

Statecharts exist in different semantic flavors and itemis CREATE supports a large range of semantical options. These variants can be defined for each statechart individually by specifying by annotating statecharts.This section gives an overview of the different annotations which are available. As all annotations influence the behavior of statecharts specifying these will have impact on the simulation and the generated code. All annotations are supported by all code generators.

@CycleBased

The @CycleBased annotation specifies that the cycle-based execution scheme is to be used.

Synopsis: @CycleBased( period)

The mandatory parameter period indicates the suggested period of time between two successive run-to-completion steps in milliseconds. Only the statechart simulator and the SCTUnit testing framework take the period value into account, however. It is neither of significance to nor reflected in the generated code, and thus it remains the client code’s responsibility to explicitly call runCycle() – and to decide when to do so.

If the definition section contains neither the @CycleBased nor the @EventDriven annotation, the state machine will behave as if @EventDriven would have been coded.

Example: The definition section below specifies that the state machine should behave according to the cycle-based execution scheme with an interval of 100 milliseconds between two cycles.

@CycleBased(100)

interface:
    in event e

@EventDriven

The @EventDriven annotation specifies that the event-driven execution scheme is to be used.

Synopsis: @EventDriven

If the definition section contains neither the @CycleBased nor the @EventDriven annotation, the state machine will behave as if @EventDriven would have been coded.

Example: The definition section below specifies that the state machine should behave according to the event-driven execution scheme.

@EventDriven

interface:
    in event e

@SuperSteps

The @SuperSteps(yes | no) annotation enables or disables the superstep semantic for a run-to-completion step. In contrast to a regular step, a superstep executes all valid subsequent state transitions. If no @SuperSteps annotation is specified, the state machine will behave as if @SuperSteps(no) would have been coded.

Take a look at the example model below:

Example model for superstep semantic

Without the superstep semantic, an incoming event e causes only one state transition, e.g. from state A to state B. However, when superstep semantic is enabled, raising event e causes a state transition from A over B to C. As there is no other outgoing transition from C, the local reaction is also executed, hence x is set to 42.

You can think of the superstep semantic as a loop which performs a regular step until no state is entered in the regular step. See the following pseudo-code (a regular step is called microStep here):

do {
    stateEntered = false
    microStep()
} while (stateEntered)

Please note, the flag stateEntered is set to true inside a microStep whenever a state is entered. During the execution of a superstep all activated events remain active. The choice of superstep semantics has no impact on the semantic variants specified by other annotations like event-driven or cycle-based state machines, event buffering or parent-first / child-first execution order.

Local events can also lead to a multi-step execution of a state machine. The execution of these multiple steps are a result of the iterative processing of the local event buffer (queue in event-driven case or vector when cycle-based). Supersteps are applied to each of these local event processing steps. So event loops are executed on a higher execution level than supersteps. To sum up, let’s take a look at a slightly more complicated example:

Example model for superstep semantic in event-driven statechart

What happens when state A is active and event e is raised? First, event e invokes a superstep like in the previous example. While taking the state transition to B and C, the local events local1 and local2 are put into the internal event buffer (queue or vector). However, they are not visible until the processing of event e is finished. That means that the local reaction in state C is executed because no outgoing transition can be taken. Hence, x is set to 42. Afterwards, the local events are processed, event by event in the event-driven case or all at once if cycle-based. This again invokes a superstep and state L is entered. As with each self-transition, state L is exited and re-entered again, the superstep loop continues until x equals to 17. Next, internal event local2 is considered and state C is entered. The local reaction in state C is not executed, as event e is no more raised.

Please note: The example above also reveals a potential problem when using superstep semantics. If we omitted the guard [x > 17] at the self-transition of state L, the execution of the state machine would end up in an infinite loop. This is because a self-transition leaves and re-enters its target state, causing the superstep loop to continue. As during its execution all activated events remain active, the state machine ends up in an infinite loop. This is not the case for time triggers. Time triggers are always deactivated after the transition has been taken.

@ChildFirstExecution

The @ChildFirstExecution annotation specifies that the state machine should always execute the substates (“children”) of an active composite state first, before executing the composite state (“parent”) itself. Please see section "Parent-first versus child-first execution" for details and examples.

Synopsis: @ChildFirstExecution

Please note that @ParentFirstExecution specifies the opposite behaviour. Both @ChildFirstExecution and @ParentFirstExecution are global settings for all composite states.

If the definition section contains neither the @ParentFirstExecution nor the @ChildFirstExecution annotation, the state machine will behave as if @ChildFirstExecution would have been coded.

@ParentFirstExecution

The @ParentFirstExecution annotation specifies that the state machine should always first execute an active composite state (“parent”) itself, before executing its substates (“children”). Please see section "Parent-first versus child-first execution" for details and examples.

Synopsis: @ParentFirstExecution

Please note that @ChildFirstExecution specifies the opposite behaviour. Both @ChildFirstExecution and @ParentFirstExecution are global settings for all composite states.

If the definition section contains neither the @ParentFirstExecution nor the @ChildFirstExecution annotation, the state machine will behave as if @ChildFirstExecution would have been coded.

@EventBuffering

The @EventBuffering annotation specifies the strategy for buffering incoming and local events. By default event buffering is enabled for incoming and local events.

Synopsis: @EventBuffering( inEvents, localEvents)

The event buffering strategy has a large impact on event processing and which constraints must be considered when integrating generated state machine code. With event buffering enabled all events will be buffered before they are processed. At the beginning of a run to completion step (RTCS) all events which will be processed during the step will be taken from the buffer and activated for processing. After the step all events are consumed. If events are raised during a run to completion step they will be stored in the buffer. So they won’t have an effect on the current step but are processed in following steps.

The kind of buffers are different for event-driven and cycle-based state machines. An event-driven state machine will use a queue for buffering events. Each event from the queue is processed in a single RTCS and events are processed in the order of arrival. As events are the trigger for run to completion steps the queue will be processed until it is empty. This means that all events which are raised during a RTCS will directly be processed so that multiple RTCS might be executed as the result of raising one event.

In contrast, cycle-based state machines are triggered by explicit calls to the state machines runCycle() method. This call triggers a RTCS in which all buffered events will be activated for processing. As cycle-based state machines process an event vector during a RTCS also the event buffer is a vector.

Statecharts support incoming events which can be raised on their interface and local events which are only visible within the state machine. Event buffering covers both kind of events but uses two separate buffers. Local events are guaranteed to be always processed before any other incoming event. This means that if local events are raised by the state machine during a RTCS these will be buffered and then be processed directly after the step finished. During processing of an local event further local events may be raised which also trigger the next step. So you have to be careful not to construct infinite local event processing loops. While the general approach is the same for event-driven and cycle-based state machines the details differ again. In the cycle-based case all local events raised within a step will be activated in the following step while in the event-driven case local events are processed one by one.

Event buffering is enabled by default but you can explicitly specify the buffering strategy using an annotation.

@EventBuffering(inEvents = true, localEvents = true)

While enabling event buffering is the best choice in general there are two main reasons why you may want to disable it. The first is backward compatibility to state machines developed with tool versions 3.x and earlier. The second reason is to save memory required by event buffers. You should consider the following points:

  1. If event buffering for incoming events is disabled then you must make sure that no event is raised on the state machine while the machine is processing a RTCS. This is during a runCycle() call of cycle-based state machines or during raising an event in the event-driven case. Events raised during an RTCS won’t be processed properly.
  2. If you use an external event queue e.g. provided by an RTOS then the in event queue may not be required in the event-driven case.
  3. For event-driven statecharts the local event buffering can’t be deactivated.
  4. To make cycle-based state machine code to behave like in version 3.x then you have to use @EventBuffering(inEvents=false, localEvents=false).
  5. When deactivating local event buffering for cycle-based statecharts then behavior may change considerably. Without a buffer local events are directly activated when they are raised and are only visible in the current RTCS. As a result these events are only visible to those parts in parallel regions which are processed after raising. This is called downstream visibility.
  6. When deactivating local event buffering for cycle-based statecharts then the RTCS step is guaranteed to be processed in constant time as no iteration produced by local events can occur.

Reactions

Reactions are one of the most important features of the itemis CREATE language. Basically everything that happens in a statechart happens in a reaction.

Reactions can be attached to states as well as to transitions. While states can have as many reactions as you wish, transitions can only have one.

The syntax follows the standards of automata theory, where the output is put into relation to the input of the automaton using the following notation (especially Mealy automata):

input / output

itemis CREATE uses the following syntax for all reactions:

trigger [ guard ] / effect

The possible values that can be specified as a trigger depend on the context, which is either a state or a transition.

All three components are grammatically optional, though a reaction with neither a trigger nor a guard will never happen. Reactions with no effect are useful for transitions, the slash / can be omitted as well then.

Trigger specifications

Reactions can define a trigger that needs to occur to activate the reaction. Events are possible triggers, as well as certain keywords defined in the statechart language.

Triggers can be combined with guards to further define the execution conditions of the reaction. In that case, the reaction is only executed if both the trigger occurs and the guard condition is true.

You can define multiple triggers for a reaction, separated by comma: trigger1, trigger2. For the combined trigger to fire, it is sufficient that one of the individual triggers occurs.

There are a couple of special triggers defined by the statechart language:

Examples:

Figure "Event specifications syntax overview" shows where to put event specifications in a reaction trigger and how their syntax is defined.


Event specifications syntax overview

Event specifications syntax overview

Reaction trigger "after"

The after trigger specifies a one-shot time event.

After the specified period of time the reaction is triggered. An after trigger can be used in transitions of states as well as in local reactions of states and statecharts. The specified period of time starts when the state or statechart is entered.

after 20 s

Synopsis: after time unit

The time value is a integer literal or an expression with an integer value.

The time unit is one of:

Reaction trigger "every"

The every trigger specifies periodic time events.

The reaction is triggered recurrently after each passing of the specified period of time. An every trigger can be used in transitions as well as in local reactions of states and statecharts. The specified period of time starts when the state or statechart is entered and repeats periodically.

every 200 ms

Synopsis: every time unit

The time value is a integer literal or an expression with an integer value.

The time unit is one of:

Reaction trigger "always"

The always trigger is always true and enables a reaction to be executed in every run-to-completion step (RTC). This trigger is equivalent to the oncycle trigger.

Reaction trigger "oncycle"

The oncycle trigger is always true and enables a reaction to be executed in every run-to-completion step (RTC). This trigger is equivalent to the always trigger.

Reaction trigger "else"

The else trigger is intended to be used for the outgoing transitions of choice pseudo states to make sure that there is always an outgoing transition that can be taken. It can only be be used in transitions and implies the lowest evaluation priority for that transition. The default trigger is equivalent to the else trigger.

Reaction trigger "default"

The default trigger is intended to be used for the outgoing transitions of choice pseudo states to make sure that there is always an outgoing transition that can be taken. It can only be be used in transitions and implies the lowest evaluation priority for that transition. The default trigger is equivalent to the else trigger.

Reaction trigger "entry"

An entry trigger marks actions that are carried out when entering a state or state machine, immediately before making it active.

Please note: A self-transition, leading from a state back to itself, actually first leaves and then re-enters the state. That means that its exit effects as well as its entry effects are executed. This is in contrast to a local reaction, which is executed without leaving the active state. Thus exit and entry effects are not executed in the latter case.

Reaction trigger "exit"

An exit trigger marks actions that are carried out when exiting a state or state machine, immediately after making it inactive.

Please note: A self-transition, leading from a state back to itself, actually first leaves and then re-enters the state. That means that its exit effects as well as its entry effects are executed. This is in contrast to a local reaction, which is executed without leaving the active state. Thus exit and entry effects are not executed in the latter case.

Guard conditions

A guard condition, or simply guard, is another option that can be used to specify when a reaction should be executed. Guard conditions can be used on their own or in conjunction with a specified trigger . In the latter case, the trigger needs to be fired and the guard needs to be true for the reaction to fire its effect.

As a reminder, the complete reaction syntax is as follows:

trigger [ guard ] / effect

In the square brackets you can use any expression that evaluates to a boolean. Boolean variables, all kinds of comparisons, and operations returning a boolean fall into this category. Furthermore, events are also treated as booleans which are true when the event is active. This allows to check for the simultaneous occurrence of multiple events by concatenating them with ‘&&’.

Please note: itemis CREATE does not support the concept of “truthy and falsey” seen in C, Javascript or Python. [x] is not a valid guard condition, unless the type of x is boolean.

Please consult figure "Guard condition syntax overview" to find out how a guard condition syntactically fits into a reaction.


Guard condition syntax overview

Guard condition syntax overview

Actions and reaction effects

A transition specification may contain zero, one or more actions that are executed when the transition is taken. An action could be something like assigning a value to a variable, calling an operation, or raising an event. All actions taken together are called the transition’s reaction effect, or simply effect. The complete syntax for reactions is as follows:

trigger [ guard ] / effect

This means that the effect will only be executed if the trigger fires or does not exist and the guard condition evaluates to true or does not exist and at least a trigger or a guard exist. See the sections about triggers and guard conditions.

Normally, actions are statements. Note that you can also use the conditional expression to make some constructs more elegant.

If an effect shall consist of multiple actions, they must be separated by a semicolon. That means the last action is not followed by a semicolon. The syntax is:

trigger [ guard ] / action1 ; action2 ; action3 ;

A reaction in a state always has a reaction effect with at least one action.

Figure "Reaction effect syntax" shows the syntax definition.


Reaction effect syntax

Reaction effect syntax

Example: When a transition or local reaction specified as ev1 [x > 3] / x += 1; notify(x); raise ev2 is executed, it increments variable x by 1, calls the notify operation with x as parameter, and raises event ev2.

Raising and processing an event

For the syntax of event raising, see section "Raising an event".
For the syntax of event declaration, see section "Events".

There are different variants of event processing semantics. These can be defined individually for each statechart by using different annotations:

Types

The itemis CREATE statechart language has an integrated type system consisting of the following simple types by default:

Specific statechart domains like the C/C++ Domain or the Java Domain contribute additional types.

Statements

A statement is one of three kinds:

Assignments

The language has the following assignment operators:

simple assignment =
multiply and assign *=
divide and assign /=
calculate modulo and assign %=
add and assign +=
subtract and assign -=
bitshift left and assign <<=
bitshift right and assign >>=
bitwise AND and assign &=
bitwise XOR and assign ^=
bitwise OR and assign |=

Raising an event

An event is raised by using the keyword raise, followed by the event name, e. g. raise incoming_call. If the event is an interface event, the name of the interface must be prepended, using dot notation.

Example:

interface intrfc:
  out event ev

Usage in the statechart:

always / raise intrfc.ev

See also sections "Declaring events" and "Raising and processing an event".

Calling an operation

An operation is called similarly to other programming languages using the operation name and passing actual parameter values in parenthesis and separated by comma. The parameters can be expressions. The parenthesis can be omitted when no parameters are passed. Please see section "Operations" for an example.

Expressions

Expressions in the itemis CREATE statechart language are similar to expressions in other programming languages. The language provides operators for logical expressions, number arithmetic, bitwise arithmetic, and bit shifting.

The type of a logical expression is boolean.

Logical AND

expr1 && expr2

Logical OR

expr1 ||  expr2

Logical NOT

!expr1

Conditional expression

expr1 ? expr2 : expr3

If expr1 evaluates to true, this returns expr2, else exp3. This can be used to assign values to variables:

y = x > 5 ? 1 : 2

This does the same as the following snippet of C code:

if(x > 5) {
  y = 1;
} else {
  y = 2;
}

Bitwise XOR

expr1 ^ expr2

Bitwise OR

expr1 | expr2

Bitwise AND

expr1 & expr2

Logical relations and shift operators

less than <
equal or less than <=
greater than >
equal or greater than >=
equal ==
not equal !=
shift left <<
shift right >>

Binary arithmetic operators

plus +
minus -
multiply *
divide /
modulo %

Unary arithmetic operators

positive +
negative -
complement ~

Built-in functions

event.value (was “valueof(event)” before)

An event can have a value. This function returns the value of the specified event.

If the event does not have a return value then it gets evaluated as void.

Previously the syntax for this mechanism was “valueof(event)” but this access has limited capabilities and will be deprecated in the future.

myVar = myEvent.value

as

Casts a variable. The following example casts a literal from integer to real.

myReal = 12 as real

active(state)

Returns true if the specified state is active and false otherwise. The specified state can be a regular state or a final state.

myBool = active(StateA)

triggerWithoutEvent

Performs a state machine run-to-completion step without raising any event.

entry / triggerWithoutEvent

Parent-first and child-first execution

Whenever a state machine is in a composite or orthogonal state, multiple states are active at the same time: the composite/orthogonal state itself (“parent”) and one or more of its substates (“children”).

When a micro step is executed e.g. triggered by an event, then the state machine checks each active state for a transition that can be taken, based to the event(s) received and the guard conditions on the transitions. As soon as a matching transition is found, it is taken immediately, and its target state becomes active. This will be done for each active state, i.e. all orthogonal regions are processed. Since the first match always wins, it is crucial in which order states are checked and how you can control that. In an orthogonal state, active substates are checked according to the order of their regions. The order of top level regions is displayed in the region itself. Child regions in a state are arranged either from left to right or from top to bottom depending on the visual region alignment.

Whether the parent state or its child state(s) are checked first, you can specify by setting either the @ParentFirstExecution annotation or the @ChildFirstExecution annotation in the statechart’s definition section. If the definition section contains none of these annotations, @ChildFirstExecution is assumed. Whichever variant you choose, it is statechart-global and thus applies to all composite and orthogonal states.

Please note: Specifying parent-first or child-first execution pertains to checking for matching transitions only, not to entry and exit actions. Entry actions are always executed from the outside to the inside, i.e., on the parent state first and after that on the children. Exit actions are executed in reverse : in child states first, followed by the parent state.

Examples

Parent-first versus child-first execution are best explained by a couple of examples.

Simple child-first/parent-first examples

Example 1a:

Consider the statechart in the figure below. Composite state A and its substate B are active, and the @ChildFirstExecution annotation has been specified in the definition section.

Child-first, example 1a, before transition

Child-first, example 1a, before transition

When event e occurs, the state machine considers child state B first, finds a matching transition, and thus immediately proceeds to state D, see the figure below.

Child-first, example 1a, after transition

Child-first, example 1a, after transition

Example 1b:

Consider the statechart in the figure below. Composite state A and its substate B are active, and the @ParentFirstExecution annotation has been specified in the definition section.

Parent-first, example 1b, before transition

Parent-first, example 1b, before transition

When event e occurs, the state machine considers parent state A first, finds a matching transition, and thus immediately proceeds to state C, see the figure below.

Parent-first, example 1b, after transition

Parent-first, example 1b, after transition

Child-first/parent-first and reactions in states

The following examples are somewhat more complex. The statechart used in the examples defines the integer variables m, n, o, p, q, and r. Initially, they are all set to 0. Reactions in states A and B set these variables to non-zero values on certain conditions:

This is useful to understand which actions are performed (or not performed) and in which order.

The reactions in composite state A are as follows:

entry / m = 1
e / n = 1
exit / o = 1; r = 1

The reactions in substate B are as follows:

entry / m = 2
e / p = 1
exit / q = 1; r = 2

The settings above are the same for all subsequent examples, except for example 4.

Example 2a:

Consider the statechart in the figure below. Composite state A and its substate B are active, and the @ChildFirstExecution annotation has been specified in the definition section.

Child-first, example 2a, before transition

Child-first, example 2a, before transition

In this scenario, A and B have just been entered, and their entry actions have already been executed. Since the execution order of entry actions is independent of parent-first/child-first execution order and always proceeds from outer states to inner states, the entry action of A is executed first and sets variable m to 1. After that, the entry action of B is executed and overrides variable m with a value of 2.

When event e occurs, the state machine considers child state B first, finds a matching transition, and thus immediately proceeds to state D, see the figure below. The state machine executes the exit actions of A and B after these states have become inactive.

Child-first, example 2a, after transition

Child-first, example 2a, after transition

It is worth having a look at the variables and understand what has happened. When the state machine is in state D, the variable values are as follows:

Variable Value
m 2
n 0
o 1
p 0
q 1
r 1

We have already seen why m is 2.

Variable n would be set to 1 by a reaction in A, triggered by event e. However, since the statechart is in child-first mode, and the e event triggers an immediate transition from B to D, it is no surprise that n remains 0. The composite state is left before e / n = 1 in A gets any chance to be executed.

However, p is also 0, although B has priority over A, according to child-first execution. The reason is that an active state is checked for possible transitions first, and reactions within the state are executed second. This can lead to certain reactions not being executed at all. In this case, checking for possible transitions after receiving e finds the transition from B to D. This transition is executed immediately. “Immediately” means that B is left straight away. No further action will be done on it, and consequently the reaction e / p = 1 fails to be executed.

The only exception to the rule is are exit actions, because they are always executed when the corresponding state becomes inactive. That’s why the variables o, q, and r all have a value of 1: They have been modified in the exit actions of A and B. The execution of exit actions starts with the inner-most state and then proceeds to the outside. Here, the exit action of B has set q to 1 and r to 2. After that, the exit action of A has set o to 1 and has overridden r with 1.

Example 2b:

Consider the statechart in the figure below. Composite state A and its substate B are active, and the @ChildFirstExecution annotation has been specified in the definition section.

Parent-first, example 2b, before transition

Parent-first, example 2b, before transition

In this scenario, A and B have just been entered, and their entry actions have already been executed. Variable m has a value of 2, as explained in example 2a.

When event e occurs, the state machine considers parent state A first, finds a matching transition, and thus immediately proceeds to state C, see the figure below. The state machine executes the exit actions of A and B after these states have become inactive.

Parent-first, example 2b, after transition

Parent-first, example 2b, after transition

The variable values are the same as in example 2a and essentially for the same reasons: Entry and exit actions are executed in the same order, and any reactions on event e are not executed at all.

Example 3a:

Let’s make a small change now to the statechart in example 2a and add a guard condition [p == 1] to the transition B → D, see the figure below. Please note that the @ChildFirstExecution annotation has been specified in the definition section.

Child-first, example 3a, before transition

Child-first, example 3a, before transition

Event e causes the following to happen:

  1. Due to the @ChildFirstExecution annotation, state B is checked first for any transitions to be taken. However, since p is 0, the guard condition of B → D is not fulfilled, and the transition is not triggered.
  2. After that, the reactions of state B are considered. There is one reaction to an e event, and it sets variable p to 1. Now the guard condition would be fulfilled. However, looking for a matching transition has already been done and won’t be repeated in the current run-to-completion step.
  3. Since the child (state B) didn’t trigger a transition, checking continues with the parent (state A). Here a matching transition is found, and the execution flow proceeds to state C.
  4. The exit actions of B and A are executed.

The figure below shows the result.

Child-first, example 3a, after transition

Child-first, example 3a, after transition

The variables are set as follows:

Variable Value
m 2
n 0
o 1
p 1
q 1
r 1

Example 3b:

This example is here for the sake of completeness only. It is like example 3a, but with the @ParentFirstExecution annotation in effect.

The state machine reacts to an event e just like the one in example 2b: Since the parent is checked first and a matching transition from A to C is found, that transition is taken immediately, without considering B in any way, except for executing its exit action.

Thus in state C the variable values are as follows:

Variable Value
m 2
n 0
o 1
p 0
q 1
r 1

Example 4:

Last but not least, here’s an example that is left as an exercise to the reader: What is the next state in the statechart below after event e arrives? To find out whether your guess is correct, recreate the example and check it with the interactive statechart simulator.

Child-first, example 4, before transition

Child-first, example 4, before transition

Complete statechart language grammar

This section presents the complete grammar of the statechart language. If you are in doubt how to write down a transition specification, a variable declaration, or any other syntactical construct of the itemis CREATE statechart language, this is your definite reference that clarifies all syntactical questions.

The grammar is visualized using railroad diagrams. Railroad diagrams are easy to read and comprise all syntactically valid language constructs. Figure "Railroad diagrams explained" shows an example:

Railroad diagrams explained

Railroad diagrams explained

On the left-hand side you’ll find the so-called non-terminal symbol (or non-terminal for short) that is being defined by this particular diagram. Here the non-terminal is SimpleElementReferenceExpression. To find out what a SimpleElementReferenceExpression is allowed to look like, follow the “railroad track” just like a train would do. At each junction, the train either keeps its direction or changes it by 45 degrees, but it cannot make sharp turns of 90 degrees or more.

On its way, the train passes several “stations”. Each station represents a language element that is valid at this point. In our example, the first station is a rectangle with a grey background. The grey background denotes a non-terminal, and the word inside the rectangle is the non-terminal’s name, here: ID. You will have to look up this particular non-terminal’s railroad diagram to learn more about it. However, for simplicity and because their meanings are more or less obvious, a few non-terminals are not refined further. Examples are STRING, INT, BOOL, or ID.

In a SimpleElementReferenceExpression, a valid ID – a name – is always the first element, e.g., init42. If the train turns right at the junction, it moves directly to the railroad diagram’s exit. That means an ID like init42 is a valid SimpleElementReferenceExpression. Please note that when the train reaches the junction right before the exit, it cannot turn left, because trains don’t move that way. That is, the train is unable to travel to the ( station.

The train can reach the ) from the opposite direction only. After having left the initial ID station, the train can move to the left at the junction and then run a stretch touching only the ( and ) stations, in that order. These rectangles have a white background color, denoting a terminal symbol or terminal for short. A terminal stands for itself; write it down as it is.

Following that rule, init42() is a valid SimpleElementReferenceExpression. One or more Expressions inside the paranthesis, separated by the , terminal, are also valid. Example: init42(foo, bar + 27).

Please note:

The railroad diagrams themselves are generated from a textual grammar representation established and maintained with Xtext. If you suspect the diagrams shown here are lagging behind the actual implementation, look for files with the .xtext extension in the itemis CREATE source code distribution!

Please also note:

Not each and every construction that is syntactically allowed does make sense semantically. The statechart editor will flag such constructions as errors.

Statechart grammar

Figure "Statechart grammar" shows the statechart grammar. It makes use of the expressions grammar.

Statechart grammar

Statechart grammar

Expressions grammar

Figure "Expressions grammar" shows the expressions grammar. It is used by the statechart grammar.

Expressions grammar

Expressions grammar