Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 07:28
Оценка: 3 (1)
Известная скандальная ветка спровоцировала некоторые, измышлизмы, результаты которых выкладываю здесь. С интересом выслушаю любую критику. Ногами прошу сильно не пиннать, времени на отладку особо не было (писалось в свободное время). С темой
Автор: TepMuHyc
Дата: 13.11.03
ознакомился уже после того как почти все закончил.
P.S. Публикуемый код может использоваться в любом объеме и в любых целях без указания авторства
Re: Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 07:33
Оценка:
Sorry, не разобрался с прикрепленными файлами


#pragma once
#include "TypeLists.h"
#include <memory>

namespace RegExp {

    enum ERROR_STATE {
        esNoError            = 0,
        esLimitError         = 1,
        esNoMatch            = 2,
        esOtherError         = 3
    };

    // Интерфейс результата разбора
    //////////////////////////////////////////////////////////////////////////////////////////////
    class CResIf
    { public:
        virtual ~CResIf() {}
        virtual void AddNode(CResIf* n) = 0;
        virtual void AddValue(const char* v, unsigned size = 0) = 0;
        virtual unsigned GetType(void) const = 0;
        virtual void SetParent(CResIf* p) {}
    };

    // Интерфейс интерпретатора регулярных выражений
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Match может выполняться несколько раз. При передаче src==NULL, продолжается поиск в строке
    //       использованной в предыдущем вызове
    // Reset сбрасывает результат поиска, что позволяет искать пересекающиеся диапазоны
    class CRegExpIf
    { public:
        virtual bool           Match(CResIf*& r, const char* src = NULL, unsigned size = 0) = 0;
        virtual const char*    Catch(unsigned level, unsigned& size) = 0;
        virtual ERROR_STATE  Replace(char* dst, unsigned size) = 0;
        virtual void           Reset(void) = 0;
        virtual CRegExpIf*     Clone(void) const = 0;
    };

    enum PREDICATE_TYPE {
        ptSpace              = 0,       // \s
        ptBegin              = 1,       // ^
        ptEnd                = 2,       // $
        ptSomeChar           = 3,       // .
        ptDigit              = 4,       // \d
        ptWordChar           = 5,       // \w
        ptWordBorder         = 6        // \b
    };

    enum QUANTIFIER_TYPE {
        qtGreed              = 0,
        qtLazy               = 1,
        qtFast               = 2
    };

    // Однократное сопоставление
    //////////////////////////////////////////////////////////////////////////////////////////////
    class O 
    { public:
        O(): IsOnce(true) {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { if (!IsOnce) return -1;
          IsOnce = false;          
          return size;
        }
        const char* Catch(unsigned level, unsigned& size) { return NULL; }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) { return esOtherError; }
        void Clear(void) { IsOnce = true; }
      private:
        bool IsOnce;
    };

    // Последовательность подвыражений
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Должны быть последовательно выполнены все подвыражения
    //
    // 1. Вызывает Head.Match, пока не вернет -1 (для повтора квантификаторов)
    // 2. При неуспехе, вызывает Clear для Head и Tail
    template <class T> class E;
    template <> class E<NullType> 
    { public:
       int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) {return 0;} 
       const char* Catch(unsigned level, unsigned& size) { return NULL; }
       ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) {return esNoError;}
       void Clear(void) {}
    };
    template <class T, class U>
    class E< TypeList<T,U> > 
    { public:
        E(): Head(), Tail() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { int Offset = 0;
          for (;;) {
              Offset = Head.Match(m,s,size,res);
              if (Offset<0) {
                  Clear();
                  return Offset;
              }
              int r = Tail.Match(m,s+Offset,size-Offset,res);
              if (r>=0) {
                  Offset += r;
                  break;
              }
          }
          return Offset;
        }
        const char* Catch(unsigned level, unsigned& size)
        { const char* r = Head.Catch(level,size);
          if (r==NULL)
              r = Tail.Catch(level,size);
          return r;
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { ERROR_STATE r = Head.Replace(m,dst,maxsize);
          if (r!=esNoError) return r;
          return Tail.Replace(m,dst,maxsize);
        }
        void Clear(void) 
        { Head.Clear();
          Tail.Clear();
        }
      private:
        T      Head;
        E< U > Tail;
    };
    template <class T> class E
    { public:
        E(): Elem() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { return Elem.Match(m,s,size,res);
        }
        const char* Catch(unsigned level, unsigned& size)
        { return Elem.Catch(level,size);
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { return Elem.Replace(m,dst,maxsize);
        }
        void Clear(void) 
        { Elem.Clear();
        }
      private:
        E< TL_1(T) > Elem;
    };

    // Дизъюнкция подвыражений
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Должно быть выполнено любое из подвыражений
    template <class T> class D;
    template <> class D<NullType> 
    { public:
       int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) {return -1;} 
       const char* Catch(unsigned level, unsigned& size) { return NULL; }
       void Clear(void) {}
    };
    template <class T, class U>
    class D< TypeList<T,U> > 
    { public:
        D(): Head(), Tail() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { int r = Head.Match(m,s,size,res);
          if (r<0)
              r = Tail.Match(m,s,size,res);
          return r;
        }
        const char* Catch(unsigned level, unsigned& size)
        { const char* r = Head.Catch(level,size);
          if (r==NULL)
              r = Tail.Catch(level,size);
          return r;
        }
        void Clear(void) 
        { Head.Clear();
          Tail.Clear();
        }
      private:
        T      Head;
        D< U > Tail;
    };
    template <class T> class D
    { public:
        D(): Elem() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { int r = Elem.Match(m,s,size,res);
          if (r<0) return 0;
          return r;
        }
        const char* Catch(unsigned level, unsigned& size)
        { return Elem.Catch(level,size);
        }
        void Clear(void) 
        { Elem.Clear();
        }
      private:
        T Elem;
    };

    // Квантификатор
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Проверка r==0 после Elem.Match предназначена для определения утверждений нулевой ширины 
    // под квантификатором
    template <class T, class U = NullType, int mn = 0, int mx = 0, QUANTIFIER_TYPE t = qtFast>
    class Q
    { public:
        Q(): Elem(), Stop(), Cnt(-1) {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { return Match(m,s,size,res,Int2Type<t>());
        }
        const char* Catch(unsigned level, unsigned& size)
        { return Elem.Catch(level,size);
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { for (int i=0;i<mn;i++) {
               ERROR_STATE r = Elem.Replace(m,dst,maxsize);
               if (r!=esNoError) return r;
          }
          return esNoError;
        }
        void Clear(void) 
        { Elem.Clear();
        }
      private:
        template <class S>
        int StopCond(CRegExpIf* m, const char* s, unsigned size, Type2Type<S>)
        { CResIf* r = NULL;
          Stop.Clear();
          return Stop.Match(m,s,size,r);
        }
        template <>
        int StopCond(CRegExpIf* m, const char* s, unsigned size, Type2Type<NullType>)
        { return -1;
        }
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res, Int2Type<qtGreed>)
        { unsigned Offset = 0;
          if (Cnt<0) {
              for (Cnt=0;;) {
                   int r = StopCond(m,s+Offset,size-Offset,Type2Type<U>());
                   if (r>=0) break;
                   Elem.Clear();
                   r = Elem.Match(m,s+Offset,size-Offset,res);
                   if (r<0) return break;
                   Cnt++;
                   Offset += r;
                   if (mx>0)
                       if (Cnt>=mx) break;
              }
              if (Cnt<mn) return -1;
              return Offset;
          }
          if (Cnt<=mn) return -1;
          Cnt--;
          for (int i=0;i<Cnt;i++) {
              Elem.Clear();
              int r = Elem.Match(m,s+Offset,size-Offset,res);
              if (r<0) return -1;
              Offset += r;
          }
          return Offset;
        }        
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res, Int2Type<qtLazy>)
        { unsigned Offset = 0;
          if (mx>0)
              if (Cnt>=mx) return -1;
          for (int i=0;i<Cnt;i++) {
              Elem.Clear();
              int r = Elem.Match(m,s+Offset,size-Offset,res);
              if (r<0) return -1;
              Offset += r;
          }
          for (;;) {
              int r = StopCond(m,s+Offset,size-Offset,Type2Type<U>());
              if (r>=0) break;
              Elem.Clear();
              r = Elem.Match(m,s+Offset,size-Offset,res);
              if (r<=0) break;
              if (Cnt<0) Cnt = 0;
              Cnt++;
              Offset += r;
              if (mx>0)
                  if (Cnt>=mx) break;
          }
          if (Cnt==0) return -1;
          if (Cnt<0)  Cnt = 0;
          if (Cnt<mn) return -1;
          return Offset;
        }        
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res, Int2Type<qtFast>)
        { unsigned Offset = 0;
          if (Cnt>=0) return -1;
          for (Cnt=0;;) {
              int r = StopCond(m,s+Offset,size-Offset,Type2Type<U>());
              if (r>=0) break;
              Elem.Clear();
              r = Elem.Match(m,s+Offset,size-Offset,res);
              if (r<=0) break;
              Cnt++;
              Offset += r;
              if (mx>0)
                  if (Cnt>=mx) break;
          }
          if (Cnt<mn) return -1;
          return Offset;
        }        
        E< T > Elem;
        U      Stop;
        int    Cnt;
    };

    // Захват
    //////////////////////////////////////////////////////////////////////////////////////////////
    template <class T> class B
    { public:
        B(): Elem(), Start(NULL), Size(0) {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { Clear();
          int r = Elem.Match(m,s,size,res);
          if (r>=0) {
              Start = s;
              Size  = size;
              if (res!=NULL)
                  res->AddValue(s,Size);
          }
          return r;
        }
        const char* Catch(unsigned level, unsigned& size)
        { if (level==0) {
              size = Size;
              return Start;
          }
          return Elem.Catch(level-1,size);
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { return Elem.Replace(m,dst,maxsize);
        }
        void Clear(void)
        { Start = NULL;
          Size  = 0;
        }
      private:
        E< T >      Elem;
        const char* Start;
        unsigned    Size;
    };

    // Предикат
    //////////////////////////////////////////////////////////////////////////////////////////////
    // f задает инверсию предиката
    template <PREDICATE_TYPE p, bool f = false> class P;
    template <bool f> class P<ptSpace,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { int r = -1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if (s[0]==' ')  r = 1;
          if (s[0]==0x09) r = 1;
          if (s[0]==0x0A) r = 1;
          if (s[0]==0x0D) r = 1;
          if (f) r = -r;
          return r;
        }
    };
    template <bool f> class P<ptBegin,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { unsigned sz;
          if (O::Match(m,s,0,res)<0) return -1;
          const char* str = m->Catch(0,sz);
          if (str==NULL) return -1;
          int r = -1;
          if (str==s) r = 1;
          if (f) r = -r;
          return r;
        }
    };
    template <bool f> 
    class P<ptEnd,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { if (O::Match(m,s,0,res)<0) return -1;
          if (size==0) return f?-1:0;
          return f?0:-1;
        }
    };
    template <bool f> class P<ptSomeChar,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if (f) return -1;
          return 1;
        }
    };
    template <bool f> class P<ptDigit,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { int r = -1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if ((s[0]>='0')&&(s[0]<='9')) r = 1;
          if (f) r = -r;
          return r;
        }
    };
    template <bool f> class P<ptWordChar,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { int r = -1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if (s[0]=='_') r = 1;
          if ((s[0]>='a')&&(s[0]<='z'))         r = 1;
          if ((s[0]>='A')&&(s[0]<='Z'))         r = 1;
          if ((s[0]>='а')&&(s[0]<='я'))         r = 1;
          if ((s[0]>='А')&&(s[0]<='Я'))         r = 1;
          if ((s[0]=='ё')||(s[0]=='Ё'))         r = 1;
          if (P<ptDigit>().Match(m,s,1,res)==1) r = 1;
          if (f) r = -r;
          return r;
        }
    };
    template <bool f> class P<ptWordBorder,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { unsigned sz;
          if (O::Match(m,s,0,res)<0) return -1;
          if (size==0) return f?-1:0;
          const char* str = m->Catch(0,sz);
          if (str==NULL) return -1;
          if (str==s) return f?-1:0;
          const char* p = s-1;
          if ((P<ptWordChar>().Match(m,p,1,res)==1)&&
              (P<ptWordChar>().Match(m,s,1,res)!=1)) return f?-1:0;
          if ((P<ptWordChar>().Match(m,p,1,res)!=1)&&
              (P<ptWordChar>().Match(m,s,1,res)==1)) return f?-1:0;
          return f?0:-1;
        }
    };

    // Диапазон символов
    //////////////////////////////////////////////////////////////////////////////////////////////
    // f задает инверсию диапазона
    template <int start,int end = 0, bool f = false> 
    class C: public O
    { public:
        C(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { int r = 1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if (s[0]<start) r = -1;
          if (end>start) {
              if (s[0]>end) r = -1;
          } else {
              if (s[0]>start) r = -1;
          }
          if (f) r = -r;
          return r;
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { if (maxsize<1) return esLimitError;
          if ((end!=0)&&(start!=end)) return esOtherError;
          dst[0] = start;
          dst++;
          maxsize--;
          return esNoError;
        }
    };

    // Символьный набор
    //////////////////////////////////////////////////////////////////////////////////////////////
    // f задает инверсию набора
    template <class T, bool f = false> class S;
    template <bool f> class S<NullType,f> 
    { public:
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { return true; 
        } 
    };
    template <class T, class U, bool f>
    class S< TypeList<T,U>, f>: public O
    { public:
        S< TypeList<T,U>, f>(): O(), Head(), Tail() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { int r = -1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if ((Head.Match(m,s,1,res)==1)||
              (Tail.Match(m,s,1,res)==1)) r = 1;
          if (f) r = -r;
          return r;
        }
      private:
        T       Head;
        S< U >  Tail;
    };
    template <class T, bool f>
    class S
    { public:
        S(): Elem() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { return Elem.Match(m,s,size,res);
        }
      private:
        S<TL_1(T),f> Elem;
    };

    // Переменная
    //////////////////////////////////////////////////////////////////////////////////////////////
    template <int level> 
    class V: public O
    { public:
        V(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { unsigned sz;
          const char* v = m->Catch(level,sz);
          if (v==NULL) return -1;
          if (sz>size) return -1;
          if (memcmp(s,v,sz)==0) return sz;
          return -1;
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { unsigned sz;
          const char* v = m->Catch(level);
          if (v==NULL) return esNoMatch;
          if (sz>maxsize) return esLimitError;
          memcpy(dst,v,sz);
          dst += sz;
          maxsize -= sz;
          return esNoError; 
        }
    };

    // Рекурсивное применение выражения
    //////////////////////////////////////////////////////////////////////////////////////////////
    template <class T = NullType, class U = NullType> class R;
    template <>
    class R<NullType,NullType>: public O
    { public:
        R(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { if (size==0) return 0;
          std::auto_ptr<CRegExpIf> p(m->Clone());
          return p->Match(res,s,size);
        }
    };
    template <class T, class U>
    class R: public CRegExpIf,
             public O
    { public: 
        R(): CRegExpIf(), Elem(), Found(-1) {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { Match(res,s,size);
          return Found;
        }
        virtual bool Match(CResIf*& r, const char* src = NULL, unsigned size = 0)
        { CreateNode(r,Type2Type<U>());
          Found = Elem.Match(this,src,size,r);
          return (Found>=0);
        }
        virtual const char* Catch(unsigned level, unsigned& size) {return NULL;}
        virtual ERROR_STATE Replace(char* dst, unsigned size) {return esOtherError;}
        virtual void Reset(void) {}
        virtual CRegExpIf* Clone(void) const { return new R<T,U>; }
      private:
        template <class S>
        void CreateNode(CResIf*& r, Type2Type<S>)
        { CResIf* p = new S;
          if (r!=NULL) r->AddNode(p);
          r = p;
        }
        template <>
        void CreateNode(CResIf*& r, Type2Type<NullType>) {}
        E< T > Elem;
        int    Found;
    };

    // Интерпретатор регулярных выражений
    //////////////////////////////////////////////////////////////////////////////////////////////
    template < class T, class U = NullType>
    class CRegExp: public CRegExpIf
    { public:
        CRegExp(): Expr(), Repl(), Start(NULL), Str(NULL), Size(0), Found(-1) {}

        virtual bool           Match(CResIf*& r, const char* src = NULL, unsigned size = 0);
        virtual const char*    Catch(unsigned level, unsigned& size);
        virtual ERROR_STATE  Replace(char* dst, unsigned size);
        virtual void           Reset(void) { Found = -1; }
        virtual CRegExpIf*     Clone(void) const { return new CRegExp<T,U>; }

      private:
        E< T >       Expr;
        E< U >       Repl;
        const char*  Start;
        const char*  Str;
        unsigned     Size;

      public:
        int          Found;
    };

    template <class T, class U>
    bool CRegExp<T,U>::Match(CResIf*& r, const char* src, unsigned size) 
    { 
      if (src!=NULL) {
          Str   = src;
          Start = src;    
          Size  = size;
          if (Size==0) 
              Size = (unsigned)strlen(src);
      } else {
          if (Str==NULL) return false;
          int step = (Found<=0)?1:Found;
          if (Size<=(unsigned)step) return false;
          Str  += step;
          Size -= step;
      }
      Reset();
      while ((Found=Expr.Match(this,Str,Size,r))==-1) {
          if (Size<=1) return false;
          Str++;
          Size--;
      }
      return true;
    }

    template <class T, class U>
    ERROR_STATE CRegExp<T,U>::Replace(char* dst, unsigned size)
    { return Repl.Replace(this,dst,size);
    }

    template <class T, class U>
    const char* CRegExp<T,U>::Catch(unsigned level, unsigned& size)
    {
      if (level==0) {
          size = (Found<0)?Size:Found;
          return (Found<0)?Start:Str;
      }
      return Expr.Catch(level-1,size);
    }

}



#pragma once
#include "RegExp.h"

namespace RegExp {

typedef C<'0','9'>                                   Digit;
typedef C<'A','F'>                                   HexUpper;
typedef C<'a','f'>                                   HexLower;
typedef D_2(HexUpper, HexLower)                      Hex;
typedef C<'0','1'>                                   Max1w0;
typedef C<'0','2'>                                   Max2w0;
typedef C<'0','4'>                                   Max4w0;
typedef C<'0','5'>                                   Max5w0;
typedef C<'1','2'>                                   Max2;
typedef C<'0','5'>                                   Max5;

// Короткая форма представления сетевой маски
typedef E_2(Max2, Digit)                             Octet29;
typedef E_2(C<3>, Max2w0)                            Octet32;
typedef D_3(Digit, Octet29, Octet32)                 IPMaskShort;

typedef Q<Max1w0, NullType, 0, 1>                    IPForm1p1;
typedef Q<Digit,  NullType, 0, 1>                    IPForm1p2;
typedef E_3(IPForm1p1, Digit, IPForm1p2)             IPForm1;
typedef E_3(C<'2'>, Max4w0, Digit)                   IPForm2;
typedef E_3(C<'2'>, C<'5'>, Max5w0)                  IPForm3;
typedef B< D_3(IPForm1, IPForm2, IPForm3) >          IPOctet;
typedef Q< E_2(C<'.'>, IPOctet), NullType, 3, 3 >    IPTail;
typedef E_2(IPOctet, IPTail)                         IPAddress;

// Mac-адрес
typedef B< Q<Hex, NullType, 2, 2> >                  MacOctet;
typedef Q< E_2(C<':'>, MacOctet), NullType, 5, 5 >   MacTail;
typedef E_2(MacOctet, MacTail)                       MacAddress;

}



#pragma once

class NullType {};

template <int n>
struct Int2Type
{
    enum { value = n };
};

template <class T>
struct Type2Type
{
    typedef T result;
};

template <class T, class U>
struct TypeList
{
    typedef T Head;
    typedef U Tail;
};

#define TL_1(T1) TypeList<T1, NullType >
#define TL_2(T1, T2) TypeList<T1, TL_1(T2) >
#define TL_3(T1, T2, T3) TypeList<T1, TL_2(T2, T3) >
#define TL_4(T1, T2, T3, T4) TypeList<T1, TL_3(T2, T3, T4) >
#define TL_5(T1, T2, T3, T4, T5) TypeList<T1, TL_4(T2, T3, T4, T5) >
#define TL_6(T1, T2, T3, T4, T5, T6) TypeList<T1, TL_5(T2, T3, T4, T5, T6) >
#define TL_7(T1, T2, T3, T4, T5, T6, T7) TypeList<T1, TL_6(T2, T3, T4, T5, T6, T7) >
#define TL_8(T1, T2, T3, T4, T5, T6, T7, T8) TypeList<T1, TL_7(T2, T3, T4, T5, T6, T7, T8) >
#define TL_9(T1, T2, T3, T4, T5, T6, T7, T8, T9) TypeList<T1, TL_8(T2, T3, T4, T5, T6, T7, T8, T9) >
#define TL_10(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) TypeList<T1, TL_9(T2, T3, T4, T5, T6, T7, T8, T9, T10) >

#define C_1(C1) E<TL_1(C<'C1'>) >
#define C_2(C1, C2) E<TL_2(C<'C1'>,C<'C2'>) >
#define C_3(C1, C2, C3) E<TL_3(C<'C1'>,C<'C2'>,C<'C3'>) >
#define C_4(C1, C2, C3, C4) E<TL_4(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>) >
#define C_5(C1, C2, C3, C4, C5) E<TL_5(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>) >
#define C_6(C1, C2, C3, C4, C5, C6) E<TL_6(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>) >
#define C_7(C1, C2, C3, C4, C5, C6, C7) E<TL_7(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>,C<'C7'>) >
#define C_8(C1, C2, C3, C4, C5, C6, C7, C8) E<TL_8(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>,C<'C7'>,C<'C8'>) >
#define C_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) E<TL_9(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>,C<'C7'>,C<'C8'>,C<'C9'>) >
#define C_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) E<TL_10(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>,C<'C7'>,C<'C8'>,C<'C9'>,C<'C10'>) >

#define E_1(C1) E< C1 >
#define E_2(C1, C2) E< TL_2(C1, C2) >
#define E_3(C1, C2, C3) E< TL_3(C1, C2, C3) >
#define E_4(C1, C2, C3, C4) E< TL_4(C1, C2, C3, C4) >
#define E_5(C1, C2, C3, C4, C5) E< TL_5(C1, C2, C3, C4, C5) >
#define E_6(C1, C2, C3, C4, C5, C6) E< TL_6(C1, C2, C3, C4, C5, C6) >
#define E_7(C1, C2, C3, C4, C5, C6, C7) E< TL_7(C1, C2, C3, C4, C5, C6, C7) >
#define E_8(C1, C2, C3, C4, C5, C6, C7, C8) E< TL_8(C1, C2, C3, C4, C5, C6, C7, C8) >
#define E_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) E< TL_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) >
#define E_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) E< TL_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) >

#define D_1(C1) D< C1 >
#define D_2(C1, C2) D< TL_2(C1, C2) >
#define D_3(C1, C2, C3) D< TL_3(C1, C2, C3) >
#define D_4(C1, C2, C3, C4) D< TL_4(C1, C2, C3, C4) >
#define D_5(C1, C2, C3, C4, C5) D< TL_5(C1, C2, C3, C4, C5) >
#define D_6(C1, C2, C3, C4, C5, C6) D< TL_6(C1, C2, C3, C4, C5, C6) >
#define D_7(C1, C2, C3, C4, C5, C6, C7) D< TL_7(C1, C2, C3, C4, C5, C6, C7) >
#define D_8(C1, C2, C3, C4, C5, C6, C7, C8) D< TL_8(C1, C2, C3, C4, C5, C6, C7, C8) >
#define D_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) D< TL_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) >
#define D_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) D< TL_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) >

#define S_1(C1) S< C1 >
#define S_2(C1, C2) S< TL_2(C1, C2) >
#define S_3(C1, C2, C3) S< TL_3(C1, C2, C3) >
#define S_4(C1, C2, C3, C4) S< TL_4(C1, C2, C3, C4) >
#define S_5(C1, C2, C3, C4, C5) S< TL_5(C1, C2, C3, C4, C5) >
#define S_6(C1, C2, C3, C4, C5, C6) S< TL_6(C1, C2, C3, C4, C5, C6) >
#define S_7(C1, C2, C3, C4, C5, C6, C7) S< TL_7(C1, C2, C3, C4, C5, C6, C7) >
#define S_8(C1, C2, C3, C4, C5, C6, C7, C8) S< TL_8(C1, C2, C3, C4, C5, C6, C7, C8) >
#define S_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) S< TL_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) >
#define S_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) S< TL_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) >
Re[2]: Метапрограммирование C++ (RegExp)
От: frogkiller Россия  
Дата: 06.11.07 09:25
Оценка:
Здравствуйте, Gluk_Kazan, Вы писали:

G_K>Sorry, не разобрался с прикрепленными файлами


G_K>
...
G_K>


Много букв, очень сложно понять. Приведи пример использования.
Кстати, ты видел GRETA'у?
Имхо сильно приятнее буста.

PS. С прикриплёнными файлами такая засада — сервер не понинимает mime типа .cpp или .h.
Замени их на .cpp.txt или .h.txt соответственно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[3]: Метапрограммирование C++ (RegExp)
От: Кодт Россия  
Дата: 06.11.07 10:25
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>PS. С прикриплёнными файлами такая засада — сервер не понинимает mime типа .cpp или .h.

F>Замени их на .cpp.txt или .h.txt соответственно.

Либо зазипуй.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re: Метапрограммирование C++ (RegExp)
От: jazzer Россия Skype: enerjazzer
Дата: 06.11.07 10:30
Оценка:
Здравствуйте, Gluk_Kazan, Вы писали:

G_K>Известная скандальная ветка спровоцировала некоторые, измышлизмы, результаты которых выкладываю здесь. С интересом выслушаю любую критику. Ногами прошу сильно не пиннать, времени на отладку особо не было (писалось в свободное время). С темой
Автор: TepMuHyc
Дата: 13.11.03
ознакомился уже после того как почти все закончил.

G_K>P.S. Публикуемый код может использоваться в любом объеме и в любых целях без указания авторства

http://boost.org/doc/html/xpressive.html
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Метапрограммирование C++ (RegExp)
От: Vain Россия google.ru
Дата: 06.11.07 10:31
Оценка: :)
Здравствуйте, Кодт, Вы писали:

F>>PS. С прикриплёнными файлами такая засада — сервер не понинимает mime типа .cpp или .h.

F>>Замени их на .cpp.txt или .h.txt соответственно.
К>Либо зазипуй.
Говорят
Автор: Vain
Дата: 05.11.07
google не пропустит
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[3]: Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 10:39
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>Много букв, очень сложно понять. Приведи пример использования.

F>Кстати, ты видел GRETA'у?
F>Имхо сильно приятнее буста.

Помимо предотвращения застоя ума, побудительные причины были следующие:

1. Попытаться применить приемы, описанные Александреску для создания чего нибудь практичного и полезного и осознание через это упомянутых приемов
2. Заявление Хenocefal-а о том, что одним из мерил универсальности языка он рассматривает возможность реализации Compile Time RegExp-ов

Собственно понятно, почему это невозможно и что возможно на самом деле. Хотелось прочувствовать на собственной шкуре чего именно не хватает для полного счастья в шаблонах и маросах. В результате родилось ... Самих реализаций RegExp-ов разумеется пруд пруди (у меня собственных есть парочка), интересно было сформировать конкретную машинку в Compile Time.
Пример использования во втором блоке кода, кусочек Utils.h для разбора IP-адресов, дат и т.п. Можно сделать парсер арифметических выражений, скриптового языка, XML или ASN. По поводу последнего, опять же попытка самоосознания ограничений RegExp-ов и расширение их с целью поддержки рекурсии.

P.S. Знаю, что лисапед, но в настоящий момент сие относится к категории Just For Fun
P.P.S. К первому посту пытался прицепить .zip, но видно что-то недонажимал. После скруля шибко непривычно
Re[5]: Метапрограммирование C++ (RegExp)
От: Кодт Россия  
Дата: 06.11.07 11:48
Оценка:
Здравствуйте, Vain, Вы писали:

V>Говорят
Автор: Vain
Дата: 05.11.07
google не пропустит


Гугл не пропустит, если ты зип к письму прикрепишь и на submit@rsdn.ru пошлёшь. А если залить файл на сервер RSDN и дать ссылку — то какие сложности и при чём здесь гугл?
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: Метапрограммирование C++ (RegExp)
От: frogkiller Россия  
Дата: 06.11.07 11:51
Оценка:
Здравствуйте, Gluk_Kazan, Вы писали:

G_K>Пример использования во втором блоке кода, кусочек Utils.h для разбора IP-адресов, дат и т.п. Можно сделать парсер арифметических выражений, скриптового языка, XML или ASN. По поводу последнего, опять же попытка самоосознания ограничений RegExp-ов и расширение их с целью поддержки рекурсии.


И как его вызывать?
RegExp::IPAddress ipaddr;
int res = ipaddr.Match(&ipaddr, "127.0.0.1", 10); //не компиляется.
int res = ipaddr.Match("127.0.0.1", 10); //не компиляется.


Я ожидал использования наподобие:
regex::rpattern pat( "^((\\d|\\*|\\?|#|[a-fA-F])+%{0,1}|%)$" ); // собственно, паттерн
regex::match_results results;
regex::match_results::backref_type br = pat.match( str, results ); //str - анализируемая строка


G_K>P.S. Знаю, что лисапед, но в настоящий момент сие относится к категории Just For Fun


Имхо очень интересный "лисапед"

G_K>P.P.S. К первому посту пытался прицепить .zip, но видно что-то недонажимал. После скруля шибко непривычно


Не, не надо прикреплять к посту, их надо ручками загрузить в свой профайл, и уже потом в посте давать ссылку.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[5]: Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 12:18
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>И как его вызывать?


    CRegExp<IPAddress> m;
    CResIf* r = NULL;
    if (m.Match(r,"127.0.0.1",9))
    { ...
    }


Честно признаюсь, что с такими сложными выражениями еще не отлаживал
Урывками им занимаюсь, а Utils вообще прямо сейчас в качестве примера набросал.
Хочется следующее отладить:

typedef Q< P<ptSpace> > Space;
typedef B< Q< P<ptSomeChar>, C<'"'> > > AttrValue;
typedef E_4( Space, C<'"'>,
             AttrValue, C<'"'>
           ) XMLVal;
typedef B< Q< P<ptWordChar>, NullType, 1 > > AttrIdent;
typedef D< E_3(Space, C<','>, R<>) > ListTail;
typedef R< E_6( Space, AttrIdent,
                Space, C<'='>, XMLVal,
                ListTail
              ),CXMLAttr
         > XMLAttrs;
typedef B< Q< S_2(P<ptWordChar>, C<':'> ), NullType, 1 > > TagIdent;
typedef E_2( Space, C_2(/,>) ) CloseTag;
typedef Q< P<ptSomeChar>, C<'<'> > BeginTag;
typedef C_2(<,/) CloseBody;
typedef B < Q < E_2(BeginTag , R<>),
                E_2(Space, CloseBody)
              >
          > TagBody;
typedef D_2 ( CloseTag,
              E_9( Space, C<'>'>, TagBody, 
                   Space, CloseBody, 
                   Space, V<1>, Space, C<'>'>
                 )
            ) EndTag;
typedef R< E_6( Space, C<'<'>,
                Space, TagIdent, XMLAttrs, 
                EndTag
              ), CXMLTag
         > XMLTag;


Re[5]: Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 12:27
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>Я ожидал использования наподобие:

F>
F>regex::rpattern pat( "^((\\d|\\*|\\?|#|[a-fA-F])+%{0,1}|%)$" ); // собственно, паттерн
F>


Этт она еще не умеет, но на ее основе можно построить парсер строки регулярного выражения, который на выходе будет давать динамическую структуру (дерево), аналогичную тем, которые сейчас строятся в статике. И эту машинку можно будет нашпиговывать различными фичами PCRE, типа предпросмотра или кластеризации без захвата и т.п. Благо модульность это позволяет.
Та самописная машинка, которую мы сейчас используем в продакте в принципе не расширяема подобным образом. Слишком монолитна
Re[5]: Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 12:30
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>Не, не надо прикреплять к посту, их надо ручками загрузить в свой профайл, и уже потом в посте давать ссылку.


ссылка
Re[2]: Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 12:42
Оценка:
Исправление:


    template <bool f> class P<ptWordBorder,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { unsigned sz;
          if (O::Match(m,s,0,res)<0) return -1;
          const char* str = m->Catch(0,sz);
          if (str==NULL) return -1;
          const char* p = s-1;
          if (str==s) {
              if ((size>0)&&(P<ptWordChar>().Match(m,s,1,res)==1)) return f?-1:0;
              return f?0:-1;
          }
          if (size==0) {
              if ((str!=s)&&(P<ptWordChar>().Match(m,p,1,res)==1)) return f?-1:0;
              return f?0:-1;
          }
          if ((P<ptWordChar>().Match(m,p,1,res)==1)&&
              (P<ptWordChar>().Match(m,s,1,res)!=1)) return f?-1:0;
          if ((P<ptWordChar>().Match(m,p,1,res)!=1)&&
              (P<ptWordChar>().Match(m,s,1,res)==1)) return f?-1:0;
          return f?0:-1;
        }
    };
Re[6]: Метапрограммирование C++ (RegExp)
От: frogkiller Россия  
Дата: 06.11.07 12:50
Оценка:
Здравствуйте, Gluk_Kazan, Вы писали:

Компиляю в MSVC 7.1:
RegExp::CRegExp<RegExp::IPAddress> m;
RegExp::CResIf* r = NULL;
int res = m.Match(r,"127.0.0.1",9);

нормально компиляется.
Результат выполнения:

res == 0
r == NULL

Понять, почему так произошло, довольно проблематично, сам понимаешь, сплошная рекурсия.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[7]: Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 13:03
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>res == 0

F>r == NULL

F>Понять, почему так произошло, довольно проблематично, сам понимаешь, сплошная рекурсия.


Да не, можно нормально отлаживать, если привыкнуть. То что СЫРО факт.
Как будет время посмотрю. D я еще не отлаживал, а в IPAddress оно активно используется.
А r и должен быть равен NULL, там только R формирует что-то, если ей тип скормить, это
результат разбора. B в текущий узел (если он сформирован R) значения добавляют.

Идея в том, чтоб статическую часть после окончательной отладки не трогать, а парсеры строить из ранее отлаженных кирпичиков
Re: оффтоп
От: Lorenzo_LAMAS  
Дата: 06.11.07 13:53
Оценка: +1
Здравствуйте, Gluk_Kazan, Вы писали:

G_K>Известная скандальная ветка

Ксеноцефал своей манерой общения очень кого-то напоминает. И на рсдн был похожий (ИМХО) человек, точнее, ников было несколько, а вот сколько за ними было человек реально —
Of course, the code must be complete enough to compile and link.
Re[2]: оффтоп
От: Gluk_Kazan  
Дата: 07.11.07 05:17
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Ксеноцефал своей манерой общения очень кого-то напоминает. И на рсдн был похожий (ИМХО) человек, точнее, ников было несколько, а вот сколько за ними было человек реально —


Как минимум два ника. Читал.
Какая разница если вдуматься ?
Просто есть мнение, в чем-то обоснованное
Есть нелюбовь почему-то именно к C++ никам
Есть жуткая ненависть к кодерам
Есть заметный опыт в программировании
Есть обожание LISP-а и всего что с ним связано

В конце концов, иы всегда будем видеть только виртуала. Какая разница, кто за ним стоит ?
Re[2]: оффтоп
От: Gluk_Kazan  
Дата: 07.11.07 05:32
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Ксеноцефал своей манерой общения очень кого-то напоминает.


Кстати, если бы меня кто то из кодеров в привате спросил, почему за программизм на C++ мало платят, я бы возможно и похлеще ответил
А то что за такой же онанизм на яве платят (в настоящий момент) в среднем больше — так это РЫНОК.
И еще, в Казани к примеру, LISP-ом семью не прокормишь и далеко не все так легки на подъем как Ксеня, чтобы такую работу найти.
Ностальгизм по старым добрым временам когда программисты ценились на вес золота — это конечно хорошо, но запросы рынка надо как то удовлетворять
Re[3]: оффтоп
От: Lorenzo_LAMAS  
Дата: 07.11.07 10:13
Оценка:
G_K>Какая разница если вдуматься ?

Я назвал свое сообщение "оффтоп", так что да, оффтоп. Разница? Ну мне его высказывания показались интересными, хотя аргументация у него, имхо, слишком часто так себе.

G_K>Просто есть мнение, в чем-то обоснованное

G_K>Есть нелюбовь почему-то именно к C++ никам
G_K>Есть жуткая ненависть к кодерам
G_K>Есть заметный опыт в программировании
G_K>Есть обожание LISP-а и всего что с ним связано

Ага, и еще он физик по образованию, что кого-то напоминает

Большинство его оппонентов как-то очень злостно тормозили, впечатление такое, что они нарочно ему подыгрывали. Он часто говорит о компиляторах и о более эффективном коде, генерируемом не С++ компиляторами (и о том что в С++ получится крайне неэффективный код) — мог бы и привести конкретные примеры, он же, по его словам, занимается компиляторами. Детали были бы интересны. А то все какие-то общие словеса про потенциальное распараллеливание и т.д.

G_K>В конце концов, иы всегда будем видеть только виртуала. Какая разница, кто за ним стоит ?

Просто возникло впечатление, что несколько раз в разных форумах под разными никами был один и тот же человек. И стало интересно, только ли у меня такое впечатление
Of course, the code must be complete enough to compile and link.
Re[4]: оффтоп
От: Gluk_Kazan  
Дата: 07.11.07 10:39
Оценка: +1
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Ага, и еще он физик по образованию, что кого-то напоминает


На мой взгляд имеются некоторые нестыковочки (в частности в отношении к Linux-у и к .Net-у)
у меня создалось впечатление, что это все-таки плод коллективного разума.
Но стиль в упомянутых вами никах безусловно соблюден
Еще про панславянизм надо было задвинуть и была бы полная картина

L_L>Большинство его оппонентов как-то очень злостно тормозили, впечатление такое, что они нарочно ему подыгрывали.


Просто никто из более менее серьезных оппонентов с ним не связывался (IMHO)
Да и вообще он по большей части дело говорил (если отвлечься от формы)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.