#!/usr/bin/perl
# Copyright (c) 2014, Thomas Block ( source [at] block-net.de )
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#   Date:     $Date: 2018-06-16 13:35:59 +0200 (Sa, 16 Jun 2018) $
#   Revision: $Revision: 100 $
#   For more information please visit
#   http://www.block-net.de/Programmierung/cpp/fsm/fsm.html

# This script is used to 
# 1) generate plantuml output
#    from the transition table of the fsm framework
#    The output is given to stdout and can be redirected in 
#    an other file call as follows
#    perl fsm2plantuml_pl -tt inputFile > outputFile.uml
# 2) generate a cpp state machine file just by defining 
#    the transition table
#    So you just need to fill the generated state functions with your
#    code and to fill the superstate, if configured.
#    Create a FSM based on fsm.hpp
#    perl fsm2plantuml_pl -tt transition_table -sw MyFsm > MyFsm.cpp
#
#    Create a FSM standalone without virtual function but state methods
#    use option -nee without using entry/exit parts per state
#    perl fsm2plantuml_pl -tt transition_table -sm MyFsm > MyFsm.cpp
#
#    Create a FSM standalone without virtual function  but state switch/case
#    use option -nee without using entry/exit parts per state
#    perl fsm2plantuml_pl -tt transition_table -sm MyFsm > MyFsm.cpp

use File::Basename;
use DirHandle;
use Data::Dump qw(dump);

#---- setup messages for help screen
$usage_str =<<ENDUSAGE;
 {[] [] } -[h|?|help] -tt filename -{cpp|sw|sm|csw|csm|vctst} classname [-nee] [-extt]

 Parameter in [] means optional
 only one Option in {} may be used
 nee and extt is only valid for options sw, sm, csw, csm

Parameter:
 -h             prints this help messages
 -tt  filename  filename contains the transition table
 -cpp classname Generate an FSM cpp template 
 -c   fsmname   Generate an FSM C template  
 -sw            Implement state handling inside a switch/case and do not use functions for each state
 -base          the template is either derived from fsm.hpp or fsm.h
 -nee           No entry/exit (only valid for sw) 
 -extt          Expand transition table in code
 -vctst fileFsm namespaceFsm objFsm classFsm
 
This script is used to generate plantuml output or a state machine cpp template
from the transition table of the fsm framework.
The output is given to stdout and can be redirected in an other file.
ENDUSAGE

($pname, $d, $e) = fileparse ($0, "");
$usage = "$pname $usage_str";


#---- main ----------------------------------------------------------------------
#internal variables and constants
my @search_list;
my @states, @events; 
my @table;
my @fsm_attr;
my @pattern;
my %map;
my ($cst, $nst, $sig, $grd, $act, $tState, $tEvent);
my ($replaceClassName, $variant);
my $nee = 0;


use constant {
  TT => 0,
  TTBEG => 1,
  TTCNT => 2,
  TTSS => 11,
  TTEND => 3,
  TTINIT => 4,
  STENTRY => 5,
  STDO => 6,
  STEXIT => 7,
  ATTR => 8,
  TTMARK => 10,
  VRNT_CPP => 2,
  VRNT_C => 4,
  VRNT_VCST => 102  
};

#---- parse command line for options
$sm = 1;
$base = 0;
while( $_ = $ARGV[0], /^-/ ) {
  shift;
  print STDERR "\nOption $_ used\n";
  #---- help option
  #---- complete with your options!
  if( /^-(?:h|-help|\?)$/ ) {
    print $usage;
    exit;
  }
  elsif( /^-vctst$/ ) {
    $fileFsm = shift;
    $namespaceFsm = shift;
    $objFsm = shift;
    $classFsm = shift;
    $variant = VRNT_VCST;
  }
  elsif( /^-tt$/ ) {
    $file = shift;
    print STDERR "\nInvestigate file $file\n";
    open( FILE, "$file" ) || die "can not open file $file";
  }
  elsif( /^-cpp$/ ) {
    $template = shift;
    print STDERR "\nCreating class $template\n";
	  $variant = VRNT_CPP;
  }
  elsif( /^-c$/ ) {
    $template = shift;
    print STDERR "\nCreating FSM $template\n";
	  $variant = VRNT_C;
  }
  elsif( /^-base$/ ) {
    print STDERR "\nUsing base class/functions\n";
    $base = 1;
  }
  elsif( /^-sw$/ ) {
    print STDERR "\nDo state actions in runSt switch\n";
    $sm = 0;
  }
  elsif( /^-nee$/ ) {
    $nee = 1;
    print STDERR "\nno entry exit\n";
  }
  elsif( /^-extt$/ ) {
    $extt = 1;
    print STDERR "\nExpanding transition table\n";
  }
  elsif( /^-test/ ) {
    $tmp =<<TEST_PATTERN;
FSM_TT(tState, tEvent)
  FSM_TT_BEG( State1, State2, eEvntStart,    mData==1, TRACE("\\n  ", "Goto state 2\\n") )
  FSM_TT_CNT(         State1, eEvntStart,    mData==0, TRACE("\\n  ", "Self Transition to state 1\\n"); mData=1  )
  FSM_TT_CNT(         State3, eEvntContinue, mData==1, TRACE("\\n  ", "Goto state 3\\n"); ++mData  )
  FSM_TT_BEG( State2, State3, eEvntStart,    true, TRACE("\\n  ", "Goto state 3 \\n") )
  FSM_TT_BEG( State3, State1, eEvntContinue, true,  )
FSM_TT_END
FSM_TT_INIT( State1, mData = 0 )

// <FSM_ST><entry> State1
mData2=0; 
// </FSM_ST>

// <FSM_ST><do> State1
mData2++;
// </FSM_ST>

// <FSM_ST><exit> State1
mData2++;
// </FSM_ST>

// <FSM_ST><entry> State2
// entry action
// </FSM_ST>

// <FSM_ST><do> State2
// do action
// </FSM_ST>

// <FSM_ST><exit> State3
// exit action
// </FSM_ST>

// <FSM_ST><attr> 
int mData;
int mData2;
// </FSM_ST>

TEST_PATTERN
  print $tmp;
  exit;
  }
} 

if( ( ($base == 1) && ($variant == VRNT_C) ) 
    && ($nee == 1) ) {
	die "\nNot a valid argument combination!";
}

#--- the search patterns of the transition table
$pattern{codeFsm} = 'FSM_TT';
$pattern{codeTt} = 'FSM_TT';
$pattern{codeTtInit} = 'FSM_TT_INIT';
$pattern{codeTtBeg} = 'FSM_TT_BEG';
$pattern{codeTtCnt} = 'FSM_TT_CNT';
$pattern{codeTtEnd} = 'FSM_TT_END';
$pattern{codeTtSs} = 'FSM_TT_SS';

$pattern{arg1} = '\s*\(\s*(.+?)\s*\)';
$pattern{arg1Or2} = '\s*\(\s*(.+?)\s*(?:,\s*(.+?)\s*)?\)';
$pattern{arg2} = '\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)';
$pattern{arg2Or3} = '\s*\(\s*(.+?)\s*,\s*(.+?)\s*(?:,\s*(.+?)\s*)?\)';
$pattern{arg3} = '\s*\(\s*(.+?)\s*,\s*(.+?)\s*\,\s*(.+?)\s*\)';
$pattern{arg4} = '\s*\(\s*(.+?)\s*,\s*(.+?)\s*,\s*(.+?)\s*,\s*(.*?)\s*\)';
$pattern{arg5} = '\s*\(\s*(.+?)\s*,\s*(.+?)\s*,\s*(.+?)\s*,\s*(.+?)\s*,\s*(.*?)\s*\)';

$pattern{fsmMark} = '\s*'  .$pattern{codeFsm};
$pattern{ttMark}  = '^\s*' .$pattern{codeTt}    .'\s*\(';
if( ($tTemplate == VRNT_CPP) && ($base == 1) ) {
  $pattern{tt}      = '^\s*' .$pattern{codeTt}    .$pattern{arg2or3} .'[\s;]*$';
}
else {
  $pattern{tt}      = '^\s*' .$pattern{codeTt}    .$pattern{arg2} .'[\s;]*$';
}
$pattern{ttBeg}   = '^\s*' .$pattern{codeTtBeg} .$pattern{arg5} .'[\s;]*$';
$pattern{ttCnt}   = '^\s*' .$pattern{codeTtCnt} .$pattern{arg4} .'[\s;]*$';
$pattern{ttInit}  = '^[\s/#]*' .$pattern{codeTtInit} .$pattern{arg1Or2};
$pattern{ttSs}  = '^\s*(?:else)*\s*' .$pattern{codeTtSs} .$pattern{arg4} .'[\s;]*$';

$pattern{fsmStStart} = '\s*//\s*<\s*FSM_ST>';
$pattern{fsmStEnd}   = '\s*//\s*<\s*/FSM_ST>';
$pattern{fsmStEntry} = $pattern{fsmStStart} . '\s*<\s*entry>\s*(\S+?)<CR>';
$pattern{fsmStDo}    = $pattern{fsmStStart} . '\s*<\s*do>\s*(\S+?)<CR>';
$pattern{fsmStExit}  = $pattern{fsmStStart} . '\s*<\s*exit>\s*(\S+?)<CR>';

$pattern{fsmTtAttrStart} = $pattern{fsmStStart} .'\s*<\s*attr>\s*';


#---- helper --------------------------------------------------------------------
sub printHashKeys
# print the key of the given hash reference
{
  my $ref = $_[0];
  foreach (sort keys %{$ref}) {
    print STDERR "\nkey=$_";
  }
  print "\n";
}

sub printArray
# print the key of the given hash reference
{
  my $ref = $_[0];
  foreach (@{$ref}) {
    print STDERR "\n$_";
  }
  print "\n";
}

sub delDouble
# delete double entries in given array
{ 
  my %all;
  grep {$all{$_}=0} @_;
  return (keys %all);
}

sub loadTransitionTable
# load the transition table data and return as an array.
{
  my $tmp = "";
  while( $_ = <FILE> ) {
    chomp; 
    if( /$pattern{ttInit}/) {
      #print STDERR "\n### ttInit $_";
      push @table, ( $_ );    
      $_=$1;
      $replaceInitAction = "$2;";
      s/\s+//g;
      $replaceInitState = $_;
    }
    #--- attributes  marked as a comment
    elsif( /$pattern{fsmTtAttrStart}/ ) {
      die '\nPrevious entry,do,exit or attr pattern is missing ' .$pattern{fsmStEnd}  if( 1 == $plantUml{flag});
      $plantUml{data} = "";
      $plantUml{flag} = 1;
      s/^\s/./;
      $plantUml{data} = "$_<CR>";
    }
    #--- entry, do, exit actions when marked as a comment
    elsif( /$pattern{fsmStStart}/ ) {
      die '\nPrevious entry,do,exit or attr pattern not finished' if( 1 == $plantUml{flag});
      $plantUml{data} = "";
      $plantUml{flag} = 1;
      s/^\s/./;
      $plantUml{data} = "$_<CR>";
    }
    elsif( /$pattern{fsmStEnd}/ ) {
      $plantUml{flag} = 0;
       push @table, ( $plantUml{data} );
    }
    elsif( 1 == $plantUml{flag} ) {
      s/^\s/./;
      $plantUml{data} .= "$_<CR>";
    }
    elsif( /$pattern{fsmMark}/ ) {
      if($variant == VRNT_C && /$pattern{ttMark}/ ) {
        # a c transition table differs from a c++ one, 
        # so we make a hack here to get a C template.
        $tState = "FSM_ST_T";
        $tEvent = "FSM_EV_T";
        $map{typeState} = $tState;
        $map{typeEvent} = $tEvent;
        $_ = $pattern{codeTt}."( $template )";
      }
      push @table, ( $_ );    
    }
    
  } # end while
  return @table;
}

sub formatTtArgs
# beautify the transition table by aligning the commas
{
  my @sz = (0,0,0,0);
  my @args, @tbl;
  my $tmp, $i, $j;
  my $pattern1 = '\s*' .$pattern{codeTtBeg} .'\s*\(\s*(.+)';
  my $pattern2 = '\s*' .$pattern{codeTtCnt} .'\s*\(\s*(.+)';

  # calculate max string sizes of each argument
  foreach (@table) {
    $j=-1;
    if( /$pattern1/ ) {
      $j = 0;
    }
    elsif( /$pattern2/ ) {
      $j = 1;
    }
    if( $j >= 0 ) {
      @args = split ",", $1;
      for( $i=$j; $i<4; ++$i ) {
        $args[$i-$j] =~ s/^\s*//;
        $tmp = length $args[$i-$j];
        # max string size
        $sz[$i] = $tmp>$sz[$i] ? $tmp : $sz[$i];
      }
    }
  }
  # reformat table
  foreach (@table) {
    $j = -1;
    if( /$pattern1/ ) {
      $tmp = "FSM_TT_BEG( ";
      $j = 0;
    }
    elsif( /$pattern2/ ) {
      $tmp = "FSM_TT_CNT( ";
      $j = 1;
    }
    else {#if( /"\s*$pattern{codeFsm}"/ ) {
      push @tbl, ($_);
    }
    if( $j >= 0 ) {
      @args = split ",", $1;
      for( $i=0; $i<4-$j; ++$i ) {
        $args[$i] =~ s/^\s*//;
        if( $i==0 && $j==1 ) {
          $tmp .= " "x$sz[0] ."  ";
        }        
        $tmp .= $args[$i]. " "x($sz[$i+$j]-length($args[$i])). ", ";
      }
      $j = 4-$j;
      foreach $i (@args[$j..$#args]) {
        $tmp .= "$i,";
      }
      # remove last ,
      $tmp =~ s/,$//;
      push @tbl, $tmp;
    }
  }
  return @tbl;
}

$parsePatternsLastState ="";
sub parsePatterns
# parses $_ and returns 
# pattern number
# current state, next state, signal, guard, action
# for nr == TT, tState and tEvent
{
  my ($nr, $cst, $nst, $sig, $grd, $act, $tState, $tEvent) = (-1);
  $_ = $_[0];
  
  if( /$pattern{tt}/ ) {
    $nr = TT;
    $tState = $1;
    $tEvent = $2;
  }
  elsif( /$pattern{ttBeg}/ ) {
    $nr = TTBEG;
    $cst = $1;
    $nst = $2;
    $sig = $3;
    $grd = $4;
    $act = $5;
    $parsePatternsLastState = $cst;
  }
  elsif( /$pattern{ttCnt}/ ) {
    $nr = TTCNT;
    $nst = $1;
    $sig = $2;
    $grd = $3;
    $act = $4;
    $cst = $parsePatternsLastState;
  }
  elsif( /$pattern{ttSs}/ ) {
    $nr = TTSS;
    $nst = $1;
    $sig = $2;
    $grd = $3;
    $act = $4;
    $cst = "STATE_NONE";
  }
  elsif( /$pattern{codeTtEnd}/ ) {
    $nr = TTEND;
  }
  elsif( /$pattern{ttInit}/ ) {
    $nr = TTINIT;
    $cst = $1;
    $act = $2;
    $cst =~ s/\s+//g;
  }
  elsif( /$pattern{fsmTtAttrStart}/ ) {
    $nr = ATTR;
    $act = $1;
    #remove pattern at beginning
    $act = substr $_, 4+index $_, '<CR>';    
  }
  elsif( /$pattern{fsmStEntry}/ ) {
    $nr = STENTRY;
    $cst = $1;
    #remove pattern at beginning
    $act = substr $_, 4+index $_, '<CR>';    
  }
  elsif( /$pattern{fsmStDo}/ ) {
    $nr = STDO;
    $cst = $1;
    #remove pattern at beginning
    $act = substr $_, 4+index $_, '<CR>';    
  }
  elsif( /$pattern{fsmStExit}/ ) {
    $nr = STEXIT;
    $cst = $1;
    #remove pattern at beginning
    $act = substr $_, 4+index $_, '<CR>';    
  }
  elsif( /$pattern{ttMark}/ ) {
    $nr = TTMARK;
  }
  return ($nr, $cst, $nst, $sig, $grd, $act, $tState, $tEvent);
}

sub createAttrStr
# create the attribute markers
{
  my $tmp, $i;
  $tmp = "\n  // <FSM_ST><attr><CR>";
  #foreach $i (@fsm_attr) {
    $tmp .= "@fsm_attr";
  #}
  $tmp =~ s/<CR>/\n  /smg; 
  $tmp .= "// </FSM_ST>";
  return $tmp;
}

#-------------------------------------------------------------------------------
sub replaceCodeDependent
# replace tokens in generated code parts given in $_
# codes are:
# #FSM_TT#
# #class#
# #event#
# #state#
# #doTrnstn#
# #defDoTrnstn#
# #defRunSt#
# #runSt#
# #defStateArg#
# #callStateArg#
# #super#
# #entry#
# #exit#
# #bDoTransition#
# #consumeEvt#
# #DEF_ST_TO_MTHD_BEG#
# #fsmAttr#
{
  if( $variant == VRNT_CPP ) {
    # CPP code
    $tmp=<<ENDTXT;
#define FSM_TT(st,ev) \\
#defDoTrnstn# \\
{ \\
    st ret = #state#;\\
    switch( #state# )\\
    {\\
    default:
ENDTXT
    s/#FSM_TT#/$tmp/g;
  
    s/#class#/$replaceClassName\:\:/g;
    s/#event#/mEvent/g;
    s/#state#/mState/g;
    s/#doTrnstn#/doTrntn/g;
    s/#defDoTrnstn#/void $replaceClassName\:\:doTrnstn\( bool doAction \)/g;
    s/#defRunSt#/$replaceClassName\:\:runSt\(void\)/g;
    s/#runSt#/runSt/g;
    s/#defStateArg#/void/g;
    s/#callStateArg#//g;
    s/#super#/doSuperstate/g;
    s/#entry#/isEntry\(\)/g;
    s/#exit#/isExit\(\)/g;
    s/#bDoTransition#/bDoTransition/g;
    s/#consumeEvt#/consumeEvt\(\)/g;
    s/#DEF_ST_TO_MTHD_BEG#/DEF_ST_TO_MTHD_BEG($replaceStateType)/g;
    $tmp = createAttrStr;
    s/#fsmAttr#/$tmp/g;

  }
  else {
    # C code
    $tmp=<<ENDTXT;
#define FSM_TT(pr) \\
#defDoTrnstn# \\
{ \\
    FSM_ST_T ret = #state#;\\
    switch( #state# )\\
    {\\
    default:
ENDTXT

    $tmp2 = $replaceClassName . "_runSt";
    s/#FSM_TT#/$tmp/g;
    s/#class#//g;
    s/#event#/fsm->mEvent/g;
    s/#state#/fsm->mState/g;
    s/#doTrnstn#/doTrntn_$replaceClassName/g;
    s/#defDoTrnstn#/FSM_ST_T doTrnstn_$replaceClassName\( tFsmc* fsm, bool doAction \)/g;
    s/#defRunSt#/$tmp2\(FSM_ST_T el, tFsmc* fsm\)/g;
    s/#runSt#/$tmp2/g;
    s/#defStateArg#/tFsmc* fsm/g;
    s/#callStateArg#/fsm/g;
    s/#super#/doSuperstate_$replaceClassName/g;
    s/#entry#/isEntryFsmc\(fsm\)/g;
    s/#exit#/isExitFsmc\(fsm\)/g;
    s/#bDoTransition#/fsm->bDoTransition/g;
    s/#consumeEvt#/consumeEvt\(fsm\)/g;
    s/#DEF_ST_TO_MTHD_BEG#/DEF_ST_TO_MTHD_BEG($replaceClassName, fsm)/g;
    $tmp = createAttrStr;
    s/#fsmAttr#/$tmp/g;
 }
 print;
}

sub getStatesAndEvents
# extract states and events from the transition table
# out @states              , contains the states defined in the transition table
# out @superstates         , contains for the superstates: next state, event, guard, action
# out @events              , contains the events defined in the transition table
# out @{$map{table}}       , contains current state, next state, signal, guard for each transition
# out @{$fsm_entry{$state}}, contains the entry actions of a state
# out @{$fsm_do   {$state}}, contains the do  actions of a state
# out @{$fsm_exit {$state}}, contains the exit actions of a state
# out @fsm_attr            , contains the class attributes
# out $map{typeState}      , contains the state type defined in the transition table
# out $map{typeEvent}      , contains the event type defined in the transition table
# out $replaceStateType
# out $replaceEventType
{
  @table = loadTransitionTable;
  foreach( @table ) {
    # state, state, event, guard, action
    ($nr, $cst, $nst, $sig, $grd, $act, $tState, $tEvent) = parsePatterns( $_ );

    if( $nr == TTBEG ) {
      $lastState = $cst;
      push @{$map{table}},( cst => $cst, nst => $nst, sig => $sig, guard => $grd);
      push @states, ($lastState) if( $lastState ne "STATE_NONE"); 
      push @superstates, ($nst, $sig, $grd, $act) if( $lastState eq "STATE_NONE"); 
      push @states, ($nst) if( $nst ne "STATE_NONE"); 
      push @events, ($sig) if( $sig ne "EVENT_NONE");
    }
    elsif( $nr == TTCNT ) {
      push @{$map{table}},( cst => $lastState, nst => $nst, sig => $sig, guard => $grd);
      push @states, ($nst) if( $nst ne "STATE_NONE" );
      push @events, ($sig) if( $sig ne "EVENT_NONE" );
    }
    elsif( $nr == TTSS ) {
      #dump
      push @{$map{table}},( nst => $nst, sig => $sig, guard => $grd);
      push @states, ($nst) if( $nst ne "STATE_NONE" );
      push @events, ($sig) if( $sig ne "EVENT_NONE" );
    }
    elsif( $nr == TT ) {
      $map{typeState} = $tState;
      $map{typeEvent} = $tEvent;
    }
    elsif( $nr == STENTRY ) {
      push @{$fsm_entry{$cst}}, ($act);
    }
    elsif( $nr == STDO ) {
      push @{$fsm_do{$cst}}, ($act);
    }
    elsif( $nr == STEXIT ) {
      push @{$fsm_exit{$cst}}, ($act);
    }
    elsif( $nr == ATTR ) {
      push @fsm_attr, ($act);
    }
    elsif( /DEF_STATE_NR\s*\((.+?)\)/) {
      @trn = split ',',$1;
      shift @trn;
      foreach (@trn) {
        s/\s+//g;
        $fsm{$_}=[];
      }
      #printHashKeys(\%fsm);
    }
  } # end while  
  @states = sort( delDouble( @states ) );
  @events = sort( delDouble( @events ) );
  # test if the init state exists at all
  $tmp = $replaceInitState;
  $replaceInitState = "";
  if( $tmp ne "" ) {
    foreach (@states) {
      if( $_ eq $tmp ) {
        $replaceInitState = $tmp;
        last;
      }
    }
  }
  $replaceStateType = $map{typeState};
  $replaceEventType = $map{typeEvent};
  
  #dump %map;
}

sub replaceTemplateCodeWords
# replace the template code words with the generated code parts
# codes are:
#replaceStateTrace
#replaceEventTrace
#replaceStates
#replaceEvents
#replaceEventsWith
#replaceStateType
#replaceEventType
#replaceTransitionTable
#replaceMethodDeclarations
#replaceMethodDefinitions
#replaceState2MethodTable
#replaceTableMacros
#replaceClassName
#replaceMax
#replaceInitAction
#replaceInitState
#replaceSuperstateTable
{
  s/replaceStateTrace/$replaceStateTrace/smg;
  s/replaceEventTrace/$replaceEventTrace/smg;
  s/replaceStatesWith/$replaceStatesWith/smg;    
  s/replaceStates/$replaceStates/smg;
  s/replaceEventsWith/$replaceEventsWith/smg;    
  s/replaceEvents/$replaceEvents/smg;  
  s/replaceStateType/$replaceStateType/smg;
  s/replaceEventType/$replaceEventType/smg;
  s/replaceTransitionTable/$replaceTransitionTable/smg;
  s/replaceMethodDeclarations/$replaceMethodDeclarations/smg;
  s/replaceMethodDefinitions/$replaceMethodDefinitions/smg;
  s/replaceSuperstateTable/$replaceSuperstateTable/smg;
  s/replaceState2MethodTable/$replaceState2MethodTable/smg;
  s/replaceTableMacros/$replaceTableMacros/smg;
  s/replaceClassName/$replaceClassName/smg;
  $tmp = $#events+2;
  s/replaceMax/$tmp/smg;
  if( $replaceInitState ne "" ) {
    s/replaceInitState/$replaceInitState/smg;
	s/replaceInitAction/$replaceInitAction/smg;
  } else {
    s/replaceInitState/$replaceStateType(0)/smg;
  }
}

#---- specific to PlantUML output ----------------------------------------------
sub formatWithPrefix
# divide the string in chunks of length with prefix and a hanging
# Parameter 1: prefix
# Parameter 2: the string
# Parameter 3: is the hang after prefix from second line onwards
# Parameter 4: max length of the returned string line
{
  my ($prefix,$str,$hang, $len) = (@_);
  my $szPrefix = length($prefix);
  my $sz = $len - $szPrefix;
  my $i = 0;
  my $dst = "";
  my $tmp;

  # if we have a marker <CR> replace by a line feed
  @lines = split '<CR>', $str;
  foreach $str (@lines) 
  {
    $i = 0;
    $dst .= "$prefix" . substr($str,0, $sz);
    $i += $sz;
    $sz -= length($hang);
    for( ; $i < length($str); $i += $sz ) {
      $tmp = substr($str,$i, $sz);
      if( $tmp =~ /^\s*==/ ) {
        $tmp =~ s/^\s*==//;
        $dst .=  '==';
      }
      $dst .= "$prefix$hang$tmp";
    }
  }
  return $dst;
}

sub createUmlOutput
# prints a PlantUml output to stdio
{
  $fsm = ();
  my ($lastState, $start);
  my @trn;
  $start="";
  @table = loadTransitionTable;

#  while( $_ = <FILE> ) {
  #dump @table;
  foreach $_ (@table) {
    ($nr, $cst, $nst, $sig, $grd, $act, $tState, $tEvent) = parsePatterns( $_ );
    if( ($nr == TTBEG) || ($nr == TTCNT) ) {
      $lastState = $cst if( $nr == TTBEG );
      push @{$fsm{$lastState}}, ($nst, $sig, $grd );    
      # replace " by ' since plantUML makes problems with "
      $act =~ s/"/'/g;
      # replace \ by \\
      $act =~ s/\\/\\\\/g;
      push @{$fsm{$lastState}}, ( $act );    
    }
    elsif( $nr == TTSS ) {
      push @{$fsm{$cst}}, ($nst, $sig, $grd );    
      # replace " by ' since plantUML makes problems with "
      $act =~ s/"/'/g;
      # replace \ by \\
      $act =~ s/\\/\\\\/g;
      push @{$fsm{$cst}}, ( "$act" );    
    }
    elsif( $nr == STENTRY  ) {
      push @{$fsm_ede{$cst}}, ( formatWithPrefix "\n    $cst : ", "<b>entry</b>:<CR>$act", "", 80 );
    }
    elsif( $nr == STDO  ) {
      push @{$fsm_ede{$cst}}, ( formatWithPrefix "\n    $cst : ", "<b>do</b>:<CR>$act", "", 80 );
    }
    elsif( $nr == STEXIT  ) {
      push @{$fsm_ede{$cst}}, ( formatWithPrefix "\n    $cst : ", "<b>exit</b>:<CR>$act", "", 80 );
    }
    elsif( /DEF_STATE_NR\s*\((.+?)\)/) {
      @trn = split ',',$1;
      shift @trn;
      foreach (@trn) {
        s/\s+//g;
        $fsm{$_}=[];
      }
      #printHashKeys(\%fsm);
    }
    elsif( /$pattern{ttInit}/) {
      $_=$1;
      s/\s+//g;
      if( defined $fsm{$_} ) {
        $start = $_;
        $replaceInitState = $start;
      }
    }
  } # end while
  
$uml_str =<<ENDTXT;
  \@startuml
  skinparam state {
    BackgroundColor<<Warning>> Red
  }

  [*] --> Fsm
  state Fsm { 
ENDTXT

  print $uml_str;

  if( $start ne "" ) {
    print "\n  [*] -> $start";
  }

  my $addWarningNote = 0;
  # for every state
  foreach $ky (keys %fsm) { 
    my $j = 0;
    my $tmp;
    my $out;
	   
    $out = "";    
    # for every transition
    while($j < $#{$fsm{$ky}} ) {
      if( ($ky eq "STATE_NONE") ) {
        $out = "\n  Fsm --> " .$fsm{$ky}[$j++];
      }
      else {
        $out = "\n  $ky --> " .$fsm{$ky}[$j++];
      }
      $tmp = $fsm{$ky}[$j++]; # event
      if( $tmp !~ /^\s*EVENT_NONE\s*$/ ) { # no event
        $out .= " : $tmp";
      }
      $tmp = $fsm{$ky}[$j++]; # guard
      if( $tmp !~ /^\s*true\s*$/ ) { #guard only true
        $out .= " : " if( $out !~ /:/ );
        $out .= "\\n[$tmp]";
      }
      $tmp = $fsm{$ky}[$j++]; # action
      if( $tmp !~ /^\s*$/ ) { # no action
        $out .= " : " if( $out !~ /:/ );
        $out .= formatWithPrefix "\\n", "/$tmp", "", 60;
      }
      if( $out =~ /^\s*(\S+)\s*-->\s*(\S+)\s*$/ ) {
        if( $1 eq $2 ) {
          $out .= " <<warning>>";
          $addWarningNote = 1;
        }
      }
      print $out;
    }
  }
  foreach $ky (keys %fsm) { 
    my $out;
	   
    $out = "";
    foreach $ede (@{$fsm_ede{$ky}}) {
      $out .= "$ede";
    }
    print $out;
  }
  print "\n  Note \"Red states probably \\nhave an endless loop.\" as N1" if( $addWarningNote );
  print "\n}\n\@enduml";
}
#---- Vectorcast test script generation ---------------------------------------
sub getVcastTemplate
{
  my ($item) = @_;
  if( $item eq "initState" ) {
  }
  elsif( $item eq "dispatchEvent" ) {
  }
  elsif( $item eq "transition" ) {
  }
}

#-------------------------------------------------------------------------------
#  specific to the Vectorcast tests for the stand alone C++ state machine 
sub getVcastTemplateInitInstance
# <stateFsm>
# <objFsm> "obj.Class.obj.Class..."
# <namespaceFsm> Bt::
# <classFsm>
{
  $_=<<END_VCAST_TEMPLATE1;
-- Script Features
TEST.SCRIPT_FEATURE:C_DIRECT_ARRAY_INDEXING
TEST.SCRIPT_FEATURE:CPP_CLASS_OBJECT_REVISION
TEST.SCRIPT_FEATURE:MULTIPLE_UUT_SUPPORT
TEST.SCRIPT_FEATURE:MIXED_CASE_NAMES
TEST.SCRIPT_FEATURE:STANDARD_SPACING_R2
TEST.SCRIPT_FEATURE:OVERLOADED_CONST_SUPPORT
TEST.SCRIPT_FEATURE:UNDERSCORE_NULLPTR
TEST.SCRIPT_FEATURE:FULL_PARAMETER_TYPES

TEST.SUBPROGRAM:<<INIT>>
TEST.NEW
TEST.NAME:<<INIT>>.INSTANCE
TEST.COMPOUND_ONLY
TEST.NOTES:
Description:
- Set instance of the FSM
!!! TODO: this function you need to modify  
    VECTORCAST needs for many parts the form object.class 
    but for this part you need to remove the .class part in the user code.
TEST.END_NOTES:
TEST.VALUE_USER_CODE:<<<namespaceFsm><classFsm> instance>>
<<<namespaceFsm><classFsm> instance>> = ( &<namespaceFsm><objFsm> );
TEST.END_VALUE_USER_CODE:
TEST.END

END_VCAST_TEMPLATE1
}

sub getVcastTemplateInitState
# <stateFsm>
# <objFsm> "obj.Class.obj.Class..."
# <namespaceFsm> Bt::
# <fileFsm> filename
# <classFsm>
# <eventFsm>
# <fromStateToStateFsm>
#TEST.UNIT:<fileFsm>
#TEST.SUBPROGRAM:(cl)<namespaceFsm><classFsm>::init
{
  $_=<<END_VCAST_TEMPLATE1;
TEST.SUBPROGRAM:<<INIT>>
TEST.NEW
TEST.NAME:<<INIT>>.<stateFsm>
TEST.COMPOUND_ONLY
TEST.NOTES:
Description:
- Set state of <objFsm>:<stateFsm>
TEST.END_NOTES:
TEST.VALUE:<fileFsm>.<<GLOBAL>>.<namespaceFsm><objFsm>.<namespaceFsm><classFsm>.mState:<stateFsm>
TEST.EXPECTED:<fileFsm>.<<GLOBAL>>.<namespaceFsm><objFsm>.<namespaceFsm><classFsm>.mState:<stateFsm>
TEST.END

END_VCAST_TEMPLATE1
}

sub getVcastTemplateDispatch
# <stateFsm>
# <objFsm> gCnctMngr
# <namespaceFsm> Bt::
# <fileFsm> 
# <classFsm>
# <eventFsm>
# <fromStateToStateFsm>
{
  $_=<<END_VCAST_TEMPLATE2;
-- Subprogram: (cl)<namespaceFsm><classFsm>::dispatch
 
-- Test Case: (cl)<namespaceFsm><classFsm>::dispatch.<eventFsm>
TEST.UNIT:<fileFsm>
TEST.SUBPROGRAM:(cl)<namespaceFsm><classFsm>::dispatch
TEST.NEW
TEST.NAME:(cl)<namespaceFsm><classFsm>::dispatch.<eventFsm>
TEST.COMPOUND_ONLY
TEST.NOTES:
Description:
- Calls the state machine for the event <eventFsm>.
TEST.END_NOTES:
TEST.STUB:<fileFsm>.(cl)<namespaceFsm><classFsm>::doSuperstate
TEST.VALUE:<fileFsm>.(cl)<namespaceFsm><classFsm>::dispatch.evnt:<eventFsm>
TEST.END
END_VCAST_TEMPLATE2
}

sub getVcastTemplatePeek
# <stateFsm>
# <objFsm> 
# <namespaceFsm> Bt::
# <fileFsm> 
# <classFsm>
# <eventFsm>
# <fromStateToStateFsm>
{
  $_=<<END_VCAST_TEMPLATE3;
-- Subprogram: (cl)<namespaceFsm><classFsm>::peekEntry
 
-- Test Case: (cl)<namespaceFsm><classFsm>::peekEntry.is<stateFsm>
TEST.UNIT:<fileFsm>
TEST.SUBPROGRAM:(cl)<namespaceFsm><classFsm>::peekEntry
TEST.NEW
TEST.NAME:(cl)<namespaceFsm><classFsm>::peekEntry.is<stateFsm>
TEST.COMPOUND_ONLY
TEST.NOTES:
Description:
- Test that the state is <stateFsm>
TEST.END_NOTES:
TEST.EXPECTED:<fileFsm>.<<GLOBAL>>.<namespaceFsm><objFsm>.<namespaceFsm><classFsm>.mState:<stateFsm>
TEST.END
END_VCAST_TEMPLATE3
}

sub getVcastTemplateCompound
# <stateFsm>
# <objFsm> 
# <namespaceFsm> Bt::
# <fileFsm> 
# <classFsm>
# <eventFsm>
# <fromStateToStateFsm>
{
  $_=<<END_VCAST_TEMPLATE4;
-- COMPOUND TESTS
 
TEST.SUBPROGRAM:<<COMPOUND>>
TEST.NEW
TEST.NAME:<<COMPOUND>>.<fromStateToStateFsm>
TEST.NOTES:
Description:
- Test the state machine. For test steps see the specific subtest.
- TODO set guards and compare actions!
TEST.END_NOTES:
TEST.SLOT: "1", "<<INIT>>", "<<INIT>>", "1", "<<INIT>>.INSTANCE"
TEST.SLOT: "2", "<<INIT>>", "<<INIT>>", "1", "<<INIT>>.<stateFsm>"
TEST.SLOT: "3", "<fileFsm>", "(cl)<namespaceFsm><classFsm>::dispatch", "1", "(cl)<namespaceFsm><classFsm>::dispatch.<eventFsm>"
TEST.SLOT: "4", "<fileFsm>", "(cl)<namespaceFsm><classFsm>::peekEntry", "1", "(cl)<namespaceFsm><classFsm>::peekEntry.is<stateFsmTo>"
TEST.END
--
END_VCAST_TEMPLATE4
}

sub createVCastCppTestsPerState
# replaces the reserved words in the template with the 
# states, events and state handlers
{
  # out map{state} => method
  # out map{events} 
  # out state type, event type
  my $state, $event,$strOut,$clState;
  my $i = 0;
  
  getStatesAndEvents;
    
  $strOut = "";
  getVcastTemplateInitInstance
  s/<stateFsm>/$state/smg; 
  s/<objFsm>/$objFsm/smg;
  s/<namespaceFsm>/$namespaceFsm/smg;
  s/<fileFsm>/$fileFsm/smg;
  s/<classFsm>/$classFsm/smg;
  $strOut .= $_;
  
  foreach (@states) {
    ++$i;
    $state = $_;
    $clState = uc $state;
    #--- create compound init
    getVcastTemplateInitState;
    s/<ClStateFsm>/$clState/smg; 
    s/<stateFsm>/$state/smg; 
    s/<objFsm>/$objFsm/smg;
    s/<namespaceFsm>/$namespaceFsm/smg;
    s/<fileFsm>/$fileFsm/smg;
    s/<classFsm>/$classFsm/smg;
    s/(TEST.NAME:.*?\n)/uc($1)/esmg;

#    s/mState:$state/mState:$i/smg;
    $strOut .= $_;

    getVcastTemplatePeek;
    s/<ClStateFsm>/$clState/smg; 
    s/<stateFsm>/$state/smg;    
    s/<objFsm>/$objFsm/smg;
    s/<namespaceFsm>/$namespaceFsm/smg;
    s/<fileFsm>/$fileFsm/smg;
    s/<classFsm>/$classFsm/smg;
    s/(TEST.NAME:.*?\n)/uc($1)/esmg;

#    s/mState:$state/mState:$i/smg;
    $strOut .= $_;
  }
  push @events , ( EVENT_NONE );
  foreach (sort(@events)) {
    $event = $_;
    #--- create compound dispatch event call test
    getVcastTemplateDispatch;
    s/<eventFsm>/$event/smg;    
    s/<objFsm>/$objFsm/smg;
    s/<namespaceFsm>/$namespaceFsm/smg;
    s/<fileFsm>/$fileFsm/smg;
    s/<classFsm>/$classFsm/smg;
    s/(TEST.NAME:.*?\n)/uc($1)/esmg;
    if( $event =~ /EVENT_NONE/ ) {
      s/(TEST\.VALUE:.*?)\:EVENT_NONE\n/"$1:0\n"/esmg;
    }
    $strOut .= $_;
  }

 
  # for each state transition
  # create a transition compound test
  @table = loadTransitionTable;
  my ($l1t,$ost);
  foreach( @table ) {
    # state, state, event, guard, action
    ($nr, $cst, $nst, $sig, $grd, $act, $tState, $tEvent) = parsePatterns( $_ );
    if( $nr == TTBEG ) {
      getVcastTemplateCompound;
      # set init to current state
      # !todo set guard 
      # call dispatch with event
      # check that action has been done
      # check that new state is next state
      s/<objFsm>/$objFsm/smg;
      s/<namespaceFsm>/$namespaceFsm/smg;
      s/<fileFsm>/$fileFsm/smg;
      s/<classFsm>/$classFsm/smg;
      
      $l1t = uc($cst . "_To_" . $nst);      
      $ost = $cst;
      s/<fromStateToStateFsm>/$l1t/smg;
      s/<stateFsm>/$cst/smg;    
      s/<stateFsmTo>/$nst/smg;    
      s/<eventFsm>/$sig/smg;
      s/(\", \"1\", \".*?\n)/uc($1)/esmg;
      $strOut .= $_;
      $lastState = $cst;
    }  
    elsif( $nr == TTCNT ) {
      getVcastTemplateCompound;
      # set init to current state
      # !todo set guard 
      # call dispatch with event
      # check that action has been done
      # check that new state is next state
      s/<objFsm>/$objFsm/smg;
      s/<namespaceFsm>/$namespaceFsm/smg;
      s/<fileFsm>/$fileFsm/smg;
      s/<classFsm>/$classFsm/smg;
      
      $l1t = uc($lastState . "_To_" . $nst);      
      s/<fromStateToStateFsm>/$l1t/smg;
      s/<stateFsm>/$lastState/smg;    
      s/<stateFsmTo>/$nst/smg;    
      s/<eventFsm>/$sig/smg;
      s/(\", \"1\", \".*?\n)/uc($1)/esmg;
      $strOut .= $_;
    }  
  }
  print $strOut;
}
#------------------------------------------------------------------------------
sub getEntryDoExitPartStrs
# returns an array containing entry, do, exit string parts
# which are used for each state
{
  my @tmp;
  if( $nee == 1 ) {
   $tmp[0] = "";
  } 
  else {
		if( ($sm==1) || ($base == 1) ) {
#		if($sm==1 || $variant == VRNT_C) {
			$tmp[0] = "\n    if( #entry# ) {\n      TRACE_STATE_ENTRY;" ;
		}
		else {
			$tmp[0] = "\n    if( entry ) {\n      TRACE_STATE_ENTRY;";
		}
		$tmp[0] .= "\n      // do entry action\n";
		$tmp[1] =<<ENDUSAGE;
    }
    // do normal action
ENDUSAGE

    $tmp[2] =<<ENDUSAGE;
    if( #exit# ) {
      // do exit action
ENDUSAGE

    $tmp[3] =<<ENDUSAGE;
    }
ENDUSAGE
  }
  return @tmp;
}

sub addMarkForEntryDoExitPerState
# Returns the whole entry do exit code snipplet with marker
# Parameter 1: array reference to actions
# Parameter 2: The string part for the marker, e.g. <entry>, <do>, <exit>
# Parameter 3: The state string
# Parameter 4: The string prefix added from the 2nd line onwards
{
  my ($refAr, $strPart, $state, $hang) = (@_);
  my $ret;
  
  if( $$refAr ) { 
    if( $strPart =~ /</ ) { # we use <do|entry|exit>
      $ret = "$hang// <FSM_ST>$strPart $state\n";
      foreach $i (@{$$refAr}) {	
        $i =~ s/<CR>/\n/smg;
        $ret .= "$hang$i";
      }
      $ret .= "$hang// </FSM_ST>\n";
    }
    else { # we use a macro
      $ret .= "  FSM_ST_$strPart( $state, ";
      foreach $i (@{$$refAr}) {	
        $i =~ s/<CR>/\\\n/smg;
        $ret .= "$hang$i";
      }
      $ret .= "  );\n";
    }
  }
  return $ret;
}

sub getEntryDoExitStrPerState
# returns entry, do, exit string for a state
# Parameter 1: state string
# Parameter 2: entry, do, exit strings in array ref
# Parameter 3: The string prefix added from the 2nd line onwards
{
  my $i, $ret;
  my ($state, $edeRef, $hang) = (@_);

  #print STDERR "\n+++++$edeRef";
  $ret = "";
  return $ret if( $nee == 1 );
  $ret .= $$edeRef[0];
  # calculate the spaces to be added in front.
  $$edeRef[0] =~ /^(\s*)/;
  $hang = " " x length( $1 ) . " ";
  # insert FSM_TT_ENTRY parts
  $ret .= addMarkForEntryDoExitPerState \$fsm_entry{$state}, '<entry>', $state, $hang;
  $ret .= $$edeRef[1];
  $$edeRef[1] =~ /^(\s*)/;
  $hang = " " x length( $1 );
  # insert FSM_TT_DO parts
  $ret .= addMarkForEntryDoExitPerState \$fsm_do{$state}, '<do>', $state, $hang;
  $ret .= $$edeRef[2];
  $$edeRef[2] =~ /^(\s*)/;
  $hang = " " x length( $1 ) . "  ";
  # insert FSM_TT_EXIT parts
  $ret .= addMarkForEntryDoExitPerState \$fsm_exit{$state}, '<exit>', $state, $hang;
	$ret .= $$edeRef[3];
  return $ret;
}

#---- C++ code generation -----------------------------------------------------
sub getCodeTemplate
# copies the code template to $_
# Parameter 1: template type
{
  my $tTemplate = $_[0];
  #----------------------------------------------------------------------  
  if( ($tTemplate == VRNT_CPP) && ($base == 1)  ) {
  #----------------------------------------------------------------------
    $_=<<END_CODE_TEMPLATE;
/*----------------------------------------------------------------------
   This is auto generated code from a state transition table
   For more information please see
   http://block-net.de/Programmierung/cpp/fsm/fsm.html
----------------------------------------------------------------------*/   

/*------------------------------< Includes >----------------------------------*/

// for getting trace output on the screen
#define FSM_DEBUG
// The statemachine framework
#include "fsm.hpp"

/*------------------------------< Defines >-----------------------------------*/
// just some macros for debugging entry state
#define TRACE_STATE_ENTRY            TR_FILTER( TRACE("\\n  state=%s", strState(mState) ) )
#define TRACE_SUPERSTATE             TR_FILTER( TRACE("\\n  super state=%s", strState(mState) ) )

/*------------------------------< Macros >------------------------------------*/

/*------------------------------< Typedefs >----------------------------------*/
/**
* \\brief   available states
*
*/
typedef enum { 
  eStateVoid_replaceStateType=0, 
  replaceStates 
} replaceStateType;

/**
* \\brief   available events
*
*/
typedef enum { 
  eEventVoid_replaceEventType=0, 
  replaceEvents 
} replaceEventType;


/*------------------------------< Constants >---------------------------------*/

/*------------------------------< Variables >---------------------------------*/

/*------------------------------< Prototypes >--------------------------------*/
/*
    Generated FSM replaceClassName derived from Fsm.
*/
class replaceClassName : public Fsm<replaceStateType, replaceEventType>
{
public:
  replaceClassName( void ) { init(replaceInitState); replaceInitAction } // TODO: initialization

  // For each state a method is defined
  // In the state no transition is done.
replaceMethodDeclarations

  protected:

#ifndef FSM_STYLE_STFP  
     virtual void runSt(void);
#endif
  
  /*
     The state transition table.
     This defines   virtual void doTrnstn( bool doAction );
     To generate a plantUML file do execute on cmd line:
     perl fms2plantuml_pl -i inputFile > outputFile.uml
  */
replaceTransitionTable

#if (FSM_WITH_SUPERSTATE == true) 
    void doSuperstate (void);
#endif
  
  private: 
  // TODO: enter other parts as necessary
  #fsmAttr#
};

#if TRUE == FSM_DEBUG_replaceClassName
const char* strState(replaceStateType st);
const char* strEvent(replaceEventType ev);
#endif

//----------------------------------------------------------------------
// --- FSM definition
//----------------------------------------------------------------------
#ifndef FSM_STYLE_STFP  
  replaceState2MethodTable
#endif

#if (FSM_WITH_SUPERSTATE == true) 
void replaceClassName::doSuperstate (void)
{
  // TODO: Please fill when you have configured a superstate
  replaceSuperstateTable
}
#endif

//--- the worker classes for the states
replaceMethodDefinitions

//----------------------------------------------------------------------
#ifdef FSM_DEBUG
/**
* \\brief   Function returning the state name 
*
* \\param[in]     st the state as a number.
*
* \\api
*/
replaceStateTrace

/**
* \\brief   Function returning the event name 
*
* \\param[in]     ev the event as a number.
*
* \\api
*/
replaceEventTrace
#endif
//----------------------------------------------------------------------
#if 1
// An example function to get a sequence of events.
// With eEvntVoid the program will exit.
// TODO: enter an own event sequence to test your FSM
//       the given values are just an example 
replaceEventType getEvent(void)
{
  // TODO: adapt to your needs for a test
  static int i = 0;
  static replaceEventType event[] = { replaceEvents,eEventVoid_replaceEventType };
  
  if( event[i] == eEventVoid_replaceEventType ) {
    return eEventVoid_replaceEventType;
  }
  return event[i++];
}

// A typical call procedure of the Fsm
void replaceClassName_Test (void)
{
  replaceClassName fsm;
  // default event
  replaceEventType evnt = eEventVoid_replaceEventType;
  // when getEvent returns eEventVoid_replaceEventType the function replaceClassName_Test returns
  do   {
    evnt = getEvent();
    fsm.dispatch( evnt );  
  } while( evnt != eEventVoid_replaceEventType );
}
    
// A main for a simple FSM test
int main (void)
{
  replaceClassName_Test();
  return 0;
}
#endif

END_CODE_TEMPLATE
  }
  #======================================================================
  elsif( ($tTemplate == VRNT_CPP) && ($base == 0) ) {
  #======================================================================
    $_=<<END_CODE_TEMPLATE;
/*----------------------------------------------------------------------
   This is auto generated code from a state transition table
   For more information please see
   http://block-net.de/Programmierung/cpp/fsm/fsm.html
----------------------------------------------------------------------*/   

/*------------------------------< Includes >----------------------------------*/

/*------------------------------< Defines >-----------------------------------*/
/**
* \\brief   use this define, if you do not use an event or state in the transition table
*
*/
#define EVENT_NONE mEvent
#define STATE_NONE el

/*------------------------------< Typedefs >----------------------------------*/

/*------------------------------< Constants >---------------------------------*/

/*------------------------------< Variables >---------------------------------*/

/*------------------------------< Macros >------------------------------------*/

/*------------------------------< Prototypes >--------------------------------*/

/**
 * \\class The generated statemachine replaceClassName
 *
 * \\brief TODO description.
 *
 */
class replaceClassName
{
public:
  /**
  * \\brief   available states
  *
  */
  typedef enum { 
    eStateVoid=0, replaceStates  } replaceStateType;

  /**
  * \\brief   available events
  *
  */
  typedef enum { 
    eEventVoid=0, replaceEvents  } replaceEventType;

  replaceClassName( void ); 

  void init( replaceStateType StStart );

  /**
  * \\brief   Test if we are in entry condition of a state.
  *
  * \\return         true if isEntry will return true.
  *
  * \\api
  */  
  bool peekEntry(void) const { return bDoTransition; }

  bool isEntry(void);

  // sets the next state and checks if in exit condition
  bool isExit(void);
  
  // set the event and run the state machine until the event is consumed
  //  and the possible transitions are made.
  void dispatch (replaceEventType evnt);

  /**
  * \\brief   getter for the current event.
  *
  * \\return         The current handle event value.
  *
  * \\api
  */  
  replaceEventType getEvent(void) const { return mEvent; }

  /**
  * \\brief   getter if a call of dispatch had made at least one transition.
  *
  * \\return         true when the event has been consumed.
  *
  * \\api
  */  
  bool isEvtConsumed(void) const { return bEvtConsumed; }

  /**
  * \\brief   if in a state an event is consumed, we have to
  *           inform the base class about it with this method.
  *
  * \\nonapi
  */  
  void consumeEvt(void) { bEvtConsumed = true; }
  // executes the state
  void runSt( void );
  // tests or executes a transition
  void doTrnstn( bool doAction );
  /**
  * \\brief   Adds an event to the FSM, processed after the current event
  *
  * \\param[in]     event  The event to be injected to the FSM.
  *
  * \\nonapi
  */  
  void addEvent(replaceEventType event) { mEventNew = event; }
  
  // called when an event does not lead to a transition
  void doSuperstate (void);

replaceMethodDeclarations

private: 
  /**
  * \\brief   variable for storing if an event has been consumed
  */  
  bool bEvtConsumed;
  /**
  * \\brief   variable for storing if a transition shall be executed
  */  
  bool bDoTransition;
  /**
  * \\brief   variable for storing if superstate has to be processed
  */  
  bool bDoSuperstate;
  /**
  * \\brief   variable for storing the current event
  */  
  replaceEventType mEvent;
  /**
  * \\brief   variable for storing the new event injected from the FSM
  */  
  replaceEventType mEventNew;
  /**
  * \\brief   variable for storing the current state
  */  
  replaceStateType mState;
  
  // TODO: enter other parts as necessary
  #fsmAttr#
};



/*----------------------------------------------------------------------
   This is auto generated code from a state transition table
   For more information please see
   http://block-net.de/Programmierung/cpp/fsm/fsm.html
----------------------------------------------------------------------*/   

/*------------------------------< Includes >----------------------------------*/

/*------------------------------< Defines >-----------------------------------*/

//---- user settings --------------------------------------------------
/**
* \\brief   true for having a superstate
* \\details The superstate is called when an event cannot be resolved.
*          This requires also to define the void doSuperstate(void) method
*/
#define FSM_WITH_SUPERSTATE (true)

/**
* \\brief   true for leaving the FSm in case an event cannot be resolved.
* \\details If no superstate is active isExit is true when an event cannot 
*          be resolved and dispatch function would leave
*          
*/
#define FSM_EXIT_UNRESOLVED (true)

/**
* \\brief   true for setting isEntry to true when FSM is entered again from
*          superstate or a left dispatch due to a not consumed event.
* \\details Going back from a superstate into the FSM makes isEntry true.
*          If no superstate is active isEntry is true when dispatch function 
*          was left due to a not consumed event.
*/
#define FSM_ENTRY_UNRESOLVED (true)

/**
* \\brief   true for setting isEntry to true for first call after initialization. 
*          
*/
#define FSM_ENTRY_INIT (true)

/**
* \\brief   true for transition action is executed after the state exit.
* \\details If false the overhead is less and execution speed better.
*          
*/
#define FSM_TR_ACTION_AFT_EXIT (false)

// define as TRUE for getting trace output on the screen
#define FSM_DEBUG              TRUE

// set to TRUE for a main function to test the code
#define FSM_TEST               TRUE


/*------------------------------< Typedefs >----------------------------------*/

/*------------------------------< Constants >---------------------------------*/

/*------------------------------< Variables >---------------------------------*/

/*------------------------------< Macros >------------------------------------*/
#if TRUE == FSM_DEBUG
#include <iostream>
#include <stdio.h>

#define TR_FILTER(x)  x

/**
* \\brief   some trace macros for output on stdio
*
*/
#ifndef __FUNCTION__
#define __FUNCTION__  __func__
#endif

#else
#define TR_FILTER(x)
#endif // FSM_DEBUG

#define TRACE_FUNC_ENTRY(...)        TR_FILTER( std::cout << "\\n  -> " << __FUNCTION__ << "(" << __VA_ARGS__<< ")" )
#define TRACE_FUNC_EXIT(...)         TR_FILTER( std::cout << "\\n  <- " << __FUNCTION__ << "() : " << __VA_ARGS__ )
#define TRACE(f, ...)                TR_FILTER( printf(f, __VA_ARGS__) )
#define TRACE_STATE_ENTRY            TRACE("\\n  state=%s", strState(mState) ); 
#define TRACE_SUPERSTATE             TRACE("\\n super state=%s", strState(mState) ); 



/**
* \\brief   macros creating the transition handling depending on the configuration
*
*/
// encapsulate the FSM_TR_ACTION_AFT_EXIT behaviour
#if FSM_TR_ACTION_AFT_EXIT == true
#define FSM_ACTN_HANDLING(action) if( doAction ) { action; }
#define FSM_ST_HANDLING(action)   if( doAction ) { #state# = ret; }

#else
#define FSM_ACTN_HANDLING(action) action;
#define FSM_ST_HANDLING(action)   #state# = ret;
#endif

replaceTableMacros
/*------------------------------< Prototypes >--------------------------------*/
#if TRUE == FSM_DEBUG
const char* strState(replaceClassName::replaceStateType st);
const char* strEvent(replaceClassName::replaceEventType ev);
#endif

//----------------------------------------------------------------------
// --- FSM definition
//----------------------------------------------------------------------

/**
* \\brief   Checks if in entry condition. The next 
*          call in the same state will return false.
*
* \\return         true if in entry condition.
*
* \\api
*/  
bool replaceClassName::isEntry(void)
{
TRACE_FUNC_ENTRY("");
bool ret = bDoTransition;
bDoTransition = false;
return ret;
}

/**
* \\brief   Sets the next state and checks if in exit condition.
*
* \\return        true when state is leaving.
*
* \\api
*/
bool replaceClassName::isExit(void)
{
  TRACE_FUNC_ENTRY("");
  // prepare a state transition, but do not execute transition action
  doTrnstn( false ); 
  bDoSuperstate = ( !bEvtConsumed );
  return bDoTransition
#if FSM_EXIT_UNRESOLVED == true
        || (bDoSuperstate)
#endif
  ;
}

/**
* \\brief   The part handles the whole finite state machine.
* \\details It dispatches the given event and is driving the state machine. 
*          If an event cannot be processed in the state superstate is called.
*
* \\param[in]     evnt  The event processed by the FSM.
*
 * \\externals
 * \\external{ [in;out], mNewEvent, if a new event is scheduled in the FSM itself 
 *   this variable is set to the new event.
 *   Set to eEventVoid, when the event is handled. }
 * \\endexternals
 *
* \\api
*/
void replaceClassName::dispatch (replaceEventType evnt)
{
  do {
    TRACE_FUNC_ENTRY( strEvent(evnt) ); 
    mEvent = evnt;
    bEvtConsumed = bDoSuperstate = false;
    do {
      runSt();
      if( bDoTransition ) { // entry for next state
  #if FSM_TR_ACTION_AFT_EXIT == true
        // now execute the state transition action
        doTrnstn( true );
  #endif
        if( bEvtConsumed ) {
          mEvent = eEventVoid;
        }
      }
    }
    while( bDoTransition );

    if( bDoSuperstate )
    {
  #if (FSM_WITH_SUPERSTATE == true)
      doSuperstate();
  #else
      TRACE( "\\n%s", "Exit Fsm");
  #endif
  #if(FSM_ENTRY_UNRESOLVED == true)
      bDoTransition = true; // leads to isEntry == true in next called state
  #endif
    }
    TRACE_FUNC_EXIT( "" );
    evnt = mEventNew;
    mEventNew = eEventVoid;
  }
  while( evnt !=  eEventVoid );
}

replaceState2MethodTable

replaceTransitionTable

/**
* \\brief   The constructor for replaceClassName
*
* \\init
*/
replaceClassName::replaceClassName( void ) 
{ 
  init(replaceInitState); 
}

/**
* \\brief   Initializes the FSM
* \\details including stack related variables.
*
* \\init
*/
void replaceClassName::init( replaceStateType StStart )
{
  TRACE_FUNC_ENTRY( StStart );
  mState = StStart;
  bDoTransition = FSM_ENTRY_INIT;
  mEventNew = eEventVoid;
  // TODO: initialization
  replaceInitAction  
}

/**
* \\brief   The superstate handling all events not consumed in the state machine 
*           so far.
* \\details Here we can handle e.g. common errors.
*
* \\api
*/
void replaceClassName::doSuperstate (void)
{
#if (FSM_WITH_SUPERSTATE == true) 
  // TODO: Please fill when you have configured a superstate
  replaceSuperstateTable
#endif
}

/**
* \\brief   The state methods which are called by runSt.
* \\details It executes the parts not handled by the transition actions.
*
* \\api
*/
replaceMethodDefinitions

//----------------------------------------------------------------------
#if TRUE == FSM_DEBUG
/**
* \\brief   Function returning the state name 
*
* \\param[in]     st the state as a number.
*
* \\api
*/
replaceStateTrace

/**
* \\brief   Function returning the event name 
*
* \\param[in]     ev the event as a number.
*
* \\api
*/
replaceEventTrace
#endif
//----------------------------------------------------------------------
#if TRUE == FSM_TEST
/**
* \\brief   An example function to get a sequence of events.
* \\details With eEventVoid_replaceEventType the program will exit.
*           TODO: enter an own event sequence to test your FSM
*           the given values are just an example
* \\return  Next event to process in the FSM.
*
* \\api
*/
replaceClassName::replaceEventType getEvent(void)
{
  // TODO: adapt to your needs for a test
  static int i = 0;
  static replaceClassName::replaceEventType event[] = { replaceEventsWith,replaceClassName::eEventVoid };
  
  if( event[i] == replaceClassName::eEventVoid ) {
    return replaceClassName::eEventVoid;
  }
  return event[i++];
}

/**
* \\brief   A typical call procedure of the Fsm.
*
* \\nonapi
*/
void replaceClassName_Test (void)
{
  replaceClassName fsm;
  // default event
  replaceClassName::replaceEventType evnt = replaceClassName::eEventVoid;
  // when getEvent returns eEventVoid the function replaceClassName_Test returns
  do   {
    evnt = getEvent();
    fsm.dispatch( evnt );  
  } while( evnt != replaceClassName::eEventVoid );
}
    
// A main for a simple FSM test
int main (void)
{
  replaceClassName_Test();
  return 0;
}
#endif
END_CODE_TEMPLATE
  }


  #======================================================================
  elsif( ($tTemplate == VRNT_C) && ($base == 1) ) {
  #======================================================================
    $_=<<END_CODE_TEMPLATE;
/*----------------------------------------------------------------------
   This is auto generated code from a state transition table
   For more information please see
   http://block-net.de/Programmierung/cpp/fsm/fsm.html
----------------------------------------------------------------------*/   

/*
   This is an example finite state machine based on the 
   C Fsm framework.
   The FSM is declared and defined in one C file
   for ease of understanding. 
   
   Can be compiled with e.g gcc with: 
   gcc filename -o fsm.exe
*/

/* we need to define the parts which need to be available before 
   including fsm.h */
/* define for getting some output on the screen */
#define FSM_DEBUG

typedef enum { eStateVoid_replaceClassName=0, replaceStates  } tFsmcSt_replaceClassName; 
/* The events */
typedef enum { eEventVoid_replaceClassName=0, replaceEvents } tFsmcEv_replaceClassName; 

#define FSM_ST_T tFsmcSt_replaceClassName
#define FSM_EV_T tFsmcEv_replaceClassName

/* The state machine framework */
#include "fsm.h"

/* just some macros for debugging entry state */
#define TRACE_STATE_ENTRY   TR_FILTER( TRACE("\\n  state=%s", strState(fsm->mState) ) );
#define TRACE_SUPERSTATE

    #fsmAttr#

/*----------------------------------------------------------------------------*/
#ifdef FSM_DEBUG
replaceStateTrace

replaceEventTrace
#endif
/*----------------------------------------------------------------------------*/

/*--- the worker functions for the states */
replaceMethodDefinitions

#if (FSM_WITH_SUPERSTATE == true)
void doSuperstate (void)
{
  /* TODO: Please fill when you have configured a superstate */
  replaceSuperstateTable
}
#endif

/* 
   Defines function void runSt( tState el )
   This function calls for a state 
   the assigned function.
*/   
replaceState2MethodTable
  
/*
   Now the transitions from one state to an other are defined.  
   It can be easily parsed from humans and also from the script 
   which generated this file to created a state diagram code 
   e.g. for PlantUML.
   This is to have the states and transitions
   here as some kind of documentation.
*/
replaceTransitionTable

/*----------------------------------------------------------------------------*/
#if 1
/* An example function to get a sequence of events to go through the
   state machine, with eEventVoid_replaceClassName the program will exit. */
FSM_EV_T getEvent(void)
{
  // TODO: adapt to your needs for a test
  static int i = 0;
  static FSM_EV_T event[] = { replaceEvents,eEventVoid_replaceClassName };
  
  if( event[i] == eEventVoid_replaceClassName ) {
    return eEventVoid_replaceClassName;
  }
  return event[i++];
}
    
/* A typical call procedure of the Fsm */
void replaceClassName_Test (void)
{
  tFsmc fsm;
  /* default event */
  FSM_EV_T evnt = eEventVoid_replaceClassName;
  /* initialize the state machine with fsm pointer and state 1.
     So dispatch will start with state1 execution.
     when getEvent returns eEvntVoid_replaceClassName the program is stopped */
  FSM_INIT(replaceClassName, &fsm, replaceInitState);
  replaceInitAction
  do   {
    evnt = getEvent();
    dispatchFsmc( &fsm, evnt );  
  } while( evnt != eEventVoid_replaceClassName );
}

int main (void)
{
  replaceClassName_Test();
  return 0;
}
#endif
END_CODE_TEMPLATE
  }
  
  #======================================================================
  elsif( ($tTemplate == VRNT_C) && ($base == 0) ) {
  #======================================================================
    $_=<<END_CODE_TEMPLATE;
/*----------------------------------------------------------------------
   This is auto generated code from a state transition table
   For more information please see
   http://block-net.de/Programmierung/cpp/fsm/fsm.html
----------------------------------------------------------------------*/   

/*
   This is an example finite state machine based on the 
   C Fsm framework.
   The FSM is declared and defined in one C file
   for ease of understanding. 
   
   Can be compiled with e.g gcc with: 
   gcc filename -o fsm.exe
*/

//---- user settings --------------------------------------------------
// true when having a superstate
//   The superstate is called when an event cannot be resolved.
//   This requires also to define a void doSuperstate(void) method
//   in the derived FSM
#define FSM_WITH_SUPERSTATE (true)

// true
//   Before a superstate is called isExit is true.
//   If no superstate is active isExit is true when an event cannot be resolved
//   and dispatch function would leave
#define FSM_EXIT_UNRESOLVED (true)

// true
//   Going back from a superstate into the FSM makes isEntry true.
//   If no superstate is active isEntry is true when dispatch function was left
//   due to a not consumed event.
#define FSM_ENTRY_UNRESOLVED (true)

// If true the call of dispatch after initialization
//   will call onEntry part in the first state
#define FSM_ENTRY_INIT (true)

// if set true the transition action is executed after the state exit
//   action is executed otherwise before. If false the overhead is less
//   and execution speed better.
#define FSM_TR_ACTION_AFT_EXIT (false)


/* we need to define the parts which need to be available before 
   including fsm.h */
/* define for getting some output on the screen */
#define FSM_DEBUG_replaceClassName
//---- user settings end ------------------------------------------------

typedef enum { eStateVoid_replaceClassName=0, replaceStates  } tFsmcSt_replaceClassName; 
/* The events */
typedef enum { eEventVoid_replaceClassName=0, replaceEvents } tFsmcEv_replaceClassName; 

#define FSM_ST_T tFsmcSt_replaceClassName
#define FSM_EV_T tFsmcEv_replaceClassName

// some debugging macros
#ifdef FSM_DEBUG_replaceClassName
#include <stdio.h>

#define TR_FILTER(x)  x

#ifndef __FUNCTION__
#define __FUNCTION__  __func__
#endif

#else
#define TR_FILTER(x)
#endif // FSM_DEBUG_replaceClassName

#define TRACE_FUNC_ENTRY()          TR_FILTER( printf("\\n  -> %s()", __FUNCTION__) )
#define TRACE_FUNC_EXIT()           TR_FILTER( printf("\\n  <- %s()", __FUNCTION__) )
#define TRACE_FUNC_ENTRY_(f,...)    TR_FILTER( printf("\\n  -> %s(" f, __FUNCTION__, __VA_ARGS__) )
#define TRACE_FUNC_EXIT_(f,...)     TR_FILTER( printf("  <- %s()" f, __FUNCTION__, __VA_ARGS__) )

#define TRACE(f, ...)               TR_FILTER( printf(f, __VA_ARGS__) )
#define TRACE_STATE_ENTRY   		TRACE("\\n  state=%s", strState(fsm->mState) );

#ifndef bool
#define bool unsigned char
#endif

#ifndef true
#define true (1)
#endif

#ifndef false
#define false (0)
#endif

// use this define, if you do not use an event as parameter sig in macros DEF_TRNS_BEG and DEF_TRNS_CONT
#define EVENT_NONE (fsm->mEvent)

/*
   Macros for defining the doTrnstn method
   If used, easily a state chart can be generated
*/
// first encapsulate the FSM_TR_ACTION_AFT_EXIT behaviour
#if FSM_TR_ACTION_AFT_EXIT == true  
#define FSM_ACTN_HANDLING(action) if( doAction ) { action; } 
#define FSM_ST_HANDLING(action)   if( doAction ) { fsm->mState = ret; }

#else
#define FSM_ACTN_HANDLING(action) action;
#define FSM_ST_HANDLING(action)   fsm->mState = ret;

#endif
    
// macro to prevent manual code duplication	
#define FSM_TMP(cur_state, next_state, sig, guard, action) \\
  if( (sig == fsm->mEvent) && (guard) ) { \\
    fsm->bDoTransition = true;\\
    FSM_ACTN_HANDLING(action) \\
    if( sig == fsm->mEvent ) { consumeEvt(fsm); } \\
    ret = next_state; \\
  } 

  /* Used for two parts
   1) To test if a transition would be true
   2) To execute the transition 
   
   Parameter doAction false, do 1)
                      true, do 2)
                      
    retval [external out]  sets bDoExit=true when 1) is true
    retval [external out]  sets mState for 2) after transition.
*/
#define FSM_TT(pr) \\
FSM_ST_T doTrnstn_##pr( tFsmc* fsm, bool doAction ) \\
{ \\
  FSM_ST_T ret = fsm->mState;\\
  switch(fsm->mState)\\
  {\\
    default: 

#define FSM_TT_BEG(cur_state, next_state, sig, guard, action ) \\
        break; \\
    case cur_state: \\
      FSM_TMP(cur_state, next_state, sig, guard, action ) 
      
#define FSM_TT_CNT(next_state, sig, guard, action) \\
      else FSM_TMP(, next_state, sig, guard, action ) 
            
#define FSM_TT_END \\
      break;\\
    } \\
    FSM_ST_HANDLING(doAction)\\
}

#define FSM_TT_SS( ev, guard, nst, actn ) \\
  if( (ev == fsm->mEvent) && (guard) ) { \\
    fsm->mState = nst; \\
    TRACE_SUPERSTATE \\
    actn; \\
  }

//--- Macros for defining the void runSt method
#define DEF_ST_TO_MTHD_BEG(pr, var) \\
  void pr##_runSt( FSM_ST_T el, tFsmc* var )\\
  {   \\
    switch(el)\\
    {
    
#define DEF_ST_TO_MTHD(st, mt) \\
  case st: \\
    mt; \\
    break;

#define DEF_ST_TO_MTHD_END } };



/*
  The structure holding the fsm information.
  You can have several variables of type tFsmc
  but only one FSM_ST_T and one FSM_EV_T.
  So you can have several FSMs in the code.
*/
typedef struct sFsmc { 
  FSM_ST_T mState; 
  FSM_EV_T mEvent;
  void (*runSt)( FSM_ST_T el, struct sFsmc* fsm);
  FSM_ST_T (*doTrnstn)( struct sFsmc* fsm, bool action );
  bool bEvtConsumed;
  bool bDoTransition;
  bool bDoSuperstate;
  /* TODO enter here module variables as needed */
} tFsmc;

typedef void (*tFctRunSt)( FSM_ST_T el, tFsmc *fsm);
typedef FSM_ST_T (*tFctDoTrnstn)( tFsmc* fsm, bool action );
void doSuperstate_replaceClassName (void);


    /* postfix, pointer to fsm, state */
#define FSM_INIT(pf, pfsm, st) \\
  initFsmc( pfsm, st, pf##_runSt,  doTrnstn_##pf  );

    #fsmAttr#

/*----------------------------------------------------------------------------*/
#ifdef FSM_DEBUG_replaceClassName
replaceStateTrace

replaceEventTrace
#endif
/*----------------------------------------------------------------------------*/
/* Initialize the state machine */
void initFsmc (tFsmc* fsm, FSM_ST_T StStart, tFctRunSt pfRun, 
               tFctDoTrnstn pfTrans) 
{ 
  TRACE_FUNC_ENTRY(  );
  fsm->mState = StStart;
  fsm->runSt = pfRun;
  fsm->doTrnstn = pfTrans;
  fsm->bDoTransition = FSM_ENTRY_INIT;
}

/* test if we are in entry condition of a state */
bool peekEntryFsmc(tFsmc* fsm) 
{
  return fsm->bDoTransition;
}  

/* checks if in entry condition 
   the next call in the same state will return false */
bool isEntryFsmc(tFsmc* fsm)
{
  if( fsm->bDoTransition ) {
    TRACE_FUNC_ENTRY();
    fsm->bDoTransition = false;
    return true;
  }
  return false;
}  

/* sets the next state and checks if in exit condition */
bool isExitFsmc(tFsmc* fsm)
{
  bool ret;
  if( 0 != fsm->doTrnstn )  (fsm->doTrnstn)( fsm, false );
  if( !fsm->bEvtConsumed )  fsm->bDoSuperstate = true;
  ret = fsm->bDoTransition
#if FSM_EXIT_UNRESOLVED == true
        || (fsm->bDoSuperstate)
#endif
  ;
  if( ret ) { TRACE_FUNC_ENTRY(); }

  return ret;
}  


/* A getter for the current state */
FSM_ST_T getStateFsmc (tFsmc* fsm) { return fsm->mState; }

/* A getter for the current event */
FSM_EV_T getEventFsmc (tFsmc* fsm) { return fsm->mEvent; }

/* Tests if an event has been consumed in the FSM */
bool isEvtConsumed(tFsmc* fsm) { return fsm->bEvtConsumed; }

/* if in a state an event is consumed, we have to
     inform the module about it with this function. */
void consumeEvt(tFsmc* fsm) { fsm->bEvtConsumed = true; }

/* set the event and run the current state function
   Since all states shall have an isEntry and isExit function.
   The call of isExit will prepare the next state. */
void dispatchFsmc (tFsmc* fsm, FSM_EV_T evnt)
{
  TRACE_FUNC_ENTRY_( "%s)", strEvent(evnt) );
  fsm->mEvent = evnt;

  fsm->bEvtConsumed = false;
  fsm->bDoSuperstate = false;
  do {
    if( 0 != fsm->runSt ) {
      fsm->runSt( fsm->mState, fsm );
    }
    // bDoEntry is set when bDoExit has been executed
    if( fsm->bDoTransition ) { // entry for next state
#if FSM_TR_ACTION_AFT_EXIT == true
      // now execute the state transition action
      (fsm->doTrnstn)( fsm, true );
#endif
      if( fsm->bEvtConsumed )
      {
        fsm->mEvent = (FSM_EV_T)0;
      }
    }
  }
  while( fsm->bDoTransition );

  if( fsm->bDoSuperstate )
  {
#if (FSM_WITH_SUPERSTATE == true)
  doSuperstate_replaceClassName();
#else
  TRACE( "\\n%s", "Exit Fsm");
#endif
#if(FSM_ENTRY_UNRESOLVED == true)
    // make an entry when moving from superstate back to a state
    fsm->bDoTransition = true;
#endif
  }
  TRACE_FUNC_EXIT();
}

#if (FSM_WITH_SUPERSTATE == true)
void doSuperstate_replaceClassName (void)
{
  /* TODO: Please fill when you have configured a superstate */
  replaceSuperstateTable
}
#endif

replaceMethodDefinitions

/* 
   Defines function void replaceClassName_runSt( tState el )
   This function calls for a state 
   the assigned function.
*/   
replaceState2MethodTable

/*
   Now the transitions from one state to an other are defined.  
   It can be easily parsed from humans and also from the script 
   which generated this file to created a state diagram code 
   e.g. for PlantUML.
   This is to have the states and transitions
   here as some kind of documentation.
*/
replaceTransitionTable

//----------------------------------------------------------------------
#if 1
/*----------------------------------------------------------------------------*/
/* An example function to get a sequence of events to go through the
   state machine, with eEventVoid_replaceClassName the program will exit. */
FSM_EV_T getEvent(void)
{
  // TODO: adapt to your needs for a test
  static int i = 0;
  static FSM_EV_T event[] = { replaceEvents,eEventVoid_replaceClassName };
  
  if( event[i] == eEventVoid_replaceClassName ) {
    return eEventVoid_replaceClassName;
  }
  return event[i++];
}
    
/* A typical call procedure of the Fsm */
void replaceClassName_Test (void)
{
  tFsmc fsm;
  /* default event */
  FSM_EV_T evnt = eEventVoid_replaceClassName;
  /* initialize the state machine with fsm pointer and state 1.
     So dispatch will start with state1 execution.
     when getEvent returns eEvntVoid_replaceClassName the program is stopped */
  FSM_INIT(replaceClassName, &fsm, replaceInitState);
  replaceInitAction
  do   {
    evnt = getEvent();
    dispatchFsmc( &fsm, evnt );  
  } while( evnt != eEventVoid_replaceClassName );
}

int main (void)
{
  replaceClassName_Test();
  return 0;
}
#endif
END_CODE_TEMPLATE

  }
}

sub expandTtMacros
# for the stand alone C++ state machine
# expand the TT macros
{
  my $doTrntn;

  getFsmStr;
  $doTrnst =<<ENDTXT;
//----------------------------------------------------------------------
// macros creating the transition handling depending on the configuration
ENDTXT

  $doTrnst .= "\n//". "-"x78;
  foreach (@table) {
    chomp;
    $doTrnst .= "\n//$_";      
  }  
  $doTrnst .= "\n//". "-"x78;
  
  $lastState = "";
  foreach (@table) {
    ($nr, $cst, $nst, $sig, $grd, $act, $tState, $tEvent) = parsePatterns( $_ );
    if( $nr == TT && ($lastState ne "STATE_NONE") ){
      $doTrnst .= "\n#defDoTrnstn#\n{";
      $doTrnst .= "\n  $tState ret = #state#;";
      $doTrnst .= "\n  switch( #state# )\n  {\n  default:";
    }
    elsif( $nr == TTMARK && ($lastState ne "STATE_NONE") ){
      $doTrnst .= "\n#defDoTrnstn#\n{";
      $doTrnst .= "\n  FSM_ST_T ret = #state#;";
      $doTrnst .= "\n  switch( #state# )\n  {\n  default:";
    }
    elsif( $nr == TTBEG || $nr == TTCNT ) {
      $lastState = $cst;
      if( $lastState ne "STATE_NONE" ) {
        if( $nr == TTBEG ) {
          $doTrnst .= "\n    break;";
          $doTrnst .= "\n  case $cst:";
          $doTrnst .= "\n    if( ";
        }
        else {
          $doTrnst .= "\n    else if( ";
        }
      }
      # if( ($sig == #event#) && ($grd) ) { ";
      if( $lastState ne "STATE_NONE" ) {
        if( $sig !~ /^\s*EVENT_NONE\s*$/ ) { # no event
          $doTrnst .= "($sig == #event#)";
        }
        else {
          $doTrnst .= "\n    if( ";
        }
        if( $grd !~ /^\s*true\s*$/ ) { #guard only true
          $doTrnst .= " && ($grd)";
        }
        $doTrnst .= " ) {";
        
        $doTrnst .= "\n      #bDoTransition# = true;";
        $doTrnst .= "\n      FSM_ACTN_HANDLING($act)";
        $doTrnst .= "\n      ret = $nst;";
        $doTrnst .= "\n    }";
      }
    }
    elsif( /\s*FSM_TT_END/ ) {
      $doTrnst .= "\n    break;\n    }";  
      $doTrnst .= "\n  if( #bDoTransition# ) { #consumeEvt#; }";
      $doTrnst .= "\n  FSM_ST_HANDLING(doAction)\n}";
    }
  }
  return $doTrnst;
}

#-------------------------------------------------------------------------------
sub strRunSt
#  creates the runSt method string
#  Parameter 1: string prefix
{
  my $str = $_[0];
  if( $nee == 1  ) {
    $str .= "  bool entry = #entry#;\n"; 
  }
  $str .=<<ENDTXT;
  switch(#state#)
  {
ENDTXT
  chop $str;  
  foreach (@states) {
    if( $_ ne "STATE_NONE" ) {  
      $str .= "\n  case $_:";
      $str .= "\n    do$_(#callStateArg#);" if( $sm == 1 );
      $str .= "\n    break;";
    }
  }  
  $str .= "\n  }";
  if( $nee == 1 ) {
    $str .= "\n  #exit#; //  used to check if we have a transition" ;
  }  
  $str .= "\n}";
  return $str;
}


sub strStateMethodDeclaration
# returns the state method declaration as a string and
# the definition in $replaceState2MethodTable
# Parameter 1: A prefix string for the declaration
# Parameter 2: The reference to an array conataining the EntryDoExit parts per state
{
  my ($str, $tmpRef) = (@_);

  if( $sm == 1 ) {
    # create for each state a method
    
    # flagged part creating runSt method by macros
    foreach (@states) {
      if( $_ ne "STATE_NONE" ) {
        $str .= "\nvoid #class#do$_(#defStateArg#)\n{\n";
        $str .= getEntryDoExitStrPerState($_,$tmpRef);
        $str .= "\n}\n\n";
      }
    }  
    $replaceState2MethodTable .=<<ENDTXT;

/**
* \\brief   The worker method for the states.
* \\details This is called in the dispatch method.
*
* \\api
*/
void #defRunSt#
{ 
ENDTXT

    $replaceState2MethodTable = strRunSt( $replaceState2MethodTable );
  } 
  #----------------------------------------------------------------------
  else {
    # insert states in big switch case
    $str .=<<ENDTXT;
void #defRunSt#
{ 
  bool entry = #entry#;
  switch( #state# )
  {  
ENDTXT

    foreach (@states) {
      if( $_ ne "STATE_NONE" ) {
        $str .= "\n  case $_ :\n    // TODO\n";
        $str .= getEntryDoExitStrPerState($_,$tmpRef);
        $str .= "    break;\n";
      }
    }  
    $str .= "\n  }";
    if( $nee == 1 ) {
      $str .= "\n  #exit#; //  used to check if we have a transition" ;
    }
    $str .= "\n}\n";
  }
  return $str;
}


#-------------------------------------------------------------------------------
#  specific to the C++ state machine with base class
sub parseTransitionTable
# replaces the reserved words in the template with the 
# states, events and state handlers
{
  # out map{state} => method
  # out map{events} 
  # out state type, event type
  getStatesAndEvents;
  
#  @states = sort( delDouble( @states ) );   
  $replaceStates = "";
  foreach (@states) {
    if( $_ ne "STATE_NONE" ) {
      $replaceStates .= "$_,";
    }
  }
  $replaceStates =~ s/,$//;

  $replaceMethodDeclarations = "";
  foreach (@states) {
    if( $_ ne "STATE_NONE" ) {
      $replaceMethodDeclarations .= "  void do$_(void);\n" if( $sm == 1 );
    }
  }

  $replaceStateTrace = "const char* strState(replaceStateType st)\n{\n  switch(st)\n  {\n";
  foreach (@states) {
    if( $_ ne "STATE_NONE" ) {
      $replaceStateTrace .= "  case $_: return \"$_\";\n";
    }
  }
  $replaceStateTrace .= "  default: return \"unknown\";\n";
  $replaceStateTrace .= "  }\n}";

  $replaceSuperstateTable = "";  
  for( $i=0; $i < $#superstates; $i+=4 ) {
    $replaceSuperstateTable .= "\n  FSM_TT_SS( $superstates[$i+1], $superstates[$i+2], $superstates[$i], $superstates[$i+3] );";
  }
  
  $replaceEvents = "";
  foreach (sort(@events)) {
    $replaceEvents .= "$_,";
  }
  $replaceEvents =~ s/,$//;
  
  $replaceEventTrace = "const char* strEvent(replaceEventType ev)\n{\n  switch(ev)\n  {\n";
  foreach (sort(@events)) {
    $replaceEventTrace .= "  case $_: return \" $_\";\n";
  }
  $replaceEventTrace .= "  default: return \"unknown\";\n";
  $replaceEventTrace .= "  }\n}";

  
  $replaceClassName = $template;
  $replaceTransitionTable = "";
  foreach (@table) {
    if( /$pattern{ttInit}/ ) {
      s/<CR>//smg;
      $replaceTransitionTable .= "//$_\n";
    }
    elsif( /$pattern{codeTt}/ ) {
      if( /STATE_NONE/ ) {
        $replaceTransitionTable .= "//";
      }
      elsif( 0 && /$pattern{tt}/ ) {
        my @cnt = /$pattern{tt}/;
        if($#cnt == 1) {
          s/(.*?)\)/$1, replaceClassName\)/;
        }
      }
      $replaceTransitionTable .= "$_\n";
    }
  }

  @tmp = getEntryDoExitPartStrs;
  $replaceMethodDefinitions = strStateMethodDeclaration( "", \@tmp );
}

#-------------------------------------------------------------------------------
#  specific to the stand alone C++ state machine without a base class
sub parseTransitionTable2
# replaces the reserved words in the template with the 
# states, events and state handlers
{
  # out map{state} => method
  # out map{events} 
  # out state type, event type
  getStatesAndEvents;
  $replaceState2MethodTable = "";
  $replaceTableMacros = "";
    
  $replaceStates = "";
  $replaceStatesWith = "";
  foreach (@states) {
    if( $_ ne "STATE_NONE" ) {
      $replaceStates .= "\n    $_,";
      $replaceStatesWith .= "\n  replaceClassName::$_,";
    }
  }
  $replaceStates =~ s/,$/\n/;
  $replaceStatesWith =~ s/,$/\n/;

  $replaceMethodDeclarations = "";
  foreach (@states) {
    if( $_ ne "STATE_NONE" ) {
      $replaceMethodDeclarations .= "  void do$_(#callStateArg#);\n" if( $sm == 1 );
    }
  }

  my $tmp = "";
  if( $variant == VRNT_CPP) {
    $tmp = "replaceClassName::";
  }
  $replaceStateTrace = "const char* strState(".$tmp."replaceStateType st)\n{\n  switch(st)\n  {\n";
  foreach (@states) {
    if( $_ ne "STATE_NONE" ) {
      $replaceStateTrace .= "  case $tmp$_: return \"$_\";\n";
    }
  }
  $replaceStateTrace .= "  }\n}";

  $replaceSuperstateTable = "";  
  for( $i=0; $i < $#superstates; $i+=4 ) {
    $replaceSuperstateTable .= "\n  FSM_TT_SS( $superstates[$i+1], $superstates[$i+2], $superstates[$i], $superstates[$i+3] );";
  }
  
  $replaceEvents = "";
  $replaceEventsWith = "";
  foreach (sort(@events)) {
    $replaceEvents .= "\n    $_,";
    $replaceEventsWith .= "\n  replaceClassName::$_,";
  }
  $replaceEvents =~ s/,$/\n/;
  $replaceEventsWith =~ s/,$/\n/;
   
  $replaceEventTrace = "const char* strEvent(".$tmp."replaceEventType ev)\n{\n  switch(ev)\n  {\n";
  foreach (sort(@events)) {
    $replaceEventTrace .= "  case $tmp$_: return \"$_\";\n";
  }
  $replaceEventTrace .= "  }\n}";

  $replaceClassName = $template;
  if( $extt == 1 ) {
    $replaceTransitionTable = expandTtMacros();
  }
  else {
    $replaceTableMacros =<<ENDTXT;
// macro to prevent manual code duplication
#define FSM_TMP(cur_state, next_state, sig, guard, action) \\
  if( (sig == #event#) && (guard) ) { \\
    #bDoTransition# = true;\\
    FSM_ACTN_HANDLING(action) \\
    ret = next_state; \\
  }

#FSM_TT#
 
#define FSM_TT_BEG(cur_state, next_state, sig, guard, action ) \\
        break; \\
    case cur_state: \\
      FSM_TMP(cur_state, next_state, sig, guard, action )

#define FSM_TT_CNT(next_state, sig, guard, action) \\
      else FSM_TMP(, next_state, sig, guard, action )

#define FSM_TT_END \\
      break;\\
    } \\
    if( #bDoTransition# ) { #consumeEvt#; }\\
    FSM_ST_HANDLING(doAction)\\
}

#define FSM_TT_SS( ev, guard, nst, actn ) \\
  if( (ev == getEvent()) && (guard) ) { \\
    mState = nst; \\
    TRACE_SUPERSTATE \\
    actn; \\
  }
ENDTXT
  
    $replaceTransitionTable =<<ENDTXT;
//----------------------------------------------------------------------
// This table defines the doTrntn method (called in isExit method and dispatch)
ENDTXT
    # reformat tt output
#   foreach (@table) {
    foreach( formatTtArgs() ) {
      if( /$pattern{ttInit}/ || 
        /$pattern{fsmTtAttrStart}/ || /STATE_NONE/) {
        s/<CR>//smg;
        $replaceTransitionTable .= "//$_\n";
      }
      elsif( /$pattern{codeTt}/ ) {
	      $replaceTransitionTable .= "$_\n";
      }
    }  
  }
  
  @tmp = getEntryDoExitPartStrs
  #----------------------------------------------------------------------
  $replaceMethodDefinitions = ""; 
  $replaceMethodDefinitions = strStateMethodDeclaration( "", \@tmp );
  if(0) {
  if( $sm == 1 ) {
    # create for each state a method
    foreach (@states) {
      if( $_ ne "STATE_NONE" ) {
        $replaceMethodDefinitions .= "\nvoid #class#do$_(#defStateArg#)\n{\n";
        $replaceMethodDefinitions .= getEntryDoExitStrPerState($_,\@tmp);
        $replaceMethodDefinitions .= "\n}\n\n";
      }
    }  
    $replaceState2MethodTable .=<<ENDTXT;

/**
* \\brief   The worker method for the states.
* \\details This is called in the dispatch method.
*
* \\api
*/
void #defRunSt#
{ 
ENDTXT

    $replaceState2MethodTable = strRunSt( $replaceState2MethodTable );
  } 
  #----------------------------------------------------------------------
  else {
    # insert states in big switch case
    $replaceMethodDefinitions .=<<ENDTXT;
void #defRunSt#
{ 
  bool entry = #entry#;
  switch( #state# )
  {  
ENDTXT

    foreach (@states) {
      if( $_ ne "STATE_NONE" ) {    
        $replaceMethodDefinitions .= "\n  case $_ :\n    // TODO\n";
        $replaceMethodDefinitions .= getEntryDoExitStrPerState($_,\@tmp);
        $replaceMethodDefinitions .= "    break;\n";
      }
    }  
    $replaceMethodDefinitions .= "\n  }";
    if( $nee == 1 ) {
      $replaceMethodDefinitions .= "\n  #exit#; //  used to check if we have a transition" ;
    }
    $replaceMethodDefinitions .= "\n}\n";
  }
  }
}


#-------------------------------------------------------------------------------
# main continued
if( $variant == VRNT_CPP || $variant == VRNT_C ) {
  if( $base == 1 ) {
    # creates the state machine output based on the Fsm base class
    parseTransitionTable;
  }
  else {
    # creates the stand alone C/C++ state machine output 
    parseTransitionTable2;
  }
  getCodeTemplate( $variant );
  replaceTemplateCodeWords;
  replaceCodeDependent;
}
elsif( $variant == VRNT_VCST ) {
  # vectorcast tests for variant 2
  createVCastCppTestsPerState;
}
else {
  createUmlOutput;
}
END { close( STDOUT ) || die "can not close stdout"; }
