Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members  

streamable_dfa.hh

00001 /*
00002 *  Name:      streamable_dfa.hh
00003 *  Author:    Rafael Jesus Alcantara Perez
00004 *  Summary:   Streamable Deterministic Finite Automaton
00005 *  Date:      $Date: 2003/04/14 00:18:31 $
00006 *  Revision:  $Revision: 1.1 $
00007 *
00008 *  Copyright (C) 1999-2002  Rafael Jesus Alcantara Perez <rafa@dedalo-ing.com>
00009 *
00010 *  This program is free software; you can redistribute it and/or modify
00011 *  it under the terms of the GNU General Public License as published by
00012 *  the Free Software Foundation; either version 2 of the License, or
00013 *  (at your option) any later version.
00014 *
00015 *  This program is distributed in the hope that it will be useful,
00016 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 *  GNU General Public License for more details.
00019 *
00020 *  You should have received a copy of the GNU General Public License
00021 *  along with this program; if not, write to the Free Software
00022 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00023 *  MA 02111-1307, USA.
00024 */
00025 
00026 #ifndef _MPCL_AUTOMATON_STREAMABLE_DFA__
00027 #define _MPCL_AUTOMATON_STREAMABLE_DFA__
00028 
00029 #include <iostream>
00030 #include <iterator>
00031 #include "../event/event_handler.hh"
00032 #include "../io/streamable.hh"
00033 #include "../text/regex/matcher.hh"
00034 #include "../text/string.hh"
00035 #include "../util/collection/map.hh"
00036 #include "defs.hh"
00037 #include "deterministic_finite_automaton.hh"
00038 
00039 
00041 namespace mpcl
00042 {
00043 
00045   namespace automaton
00046   {
00047 
00048     using event::TEventHandler;
00049     using io::IStreamable;
00050     using text::TString;
00051     using text::regex::TMatcher;
00052 
00060     template <typename TState, typename TEvent>
00061     class TStreamableDfa                                   :
00062       public IStreamable<>                                 ,
00063       public TDeterministicFiniteAutomaton<TState, TEvent>
00064     {
00065 
00066       public:
00067 
00069         typedef
00070           IStreamable<>::char_type
00071           char_type;
00072 
00074         typedef
00075           IStreamable<>::traits_type
00076           traits_type;
00077 
00078 
00079       protected:
00080 
00082         typedef
00083           typename TDeterministicFiniteAutomaton<TState, TEvent>::TPair
00084           TPair;
00085 
00087         typedef
00088           typename TDeterministicFiniteAutomaton<TState, TEvent>::TTransitionMap
00089           TTransitionMap;
00090 
00092         typedef
00093           typename TDeterministicFiniteAutomaton<TState, TEvent>::TStateSet
00094           TStateSet;
00095 
00097         TEventHandler<TEvent>&   rtEventHandler;
00098 
00099 
00100       protected:
00101 
00103         typedef
00104           TMap<TString, TEvent>
00105           TStringToEventMap;
00106 
00108         typedef
00109           TMap<TString, TState>
00110           TStringToStateMap;
00111 
00113         TStringToEventMap   tStringToEventMap;
00114 
00116         TStringToStateMap   tStringToStateMap;
00117 
00119         TString   yDescription;
00120 
00122         TString   yName;
00123 
00125         TString   yPublic;
00126 
00128         TString   ySystem;
00129 
00130 
00131       protected:
00132 
00133         //
00134         //  C O N S T R U C T O R S
00135         //
00136 
00141         void read (std::basic_istream<char_type, traits_type>& rtSOURCE_ISTREAM);
00142 
00147         void readFooter (TMatcher& rtSOURCE_REM);
00148 
00153         void readHeader (TMatcher& rtSOURCE_REM);
00154 
00159         void readTransitionTable (TMatcher& rtSOURCE_REM);
00160 
00161 
00162       public:
00163 
00164         //
00165         //  C O N S T R U C T O R S
00166         //
00167 
00173         TStreamableDfa (TEventHandler<TEvent>& rtSOURCE_EVENT_HANDLER)           :
00174           IStreamable<>                                 ()                       ,
00175           TDeterministicFiniteAutomaton<TState, TEvent> ()                       ,
00176           rtEventHandler                                (rtSOURCE_EVENT_HANDLER) ,
00177           tStringToEventMap                             ()                       ,
00178           tStringToStateMap                             ()                       ,
00179           yDescription                                  ()                       ,
00180           yName                                         ()                       ,
00181           yPublic                                       ()                       ,
00182           ySystem                                       ()                       {}
00183 
00185         void start (void);
00186 
00187 
00188       protected:
00189 
00190         //
00191         //  S E L E C T O R S
00192         //
00193 
00195         virtual void check (void) const;
00196 
00202         TString eventToString (const TEvent& krtSOURCE_EVENT) const
00203           throw (TNotFoundException);
00204 
00210         TString stateToString (const TState& krtSOURCE_STATE) const
00211           throw (TNotFoundException);
00212 
00217         void write (std::basic_ostream<char_type, traits_type>& rtTARGET_OSTREAM) const
00218         {
00219           writeHeader          (rtTARGET_OSTREAM);
00220           writeTransitionTable (rtTARGET_OSTREAM);
00221           writeFooter          (rtTARGET_OSTREAM);
00222         }
00223 
00228         void writeFooter (std::basic_ostream<char_type, traits_type>& rtTARGET_OSTREAM) const
00229         {
00230           rtTARGET_OSTREAM << "</dfaml>\n";
00231         }
00232 
00237         void writeHeader (std::basic_ostream<char_type, traits_type>& rtTARGET_OSTREAM) const;
00238 
00243         void writeTransitionTable (std::basic_ostream<char_type, traits_type>& rtTARGET_OSTREAM) const;
00244 
00245 
00246       public:
00247 
00248         //
00249         //  S E L E C T O R S
00250         //
00251 
00252         using TDeterministicFiniteAutomaton<TState, TEvent>::isFinal;
00253 
00259         bool isFinal (const TString& rkySOURCE_STATE) const
00260         {
00261           return TDeterministicFiniteAutomaton<TState, TEvent>::isFinal (tStringToStateMap [rkySOURCE_STATE]);
00262         }
00263 
00269         bool isFinal (const char* pkcSOURCE_STATE) const
00270         {
00271           return TDeterministicFiniteAutomaton<TState, TEvent>::isFinal (tStringToStateMap [pkcSOURCE_STATE]);
00272         }
00273 
00274     };  // class TStreamableDfa
00275     
00276   }  // namespace automaton
00277 
00278 }  // namespace mpcl
00279 
00280 
00281 //
00282 //  C O N S T R U C T O R S
00283 //
00284 
00285 template <typename TState, typename TEvent>
00286 inline void mpcl::automaton::TStreamableDfa<TState, TEvent>::
00287 read (std::basic_istream<char_type, traits_type>& rtSOURCE_ISTREAM)
00288 {
00289   
00290   //
00291   //  DFAML document must be validated, so parsing
00292   //  doesn't have to worry about syntax errors.
00293   //  First it musts find DFAML tag, and then skip
00294   //  it.
00295   //
00296   TMatcher   tMatcher (rtSOURCE_ISTREAM);
00297 
00298   tTransitionMap.clear();  
00299   tMatcher.setCaseSensitiveness (false);
00300 
00301   readHeader (tMatcher);
00302   if ( !yPublic.empty() )
00303   {
00304     if ( yPublic != pkcDOCTYPE_VERSION_1_0 )
00305     {
00306       throw TNotDfamlFileException ("this isn't a DFAML doctype");
00307     }
00308   }
00309   readTransitionTable (tMatcher);
00310   readFooter (tMatcher);
00311   check();
00312 
00313 }  // read()
00314 
00315 
00316 template <typename TState, typename TEvent>
00317 inline void mpcl::automaton::TStreamableDfa<TState, TEvent>::
00318 readFooter (TMatcher& rtSOURCE_REM)
00319 {
00320 
00321   //
00322   //  DFAML end-tag.
00323   //
00324   while ( rtSOURCE_REM.scan (pkcCommentTagPattern, NULL) );
00325   rtSOURCE_REM.scan (pkcDFAML_EndTagPattern, NULL);
00326   while ( rtSOURCE_REM.scan (pkcCommentTagPattern, NULL) );
00327 
00328 }  // readFooter()
00329 
00330 
00331 template <typename TState, typename TEvent>
00332 inline void mpcl::automaton::TStreamableDfa<TState, TEvent>::
00333 readHeader (TMatcher& rtSOURCE_REM)
00334 {
00335 
00336 # define DFA_REMOVE_COMMENTS(rtREM)                           \
00337          {                                                    \
00338            while ( rtREM.scan (pkcCommentTagPattern, NULL) ); \
00339          }
00340 
00341   //
00342   //  !DOCTYPE tag.
00343   //
00344   DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00345   if ( !rtSOURCE_REM.scan (pkcDOCTYPE_TagPattern_1, NULL) )
00346   {
00347     if ( !rtSOURCE_REM.scan (pkcDOCTYPE_TagPattern_2, NULL) )
00348     {
00349       if ( !rtSOURCE_REM.scan (pkcDOCTYPE_TagPattern_3, &ySystem, NULL) )
00350       {
00351         rtSOURCE_REM.scan (pkcDOCTYPE_TagPattern_4, &yPublic, NULL);
00352         yPublic.lowercase();
00353       }
00354     }
00355   }
00356   DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00357   
00358   //
00359   //  DFAML tag.
00360   //
00361   if ( !rtSOURCE_REM.scan (pkcDFAML_TagPattern, &yName, NULL) )
00362   {
00363     throw TNotDfamlFileException ("file doesn't conform DFAML", __FILE__, __LINE__);
00364   }
00365   DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00366   
00367   //
00368   //  Reads DESC tag/DESC body/DESC end-tag.
00369   //
00370   rtSOURCE_REM.scan (pkcDESC_ElementPattern, &yDescription, NULL);
00371   DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00372   
00373 # undef DFA_REMOVE_COMMENTS
00374 
00375 }  // readHeader()
00376 
00377 
00378 template <typename TState, typename TEvent>
00379 inline void mpcl::automaton::TStreamableDfa<TState, TEvent>::
00380 readTransitionTable (TMatcher& rtSOURCE_REM)
00381 {
00382 
00383 # define DFA_REMOVE_COMMENTS(rtREM)                           \
00384          {                                                    \
00385            while ( rtREM.scan (pkcCommentTagPattern, NULL) ); \
00386          }
00387 
00393   typedef
00394     TMap<TPair, TString>
00395     TUnresolvedTransitionMap;
00396 
00397   TUnresolvedTransitionMap                            tUnresolvedTransitionMap;
00398   typename TUnresolvedTransitionMap::const_iterator   I;
00399   TState                                              tStateIterator;
00400   TString                                             yInitialState;
00401   TString                                             yStateEvent;
00402   TString                                             yStateName;
00403   TString                                             yStateNext;
00404   TString                                             yStateType;
00405 
00406   //
00407   //  Reads TRANSTBL tag/DECLARE end-tag.
00408   //  The existence and syntax of this tag is verified by external
00409   //  SGML checking tools.
00410   //
00411   tInitialState = 0;
00412   rtSOURCE_REM.scan (pkcTRANSTBL_TagPattern, &yInitialState, NULL);
00413   
00414   //
00415   //  Dynamicly binds each new state.
00416   //
00417   yInitialState.lowercase();
00418   tStringToStateMap.bind (yInitialState, tInitialState);
00419   DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00420   for (tStateIterator = tInitialState;;++tStateIterator)
00421   {
00422     yStateType.erase();
00423     if ( !rtSOURCE_REM.scan (pkcSTATE_TagPattern_1, &yStateName, NULL) )
00424     {
00425       if ( !rtSOURCE_REM.scan (pkcSTATE_TagPattern_2, &yStateName, &yStateType, NULL) )
00426       {
00427         if ( !rtSOURCE_REM.scan (pkcSTATE_TagPattern_3, &yStateType, &yStateName, NULL) )
00428         {
00429           break;
00430         }
00431       }
00432     }
00433 
00434     //
00435     //  Normalizes name and type, and binds in string to state map.
00436     //
00437     yStateName.lowercase();
00438     yStateType.lowercase();
00439     tStringToStateMap.bind (yStateName, tStateIterator);
00440     
00441     //
00442     //  If this state is a final state, then insert in final
00443     //  states set.
00444     //
00445     if ( yStateType == "final" )
00446     {
00447       tFinalStateSet.insert (tStateIterator);
00448     }
00449     
00450     //
00451     //  Reads transitions.
00452     //
00453     for (;;)
00454     {
00455       DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00456       if ( !rtSOURCE_REM.scan (pkcTRANSIT_ElementPattern_1, &yStateEvent, &yStateNext, NULL) )
00457       {
00458         if ( !rtSOURCE_REM.scan (pkcTRANSIT_ElementPattern_2, &yStateNext, &yStateEvent, NULL) )
00459         {
00460           break;
00461         }
00462       }
00463       
00464       //
00465       //  Inserts the transitions (from state (yStateName) with event
00466       //  (yStateEvent) to state (yStateNext)) into a temporary map.
00467       //  This is due to the fact, that the references to next states
00468       //  can be made before those states were defined.
00469       //
00470       yStateEvent.lowercase();
00471       yStateNext.lowercase();
00472       tUnresolvedTransitionMap.bind
00473       (
00474         std::make_pair (tStateIterator, tStringToEventMap [yStateEvent]) ,
00475         yStateNext
00476       );
00477     }
00478     rtSOURCE_REM.scan (pkcSTATE_EndTagPattern, NULL);
00479     DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00480   }
00481   rtSOURCE_REM.scan (pkcTRANSTBL_EndTagPattern, NULL);
00482   DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00483 
00484   //
00485   //  Resolves next-states names to states.
00486   // 
00487   for (I = tUnresolvedTransitionMap.begin(); ( I != tUnresolvedTransitionMap.end() ) ;++I)
00488   {
00489     tTransitionMap.bind (I->first, tStringToStateMap [I->second]);
00490   }
00491 
00492 # undef DFA_REMOVE_COMMENTS
00493 
00494 }  // readTransitionTable()
00495 
00496 
00497 template <typename TState, typename TEvent>
00498 inline void mpcl::automaton::TStreamableDfa<TState, TEvent>::
00499 start (void)
00500 {
00501 
00502   move (tInitialState);
00503   while (true)
00504   {
00505     if ( !rtEventHandler.isEmpty() )
00506     {
00507       move (next (rtEventHandler.pop()));
00508     }
00509     else
00510     {
00511       if ( !TDeterministicFiniteAutomaton<TState, TEvent>::isFinal (current()) )
00512       {
00513         throw TIntegrityException ("state is not final", __FILE__, __LINE__);
00514       }
00515       break;
00516     }
00517   }
00518   
00519 }  // start()
00520 
00521 
00522 //
00523 //  S E L E C T O R S
00524 //
00525 
00526 
00527 template <typename TState, typename TEvent>
00528 inline void mpcl::automaton::TStreamableDfa<TState, TEvent>::
00529 check (void) const
00530 {
00531 
00532   typename TTransitionMap::const_iterator   I;
00533   typename TStateSet::const_iterator        J;
00534   TStateSet                                 tNoNextStateSet;
00535   TStateSet                                 tSourceStateSet;
00536   TStateSet                                 tTargetStateSet;
00537 
00538   //
00539   //  Calculates no-next states.
00540   //  First, it calculates source and target state set.
00541   //
00542   for (I = tTransitionMap.begin(); ( I != tTransitionMap.end() ) ;++I)
00543   {
00544     tTargetStateSet.insert (I->second);
00545     tSourceStateSet.insert (I->first.first);
00546   }
00547   tNoNextStateSet.clear();
00548 
00549   //
00550   //  And then, the set of no-next states is calculated as:
00551   //
00552   //    N = T - S
00553   //
00554   //  Where N is no-next states set, T is target states set, and S is the source
00555   //  states set. Symbol '-' means relative complement of S in T.
00556   //  If T - S is empty, then N = { initial_state }
00557   //
00558   std::set_difference ( tTargetStateSet.begin()                                     ,
00559                         tTargetStateSet.end()                                       ,
00560                         tSourceStateSet.begin()                                     ,
00561                         tSourceStateSet.end()                                       ,
00562                         std::insert_iterator<TStateSet> ( tNoNextStateSet         ,
00563                                                           tNoNextStateSet.begin() ) );
00564   if ( tNoNextStateSet.empty() )
00565   {
00566     tNoNextStateSet.insert (tInitialState);
00567   }
00568 
00569   //
00570   //  If any element in no-next state set, is not included in final state set,
00571   //  then there is an integrity error.
00572   //
00573   for (J = tNoNextStateSet.begin(); ( J != tNoNextStateSet.end() ) ;++J)
00574   {
00575     if ( tFinalStateSet.find (*J) == tFinalStateSet.end() )
00576     {
00577       throw TIntegrityException ("state is not final and has no next states", __FILE__, __LINE__);
00578     }
00579   }
00580   
00581 }  // check()
00582 
00583 
00584 template <typename TState, typename TEvent>
00585 inline mpcl::text::TString mpcl::automaton::TStreamableDfa<TState, TEvent>::
00586 eventToString (const TEvent& krtSOURCE_EVENT) const
00587   throw (TNotFoundException)
00588 {
00589 
00590   typename TStringToEventMap::const_iterator   I     = tStringToEventMap.begin();
00591   typename TStringToEventMap::const_iterator   ktEnd = tStringToEventMap.end();
00592 
00593   for (; ( I != ktEnd ) ;++I)
00594   {
00595     if ( I->second == krtSOURCE_EVENT )
00596     {
00597       break;
00598     }
00599   }
00600   if ( I == ktEnd )
00601   {
00602     throw TNotFoundException ("event not found", __FILE__, __LINE__);
00603   }
00604   return I->first;
00605 
00606 }  // eventToString()
00607 
00608 
00609 template <typename TState, typename TEvent>
00610 inline mpcl::text::TString mpcl::automaton::TStreamableDfa<TState, TEvent>::
00611 stateToString (const TState& krtSOURCE_STATE) const
00612   throw (TNotFoundException)
00613 {
00614 
00615   typename TStringToStateMap::const_iterator   I     = tStringToStateMap.begin();
00616   typename TStringToStateMap::const_iterator   ktEnd = tStringToStateMap.end();
00617 
00618   for (; ( I != ktEnd ) ;++I)
00619   {
00620     if ( I->second == krtSOURCE_STATE )
00621     {
00622       break;
00623     }
00624   }
00625   if ( I == ktEnd )
00626   {
00627     throw TNotFoundException ("state not found", __FILE__, __LINE__);
00628   }
00629   return I->first;
00630 
00631 }  // stateToString()
00632 
00633 
00634 template <typename TState, typename TEvent>
00635 inline void mpcl::automaton::TStreamableDfa<TState, TEvent>::
00636 writeHeader (std::basic_ostream<char_type, traits_type>& rtTARGET_OSTREAM) const
00637 {
00638 
00639   if ( !ySystem.empty() )
00640   {
00641     rtTARGET_OSTREAM << "<!doctype dfaml system " << ySystem << ">\n";
00642   }
00643   else if ( !yPublic.empty() )
00644   {
00645     rtTARGET_OSTREAM << "<!doctype dfaml public \"" << yPublic << "\">\n";
00646   }
00647   else
00648   {
00649     rtTARGET_OSTREAM << "<!doctype dfaml>\n";
00650   }
00651   rtTARGET_OSTREAM << "<dfaml name=\"" << yName << "\">\n";
00652   if ( !yDescription.empty() )
00653   {
00654     rtTARGET_OSTREAM << "  <desc>" << yDescription << "</desc>\n";
00655   }
00656 
00657 }  // writeHeader()
00658 
00659 
00660 template <typename TState, typename TEvent>
00661 inline void mpcl::automaton::TStreamableDfa<TState, TEvent>::
00662 writeTransitionTable (std::basic_ostream<char_type, traits_type>& rtTARGET_OSTREAM) const
00663 {
00664 
00665   typename TTransitionMap::const_iterator     J;
00666   typename TStringToStateMap::const_iterator  I = tStringToStateMap.begin();
00667 
00668   //
00669   //  Writes TRANSTBL beginning tag.
00670   //
00671   rtTARGET_OSTREAM << "  <transtbl initial=\""
00672                    << stateToString (tInitialState)
00673                    << "\">\n";
00674 
00675   //
00676   //  Iterates over string to state map.
00677   //
00678   for (; ( I != tStringToStateMap.end() ) ;++I)
00679   {
00680     //
00681     //  Writes STATE beginning tag.
00682     //
00683     rtTARGET_OSTREAM << "    <state name=\"" << I->first;
00684     if ( tFinalStateSet.find (I->second) != tFinalStateSet.end() )
00685     {
00686       rtTARGET_OSTREAM << "\" type=\"final\">\n";
00687     }
00688     else
00689     {
00690       rtTARGET_OSTREAM << "\">\n";
00691     }
00692 
00693     //
00694     //  Writes the corresponding TRANSIT tags.
00695     //
00696     for (J = tTransitionMap.begin(); ( J != tTransitionMap.end() ) ;++J)
00697     {
00698       //
00699       //  Compares state value (from string to state list) to state
00700       //  value (from transition map).
00701       //
00702       if ( I->second == J->first.first )
00703       {
00704         rtTARGET_OSTREAM << "      <transit event=\"" 
00705                          << eventToString (J->first.second)
00706                          << "\" next=\"" 
00707                          << stateToString (J->second)
00708                          << "\">\n";
00709       }
00710     }
00711     rtTARGET_OSTREAM << "    </state>\n";
00712   }
00713   rtTARGET_OSTREAM << "  </transtbl>\n";
00714   
00715 }  // writeTransitionTable()
00716 
00717 
00718 #endif  // not _MPCL_AUTOMATON_STREAMABLE_DFA__

Generated on Mon Oct 13 02:35:24 2003 for MPCL by doxygen1.2.18