#ifndef _TFT_h #define _TFT_h //--------------------------------------------------------------------------- #include #include #include #include #include //#include "top.h" #include "ttrans.h" using namespace std; //--------------------------------------------------------------------------- /// Klasa bazowa przetwornika skończonego. /** \remark Po co ta klasa? Co dotyczy samych przejść, przenieść do TTrans, resztę wcielić do TFT. */ class FT { public: FT() : copy_default(false), print_mode(OO), ttn(0) {}; //print mode enum OUTPUT { II, ///< tylko symbole wejściowe OO, ///< tylko symbole wyjściowe IOIO, ///< symbol wyjściowy po wejściowym OIOI, ///< symbol wyjściowy przed wejściowym IIOO, ///< całe wejście, potem całe wyjście OOII ///< całe wyjście, potem całe wejście }; /// maks długość ścieżki static const unsigned int ftMAXPATH=500; /// maks długość opisu typu symbolu we/wy /** \remark Przenieść do TTrans */ static const unsigned int ftTYPELEN=32; /// specjalny symbol dla wartości 'epsilon' /** \remark Przenieść do TTrans */ static const char ftEPSILON='~'; /// specialny symbol dla wartości 'default' /** \remark Przenieść do TTrans */ static const char ftDEFAULT='@'; /// domyślny symbol wyjściowy (true-'@', flase-'~') /** \remark Przenieść do TTrans(???) */ bool copy_default; /// tryb wyjścia OUTPUT print_mode; /// false, jeśli automat nie ma przejść operator bool() { return (bool)ttn; }; virtual const char* intype() { return itype; }; virtual const char* outtype() { return otype; }; protected: /// liczba elementów tablicy tt unsigned long ttn; /// liczba stanów unsigned long states; /// liczba przejść unsigned long transitions; /// typ symboli wejściowych (napis) /** \remark Przenieść do TTrans(???) */ char itype[ftTYPELEN]; /// typ symboli wyjściowych (napis) /** \remark Przenieść do TTrans(???) */ char otype[ftTYPELEN]; }; //--------------------------------------------------------------------------- /// Szablon przetwornika skończonego /** \param I - typ symbolu wejściowego \param Ipass - typ, jaki ma być użyty przy przekazywaniu symbolu we jako parametru do funkcji (metody), równy \a I lub \a I& \param O - typ symbolu wyjściowego \param Opass - typ, jaki ma być użyty przy przekazywaniu symbolu wy jako parametru do funkcji (metody), równy \a O lub \a O& \param - typ przejścia, musi być podklasą TTrans */ template class TFT : public FT { public: TFT() : FT(), tt(NULL) { setiotypes(); }; /** \name Metody poziomu 1 Poziom przejść. */ //@{ /// Test, czy przejście \a t akceptuje symbol \a in. bool accepts(long t, Ipass in) const; /// Test, czy lista przejść dla aktualnego stanu jest kontynuowana po \a t. bool continued(long t) const; /// Stan, do którego prowadzi przejście \a t. /** \pre !empty(t) */ long next(long t) const; /// Symbol wejściowy przejścia \a t. Ipass input(long t) const; /// Symbol wyjściowy przejścia \a t. Opass output(long t) const; /// Zwraca \c true, jeśli symbolem we przejścia \a t jest epsilon. bool epsi(long t) const; /// Zwraca \c true, jeśli symbolem we przejścia \a t jest symbol domyślny. bool defi(long t) const; /// Zwraca \c true, jeśli symbolem wy przejścia \a t jest epsilon. bool epso(long t) const; /// Zwraca \c true, jeśli symbolem wy przejścia \a t jest symbol domyślny. bool defo(long t) const; /// Indeks przejścia przez \a in. long tra(long t, Ipass in) const; /// Indeks przejścia przez \a in - non-deterministic. long tra_nd(long t, Ipass in, long nth) const; //@} /** \name Poziom 2 Poziom stanów. Stan (indeks stanu) = indeks jego pierwszego przejścia */ //@{ /// Zwraca \c true jeśli stan \a s jest pusty (nie ma z niego przejść). bool empty(long s) const { return tt[s].empty(); } /// Zwraca \c true jeśli stan \a s jest stanem końcowym. bool final(long s) const { return tt[s].final(); } long next(long t, Ipass in) const; //long trans(const I* si, I* so, long& olen) const; long gtra(long s, const I* w, long maxpath=ftMAXPATH) const; //@} /** \name Poziom 3 Poziom ... */ //@{ long cont(long s=-1, I* c=NULL) const; long match(const I* w=NULL, long* p=NULL) const; long match_nd(const I* w=NULL, long* p=NULL) const; long lgstmatch(const I* w, long* p, long& plen, long maxpath=ftMAXPATH) const; /*NOWE*/ long lgstpath(I*& buf, long*& path, long start=0) const; long pref(I*& buf, I sep, long start=0) const; //@} protected: TT* tt; // tablica przejść long prn(const I* si, long* p, O* so) const; void prntt(ostream& os); void sort(); void setiotypes(); // NIE DZIAŁA (dlaczego???) // friend ostream& operator<<(ostream&,const CDFA&); // friend istream& operator>>(istream&,CDFA&); private: long prn_oo(const I* si, long* p, O* so) const; long prn_ioio(const I* si, long* p, O* so) const; long prn_oioi(const I* si, long* p, O* so) const; long prn_iioo(const I* si, long* p, O* so) const; long prn_ooii(const I* si, long* p, O* so) const; }; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- /** stan = indeks pierwszego przejścia state(t) = stan, do którego należy t symbol zerowy = symbol s, dla którego (bool)s zwraca \c false, w przypadku znaków - '\0' */ //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- template inline bool TFT::accepts(long t, Ipass in) const { return tt[t].accepts(in); } /// Test whether the transition list continues after \a t. template inline bool TFT::continued(long t) const { return tt[t].continued(); } /** \pre !empty(t) */ template inline long TFT::next(long t) const { return tt[t].next(); } template inline Ipass TFT::input(long t) const { return tt[t].in(); } template inline Opass TFT::output(long t) const { return tt[t].out(); } template inline bool TFT::epsi(long t) const { return tt[t].epsi(); } template inline bool TFT::defi(long t) const { return tt[t].defi(); } template inline bool TFT::epso(long t) const { return tt[t].epso(); } template inline bool TFT::defo(long t) const { return tt[t].defo(); } /** \param +t - indeks przejścia \param +in - symbol we \return Indeks przjścia (>=\a t) dla bieżącego stanu, które akceptuje symbol we \a in lub -1, jeśli nie ma takiego przejścia */ template long TFT::tra(long t, Ipass in) const { if(t<0 || t>=ttn) return -1; if(empty(t)) return -1; while(!accepts(t,in)) if(continued(t)) t++; else return -1; return t; } //--------------------------------------------------------------------------- /// Indeks przejścia - wersja dla automatu niedeterministycznego. /** \param +t - indeks przejścia \param +in - symbol we \return Indeks przjścia (>=\a t) dla bieżącego stanu, które akceptuje symbol we \a in lub -1, jeśli nie ma takiego przejścia Jeśli nth==0, t1>=t, w przeciwnym razie t1>t. */ template long TFT::tra_nd(long t, Ipass in, long nth) const { if(t<0 || t>=ttn) return -1; if(nth) if(continued(t)) t++; else return -1; else { if(empty(t)) return -1; } while(!accepts(t,in)) if(continued(t)) t++; else return -1; return t; } //} //--------------------------------------------------------------------------- //---------------------------------------------------------------------------- /// Funkcja przejścia. /** \param t - stan \param in - symbol we \return Stan, do którego można przejść z \a t po wpływem symbolu \a in lub -1, jeśli nie ma przejścia przez \a in */ template long TFT::next(long t, Ipass in) const { if(t<0 || (unsigned long)t>=ttn) return -1; if(empty(t)) return -1; while(!accepts(t,in)) if(continued(t)) t++; else { return -1; } return next(t); } //--------------------------------------------------------------------------- //---------------------------------------------------------------------------- /// Uogólniona funkcja przejscia. /** \param +s - stan \param +w - wskaźnik pierwszego elementu ciągu symboli we, zakończonego symbolem zerowym \param maxpath maksymalna długość ścieżki, domyślnie ftMAXPATH \return stan osiągalny z \a s pod wpływem \a w (na ścieżce mogą się pojawić epsilon-przejścia */ template long TFT::gtra(long s, const I* w, long maxpath) const { if(s<0 || (unsigned long)s>=ttn) return -1; long i=0; while(*w) { if(i>maxpath || empty(s)) return -1; while(!accepts(s,*w)) if(continued(s)) s++; else return -1; if(!epsi(s)) w++; s=next(s); i++; } return s; } //---------------------------------------------------------------------------- /// Kontynuacja. /** ... \param +s stan, jeśli -1 - poszukiwane jest następne rozwiązanie \param -c ciąg symboli we ze ścieżki prowadzącej z \a s do stanu końcowego \return długość ciągu \a c (= długość ścieżki) \remark DZIAŁA TYLKO DLA ZNAKÓW!!! EPSILON-PRZEJŚCIA NIEDOZWOLONE!!! */ template long TFT::cont(long s, I* c) const { static unsigned long path[ftMAXPATH]={0}; static unsigned long i=0; static bool more=false; bool found=false; if(s!=-1) { if(s<0 || (unsigned long)s>=ttn) more=false; else { i=0; c[0]=0; path[0]=s; more=true; if(final(s)) found=true; } } while(more && !found) { if(!empty(path[i]) && i0) c[--i]=0; else more=false; }while(more && !continued(path[i])); path[i]=path[i]+1; } if(final(path[i])) { found=true; c[i]=0; } } return i; } //---------------------------------------------------------------------------- /// Dopasowannie. /** \remark Nie zaimplementowane. */ template long TFT::match(const I* w, long* p) const {} //---------------------------------------------------------------------------- /// Dopasowanie niedeterministyczne. /** \param +w - wskaźnik pierwszego elementu ciągu symboli we, zakończonego symbolem zerowym, jeśli NULL - poszukiwane jest następne rozwiązanie \param -p ciąg przejść zakończony -1 \return długość dopasowania (PO CO?) */ template long TFT::match_nd(const I* w, long* p) const { static bool more=false; static I *w0, *wc; static long s=0, *p0, *pc, *pc_bound; bool found=false; if(w) { wc=w0=w; pc=p0=p; more=true; pc_bound=pc+ftMAXPATH; if(final(s=0)) { *pc=-1; return 0; } } while(more) { if(*wc && pc=0) { if(!epsi(*pc)) wc++; s=next(*pc); pc++; } else while(true) { if(pc==p0) { more=false; return -1; } if(!epsi(*(--pc))) wc--; if((*pc=trand(*pc,*wc,1))>=0) { if(!epsi(*pc)) wc++; s=next(*pc); pc++; break; } } if(final(s)) { *pc=-1; return wc-w0; } } return -1; } //---------------------------------------------------------------------------- /// Najdłuższe dopasowanie. /** \param +w wskaźnik pierwszego elementu ciągu symboli wejściowych \param -p ścieżka \param -plen długość ścieżki \param +maxpath maks ddługość ścieżki, domyślnie FT::ftMAXPATH \return długość skonsumowanego wejścia */ template long TFT ::lgstmatch(const I* w, long* p, long& plen, long maxpath) const { long s=0; long t; long i=0; const char* w0=w; long ilen=0; while(*w && i=0) { if(!epsi(t)) w++; s=next(t); i++; *(p++)=t; if(final(s)) { plen=i; ilen=w-w0; } } *p=-1; return ilen; } //---------------------------------------------------------------------------- /// Najdłuższa ścieżka. /** \param +buf wskaźnik pierwszego elementu ciągu symboli wejściowych \param -buf pozycja jeden za skonsumowanym prefiksem \param +path wskaźnik pierwszego elementu wektora przejść \param -path wskaźnik jeden za ostatnim przejściem \return długość skonsumowanego prefiksu (PO CO? LEPIEJ DŁ ŚCIEŻKI) */ template long TFT ::lgstpath(I*& buf, long*& path, long start) const { long s=start; long t; const char* buf0=buf; const long* pathlimit=path+FT::ftMAXPATH; while(*buf && path=0) { if(!epsi(t)) buf++; s=next(t); *(path++)=t; } return buf-buf0; } //---------------------------------------------------------------------------- /// Najdłuższy prefiks. /** \param +buf wskaźnik pierwszego elementu ciągu symboli wejściowych \param -buf pozycja jeden za skonsumowanym prefiksem \param +sep separator \return stan po przejściu przez \a sep \remark Działa tylko dla automatów deterministycznych, minimalnych, eps-wolnych, gdzie dł. ścieżki == dł. dopasowania. */ template long TFT ::pref(I*& buf, I sep, long start) const { static long pathtab[ftMAXPATH]; // static long* path=pathtab; long* path=pathtab; static bool more; long s; if(*buf) // pierwsze wywołanie { if(!lgstpath(buf,path,start)) return -1; --path; more=true; } else // kolejne wywołanie --buf,--path; while(more) if(path>=pathtab) if((s=next(next(*path),sep))>=0) { return s; } else --buf, --path; else { more=false; return -1; } return -1; } //---------------------------------------------------------------------------- /* template long TFT::trans(const I* si, O* so, long& olen) const { long p[ftMAXPATH]; long ilen; long plen; if((ilen=lgstmatch(si,p,plen))>0) olen=prn(si,p,so); else ilen=olen=0; return ilen; } */ //---------------------------------------------------------------------------- template long TFT::prn(const I* si, long* p, O* so) const { switch(print_mode) { case OO: return prn_oo(si,p,so); case IOIO: return prn_ioio(si,p,so); case OIOI: return prn_oioi(si,p,so); case IIOO: return prn_iioo(si,p,so); case OOII: return prn_ooii(si,p,so); } } //---------------------------------------------------------------------------- template long TFT::prn_oo(const I* si, long* p, O* so) const { char* so0=so; while(*p>=0) { long t=*p; if(!epso(t)) { if(defo(t)) *(so++)=*si; else *(so++)=output(t); } if(!epsi(t)) si++; p++; } return so-so0; } //---------------------------------------------------------------------------- template long TFT::prn_ioio(const I* si, long* p, O* so) const { char* so0=so; while(*p>=0) { long t=*p; if(!epsi(t)) *(so++)=*si; if(!epso(t)) if(defo(t)) *(so++)=*si; else *(so++)=output(t); if(!epsi(t)) si++; p++; } return so-so0; } //---------------------------------------------------------------------------- template long TFT::prn_oioi(const I* si, long* p, O* so) const { char* so0=so; while(*p>=0) { long t=*p; if(!epso(t)) { if(defo(t)) *(so++)=*si; else *(so++)=output(t); } if(!epsi(t)) *(so++)=*(si++); p++; } return so-so0; } //---------------------------------------------------------------------------- template long TFT::prn_iioo(const I* si, long* p, O* so) const { const char* si0=si; long* p0=p; char* so0=so; while(*p>=0) { long t=*p; if(!epsi(t)) { *(so++)=*si; si++; } p++; } si=si0; p=p0; while(*p>=0) { long t=*p; if(!epso(t)) if(defo(t)) *(so++)=*si; else *(so++)=output(t); if(!epsi(t)) si++; p++; } return so-so0; } //---------------------------------------------------------------------------- template long TFT::prn_ooii(const I* si, long* p, O* so) const { const char* si0=si; long* p0=p; char* so0=so; while(*p>=0) { long t=*p; if(!epso(t)) { if(defo(t)) *(so++)=*si; else *(so++)=output(t); } if(!epsi(t)) si++; p++; } si=si0; p=p0; while(*p>=0) { long t=*p; if(!epsi(t)) *(so++)=*(si++); p++; } return so-so0; } //--------------------------------------------------------------------------- template void TFT::sort() { long t=0; while(t1) { long eps=-1; long def=-1; for(int i=0; i=0 && epseps) def--; if(def>=0 && def=0) { memmove(tt+t0+def+1,tt+t0+def,tn-eps-2); tt[t-2]=temp; } else { memmove(tt+t0+def+1,tt+t0+def,tn-eps-2); tt[t-1]=temp; } } while(t0 void TFT::setiotypes() { int i=0; const char* it=typeid(I).name(); while(*it) if(*it==' ') { it++; continue; } else itype[i++]=*(it++); itype[i]='\0'; i=0; const char* ot=typeid(O).name(); while(*ot) if(*ot==' ') { ot++; continue; } else otype[i++]=*(ot++); otype[i]='\0'; }; //--------------------------------------------------------------------------- template void TFT::prntt(ostream& os) { for(long i=0; i