SMC Manual 6 0

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 109

DownloadSMC Manual 6 0
Open PDF In BrowserView PDF
SMC Programmer’s Manual

SMC Programmer’s Manual
April 2, 2016

Page 1 of 109

SMC Programmer’s Manual

Page 2 of 109

SMC Programmer’s Manual

Table of Contents
Preface

........................................................................................................................................... 7

Section 1: .sm File Layout

................................................................................................... 8

Your Task Class ....................................................................................................................... 8
The Task Finite State Machine ................................................................................................ 10
Creating an SMC .sm File ....................................................................................................... 12
Defining FSM States ............................................................................................................... 14
Defining FSM Transitions ........................................................................................................ 15
Defining FSM Transition Actions ............................................................................................. 17
Defining FSM Default Transitions ............................................................................................. 20
Defining State Entry/Exit Actions ............................................................................................. 24
Connecting Task And Task FSM ............................................................................................. 26

Section 2: From Model to SMC ........................................................................................ 28
Instantiating a Finite State Machine ........................................................................................ 28
Simple Transition .................................................................................................................... 29
Jump Transition ...................................................................................................................... 29
External Loopback Transition .................................................................................................. 29
Internal Loopback Transition ................................................................................................... 30
Transition with Actions ............................................................................................................ 30
Transition Guards ................................................................................................................... 32
Transition Arguments .............................................................................................................. 34
Entry and Exit Actions ............................................................................................................. 36

Page 3 of 109

SMC Programmer’s Manual

Table 1: Entry/Exit Execution .................................................................................................. 37
Push Transition ....................................................................................................................... 38
Pop Transition ........................................................................................................................ 39
Default Transitions .................................................................................................................. 40

Section 3: Adding a State Machine to your Class ...................................

42

C ............................................................................................................................................ 45
C++ ........................................................................................................................................ 47
C++ using -crtp ...................................................................................................................... 49
Objective-C ............................................................................................................................ 50
Java ....................................................................................................................................... 50
Incr Tcl .................................................................................................................................... 53
VB.net .................................................................................................................................... 55
C# .......................................................................................................................................... 56
Groovy ................................................................................................................................... 57
Lua ......................................................................................................................................... 59
Python .................................................................................................................................... 60
PHP ....................................................................................................................................... 61
Perl ......................................................................................................................................... 62
Ruby ...................................................................................................................................... 63
Scala ...................................................................................................................................... 64
JavaScript .............................................................................................................................. 66

Section 4: Compiling a .sm

................................................................................................ 67

Table 2: SMC target languages ............................................................................................... 68
Table 3: SMC command line options ...................................................................................... 70

Section 5: Behind the Curtain ...........................................................................................

Page 4 of 109

71

SMC Programmer’s Manual

Section 6: For Example ... ................................................................................................... 74
Example 1 .............................................................................................................................. 74
Example 2 .............................................................................................................................. 75
Example 3 .............................................................................................................................. 75
Example 7 .............................................................................................................................. 76
PHP Example ......................................................................................................................... 76

Section 7: Queuing Up ..........................................................................................................

77

Section 8: Packages & Namespaces ............................................................................

78

Fully Qualified Class Names .................................................................................................... 79

Section 9: Be Persistent .......................................................................................................

80

C++ ........................................................................................................................................ 80
Java ....................................................................................................................................... 83
[incr Tcl] .................................................................................................................................. 85
VB.net .................................................................................................................................... 88
C# .......................................................................................................................................... 90

Section 10: Get the Picture ................................................................................................. 92
Section 11: On Reflection .................................................................................................... 93
Java Sample ........................................................................................................................... 97
C# Sample ............................................................................................................................. 98
[incr Tcl] Sample ..................................................................................................................... 99

Section 12: Getting Noticed .............................................................................................

100

Java Sample ......................................................................................................................... 100
C# Sample ........................................................................................................................... 102
VB.net Sample ..................................................................................................................... 104

Page 5 of 109

SMC Programmer’s Manual

Section 13: Giving Direction .............................................................................................

106

%start .................................................................................................................................. 106
%class ................................................................................................................................. 106
%fsmclass ............................................................................................................................ 106
%fsmfile ............................................................................................................................... 106
%package ............................................................................................................................ 106
%include .............................................................................................................................. 107
%import ............................................................................................................................... 107
%declare .............................................................................................................................. 107
%access .............................................................................................................................. 107
%map .................................................................................................................................. 107

Appendix A: SMC EBNF Grammar ..............................................................................

Page 6 of 109

108

SMC Programmer’s Manual

Preface
This manual describes how to use the state machine compiler. Hopefully, you will find this tool as useful as I
have. State machines are a natural way to describe object behavior but there has not been an easy way to
mate state machines with objects. This compiler allows you to add a state machine to just about any class
you desire (more about that later.)
I encourage you to first look at the annotated SMC code in section 1. This code demonstrates SMC's
powerful simplicity. The state machine code is simple, meaning you can easily learn it. Its simplicity also
allows you to readily build powerful, robust finite state machines.
For those of you who hang around comp.lang.c++ or comp.object, you may have read some of Bob Martin's
articles. You may have even read about his state machine compiler and gotten a copy of it. You may then
notice a striking similarity between my compiler and his. There is a reason for that: this compiler was derived
from Bob Martin's original state machine compiler.
While an employee of Clear Communications Corporation (renamed Clear and now defunct), he developed
state machine classes and later a compiler to automatically generate those classes. About this time, I came
to work for the same company and was intrigued by what Bob had done. Some six months later, Bob struck
out on his own to form Object Mentor Associates and I was left to maintain the state machine compiler. I
have added many features to the original system (arguments, default transitions, push and pop transitions,
transition guards, a more YACC-like language structure, etc.)
But no matter how much I have added, the state machine compiler will always be Bob Martin's invention. I'd
like to think that I made a good thing better.

Page 7 of 109

SMC Programmer’s Manual

Section 1: .sm File Layout
Your Task Class
SMC generates finite state machines for objects - not processes or applications but for an individual object. If
you have objects that receive asynchronous callbacks and how objects respond to those callbacks are
based on the object state, then SMC provides a powerful solution.
(Note: this example is based on simple Java and is easily translated to other languages. Also, this example
assumes that you know object-oriented programming and finite state machines (FSMs).)
In this example you are developing a Task object as part of your SuperCron! product:
(Note: The ellipsis (...) code will be filled in as we go along.)
package com.acme.supercron;
public final class Task
implements TaskEventListener, TimerEventListener
{
public Task() {
// Object initialization.
...
}
// TaskEventListener Interface Implemenation.
// Time for the incomplete task to continue its work for the
// specified time slice.
public void start(long timeSlice) { ... }
// Called when a running, incomplete task should suspend
// running even though its time slice is not expired.
// Note: the task's running is also suspended when the time
// slice expires.
public void suspend() { ... }
// Called when an incomplete task is blocked. Blocked tasks
// are able to continue running when unblocked.

Page 8 of 109

SMC Programmer’s Manual

public void block() { ... }
// Called when a blocked task is unblocked and allowed
// to continue running.
public void unblock() { ... }
// Called when an incomplete task is permanently stopped.
// Stopped tasks are then deleted.
public void stop() { ... }
// Called when the task is deleted. Tasks are deleted when
// either 1) the task has completed running and is now
// stopped or 2) when the system is shutting down and all
// are to terminate immediately.
public void delete() { ... }
// TimerEventListener Interface Implementation.
// Called when the time slice timer expires. If running,
// the task is suspended.
public void handleTimeout(TimerEvent event) { ... }

}

// Remainder of class definition.
...

How the Task class should respond to the start, suspend, etc. method calls depends on what the Task is
currently doing - that is, it depends on the Task's state.

Page 9 of 109

SMC Programmer’s Manual

The Task Finite State Machine
The Task Finite State Machine (FSM) diagram is:

The Task's states are:
•

Running: the task is actively doing work. The task is allowed to run for a specified time limit.

•

Suspended: the task is waiting to run again since it is not yet completed.

•
•

Stopped: the task has either completed running or externally stopped.
Blocked: the uncompleted task is externally prevented from running again. It will stay in this state until

•

either stopped or unblocked.
Stopping: the task is cleaning up allocated resources before entering the stop state.

•

Deleted: the task is completely stopped and all associated resources returned. The task may now be
safely deleted.
This is the FSM end state.

Some notes on this FSM:
• The Task object starts in the Suspended state.

Page 10 of 109

SMC Programmer’s Manual

• The transitions match the TaskEventListener interface's methods.
• The Stopped state is reached when either the Running task completes or is externally stopped.
• The Stop, Block and Delete transitions do not start in any specified state. More on that in coding up the
FSM.
Now the problem is: how to take this FSM and put it into your code? The first step in that is encoding the
FSM in the SMC language.

Page 11 of 109

SMC Programmer’s Manual

Creating an SMC .sm file
The .sm listing below is a skeleton with no states or transitions defined. It contains only the following
features:
• A verbatim code section which is copied verbatim into the generated source code file. In this case the
verbatim code is the boilerplate copyright comments. This section is delimited by the %{ %} pair.
• The %class keyword which specifies the application class to which this FSM is associated: Task.
• The %package keyword which specifies to which class package this FSM belongs. This is the same
package as the Task class.
• The %fsmclass keyword specifies the generated finite state machine class name. If %fsmclass is not
specified, then the finite state machine class name would default to TaskContext. This keyword is not
required.
• The %fsmfile keyword specifies the generated finite state machine class file name. The appropriate suffix
for the given programming language is appended to this file name to form the complete file name. This
suffix may be changed from its default using the -suffix and -hsuffix command line parameters. See
this table for the default file name and suffix settings for each supported target language.
• The %access keyword is used to specify the generated class' accessibility level (this works only when
generating Java and C# code). In this case the FSM can only be accessed within the
com.acme.supercron package.
• The %start keyword specifies the FSM's start state. For the Task FSM it is the Suspended state.
• The %map keyword is the FSM's name.
Name the source code file TaskFSM.sm because both the %fsmclass and %fsmfile directives specify
the finite state machine class name as TaskFSM. The .sm suffix is required.
(Note: the %fsmclass directive was added to SMC version 6.0.1 and %fsmfile was added to version
6.6.0.)
%{
//
//
//
//
//
//
//
//
%}

Copyright (c) 2005 Acme, Inc.
All rights reserved.
Acme - a name you can trust!
Author: Wil E. Coyote (Hungericus Vulgarus)

// This FSM works for the Task class only and only the Task

Page 12 of 109

SMC Programmer’s Manual

// class may instantiate it.
%class Task
%package com.acme.supercron
%fsmclass TaskFSM
%fsmfile TaskFSM
%access package
// A %map name cannot be the same as the FSM class name.
%start TaskMap::Suspended
%map TaskMap
%%
...
%%

Page 13 of 109

SMC Programmer’s Manual

Defining FSM States
The state definitions are placed inside the %map TaskFSM %% ... %% delimiter:
%{
//
//
//
//
//
//
//
//
%}

Copyright (c) 2005 Acme, Inc.
All rights reserved.
Acme - a name you can trust!
Author: Wil E. Coyote (Hungericus Vulgarus)

// This FSM works for the Task class only and only the Task
// class may instantiate it.
%class Task
%package com.acme.supercron
%fsmclass TaskFSM
%fsmfile TaskFSM
%access package
// A %map name cannot be the same as the FSM class name.
%start TaskMap::Suspended
%map TaskMap
%%
Suspended { ... }
Running { ... }
// Wait here to be either unblocked, stopped or deleted.
Blocked { ... }
Stopping { ... }
Stopped { ... }
Deleted { ... }
...
%%
Like all C-syntax languages, the opening, closing braces are not needed if there is only one expression inside
the braces. But like all C-syntax languages, it is good practice to always use them. If you don't follow this
rule now, you will after you spend two days tracking down a bug due entirely to you not following this rule.
Notice the ellipsis before the closing %%? There is one more state to define even though the diagram's six
states are declared. There is an implicit state. Remember how the Stop, Block and Delete transitions have no
start state?

Page 14 of 109

SMC Programmer’s Manual

Defining FSM Transitions
A transition definition consists of four parts:
1. The transition name.
2. An optional transition guard (not used in Task FSM).
3. The transition end state.
4. The transition actions.
Only the “standard” transitions are defined for now. The Stop, Block and Delete transitions will be
covered here.
%{
//
//
//
//
//
//
//
//
%}

Copyright (c) 2005 Acme, Inc.
All rights reserved.
Acme - a name you can trust!
Author: Wil E. Coyote (Hungericus Vulgarus)

// This FSM works for the Task class only and only the Task
// class may instantiate it.
%class Task
%package com.acme.supercron
%fsmclass TaskFSM
%fsmfile TaskFSM
%access package
// A %map name cannot be the same as the FSM class name.
%start TaskMap::Suspended
%map TaskMap
%%
Suspended
{
// Time to do more work.
// The timeslice duration is passed in as a transition
// argument.
Start(timeslice: long) // Transition
Running // End state
{
... // Actions go here
}
}

Page 15 of 109

SMC Programmer’s Manual

Running
{
// Wait for another time slice.
Suspend
Suspended
{ ... }

}

// Task has completed.
Done
Stopped
{ ... }

// Wait here to be either unblocked, stopped or deleted.
Blocked
{
// The task may continue working now.
Unblock
Suspended
{ ... }
}
Stopping
{
// The task is now stopped.
Stopped
Stopped
{ ... }
}
Stopped { ... }
Deleted { ... }
...
%%

Page 16 of 109

SMC Programmer’s Manual

Defining FSM Transition Actions
Transition actions are the first coupling between the FSM and the application class Task. Actions are Task
methods. These method must have the following attributes:
• Be accessible to the FSM. This means at least public methods or, if in the same package, then package
methods.
• Have a void return type. If the method does return a value, the FSM ignores it.
SMC places no syntax limitations on transition arguments except they are enclosed in parens "()" and are
comma-separated. Go here for more information on transition actions.
%{
//
//
//
//
//
//
//
//
%}

Copyright (c) 2005 Acme, Inc.
All rights reserved.
Acme - a name you can trust!
Author: Wil E. Coyote (Hungericus Vulgarus)

// This FSM works for the Task class only and only the Task
// class may instantiate it.
%class Task
%package com.acme.supercron
%fsmclass TaskFSM
%fsmfile TaskFSM
%access package
// A %map name cannot be the same as the FSM class name.
%start TaskMap::Suspended
%map TaskMap
%%
Suspended
{
// Time to do more work.
// The timeslice duration is passed in as a transition
// argument.
Start(timeslice: long) // Transition
Running // End state
{
continueTask();
startSliceTimer(timeslice);
}
}

Page 17 of 109

SMC Programmer’s Manual

Running
{
// Wait for another time slice.
Suspend
Suspended
{
stopSliceTimer();
suspendTask();
}

}

// Task has completed.
Done
Stopped
{
stopSliceTimer();
releaseResources();
}

// Wait here to be either unblocked, stopped or deleted.
Blocked
{
// The task may continue working now.
Unblock
Suspended
{}
}
Stopping
{
// The task is now stopped.
Stopped
Stopped
{
releaseResources();
}
}
Stopped { ... }
Deleted { ... }
...
%%

Page 18 of 109

SMC Programmer’s Manual

The transition actions methods in Task are:
package com.acme.supercron;
public final class Task
implements TaskEventListener, TimerEventListener {
public Task() {...}
// TaskEventListener Interface Implementation.

// TimerEventListener Interface Implementation.

// State Machine Actions.
// Activate the underlying task and get it running again.
/* package */ void continueTask() {
...
return;
}
// Inactivate the underlying task.
/* package */ void suspendTask() {
...
return;
}
// Start the timeslice timer for the given milliseconds.
/* package */ void startSliceTimer(long timeslice) {
...
return;
}
// Stop the timeslice timer.
/* package */ void stopSliceTimer() {
...
return;
}

...
}

// Return system resources from whence they came.
/* package */ void releaseResources() {
...
return;
}

Page 19 of 109

SMC Programmer’s Manual

Defining FSM Default Transitions
Now the mystery transitions Stop, Block and Delete are defined. The reason why these transitions have
no start state is because they are taken no matter the current state. Well, not exactly.
• Stop: If a task is still alive ( in the Suspended, Running or Blocked state), then it must immediately
transition to the Stopping state. If a task is not alive (in the other three states), this transition is ignored
because the task is no longer alive.
• Block: If a task is either Suspended or Running, then it transitions to the Blocked state. Otherwise this
request is ignored.
• Delete: If a task is in any state other than Deleted, then it must transition to the Deleted state.
SMC provides two ways to define default transitions: the Default state and the Default transtion. Manual
section 2 describes how Default state and transition work. Go there to learn more about them. Task.sm
is updated with the default Stop, Block and Delete transition definitions:
%{
//
//
//
//
//
//
//
//
%}

Copyright (c) 2005 Acme, Inc.
All rights reserved.
Acme - a name you can trust!
Author: Wil E. Coyote (Hungericus Vulgarus)

// This FSM works for the Task class only and only the Task
// class may instantiate it. %class Task
%package com.acme.supercron
%fsmclass TaskFSM
%fsmfile TaskFSM
%access package
// A %map name cannot be the same as the FSM class name.
%start TaskMap::Suspended %map TaskMap
%%
Suspended {
// Time to do more work.
// The timeslice duration is passed in as a transition
// argument.
Start(timeslice: long)
Running {
continueTask();
startSliceTimer(timeslice);

Page 20 of 109

SMC Programmer’s Manual

}

}

Block
Blocked {
blockTask();
}

Running {
// Wait for another time slice.
Suspend
Suspended {
stopSliceTimer();
suspendTask();
}
Block
Blocked {
stopSliceTimer();
blockTask();
}

}

// Task has completed.
Done
Stopped {
stopSliceTimer();
releaseResources();
}

// Wait here to be either unblocked, stopped or deleted.
Blocked {
// The task may continue working now.
// No actions needed.
Unblock
Suspended {}
}
Stopping {
// The task is now stopped.
Stopped
Stopped {
releaseResources();
}

}

// We are stopping.
Stop
nil {}

Page 21 of 109

SMC Programmer’s Manual

Stopped {
// We are stopped.
Stop
nil {}

}

// Ignore all transitions until deleted.
Default
nil {}

Deleted {
// Define all known transitions as loopbacks.
Start(timeslice: long)
nil {}
Suspend()
nil {}
Block()
nil {}
Unblock()
nil {}
Done()
nil {}
Stop()
nil {}
Stopped()
nil {}

}

Delete()
nil {}

Default {
// Three states follow this transition, three states ignore.
// So define the active definition.
Stop
Stopping {
stopTask();
}
// Block is ignored by four of six states.
// Force the other two states to define this.
// Note the "nil" end state. This is a loopback transition
Block
nil {}

Page 22 of 109

SMC Programmer’s Manual

// All but the Delete state follow this transition. Define it here.
Delete
Deleted {}

}
%%

// Ignore a transition by default.
Default
nil {}

The blockTask() and stopTask() methods are added to the Task class:
package com.acme.supercron;
public final class Task
implements TaskEventListener, TimerEventListener {
public Task() { ... }

// State Machine Actions.

// Block the underlying task from running.
/* package */ void blockTask() {
...
return;
}
// Permanently stop the underlying task.
/* package */ void stopTask() {
...
return;
}

...
}
There is one more improvement to the FSM that needs to be made before we finish. Notice that the
Running state's transitions must stop the slice timer. If a new transition is added to Running, the
developer must remember to include the stopSliceTimer() action. This is a potential problem because a
different developer maintaining this FSM may not know about this. But there is a solution to this.

Page 23 of 109

SMC Programmer’s Manual

Defining State Entry/Exit Actions
The slice timer should be stopped when not in the Running state. The way to enforce this is to add an
Exit block to Running and move the stopSliceTimer() action there.
Since the state's Exit actions are being defined, it would appear natural to put the startSliceTimer()
action into a Entry block. But there two reasons against it:
1. There is only one transition into the Running state. Moving startSliceTimer() from Suspended's
Start transition to Running's entry actions gains nothing.
2. startSliceTimer() takes the Start transition's timeslice argument. If startSliceTimer()
is an entry action, then it cannot access that transition argument. The only way around it is to store the
slice time in the Task class and then retrieve it immediately in the entry action
( startSliceTimer(ctxt.getSliceTime())). Now moving the action to the entry block is worse
than doing nothing.
(Go here to learn more about state entry and exit actions.)
%{
//
//
//
//
//
//
//
//
%}

Copyright (c) 2005 Acme, Inc.
All rights reserved.
Acme - a name you can trust!
Author: Wil E. Coyote (Hungericus Vulgarus)

// This FSM works for the Task class only and only the Task
// class may instantiate it.
%class Task
%package com.acme.supercron
%fsmclass TaskFSM
%fsmfile TaskFSM
%access package
// A %map name cannot be the same as the FSM class name.
%start TaskMap::Suspended
%map TaskMap
%%


Page 24 of 109

SMC Programmer’s Manual

Running
Exit { stopSliceTimer(); }
{
// Wait for another time slice.
Suspend
Suspended {
// stopSliceTimer(); moved.
suspendTask();
}
Block
Blocked {
// stopSliceTimer(); moved.
blockTask();
}

}

// Task has completed.
Done
Stopped {
// stopSliceTimer(); moved.
releaseResources();
}


}
%%
There is one final task: connecting the task FSM to the Task application class.

// State
Idle
{
// Trans
Next State Actions
Timeout Idle
{}
}

Page 25 of 109

SMC Programmer’s Manual

Connecting Task and Task FSM
Connecting FSMs to their application class is as simple as:
• Add the data member TaskFSM _fsm to Task class.
• Instantiate TaskFSM in Task’s constructor.
• If the start state has entry actions that must be executed when the FSM is created, then call
_fsm.enterStartState() outside of Task’s constructor.
• When you need to issue a transition, call _fsm’s appropriate transition method. For example:
_fsm.Start(timeSlice);
package com.acme.supercron;
public final class Task
implements TaskEventListener, TimerEventListener {
public Task() {
...

}

// Instantiate the FSM here but perform the initial
// state's entry actions outside of the constructor
// to prevent referencing this object before its
// initialization is complete.
_fsm = new TaskFSM(this);

// Execute the start state's entry actions by calling this
// method. This method should be called only once and prior to
// issuing any transitions. Therefore this method should be
// called before registering this Task instance as a task and
// timer event listener.
public void startFSM() {
_fsm.enterStartState();
TaskManager.addListener(this);
}
// TaskEventListener Interface Implementation.
// Time for the incomplete task to continue its work for the
// specified time slice.
public void start(long timeSlice) {
_fsm.Start(timeSlice);
}
// Called when a running, incomplete task should suspend
// running even though its time slice is not expired.
// Note: the task's running is also suspended when the time

Page 26 of 109

SMC Programmer’s Manual

// slice expires.
public void suspend() {
_fsm.Suspend();
}
// Called when an incomplete task is blocked. Blocked tasks
// are able to continue running when unblocked.
public void block() {
_fsm.Block();
}
// Called when a blocked task is unblocked and allowed
// to continue running.
public void unblock() {
_fsm.Unblock();
}
// Called when an incomplete task is permanently stopped.
// Stopped tasks are then deleted.
public void stop() {
_fsm.Stop();
}
// Called when the task is deleted. Tasks are deleted when
// either 1) the task has completed running and is now
// stopped or 2) when the system is shutting down and all
// are to terminate immediately.
public void delete() {
_fsm.Delete();
}
// TimerEventListener Interface Implementation.
// Called with the time slice timer has expired. If running,
// the task is suspended.
public void handleTimeout(TimerEvent event) {
_fsm.Suspend();
}


}

// The associated finite state machine.
private final TaskFSM _fsm;

Voíla! Task's behavior is now defined by a finite state machine.

Page 27 of 109

SMC Programmer’s Manual

Section 2: From Model to SMC
This section shows a quasi-UML state machine snippet and the equivalent SMC code. I use the word "quasi"
because SMC is not directly derived from UML or Harel state machines. That means that there are
capabilities in UML that are not in SMC and vice versa. See the SMC FAQ for why this is.

Instantiating a Finite State Machine
Care must be taken when instantiating an SMC-generated finite state machine. The application class passes
a its reference to the FSM context and this reference is used when FSM actions are performed. It is safe to
instantiation an FSM within a constructor but unsafe to enter the start state while in a constructor because
the start state entry actions will call your application object before its constructor has completed.
private final AppClassContext _fsm;
public AppClass() {
// Initialize you application class. Instantiate your finite state
// machine.
// Note: it is safe to pass this to the the FSM constructor because
// the FSM constructor only stores this in a data member.
_fsm = new AppClassContext(this);
}
// Enter the FSM start state after instantiating this application object.
public void startWorking() {
_fsm.enterStartState();
return;
}
Prior to SMC v. 6, the FSM constructor incorrectly used the this pointer which meant instantiating the FSM
within the application constructor could lead to incorrect behavior. SMC v. 6 corrects this problem and it is
now safe to instantiate the FSM within your application constructor.
The enterStartState method should be called only once after instantiating the finite state machine
and prior to issuing any transition. This method is unprotected and does not prevent its being
called multiple times. If enterStartState is called after the first transition, then incorrect behavior
may occur.

Page 28 of 109

SMC Programmer’s Manual

Simple Transition
// State
Idle
{
// Trans
Run
}

Next State
Running

Actions
{}

A state and transition names must have the form "[A-Za-z_][A-Za-z0-9_]*".

Jump Transition

// State
Idle
{
// Trans
Run
}

Next State
jump(Running)

Actions
{}

The Jump transition is equivalent to the Simple Transition and is provided since this transition is used in an
Augmented Transition Network.
In a future SMC release, the Jump transition will become the only way for make an end state
outside the current map. The syntax will be: jump(AnotherMap::NextState)

External Loopback Transition
An external loopback does leave the current state and comes back to it. This means that the state's exit and
entry actions are executed. This is in contrast to an internal loopback transition.
// State
Idle
{
// Trans
Run
}

Next State
Idle

Page 29 of 109

Actions
{}

SMC Programmer’s Manual

Internal Loopback Transition

// State
Idle
{
// Trans
Next State Actions
Timeout nil
{}
}

Using "nil" as the next state causes the transition to remain in the current state and not leave it. This means
that the state's exit and entry actions are not executed. This is in contrast to an external loopback transition.

Transition with Actions
// State
Idle {
// Trans
Run
// Next State
Running {
// Actions
StopTimer("Idle");
DoWork();
}
}
1. A transition’s actions must be enclosed in a {} pair.
2. The action’s form is [A-Za-z][A-Za-z0-9_-]*(). The argument list must be
either empty or consist of comma-separated literals. Examples of literals are: integers (positive or
negative, decimal, octal or hexadecimal), floating point, strings enclosed in double quotes, constants and
transition arguments.

3. Actions must be member functions in the %class class and accessible by the state machine. Usually that
means public member functions in C++ or package in Java.
Action arguments include:
• An integer number (e.g. 1234).
Page 30 of 109

SMC Programmer’s Manual

• A float number (e.g. 12.34)
• A string (e.g. “abcde”)
• A transition argument
• A constant, #define, or global variable.
• An Independent subroutine or method call (e.g. event.getType()). Note: this subroutine/method call may
also include arguments.
If you want to call a method in the context class, then use the ctxt variable. For example, if the context
class contains a method getName() and you want to call it inside an action's argument list, then write
ctxt.getName().
Go here for sample code using the ctxt variable.
Note: Only use ctxt inside argument lists and transition guards.

Page 31 of 109

SMC Programmer’s Manual

Transition Guards

// State
Idle {
// Trans
Run
// Guard condition
[ctxt.isProcessorAvailable() == true &&
ctxt.getConnection().isOpen() == true]
// Next State
Running {
// Actions
StopTimer("Idle");
DoWork();
}
}

Run nil {RejectRequest();}

The guard must contain a condition that is valid target language source code - that is, it would be a valid "if"
statement. Your guard may contain &&s, ||s, comparison operators (==, <, etc.) and nested expressions.
SMC copies your guard condition verbatim into the generated output.
Note: If your are calling a context class method, then you must prefix the method with ctxt - SMC will not
append ctxt for you.
If the guard condition evaluates to true, then the transition is taken. If the guard condition evaluates to false,
then one of the following occurs (ordered by precedence):
1. If the state has another guarded transition with the same name and arguments, that transition's guard is
checked.

Page 32 of 109

SMC Programmer’s Manual

2. Failing that, If the state has another unguarded transition with the same name and argument list, that
transition is taken.
3. If none of the above, then the default transition logic is followed.
A state may have multiple transitions with the same name and argument list as long as they all have unique
guards. When a state does have multiple transitions with the same name, care must be taken when ordering
them. The state machine compiler will check the transitions in the same top-to-bottom order that you use
except for the unguarded version. That will always be taken only if all the guarded versions fail. Guard
ordering is only important if the guards are not mutually exclusive, i.e., it is possible for multiple guards to
evaluate to true for the same event.
Allowable argument types for a transition guard are the same as for a transition action.

Page 33 of 109

SMC Programmer’s Manual

Transition Arguments

// State
Idle {
// Transition
Run(msg: const Message&)
// Guard condition
[ctxt.isProcessorAvailable() == true &&
msg.isValid() == true]
// Next State
Running {
// Actions
StopTimer("Idle");
DoWork(msg);
}

}

Run(msg: const Message&)
// Next State Actions
nil
{RejectRequest(msg);}

Note: When using transition guards and transition arguments, multiple instances of the same transition must
have the same argument list. Just as with C++ and Java methods, the transitions Run(msg: const
Message&) and Run() are not the same transition. Failure to use the identical argument list when defining
the same transition with multiple guards will result in incorrect code being generated.

Page 34 of 109

SMC Programmer’s Manual

Tcl “arguments”:
While Tcl is a type-less language, Tcl does distinguish between call-by-value and call-by-reference. By default
SMC will generate call-by-value Tcl code if the transition argument has no specified type. But you may use
the artificial types "value" or "reference".
If your Tcl-targeted FSM has a transition:

then the generated Tcl is:

DoWork(task: value)
Working {
workOn(task);
}

public method DoWork {task} {
workOn $this $task;
}

If your Tcl-targeted FSM has a transition:

then the generated Tcl is:

DoWork(task: reference)
Working {
workOn(task);
}

public method DoWork {task} {
workOn $this task;
}

The method workOn must upvar the task parameter:
public method workOn {taskName} {
upvar $taskName task;
...
}
Lua/Python/Ruby “arguments”:
While Lua/Python/Ruby is a dynamically typed language and does not use types for function parameter
definitions, you could provide a optional data type for transition arguments. This "data type" is ignored when
generating the target Lua/Python/Ruby code. I suggest using meaningful type names.
DoWork(task: TaskObj, runtime: Ticks)
Working {
...
}
Groovy/PHP “arguments”:
While Groovy/PHP gives the choice between static and dynamic typing, you could provide a optional data
type for transition arguments. In this case, the type is used when generating the target Groovy/PHP code.
The PHP variable syntax is like Perl (named with '$').
Perl “arguments”:

Page 35 of 109

SMC Programmer’s Manual

While Perl is a dynamically typed language and does not use types for function parameter definitions, you
could provide a optional data type for transition arguments. This "data type" is ignored when generating the
target Perl code. I suggest using meaningful type names.
Only Perl scalar values (i.e., named with '$') are allowed.
DoWork($task: TaskObj, $runtime: Ticks)
Working {
...
}

Entry and Exit Actions

// State
Idle
Entry {StartTimer("Idle", 1); CheckQueue();}
Exit {StopTimer("Idle");}
{
// Transitions
}

When a transition leaves a state, it executes the state’s exit actions before any of the transition actions. When
a transition enters a state, it executes the state’s entry actions. A transition executes actions in this order:
1. “From” state’s exit actions.
2. Set the current state to null. This denotes that a transition is in progress.
3. The transition actions in the same order as defined in the .sm file.
4. Set the current state to the “to” state.
5. “To” state’s entry actions.
As of version 6.0.0, SMC generates a enterStartState method which executes the start state's entry
acitons. It is now up to the application to call the start method after instantiating the finite state machine
context. If it is not appropriate to execute the entry actions upon start up, then do not call
enterStartState. You are not required to call this method to set the finite state machine start state. That
is done when the FSM is instantiated. This method is used only to execute the start state's entry actions.

Page 36 of 109

SMC Programmer’s Manual

If you do call this method, be sure to do it outside of the context class' constructor. This is because entry
actions call context class methods. If you call enterStateState from within you context class'
constructor, the context instance will be referenced before it has completed initializing which is a bad thing to
do.
enterStartState does not protect against being called multiple times. It should be called at most
once and prior to issuing any transitions. Failure to follow this requirement may result in inappropriate finite
state machine behavior.
Whether a state's Entry and Exit actions are executed depends on the type of transition taken. The
following table shows which transitions execute the "from" state's Exit actions and which transitions
execute the "to" state's Entry actions.

Transition Type

Execute “From” State’s Exit

Execute “To” State’s Entry

Actions?

Actions?

Simple Transition

Yes.

Yes.

External Loopback Transition

Yes.

Yes.

Internal Loopback Transition

No.

No.

Push Transition

No.

Yes.

Pop Transition

Yes.

No.

Table 1: Entry/Exit Execution.
WARNING! Entry and exit actions are not supported for the Default state which is not an actual state. See
more in the Default Transitions section.
From this point on, SMC diverges from UML. SMC uses the idea of multiple machines and pushing
and popping states as way of breaking complicated behavior up into simpler parts. UML achieves much
the same by grouping states into superstates. They may be equivalent in ability but I find the idea of
pushing to a new state easier to understand because it is similar to the subroutine call.

Page 37 of 109

SMC Programmer’s Manual

Push Transition

Running {
Blocked
push(WaitMap::Blocked) {
GetResource();
}
}
Note: The end state does not have to be in another map - it could be in the same %map construct.
Conversely, a plain transition's end state may be in another map. But chances are that you will set up maps
so that you will push to another map's state and simple transitions will stay within the same map. You use
multiple maps for the same reason you create multiple subroutines: to separate out functionality into easy-tounderstand pieces.
With SMC v. 1.3.2, the push syntax was modified yet is backward compatible with the initial syntax. The new
syntax is:
Running {
Blocked
BlockPop/push(WaitMap::Blocked) {
GetResource();
}
}
This causes the state machine to:
1. Transition to the BlockPop state.
2. Execute the BlockPop entry actions.
3. Push to the WaitMap::Blocked state.
4. Execute the WaitMap::Blocked entry actions.
When WaitMap issues a pop transition, control will return to BlockPop and the pop transition issued from
there.
Use this new syntax when a state has two different transitions which push to the same state but need to
handle the pop transition differently. For example:

Page 38 of 109

SMC Programmer’s Manual

Idle {
NewTask NewTask/push(DoTask) {}
RestartTask OldTask/push(DoTask) {}
}
NewTask {
TaskDone Idle {}

}

// Try running the task one more time.
TaskFailed OldTask/push(DoTask) {}

OldTask {
TaskDone Idle {}
TaskFailed Idle {logFailure();}
}

Pop Transition

Waiting
{
Granted pop(OK) {cleanUp();}
Denied pop(FAILED) {cleanUp();}
}

The pop transition differs from the simple and push transition in that:
• The end state is not specified. That is because the pop transition will return to whatever state issued the
corresponding push.
• There pop transition has an optional argument: a transition name.
In the above example, if the resource request is granted, the state machine returns to the corresponding
state that did the push and then takes that state's OK transition. If the request is denied, the same thing
happens except the FAILED transition is taken. The code for the corresponding push transition is:
Running {
Blocked push(WaitMap::Blocked) {GetResource();}

}

// Handle the return "transitions" from WaitMap.
OK
nil {}
FAILED Idle {Abend(INSUFFICIENT_RESOURCES);}

Page 39 of 109

SMC Programmer’s Manual

As of SMC v. 1.2.0, additional arguments may be added after the pop transition's transition argument. These
additional arguments are like any others passed to an action and will be passed into the named transition.
Following the above example, given the pop transition pop(FAILED, errorCode, reason), then the FAILED
should be coded as:
FAILED(errorCode: ErrorCode, reason: string)
Idle {
Abend(errorCode, reason);
}

Default Transitions
What happens if a state receives a transition that is not defined in that state? SMC has two separate
mechanisms for handling that situation.
The first is the "Default" state. Every %map may have a special state named "Default" (the uppercase D is
significant). Like all other states, the Default state contains transitions.
Default {
// Valid run request but transition occurred in an invalid
// state. Send a reject reply to valid messages.
Run(msg: const Message&)
[ctxt.isProcessorAvailable() == true && msg.isValid() == true]
nil {
RejectRequest(msg);
}
// Ignore invalid messages are ignored when received in
// an invalid state.
Run(msg: const Message&)
nil
{}
Shutdown
ShuttingDown {
StartShutdown();
}
}
Default state transitions may have guards and arguments features as non-default transitions. This means the
Default state may contain multiple guarded and one unguarded definition for the same transition.

Page 40 of 109

SMC Programmer’s Manual

The second mechanism is the "Default" transition. This is placed inside a state and is used to back up all
transitions.
Connecting {
// We are now connected to the far-end. Now we can logon.
Connected
Connected {
logon();
}
// Any other transition at this point is an error.
// Stop the connecting process and retry later.
Default
RetryConnection {
stopConnecting();
}
}
Because any transition can fall through to the Default transition, Default transitions:
• May not have an argument list.
• A Default transition may take a guard.
• Putting a Default transition in the Default state means that all transitions will be handled - it is the transition
definition of last resort.

Transition Precedence
Transition definitions have the following precedence:
1. Guarded transition.
2. Unguarded transition.
3. The Default state’s guarded definition.
4. The Default state’s unguarded definition.
5. The current state’s guarded Default transition.
6. The current state’s unguarded Default transition.
7. The Default state’s guarded Default transition.
8. The Default state’s unguarded Default transition.
Since SMC does not force you to specify a Default state or Default transition, it is possible that
there is no transition defined. If SMC falls through this list, it will throw a “Transition Undefined”
exception.

Page 41 of 109

SMC Programmer’s Manual

Section 3:

Adding a State Machine to

your Class

The SMC-generated code is designed to be loosely coupled with your application software. The only
changes that you need to make to your code is to:
1. Include the SMC class definitions into your application (stored in smc/lib by programming language
name):
• C: Have lib/C/statemap.h in the include path.
• C++: Have lib/C++/statemap.h in the include path.
• C#: Have lib/DotNet/statemap.dll included in the build library list.
• Groovy: Have lib/Groovy/statemap.jar in the class path.
• Java: Have lib/Java/statemap.jar in the classpath.
• JavaScript: Have lib/JavaScript/statemap.js accessible to 



Navigation menu