Question Index
-
- What is the current SMC version?
- What Java version does SMC need?
- If SMC uses Java 7, is the Java-generated code Java 6 compatible?
- Where is the documentation?
- Where do I download SMC?
- Where can I get the SMC documentation in PDF?
- How do I contact SMC developers?
- Is the SMC license compatible with the Gnu Public license?
- Does the SMC license cover the output files which SMC generates from my .sm input file?
- I changed statemap.h namespace/FSMContext.java package/statemap.tcl package to fit within my application's namespace. Do I have to make my changes publicly available?
- Hey, Robert Martin has a state machine compiler named SMC! Are you ripping him off?
- Robert Martin's June, 1998 Engineering Notebook column in C++ report shows the FSM context class inheriting from the application class rather than the application class and the FSM context class kept separate. Why didn't you do it that way?
- Robert Martin's SMC uses state inheritance. Why doesn't your SMC also support that feature?
- Why did you write the state machine compiler in Java?
- What programming languages does SMC support?
- How come SMC doesn't support Smalltalk/ CLOS/name-your-favorite-object-oriented-language?
-
Why doesn't SMC follow the Harel/UML statechart
specification?
Does SMC use hierarchical state machines?
Does SMC support concurrent states? - How are SMC state machines persisted?
- I want to be told when a state change occurs rather than poll the FSM. Is this possible?
- How much overhead does SMC add to an application?
- The SMC-generated code does not pass the put name here code analyzer or generates compiler warnings. Can you clean up the SMC code generator?
-
Writing SMC Finite State Machines
-
I need to place a
#define
/#include
/package
/import
/package require
statement into the SMC-generated code. How can I do that automatically without resorting to directly editing the SMC-generated code? - Is it really necessary for me to make my state machine actions public? Can't I just make the state classes friends?
- When I issue a transition from within an action, an exception is thrown. Why can't an action issue a transition?
- But I really need to issue a transition from within an action. Is there anyway around this problem?
- Is SMC-generated code thread safe?
- Why doesn't SMC generate thread-safe C++ code?
- I have a state which has two different transitions which push the same state and I need to handle the pop transitions differently but I can define the pop transition only once. How can I get around this limitation?
- I want to use an "if" statement in an Entry action but SMC doesn't accept it. Is this a bug?
- How do I receive a callback when my state machine transitions to a new state?
- Can a transition return a value?
- Can a transition action throw an exception?
- But I really need to throw an exception from my transition!
-
My transition action needs to access the previous
state's name but
getState()
returnsNULL
! What do I do? - Tcl supports both call-by-value and call-by-reference but SMC only generates call-by-value code. How can I get SMC to generate call-by-reference code?
-
My context class is
AppClass<int>
but SMC won't accept class templates. Why not? - Can I add other arguments to a "pop" transition besides the transition name?
- Why do I have to specify a transition argument's type when I am generating Python code?
-
How do I set the generated Context class' access
level to package in Java?
How do I set the generated Context class' access level to internal in C#? - How can I determine which transitions are defined in the current state?
- I want to use SMC to write event-driven software. How to I get SMC to generate event registration and event listening code?
-
My action
object().name()
causes a compile error. Why doesn't SMC accept this code? -
My action
System.out.println("My output")
results in invalid generated code. Is this a bug? - Can I use #ifdef preprocessor statements in my .sm file?
- I want to call a static method in my transition actions. How can I do this?
-
My
%header
file is dependent on a%include
file. How can I get the%include
into the _sm.h file rather than the _sm.c or _sm.cpp file? -
I use timers in my application and when a timer
expires, I issue a transition. Sometimes this
works and sometimes I get a
StateUndefinedException
What is happening? -
I want my generated finite state machine context
class given a name different than the default
xxxContext
. How can I specify a different name? - I overload transition names in my .sm file but the generate C code doesn't compile because C doesn't support subroutine name overloading. Why don't you fix the generated C code?
-
I added the
%fsmclass
directive to my .sm file. The SMC compile works but the target language compile fails. What went wrong? -
I added the
%fsmclass
directive to my .sm file but the generated FSM class code was put into the wrong file name. How can I tell SMC to use a file name I want? -
I use several
%maps
in my FSM code but these maps have severalDefault
state transitions in common. Instead of my replicating this code across the multiple maps, wouldn't it be better if SMC generated aDefault
map with a singleDefault
state? - I want to use SMC for an embedded C++ application. But the provided statemap.h uses dynamic memory allocation. How can I get around this?
-
I tried using
-java7
but my code no longer compiles because the stateMyMap.MyState
can't be resolved. What gives?
-
I need to place a
-
Compiling SMC Finite State Machines Questions
- I've modified a .sm but its not recompiled when I build. How do I get SMC to automatically run?
-
When I compile my .sm file I get an
ArrayIndexOutOfBoundsException
. What is wrong? - I used the "-noex" command line option but SMC still generates try/catch blocks. How can I get rid of all exception-handling code?
- Generated C++ code uses dynamic_cast<>. How can I get SMC to use a different cast operator?
- I am using ant to build my application. My source files are in the src directory and .sm files are in the etc directory. But I need SMC to put the generated Context class files in the src directory not etc. How can I tell SMC to put the generated files in a different directory than where the .sm files reside?
- I am using ant to build my application. When SMC exits it takes down my entire ant build. How can I make SMC stop doing that?
- Why is getState() method/State property in the generated Context class and not in FSMContext?
- What is the difference between -java and -java7?
- The SMC Maven plug-in on Maven Central is way out of date. Why?
Miscellaneous Questions
What is the current SMC version?
The current version 7.6.0, released June 24, 2023.
What Java version does SMC need?
SMC needs Java 1.7 or better.
My software only runs on Java 6. Now that SMC runs on Java 7, is the generated code still Java 6 compatible?
Yes, SMC still generates Java 6 compatible code by default. The only caveat is when you using the SMC options -reflect and -generic7. This will generate Java 7 code which is incompatible with Java 6. For Java 6, use the options -reflect and -generic or just -reflect.
Where is the documentation?
Go here for the SMC programmer's manual. It explains how to write, compile and debug SMC finite state machines. You can also download the programmer's manual for quick, off-line reference.
Go here for the Java docs covering the SMC model, parser and generator packages.
Where do I download SMC?
At http://sourceforge.net/projects/smc in the "Latest File Releases" section.
Where are the SMC documents in PDF?
In the SMC download under SMC Programmer_s Manual. The PDF is available for SMC v. 6.6.0 and later only.
How do I contact SMC developers?
The best place to start is at http://sourceforge.net/projects/smc in the "Public Areas" section which contains links to:
- SMC discussion forums
- Bug submission and tracking pages
- Join or leave an SMC mailing list.
- Latest SMC announcements.
SMC developers are signed up to receive e-mail notification when new bugs are submitted or new articles added to the discussion forums. We will get back to you as soon as possible.
Finally, if what you really want to do is e-mail an SMC developer, the "Developer Info" box at the top of SMC project page lists all SMC developers. Note: You must be logged into SourceForge to send e-mail this way. That means you must be a SourceForge member - which is a pretty good idea. Go here to sign up as a SourceForge member.
If you are not a SourceForge member, you can send e-mail directly to me.
Is the SMC license GPL compatible?
Yes, it is as per the Gnu Open Source license review. SMC uses MPL 1.1 and its license does contain section 13 which allows the use of GPL.
Does the SMC license cover the files SMC generates?
No. The .sm files and the output files SMC generates from .sm files belong to you and are covered by your copyright (if you are using one.)
The SMC license covers those files associated with SMC (including but not limited to the source files implementing SMC, the supporting C++/Java/[incr Tcl]/VB.net/C# libraries, C++ .h files, etc.)
Note: If you do use a copyright comment in your source code, then I suggest placing that comment within the verbatim code block ( %{ ... %} ) at the top of you .sm file. SMC will place this comment at the top of the generated files (except the *_sm.h if the target language is C++).
If I change the SMC namespace/package, must I make the change publicly available?
No. In this instance you have not changed SMC's functionality. I do not require making this insignificant change publicly available.
Is this a rip-off of Robert C. Martin's state machine compiler?
No, it is not a rip-off but yes it is descended from Robert Martin's SMC. There is a more detailed explanation in the SMC User's Manual preface.
Why not have the context class inherit from the application class?
Because:
- SMC is designed to be as loosely-coupled with your application code as possible. The SMC Programmer's Manual section 3 shows just how little code it takes to hook an SMC-generated state machine into your class.
- Robert Martin's FSM pattern is not as loosely-coupled as I would like.
With Robert Martin's pattern, you write the Turnstile class and and then have AppClassFSM inherit from Turnstile. You then instantiate the TurnstileFSM class and work with that object. I think this is unnatural. My inclination is to instantiate Turnstile because that is what corresponds to the "real" world.
SMC does a variation on this theme. It generates a TurnstileContext class which inherits from FSMContext class and keeps a reference to the Turnstile object which instantiated it. TurnstileContext stores the current state and defines the "transition" methods which Turnstile calls when it issues a transition.
For a more detailed explanation of what patterns SMC uses, see the SMC Programmer's Manual, section 5 .
Why doesn't your SMC support state inheritance?
Because by the time I learned of this feature in Robert Martin's SMC, I had already added the default state and default transition feature to this SMC. State inheritance and default state/transition play the same roll: allow a transition to have virtual definitions. If the transition is not explicitly defined in the current state, then fall back on another definition. With state inheritance, you use the super state's definition. With the default states/transition, you use the next default in the chain.
See the SMC Programmer's Manual, section 5 for more about default transitions.
Why write SMC in Java?
Actually, it wasn't in Java originally. It was written in C/LEX/YACC. But I wanted to run SMC on multiple platforms like the various Unices, Linux, Windows and Macintosh. Porting the C/LEX/YACC combination to those platforms would have been a real headache.
So I instead ported SMC to a platform-independent language. I re-wrote the lexer and parser as an SMC finite state machines. Now SMC will run on whatever platform Java runs on - which includes the vast majority of boxes.
What programming languages does SMC support?
SMC generates code for the following object-oriented programming languages:
- C
- C++
- C#
- [incr Tcl]
- Groovy
- Java
- Lua
- Objective-C
- Perl
- PHP
- Python
- Ruby
- Scala
- VB.net
How come SMC doesn't support Smalltalk/CLOS/Eiffel/name-your-favorite-object-oriented-language?
Simple. I haven't done it yet and I have never used those languages. So before I can add support for those languages, I first need to study them and get a compiler/development environment. That will take some time because SMC is not my full time job.
Of course, this being an open source project and SMC's code is loaded on to a publicly accessible CVS repository, you could add support for your favorite language. If your interested, e-mail me and I can get you going. (Note:: You must be logged into SourceForge to use this e-mail service. That means you must be a SourceForge member - which you would have to be in order to work on any SourceForge project.)
Why doesn't SMC follow the Harel/UML statechart
specification?
Does SMC use hierarchical state machines?
Does SMC support concurrent states?
SMC's finite state machine approach begins with an active object. An active object receives asynchronous events and may send such events as well. The finite state machine is used to put asynchronous events in context just as a call stack is used to maintain context for synchronous programming. SMC's goal is to provide FSM support for an application's active objects. Thus the SMC-generated FSM is skeletal. The object is responsible for defining the guard conditions, entry, exit and transition actions and maintaining the member data. The focus is on developing the application object. The FSM provides only a thin layer for maintaining aysnchronous context.
SMC state machine allows an active object to be in one state at a time. Concurrent states are not supported. One way to implement concurrent states is to create a subordinate object with its own associated finite state machine. So now both the parent and child objects have their own FSM operating concurrently.
When I begain working on SMC, my experience up to then had been with formal Finite State Machines (FSM), Push-down FSM and with something called an Augmented Transition Network (ATN) which is an FSM on steriods. ATNs were used in Natural Language Processing to parse text (used mostly in the 1970s).
ATNs have transition guards, push/pop transitions, default transitions and backtracking (rewind state transitions to an earlier time and try a different transition - needed in parsing text but not possible in event-driven software unless you have a time machine.) If your are familiar with ATNs, you can see where SMC came from.
I have tried to use UML syntax whereever possible. But there is no getting around that my philosophy about state machines is distinct from the Harel/UML philosophy. The following list shows whether a UML statechart feature is supported by SMC or not.
- Hierarchical State Machine: No.
- Simple State: Yes.
- State Entry and Exit Actions: Yes.
- doActivity: Indirectly supported via entry and exit actions. An entry action would start the activity and an exit action would stop the activity.
- Final State: Not directly. SMC has no facility for tagging a state as final but developer may use default transition to make sure that once a final state is entered, that state is never left.
- Composite State: No.
- Pseudo State: No.
- Stub State: No.
- Synch State: No.
- Concurrent States: No.
- Submachine State: This concept is similar to but not the same as the SMC push/pop transition.
- Deferred Events: No. The application is responsible for posting an event back on the event queue for later processing.
- Transition Parameters: Yes.
- Transition Guard: Yes.
-
Internal Transition: Yes. SMC calls this an
internal loopback transition and is denoted by a
nil
target state. - Transition Actions: Yes.
- Compound Transition: No.
-
Completion Transition:
Completion Event: No. - Event (Signal, Call, Time, Change): Not directly supported. Application is responsible for translating an event to a transistion and passing appropriate transition parameters.
In summary, SMC is not and will never will be a Statechart implementation. The SMC and Statechart philosophies are too different to be reconciled.
How are SMC state machines persisted?
As of version 2.2.0, SMC now supports persistance via the "-serial" command line switch. See SMC Programmer's Manual for a detailed explanation on persisting FSMs. This section has sample code for persisting to a flat file in C++, Java, [incr Tcl], VB.net and C#.
How can I be informed about when an FSM changes state?
Release 5.0.1 supports asynchronous state change notification for Java only. See SMC Programmer's Manual for a detailed explanation on haw to receive state change notification.
This feature will be supported in C# and VB.net in the next release, using the .Net event delegation. There are no plans to support this feature for any other target language.
How much overhead does SMC add to an application?
Memory: There is exactly one object for each state. These state objects are instantiated at application start.
CPU: When you call a transtion method, that method calls the current state's equivalent transition method. The state transition method performs the action method calls.
Summary: Memory overhead matches the number of concrete states. CPU overhead is one subroutine call per transition. In short, overhead is negligible.
Can you fix SMC's code generators so they produce clean code?
Only if the fix is easy to implement. Remember:
- SMC is not a compiler but a glorified macro generator.
- Macro generators do not perform target code optimization or analysis.
- Which means SMC produces compilable code that may contain warnings or fail strict code analysis.
Example: SMC generates C++ code always contains the
context
parameter in the transition method.
But if context
is not used in the method
body, then C++ compilers may output a warning due to the
context
parameter being specified but not
used. The solution is to drop the name
context
from the parameter list.
But this is easier said than done. It requires a sophisticated code analysis to decide if a parameter is accessed within a method body. To do it right, SMC needs to generate a source code model from the FSM model, optimize the source code model and then generate the target code from the source code model. Is stringently clean code worth this effort? Unless I hear overwhelmingly to the contrary, my response is no.
Writing SMC Finite State Machines Questions
How do I automatically put
#define/#include/package/import/package require
statements into the generated code?
If you want SMC-generated code to be placed into
a particular Java package/C++ namespace/Tcl
namespace, then use the %package keyword:
%package <package name>
. See
SMC Programmer's Manual
for a detailed explanation in using the %package
keyword.
If you want SMC-generated code to import a
C++ namespace/Java class/Tcl package/VB.net/C#
namespace, then use the %import keyword:
%import <name>
. See
SMC Programmer's Manual
for a detailed explanation in using the %import
keyword.
If you want SMC-generated C++ code to include a
header file, then use the %include keyword:
%include <sys/time.h>
or
%include "AppTimer.h"
.
These files and the %header file appear
in the same order in the target
<context>_sm.cpp file as in the .sm file. If
you do not place either <>
or
""
around the header file, then SMC
uses ""
by default.
As for C++ #define
macros,
put these statements and all other code you want to
appear verbatim in the generated code in a
%{ ... %}
block at your .sm file's
beginning. See
SMC Programmer's Manual
for example code using the %{ ... %}
block.
Note: The %{ ... %}
block may
only appear once in a .sm file and must be at the
file's beginning before any other SMC construct.
Comments may proceed this block however.
Note: For SMC-generated C++ code, the verbatim block is placed at the top of the .cpp file and not in the .h.
Why do I have to declare state machine actions as public?
The reason why the state machine actions in your application class have to be public because that is the only way the state classes will be able to access them.
You can make each state your application class' friend but that will be tedious. Since friendship is not inherited, you have to make every state a friend. Every time you add, delete or rename a state, you will have to update your application class as well.
I understand your frustration, but the simple access scheme used in C++ and iTcl doesn't allow for a more sophisticated access capability.
Note: In Java, you can give your state machine actions package-level access as long as your application class and the SMC-generated code are in the same Java package (see this FAQ answer to see how this is done.)
Why can't I issue a transition from within an action?
In case you believe this is a flaw in SMC, let me try to explain why this is so. A transition means an object has left one state and will be entering another. While in the transition, an object is not in any state. Actions occur while the object is in transition between states. How can a transition be issued when an object is not in any state? It makes no sense. I can't apply the transition to the previous state because the object has already left that state. I can't apply the transition to the next state because the object isn't there yet.
Here is an example demonstrating just how bad things get if you allow a transition action to issue a transition. Consider the following SMC code snippet:
Disconnected
state, the openConnection
transition is
issued, and that the open
action completes
immediately, issuing the connected
transition. Since the next state Connecting
is set before the Connecting
transition
actions are called, the order in which actions are called
is:
-
open(address)
-
stopConnectionTimer()
-
tellListeners("connected")
-
startConnectionTimer()
-
tellListeners("connecting")
The technique I use to solve this problem is to have
open(address)
return a boolean and call the
action from a guard to decide the next state:
This allows the next state to be determined dynamically but still not violate the "no transition from a transition action" rule.
Is there any way to issue a transition from inside an action?
There is a simple solution to this problem. Let me restate the question differently:
I need to take a different transition depending on an action's result. How can I do this?
If this is your question, then the solution is to
place the action in the guard. That way your FSM
executes the transition associated with the action
result. For example, your context class has an method
int startTask(Task t)
which returns an
integer value zero, 1 or 2 corresponding to the
task starting successfully, task suspended and task
start failed. You want to take a different transition
for each result. There is also a method
int getLatestResult()
which returns
the latest startWork(Task t)
result. The
.sm code to accomplish this is:
If this technique does not work for you, then you could place the action in a state's Entry action list and have the action issue the transition from there. In this one case, actions may issue transitions because the current state is now set. I do not encourage this technique because it can cause more problems then solve. If you do use it, then make sure the transition is issued by the last entry action and have that action issue the transtion immediately prior to returning. In short, the transition is the very last statement executed by all the entry actions.
If transition guards and entry actions do not answer, then read the SMC programmer's manual which shows how actions can issue transitions by using timers and transition queues.
Is SMC-generated code thread safe?
- C: No.
- C++: No.
-
C#: Yes, if you use the SMC
-sync
option. -
Groovy: Yes, if you use the SMC
-sync
option. -
Java: Yes, if you use the SMC
-sync
option. - Lua: No.
- Perl: No.
- PHP: No.
- Python: No.
- Ruby: No.
-
Scala: Yes, if you use the SMC
-sync
option. - Tcl: No.
-
VB.net: Yes, if you use the SMC
-sync
option.
The -sync
command line option used with
-java
and -vb
causes SMC to
add the synchronized
keyword (Java),
SyncLock Me/End SyncLock
(VB.net) or
lock(this){...}
(C#) to the
transition methods. Therefore, if a transition has
been issued from one thread and a second thread
attempts to issue a transition before the first
thread's transition has been completed, then the
second thread will be blocked until the current
transition returns.
There are no plans to generate thread-safe Tcl code. It is up to the developer to guarantee that two separate threads cannot issue overlapping transitions.
Why doesn't SMC generate thread-safe C++ code?
Because the generated code is OS-dependent. I am unwilling to add such code and testing complexity to SMC by having SMC generate code based on both the target language and the target OS.
Why won't SMC accept my "if" statement?
Because "if" statements are not part of the SMC language but the target programming language. SMC is deliberately simple so it can support multiple target languages. The conditional statement must be moved into a context class method where the target language can handle it.
When more than one transition pushes to the same state, how can I handle the pop transitions differently?
The problem is this:
You want to handle the TaskDone
transition differently when the push came from the
DoOneThing
transition than from
DoAnyThing
transition. In pre-v. 1.3.2
releases, there is no way to resolve this problem.
Read this
manual section
to learn how v. 1.3.2 solves this problem.
How do I receive a callback when my state machine transitions to a new state?
If you are using a .Net language (C# or VB.Net), then you can hook into the FSM's StateChanged event:
There is currently no equivalent code in the other supported languages. You can implement the Observer pattern yourself since you always know when a state change has occurred:
- Your application code is responsible for issuing transitions by calling the appropriate transition method.
- The transition method does not return until the transition has completed and entered the new state.
- Therefore, your application knows when the FSM has entered a new state: the transition method has returned. It is at this point that you can issue a callback to registered state change observers.
Java's bean package could be used to implement state change events.
If your goal to execute certain actions when your FSM exits or enters a state, then see the Programmer's Manual section on Entry and Exit Actions.
Can a transition return a value?
No. Transitions are implemented as methods and called-for-effect only. If a transition's actions produce data which you need to access later, then you must store that data somewhere, probably in the FSM's associated context class.
Can a transition action throw an exception?
It is a bad idea to have a transition action deliberately throw an exception. Consider the following FSM:
A task is given only some much time to run and if it
fails to complete in the allotted time, it is stopped.
If the action startTask(task)
throws an
exception and the task is never started, then action
setStopTimer(task)
will never be called.
That may be what you want but the FSM still ends up in
the Running
state which is not what
you want. The FSM will now wait forever for a
non-existent task to complete or a non-existent timer to
expire.
A better solution is:
startTask(task)
returns true
if
the task successfully starts. Only then is the timer
started and the FSM goes to the Running
state. If the task fails to start, your FSM can perform
error recovery and stay in the Idle
state.
Note: as of v. 2.0.2, SMC-generated C++, Java and
Tcl code is protected against action-thrown exceptions.
If an exception is thrown, SMC makes certain that the
FSM's current state is set before allowing the exception
to pass on through. In Java, this is done using the
finally
keyword. If C++, the
catch (...)
construct is used along with
throw;
to rethrow the caught exception. In
Tcl catch
is used and the exception is
rethrown with error
.
But I really need to throw an exception!
One work-around is to have a transition action create an exception and have the application class throw it when the transition method has returned. In Java it would work this way:
-
In your application class, add the data member:
private Throwable _throwObj;Then add the transition action method:void setThrowable(Throwable t) { _throwObj = t; }
-
If a transition detects the need to throw an
exception, then it calls
setThrowable
and passes to it the appropriate exception object. -
When your application class issues a transition
it does the following:
_throwObj = null; _fsm.Dowork(); if (_throwObj != null) { throw (_throwObj); }
(Java only) Using this technique you can throw both runtime and checked exceptions. You can only throw runtime exceptions from a transition action because a Java method must explicitly declare the checked exceptions it throws and the generate transition methods cannot make such declarations.
How do I access the previous state inside a transition action?
When a transition starts, the current state is
cleared and getState()
returns
NULL
. However, previous state is not
gone. It can be retrieved by calling
getPreviousState()
.
How do I get SMC to generate a call-by-reference?
Because Tcl is a weakly-typed language, SMC does not require you to specify a transition argument's type. But SMC supports two Tcl "types": "value" and "reference". If a parameter's type is "value", then SMC will pass the parameter using call-by-value by prepending a "$" to the parameter name. If the type is "reference", then SMC will pass the parameter using call-by-reference and passing only the parameter name.
If no type is specified, then SMC defaults to call-by-value.
Why won't SMC accept class template instances?
Because it does not make programming sense. Consider the following:
-
%class
expects a class name after it and not a template.AppTemplate<int>
is an actual class whileAppTemplate<class T>
is not a class - it is a template for a class. -
The code for
AppTemplate<int>
is inAppTemplate<class T>
. By instantiating the class template, you are reusing previously written code. You cannot add code to a class template. -
This means that all the FSM-related code must
already be in
AppTemplate<class T>
. If the class template knows nothing about SMC-generated classes, then makingAppTemplate<int>
the context class is a waste of time. There is no application code calling the SMC-generated code.
The solution to this problem is based on your owning
the AppTemplate<class T>
code.
Create another classAppTemplateFSM
, make
it a data member in
AppTemplate<class T>
and also the
context class for the FSM. All class template
instances will then access the SMC-generated classes
through AppTemplateFSM
and SMC-generated
classes access the template class methods through
AppTemplateFSM
. In short,
AppTemplateFSM
is doing exactly the same
work as the SMC-generated context class: redirecting
method calls between application code and
SMC-generated code.
Now, if you want to use a templatized-FSM to go along
with your class template, then good luck!
Break out your Perl to read in the .sm template file
and replace all the variable <T>
class names with the target class names and then have
SMC compile the result. As for me, I will not
be supporting FSM templates.
Can I add arguments to a pop transition?
Yes you can. As the Programmer's Manual states, this feature was added in version 1.2.0. You can code up your pop transition as follows:
and have then define the FAILED
transition accepting those arguments:
Why do I have to specify a transition argument's type when I am generating Python code?
Because I do not want to condition SMC's syntax on the target language. SMC's syntax is the same no matter which language you are using.
How do I set the context class' access level?
The "%access" keyword access a target language-specific class access level.
This level is read in verbatim and used to set the context class' access level in Java and C#. The other target languages ignore this setting because they do not support class accessibility.
If you specify %access package
when
generating Java, this will be converted to
/* package */
in the generated Java
code because Java views no access level to mean
package-level access. The reason for this is due to Java
using the package
keyword to specify the
package name.
How can I determine which transitions are defined in the current state?
By compiling your .sm file with the -reflect option
(note: only supported by -csharp, -java, -tcl and
-vb). This causes either a getTransitions()
method (Java, Tcl) or Transitions
property
(C#, VB.Net) to be generated for the state classes. This
method returns a java.util.Map
,
System.Collections.IDictionary
or Tcl array
which maps transition names to an integer value:
- zero: transition undefined.
- one: transition defined in state.
- two: transition defined in Default state.
The returned map contains an entry for all transitions.
To figure out the current transition's supported transitions, use the following code:
See the Programmer's Manual to learn more.
How can I get SMC to generate event registration and event listening code?
SMC does not generate such code because that rightfully belongs in your application code. The idea is that your application receives these events from whatever event system and those events are then passed to your FSM.
The FSM's role is to remember what your object's state after the last received event. There is a natural and strong relationship between finite state machines and event-driven programming. The problem is that there are multiple places to register for events: GUIs, timers, messaging systems, etc. And for each there is a different API for each programming language. While I would love to have SMC generate such code, it simply is not feasible. For now you have to write the event system interface and pass the events to the FSM.
Why doesn't SMC accept the action
object().name()
?
The reason object().name()
does not work is
due to SMC generating code for multiple languages. This
requirement forces me to use the simplest syntax for the
transition and entry/exit actions. All programming
languages support the construct "method(args)".
But the construct object().name()
is not
easily translated to any language. Because SMC does not
directly translate the FSM code to one language, I am
forced to use an overly simple FSM language.
Why does the transition action
System.out.println("My output")
result in
invalid generated code?
No, this is not a bug. The answer to this question is the same as the previous question. Transition actions must be context class methods. This limitation makes it possible for SMC to correctly generate the target language code for multiple target programming languages. This forces you to wrap all code in context class methods. If this seems an inefficient burden, that is the price you pay for using SMC. SMC generates the myriad of tiny State Pattern classes for you. This allows you to write sophisticated finite state machines, leveraging the power of the State Pattern without the pattern's class explosiion overhead.
The price you pay is placing all code in your context class methods. You want to write output to the console? Has to be done via a context class method. Want to make an API call? Has to be done in a context class method. Don't like this limitation? Write the State Pattern classes yourself.
As the previous question states, SMC supports multiple target programming languages and so must use the lowest common programming language constructs to work. This means you have to hide your target language's complexity in your context class methods.
Can I use #ifdef preprocessor statements in my .sm file?
Sure, but you are responsible for running the .sm file through the preprocessor before passing the results to SMC. SMC knows nothing about #ifdef statements and will report them as errors.
How do I call a static method from the transition actions body.
Just like any other method:
SMC's prepending the ctxt.
before all method
names does not break calling static methods. It is a
valid way to call static methods.
How can I get SMC to place %include
in the
header file rather than the source file?
You can't and you don't have to. SMC honors your
%header
and %include
ordering.
Place the %include
before the
%header
. You will also have to do this
inclusion prior to including
%header
elsewhere in your code.
When my timer expires and I issue a transition, I
sometime get a
StateUndefinedException
. Why?
Because your code isn't thread-safe. One thread is
already in the middle when it is pre-empted by the timer
thread. The timer thread then issues another transition
but since you are already in transition, the
StateUndefinedException
.
You need to protect your transitions by either using
the -sync
option if you are using Java, C#
or VB.net or add the necessary code yourself.
How can I specify that the FSM context class name
overriding the default xxxContext
name?
In your .sm file use the keyword %fsmclass
followed by the desired FSM context class name. This
works for all supported languages.
Why doesn't SMC support overloaded transition names in generated C code?
The problem is that the link between application code and the SMC-generated code is the transition name. SMC uses the transition name as the subroutine name. The application calls this subroutine to issue a transition. But if SMC uses a subroutine name different than the transition name to avoid overloading, then the link between application and state machine is broken because the transition subroutine name is changed.
The solution is that the SMC programmer must not use transition name overloading when the targeted programming language does not support subroutine overloading, like C.
Why doesn't the SMC-generated code compile when I use
the %fsmclass
directive?
There are two possible reasons for this failure. The
first is that SMC stores the generated
%fsmclass
class code in a file named
differentln than what is expected by your build
environment. This can be corrected by using the
%fsmfile
directive (introduced in v. 6.6.0).
By combining %fsmclass
and
%fsmfile
, you have complete control over
the generated FSM context class name and that class' file
name.
The second possible reason is that your .sm file contains
a %map
directive with the same name as the
%fsmclass
name. Because map classes are
nested inside the FSM class, the map class name may not
be the same as the FSM class name.
Unfortunately, the SMC manual contained examples which
incorrectly showed %fsmclass
and
%map
directives with the same name. These
examples have since been corrected.
How can I tell SMC what file name to place the generated code?
Use the %fsmfile
directive in the .sm file.
SMC will then use that file name plus the appropriate
suffix for the generated file name. The file name suffix
can be configured using the -suffix
and
-hsuffix
command line parameters.
What doesn't SMC generate a
Default::Default
map and state?
Because the idea for this kind of ultimate
Default
state spanning all maps came late
in SMC's life. Implementing this feature changes the
fundamental design of the SMC syntax and generated code.
This feature results in much pain for little gain. There
is little demand for this feature.
But there is hope. SMC maps are a syntactic construction which allows states to be segregated for easier understanding. If your maps have this level of commonality, you could have them in one map, changing their names for easy identification. That way these states will automatically use the same Default state. Placing all your states in one map may appear confusing, but you can add comments which mark each sub-"map" within the single map.
How can I work around the dynamic memory allocation used in the C++ statemap.h?
Use both the -stack <size>
and
-noex
options. The only dynamic allocation
used in the C++ statemap.h are for allocating state stack
elements and exceptions. The only problem is if you use
push transitions that may result in a state stack depth
of unknown size. But I doubt that is the case in an
embedded application.
If your state machine does not use push transitions, you
should still use -stack 1
.
What happened to the objects
MapName.StateName
in the
-java7
-emitted code?
Because those state objects were a natural part of the
-java
-emitted code. SMC generates a class
for each %map
. Inside the map class are
nested classes for each state. Each state class contains
a method for each each of its transitions. So the
resulting Java code contains the object
MapName.StateName
.
But -java7
doesn't emit map and state
classes, only the context class. States are intances of
statemap.State7
which contains a
statemap.TransitionHandle
array. Maps and
states are now referenced using integer constants, which
is preferred. But that is violates the requirement for
backward-compatibility.
This is resolved by using -reflect
with
-java7
. This option emits a class for each
%map
. These map classes contain a
static final State7 <statename>
field
for each of the map's states. So now a reference to
object MapName.StateName
should resolve
correctly and the generated code is backward compatible.
Compiling SMC Finite State Machines Question
I've modified a .sm but it's not recompiled when I build. How do I get SMC to automatically run?
If your using make to build C++, then add the following lines to your makefile:
If your version of make does not support multiple prefixes on the same line, then split the line into two rules:
If your using make to build Java, then add these lines to your makefile:
If you are using ant, then add the following to your build.xml:
-
Specify where the Smc.jar file is located:
<property name="bin.dir" location="path to Smc.jar" /> <property name="smc.jar" location="${bin.dir}/Smc.jar" />
-
Specify where .sm files are located:
<property name="etc.dir" location="etc" /> <property name="sm.file" location="${etc.dir}/filename.sm" />
-
Specify how the target language file is
generated:
<target name="gen" description="Compile .sm file" depends="init"> <java dir="${src.dir}" jar="${smc.jar}" classpathref="class.path" fork="true"> <arg line="-target language option [put SMC options here] -d ${src.dir} ${sm.file}"/> </java> </target>
If you are using Microsoft's Visual C++, then do the following:
- Open your project in VC++.
- Add the .sm file or files to the project.
- For each .sm file, right click on the file and select the "Settings..." item from the pop-up menu.
- In the "Project Settings" dialog, select the "Custom Build" tab.
- Click in the "Build Command(s)" text box and enter: "java -jar <path to Smc.jar> -c++ ${InputPath}".
- Click in the "Output file(s)" text area and enter: "$(InputName)_sm.h $(InputName)_sm.cpp".
- Click on the dialog box's "OK" button.
If you are using VB.Net or C# in Visual Studio, then
there is no solution currently. When you select your
.sm file and look at the properties, there is a
"Custom Tool" property. What you enter here is the name
of a registered custom tool. The registered custom tools
can be found in the registry key:
HKLM\Software\Microsoft\VisualStudio\7.[01]\Generators
These generators are COM objects implementing the IVsSingleFileGenerator interface. This interface is given the file name to be custom compiled and returns a byte array containing the compilation. An SMC custom tool would:
- Fork off a Java process to do the actual compilation.
- Read the compiled _sm.cs file into the byte array and return that.
Well, no such custom tool exists. I have no experience writing COM objects nor hooking them into Visual Studio. I am not even sure if it could work given that the compilation must be done in a separate process.
Why does SMC throw any ArrayIndexOutOfBoundsException when I compile my .sm file?
Because your are using an SMC version < 3.0.0 and your .sm file contains unicode characters. SMC v. 3.0.0 and beyond is now able to handle unicode.
How can I get rid of all exception-handling code?
Firstly, "-noex" tells SMC not to initiate an exception throw. SMC still generates the try/catch/rethrow blocks to protect the FSM against application-thrown exceptions. If SMC didn't generate this code, an application exception would leave the FSM's state unset and that means your FSM would stop functioning.
If you application code does not throw exceptions, the SMC-generated try/catch/rethrow blocks are not needed. Use the "-nocatch" command line option to prevent try/catch/rethrow generation.
Note: If your application uses exceptions (especially if you are generating Java code), using "-nocatch" is strongly discouraged.
How can I tell SMC which C++ cast operator to use?
Use the "-cast <cast_operator>" command line
option. The allowed C++ cast operators are
dynamic_cast
(default),
static_cast
and
reinterpret_cast
.
How can I tell SMC where to put the generated files?
Use the "-d <directory>" command line option. The directory must be accessible from the current working directory and writeable.
How can I tell SMC not to exit?
Use SMC's "-return" command line option.
Why is getState() method/State property in the generated Context class and not in FSMContext?
If placed in FSMContext, it would have to return a vanilla State object which does nothing, forcing the need to downcast the reference to the generated State class. I chose not to place downcasts throughout the generated code but instead use one downcast in getState(). This getState() must be placed in the generated Context class and not in FSMContext.
What is the difference between -java and -java7?
-java implements the state machine using the State Pattern class layout. Each state is a separate class and the transitions are methods in those state classes.
-java7 implements the state machine as a transition
table. A transition table is two dimensional: states
are the first dimension and transitions are the second
dimension. The table elements are
java.lang.invoke.MethodHandle
, which are
similar to C function pointers. When a transition is
issued, the method handle for the current state and
transition is looked up and invokeExact
is
called, passing in the method parameters.
invokeExact
is only slightly slower than a
compiled method call, so no performance is given up by
using method handles.
The biggest difference is that -java7 results in only one
.class
file (when reflection is not used)
versus -java generating multiple .class
files, one per state.
The application interface generated by -java and -java7
are the same. An application may trasition between -java
and -java7 with no change required to the application
code. There is one caveat: -java7 is dependent on Java
1.7 or later because the java.lang.invoke
package was introduced in Java 1.7. If your application
is using Java 1.6 or earlier, than you may only use
-java.
I want to use the smc-maven-plugin for my Java Maven project but the plug-in on Maven Central is years out of date. Why is this?
Firstly the good news: net.sf.smc.smc-maven-plugin on Maven Central is now up to date with the latest SMC release. This is an all new plug-in supporting all SMC compiler options. SMC Programmer's Manual Section 14 shows how to use smc-maven-plugin.
The reason why smc-maven-plugin came to be out-of-date is due to the artifact not being part of the SMC project. Others put smc-maven-plugin versions into Maven Central with no coordination with SMC project. This is now changed and the SMC artifacts on Maven Central will be released as part of SMC updates.
Debugging SMC Finite State Machines Questions
How do I turn on state machine debugging?
- Use SMC's "-g" flag when compiling your state machine. Debugging output will be added to the generated code. Note: this debug output is not produced unless turned on at run time.
-
Find where you instantiate your state machine
context object and turn on debugging:
-
C++:
_state_machine->setDebugFlag(true);
-
Java:
_state_machine.setDebugFlag(true);
-
Tcl:
$_state_machine setDebugFlag 1
-
VB.net:
_state_machine.DebugFlag = True
-
C#:
_state_machine.DebugFlag = True
-
Python:
self._fsm.setDebugFlag(True)
-
C++:
-
The debug output is currently sent to standard
error (
System.err
in Java). This can be changed programatically:-
C++:
_state_machine->setDebugStream(ostream&);
-
Java:
_state_machine.setDebugStream(java.io.PrintStream);
-
Tcl:
$_state_machine setDebugStream %channelId%;
-
VB.net:
_state_machine.DebugStream = <System.IO.TextWriter object>
-
C#:
_state_machine.DebugStream = <System.IO.TextWriter object>
-
Python:
self._state_machine.setDebugStream(stream)
-
C++:
How do I use something other than C++ iostreams?
Use the -nostreams option to replace iostreams with the output mechanism of your choice.
Displaying SMC Finite State Machines Questions
How can I graphically display an FSM?
SMC v. 3.2.0 now generates Graphviz DOT files with the -graph option. There is a -glevel int option specifying how much FSM detail to place in the DOT file: level 0 gives you least and level 2 the most. View the gallery for more information and images of the SMC-generated DOT files using all three levels.
There is also the -table target. SMC generates an HTML table listing the actions for each state/transition pair. Each state's entry and exit actions are listed. The table is not as simple as it first seems because transition guards can make the generated HTML large and unreadable.
Since -table and -graph are targets like -c++, -java, etc., you may not use it in conjunction with other targets.
Why write state machines in text and then compile them? Why not create a GUI to draw state machines?
Because you are already using a text editor to write your C++/Java/Tcl/VB.net/C#/etc. code. The write/compile/test loop is well supported by today's IDEs and fitting SMC into that loop is easy. Fitting in a GUI is not so easy.
Then there is the issue of developing a GUI that runs on multiple platforms which is difficult even when using Java Swing. Because SMC is a command line application whose only OS interaction is reading and writing files, I am highly confident that Smc.jar will run on any Java-supported platform. But porting a GUI application would be a time consuming process - time I don't have.
Another philosophical argument against a GUI is that you spend more time trying to make the FSM drawing look nice than on actual development. Laying out the states and routing the transitions so that the drawing is somewhat readable is a time-consuming nuisance with little value.
Besides, my GUI experience is limited.
Why does SMC place only the fully-qualified <map name>::<state name> in the Graphviz DOT file? Why not just the state name?
See the Programmer's Manual for a detailed explanation. Graphviz uses a global namespace for node names and so SMC must use the fully-qualified state name as the node name to avoid confusing Graphviz. Otherwise Graphviz would view MainMap::Start and ConnectMap::Start as being the same node (Start) and mess up the links.