CHSM Language System Changes ============================ ****************************************************************************** 4.4 ****************************************************************************** NEW FEATURES ------------ * Added a set of Java classes including CHSM_Builder that allow CHSMs to be built and integrated with the Groovy dynamic language for Java. See files under src/java/lib/groovy for details. * The Java run-time library classes of Event, Machine, Parent, and Set now implement the Iterable interface so, for example, instead of having to do: for ( Iterator i = machine.iterator(); i.hasNext(); ) { State s = i.next(); // ... } you can now do: for ( State s : machine ) { // ... } BUG FIXES --------- * In the Java run-time, one of the transition algorithm debugging messages was wrong. ****************************************************************************** 4.3 ****************************************************************************** NEW FEATURES ------------ * The "dominance" rule has been extended from parent/child transitions to sibling transitions. Previously, transitions such as: state x { alpha -> b; alpha -> c; } were considered erroneous and were documented to result in arbitrary transition selection; the implementation, however, always selects the first one. The documentation was written as it was to allow the implementation the freedom to be changed without causing backwards incompatibility. It's been quite a long time and the implementation hasn't yet needed to be changed in this respect, so such the behavior of such transitions is now documented to reflect the actual behavior. The example above isn't very useful, but an example such as: state x { alpha[ some_condition ] -> b; // if ( some_condition ) ... alpha -> c; // else ... } allows an "if-else" to be done more efficiently since the condition need only be evaluated once. Previously, to be considered "legal," you would have had to write: state x { alpha[ some_condition ] -> b; alpha[ !some_condition ] -> c; } This release involves changes only to the documentation; there have been no changes to any code. ****************************************************************************** 4.2 ****************************************************************************** NEW FEATURES ------------ * Added new syntax and run-time library support for "computed target states": state s { undo -> [ expression ]; } where the expression returns a pointer to a state. If the pointer is null, the transition is not taken. This is an experimental feature the motivation for which was being able to implement an "undo" facility where the state needed to transition back to would be kept in a user-defined data structure (like a stack) and when an 'undo' event is broadcast, the state to transition back to could be popped off the stack. See the new grid example. * The CHSM::event class has a new member function: template< typename EventClass > bool is_type() const; This is a convenient shorthand to check whether an event is of a particular class: if ( trigger.is_type() ) // ... It's equivalent to: if ( dynamic_cast( &trigger ) ) // ... * The Java version is now using Java 1.5 generics where appropriate. BUG FIXES --------- * The compilers failed to check whether states referred to as the target of transitions were defined. * If the CHSM was never defined (via the "chsm" keyword), the compiler would segfault. * Transition dominance in a case like: cluster c(a,b) { alpha -> x; // this transition should dominate ... } is { state a { alpha -> b; // ... over this one } state b; } state x; didn't work right: the machine would incorrectly be in state 'b' after 'alpha' was broadcast. * The broadcast of an otherwise unused derived event would not cause the base event to be broadcast. Given: event alpha; event beta; state a { alpha -> b; } state b; and a main() like: int main() { my_machine m; m.enter(); m.beta(); } nothing would happen because 'beta' itself has no transitions and the transitions of 'alpha' were never checked. ****************************************************************************** 4.1.1 ****************************************************************************** BUG FIXES --------- * I removed what I thought was an unused typedef from what chsm2c++ emitted, but it was used. How I missed this isn't clear. * Fixed chsm2c++ user-event parameter emission. ****************************************************************************** 4.1 ****************************************************************************** NEW FEATURES ------------ * The C++ classes are now documented using Doxygen. http://www.doxygen.org/ BUG FIXES --------- * On some platforms, an explicit #include was needed for getopt(). ****************************************************************************** 4.0 ****************************************************************************** NEW FEATURES ------------ * Added Java run-time library and CHSM-to-Java compiler. * Made the C++ run-time library thread-safe. ****************************************************************************** 3.0 ****************************************************************************** NEW FEATURES ------------ * Version 3.0 is a major update (after about a decade of neglect) to make the code compile under modern ANSI C++ compilers. ****************************************************************************** 2.4.3 ****************************************************************************** NEW FEATURES ------------ * The manual pages are now also distributed in PDF. BUG FIXES --------- * Made modifications so that the code compiles with the EGCS 1.1.2 compiler. * Reworked declaration of namespace macros in fakeansi.h since they didn't work on an implementation that actually supports namespaces. ****************************************************************************** 2.4.2 ****************************************************************************** BUG FIXES --------- * Fixed a bug in the transition algorithm where a transition directly entering a state deeply nested inside a cluster would actually enter the cluster's default (or history) state. For example, given: state a { alpha -> x.y.c; } cluster x(a,y) is { state a; cluster y(b,c) is { state b; state c; } } and the event alpha, the machine would end up in x.y.b instead of x.y.c. ****************************************************************************** 2.4.1 ****************************************************************************** BUG FIXES --------- * Fixed a bug in hash_table_base::grow_table(). It was just really broken. The reason it took so long to find the bug was that nobody had used enough distinct symbols to cause the symbol-table to grow. * Fixed a bug where chsm2c++ would core dump when given a chsm fragment like: chsm C is { cluster C( a, b ) is { // ... Previously, it correctly reported the redeclaration error, but then also dumped core afterwards. ****************************************************************************** 2.4 ****************************************************************************** NEW FEATURES ------------ * Class names for derived CHSMs and states can now be complete-class-names as specified in the C++ language reference manual as opposed to merely being identifiers. For example: state< my_class > a; // legal as before state< my_class::nested_class > b; // now also legal state< my_template_class > c; // ditto * CHSM's can now have enter/exit blocks just like states: chsm machine { upon enter %{ // ... %} upon exit %{ // ... %} } is { // ... } * A root cluster introduced into the implementation of version 2.2 has now been made user-accessible. The CHSM compiler emits a cluster named "root" and all top-level states are its children. The root state is "special" in that it is not mentioned by name to access a child state: %% chsm machine { state a; cluster c(x,y) is { state x; state y; } } %% main() { machine m; if ( m.a.active() ) // not: m.root.a.active() // ... } A time to refer to the root state explicity is if you want to iterate over a CHSM's top-level children only: CHSM::const_iterator i; for ( i = m.begin(); i != m.end(); ++i ) // iterates over: a, c, c.x, c.y cluster::const_iterator j; for ( j = m.root.begin(); j != m.root.end(); ++j ) // iterates over: a, c * Upon construction, a CHSM will no longer automatically enter its states. Instead, a new function enter() must be called explicitly: main() { machine m; m.enter(); // new function // ... } Additionally, there is also a function exit() that may be called to exit all the states of a CHSM: main() { machine m; m.enter(); // ... m.exit(); } * Since a CHSM can now be entered and exited like an ordinary cluster, the language has been extended to allow a history specification for CHSMs: chsm machine( /* optional arguments */ ) history { // ... } * Since a CHSM can now be active or inactive just like an ordinary state, it now has an active() member function. It is merely a shorthand, however: main() { machine m; // ... if ( m.active() ) // same as: m.root.active() // ... } * A new command-line option (-C) was added to chsm2c++ to control the C++ code emitted. The -C option takes a numeric argument mapping to a C++ code "feature." For this release, there is only a single feature: emit_full_qual_class_names. If enabled, chsm2c++ emits nested class names as fully-qualified from global scope. (The default is not enabled.) For example, given: chsm machine { event alpha; event beta; } you get: class machine { // ... class beta_event : public machine::alpha_event { // ^^^^^^^^^ // ... }; // ... }; since some compilers (AIX C++, for example) are broken and need the above fully-qualified although the code is legal without it. The reason chsm2++ can't always emit fully-qualified class names is because some other compilers (Microsoft C++, for example) are broken in that they will not accept the extra qualification even though the code is legal. One approach to solve this problem would have been to make another compile-time test (config/src/fully_qualified.c, for example), but this would prevent chsm2c++ from being compiled on one system and having its generated code being compiled on another system (cross- compiled). The better solution is to have a command-line switch where the default is the "most C++ compiler accepted" behavior. By having the switch accept an argument, it allows for future code features to be added. * An experimental facility for adding/removing child states to a set has been added -- comments appreciated. It is an additional facility using a separate library (libdynamic_chsm.a), so it is not automatically included by the CHSM driver script. (It can be by modifying CHSM_I and CHSM_l in the driver script.) ****************************************************************************** 2.3 ****************************************************************************** NEW FEATURES ------------ * A new language feature allows the specification of "internal transitions" as they are known in the literature. For example: state s { alpha %{ do_something(); %}; } says that, on the occurrence of the event alpha (or any event derived from alpha), execute the C++ code in the following block, but do not exit state s nor transition in any way; hence the lack of any -> and target state. Compare that with the "self transition" of: state s { alpha -> s %{ do_something(); %}; } that exits s, broadcasts exit(s), enters s, broadcasts enter(s), and performs transitions as a result of said broadcasts, if any. Internal transitions can be used as an optimization where the full-blown mechanics of regular transitions are not needed. Note that in cases where derived states are used and the virtual member functions enter() and/or exit() is overridden, said functions are NOT called for internal transitions since no exit/enter takes place. In cases where the additional functionality of overridden functions is required, self transitions should be used. (For example, see examples/h2o.chsm.) IMHO, the term "internal transition" is a poor one since nothing "transitions," but it's the term in common use. * The manual-page Makefiles were enhanced to produce preformatted text versions of all the manual pages for use by people without access to the Unix man command to format them. Additionally, a new "dist" target has been added for making "distributions" of the software. (This is mostly useful for me.) It's the same as the "clobber" target except that it makes the preformatted text versions of the manual pages so they are included in the distribution; the "clobber" target, in contrast, removes the preformatted text versions in keeping with the notion that "make clobber" removes all that can be regenerated. Incidentally, the "dist" target has to be added to all Makefiles even if they don't use it so you never get "Don't know how to make dist." FEATURES REMOVED ---------------- * I removed the "tar" target since it wasn't useful because you really need to be one directory level up to make the tar file properly. ****************************************************************************** 2.2 ****************************************************************************** NEW FEATURES ------------ * A minor language extension allows events with no parameters to be declared as: event alpha(); in addition to: event alpha; as previously allowed. * The CHSM run-time library debugging output has been enhanced to provide more meaningful information and use indentation. * The CHSM compiler now checks child states declared in child lists to see if they were actually defined. If not, a warning is issued. (If they are the target of a transition, however, then an error is issued. This was checked for all along; only the warning is new.) * The CHSM compiler now checks for intra-set transitions and issues an error for any encountered. For example: chsm machine is { set s(p,q) is { state p { alpha -> q; } // now reported as an error state q; } } * A bug was fixed in the chsm driver script whereby a 0 exit status was given regardless of the exit status of chsm2c++. * A bug was fixed in the transition algorithm whereby an infinite loop was created. For example, broadcasting beta to: chsm machine is { state a { beta -> b %{ alpha(); %}; } state b { alpha -> a %{ beta(); %}; } } would result in an infinite loop. (Interestingly, this bug was not present in the 1.0 version; hence, the lack of a regression test.) * A bug was fixed in the transition algorithm whereby an erroneous set of transitions caused the semantics of a cluster to be violated. For example, broadcasting alpha to: chsm machine is { set s(a,b) is { state a { alpha -> c.x; } state b { alpha -> c.y; } } cluster c(x,y) is { state x; state y; } } would result in the machine being in both c.x and c.y -- wrong! Now, only one state is arbitrarily entered. * A bug was fixed in the language system whereby an erroneous set of transitions caused the semantics of a CHSM to be violated. For example, broadcasting alpha to: chsm machine is { set s(a,b) is { state a { alpha -> x; } state b { alpha -> y; } } state x; state y; } would result in the machine being in both x and y -- wrong! Now, only one state is arbitrarily entered. (This bug is almost exactly the same as EST1 except the reason for this one was because states at the outermost level didn't have an actual cluster parent to enforce cluster semantics -- they do now.) * A bug was fixed in the transition algorithm whereby a state being entered directly bypasing its parent caused the enter() function to be called twice. See examples/enter_once.chsm for an example. * A bug was fixed in the broadcast of base events where the transition algorithm was not performed at all if a base event's broadcast was cancelled ignoring the derived event. * The mechanism by which transitions are inherited by derived events has been changed. The reason for the change is the following: Suppose a derived event is broadcast and has no transitions to take, either because all of the source states are not active or none of the transition conditions are satisfied. In CHSM versions 2.1.3 and earlier, the broadcast would be cancelled at that point ignoring the transitions for base events. The implementation literally broadcasted base events and relied on them to handle their own transitions. Now, in CHSM version 2.2, derived events truly inherit their base event's transitions by simply having the iterator proceed to them when its own list is exhuasted. This means that broadcasting base events is no longer necessary. However, they must still be considered to be "in progress" thus preventing their being broadcast. (There is no need for them to be broadcast since the derived will cover all of its transitions.) I don't consider this to be a "bug" per se, but a clarification of what a derived event really is and what it means to broadcast it. * Many bugs with the hash-table code were fixed. * The non-interactive examples were augmented to be self-testing facilitating regression testing on the CHSM language system. * A #line directive is now printed at the very beginning of the declarations section so any C++ errors are reported by the underlying C++ compiler with respect to the original .chsm file. ****************************************************************************** 2.1.3 ****************************************************************************** * Just a code clean-up release. ****************************************************************************** 2.1.2 ****************************************************************************** NEW FEATURES ------------ * A bug was fixed in the transition algorithm whereby more than one nondeterministic transition was taken. For example, broadcasting alpha to: chsm machine is { state x { alpha -> y; alpha -> z; } state x; state y; } would result in the machine being in both x and y -- wrong! ****************************************************************************** 2.1.1 ****************************************************************************** NEW FEATURES ------------ * The chsm driver script has been enhanced so as not to depend on (sometimes a broken version of) getopt. A caveat of this, however, is that options can no longer be contiguous. For example, if you want to specify the -d and -i options, you can not say -di but must specify them seperately as -d -i. Oh, well. * The chsm driver script has new options including some GNU-style --long-option synonyms: --help | --usage Print the usage message and exit. -n | --dry-run No-execute mode. --no-lines Same as the -d option. --output Same as the -o option. --to-stdout Same as the -E option. -v | -version | --version Print the chsm2c++ version number and exit. --verbose Print individual command-lines. ****************************************************************************** 2.1 ****************************************************************************** NEW FEATURES ------------ * Classes derived from CHSM::CHSM may now have additional constructor arguments: class my_stuff : public CHSM::CHSM { public: my_stuff( CHSM_ARGS, int my_arg ) : CHSM::CHSM( CHSM_INIT ), my_member( i ) { } protected: int my_member; }; %% chsm my_machine( int my_arg ) is { // ... state s { alpha -> t %{ my_member = 0; // note: it's accessible %}; } // ... } This feature necessitated moving user precondition functions out of param_blocks and into CHSM scope so that members of CHSM derived classes would be accessible. * Enter/exit actions can now refer to the triggering event: state s { upon enter %{ if ( event == alpha ) // ... %} // ... }