Question Index
-
- What is the current SMC version?
- Where is the documentation?
- Where do I download SMC?
- Where can I get the SMC documentation in PDF?
- How do I contact SMC developers?
- 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?
- How are SMC state machines persisted?
- Does SMC use hierarchical state machines?
- Does SMC support concurrent states?
- When will SMC move to Java 6?
- 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?
-
Writing SMC Finite State Machines
-
I need to place a
#define/#include/package/import/package requirestatement 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
%headerfile is dependent on a%includefile. How can I get the%includeinto 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
StateUndefinedExceptionWhat is happening?
-
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?
Miscellaneous Questions
What is the current SMC version?
The current version 5.1.0, released May 20, 2008.
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.
Where do I download SMC?
At http://sourceforge.net/projects/smc in the "Latest File Releases" section.
Where are the SMC documents in PDF?
The programmer's manual is not available in PDF and there are no plans to provide the manual in any format other than HTML.
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.
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?
Bob Martin started SMC around 1991. I picked it up the same year. 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.
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#.
Does SMC use hierarchical state machines?
No.
Does SMC support concurrent states?
No.
When will SMC move to Java 6?
When I release SMC v. 6.0.0. This will be the release after 5.1.0.
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.
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.
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
-syncoption. -
Groovy: Yes, if you use the SMC
-syncoption. -
Java: Yes, if you use the SMC
-syncoption. - Lua: No.
- Perl: No.
- PHP: No.
- Python: No.
- Ruby: No.
-
Scala: Yes, if you use the SMC
-syncoption. - Tcl: No.
-
VB.net: Yes, if you use the SMC
-syncoption.
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
setThrowableand 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:
-
%classexpects 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?
SMC v. 4.1.0 introduces the "%access" keyword which accepts 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.
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.
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.errin 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.