00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
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
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
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 };
00275
00276 }
00277
00278 }
00279
00280
00281
00282
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
00292
00293
00294
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 }
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
00323
00324 while ( rtSOURCE_REM.scan (pkcCommentTagPattern, NULL) );
00325 rtSOURCE_REM.scan (pkcDFAML_EndTagPattern, NULL);
00326 while ( rtSOURCE_REM.scan (pkcCommentTagPattern, NULL) );
00327
00328 }
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
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
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
00369
00370 rtSOURCE_REM.scan (pkcDESC_ElementPattern, &yDescription, NULL);
00371 DFA_REMOVE_COMMENTS (rtSOURCE_REM);
00372
00373 # undef DFA_REMOVE_COMMENTS
00374
00375 }
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
00408
00409
00410
00411 tInitialState = 0;
00412 rtSOURCE_REM.scan (pkcTRANSTBL_TagPattern, &yInitialState, NULL);
00413
00414
00415
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
00436
00437 yStateName.lowercase();
00438 yStateType.lowercase();
00439 tStringToStateMap.bind (yStateName, tStateIterator);
00440
00441
00442
00443
00444
00445 if ( yStateType == "final" )
00446 {
00447 tFinalStateSet.insert (tStateIterator);
00448 }
00449
00450
00451
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
00466
00467
00468
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
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 }
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 }
00520
00521
00522
00523
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
00540
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
00551
00552
00553
00554
00555
00556
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
00571
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 }
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 }
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 }
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 }
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
00670
00671 rtTARGET_OSTREAM << " <transtbl initial=\""
00672 << stateToString (tInitialState)
00673 << "\">\n";
00674
00675
00676
00677
00678 for (; ( I != tStringToStateMap.end() ) ;++I)
00679 {
00680
00681
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
00695
00696 for (J = tTransitionMap.begin(); ( J != tTransitionMap.end() ) ;++J)
00697 {
00698
00699
00700
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 }
00716
00717
00718 #endif // not _MPCL_AUTOMATON_STREAMABLE_DFA__