source: CMT/v1r25p20140131/source/cmt_regexp.cxx @ 693

Last change on this file since 693 was 664, checked in by rybkin, 10 years ago

merge -r 646:663 HEAD

  • Property svn:eol-style set to native
File size: 36.5 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// Modified by Grigory Rybkin
5// See the complete license in cmt_license.txt "http://www.cecill.info".
6//-----------------------------------------------------------
7
8#include "cmt_std.h"
9#include "cmt_regexp.h"
10#include "cmt_vector.h"
11#include "cmt_system.h"
12
13#include "cmt.h"
14//----------------------------------------------------------
15//
16//  Declarations
17//
18//----------------------------------------------------------
19
20static int tab_level = 0;
21
22static void tab ()
23{
24  for (int i = 0; i < tab_level; i++)
25    {
26      cerr << "  ";
27    }
28}
29
30//----------------------------------------------------------
31class cmt_regexp_node
32{
33public:
34  static cmt_regexp_node& null ();
35  static int node_count ();
36 
37  cmt_regexp_node ();
38  virtual ~cmt_regexp_node ();
39 
40  virtual const cmt_regexp::iterator match (const cmt_string& text, 
41                                            int pos) const;
42  virtual bool is_char () const;
43  virtual bool is_many_node () const;
44
45  virtual void dump () const;
46 
47private:
48  static int _node_count;
49};
50//----------------------------------------------------------
51
52//----------------------------------------------------------
53class cmt_char_node : public cmt_regexp_node
54{
55public:
56  cmt_char_node (char c);
57 
58  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
59 
60  bool is_char () const;
61  operator char ();
62
63  void dump () const;
64 
65private:
66  char _c;
67};
68//----------------------------------------------------------
69
70//----------------------------------------------------------
71class cmt_string_node : public cmt_regexp_node
72{
73public:
74  cmt_string_node (const cmt_string& s);
75 
76  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
77
78  void dump () const;
79   
80private:
81  cmt_string _s;
82};
83//----------------------------------------------------------
84
85//----------------------------------------------------------
86class cmt_char_list_node : public cmt_regexp_node
87{
88public:
89  cmt_char_list_node (cmt_string list);
90 
91  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
92
93  void dump () const;
94 
95protected:
96  cmt_string _list;
97  cmt_string _choices;
98};
99//----------------------------------------------------------
100
101//----------------------------------------------------------
102class cmt_not_char_list_node : public cmt_char_list_node
103{
104public:
105  cmt_not_char_list_node (cmt_string list);
106 
107  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
108
109  void dump () const;
110};
111//----------------------------------------------------------
112
113//----------------------------------------------------------
114class cmt_any_node : public cmt_regexp_node
115{
116public:
117  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
118
119  void dump () const;
120};
121//----------------------------------------------------------
122
123//----------------------------------------------------------
124class cmt_zero_one : public cmt_regexp_node
125{
126public:
127  cmt_zero_one (cmt_regexp_node* n);
128  ~cmt_zero_one ();
129 
130  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
131
132  void dump () const;
133 
134protected:
135  cmt_regexp_node* _node;
136};
137//----------------------------------------------------------
138
139
140
141//----------------------------------------------------------
142class cmt_begin_node : public cmt_regexp_node
143{
144public:
145  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
146
147  void dump () const;
148};
149//----------------------------------------------------------
150
151//----------------------------------------------------------
152class cmt_end_node : public cmt_regexp_node
153{
154public:
155  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
156
157  void dump () const;
158};
159//----------------------------------------------------------
160
161//----------------------------------------------------------
162class cmt_regexp_node_set : public cmt_regexp_node
163{
164public:
165  cmt_regexp_node_set ();
166  cmt_regexp_node_set (cmt_regexp_node_set* father);
167  ~cmt_regexp_node_set ();
168 
169  cmt_regexp_node_set* father ();
170  void clear ();
171  void push (cmt_regexp_node* n);
172  cmt_regexp_node* pop ();
173  cmt_regexp_node* top () const;
174  int nodes () const;
175  const cmt_regexp_node* nodeAt (int index) const;
176  bool parentheses () const;
177  void set_parentheses (bool value);
178  virtual void reduce ();
179
180  virtual void dump () const;
181  void dump (const cmt_string& title) const;
182 
183protected:
184  cmt_regexp_node_set* _father;
185  cmt_vector<cmt_regexp_node*> _nodes;
186  bool _parentheses;
187};
188//----------------------------------------------------------
189
190//----------------------------------------------------------
191class cmt_and_node : public cmt_regexp_node_set
192{
193public:
194  cmt_and_node ();
195  cmt_and_node (cmt_regexp_node_set* father);
196 
197  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
198  void reduce ();
199  void fill (cmt_and_node& other, int start_index);
200
201  void dump () const;
202};
203//----------------------------------------------------------
204
205//----------------------------------------------------------
206class cmt_or_node : public cmt_regexp_node_set
207{
208public:
209  cmt_or_node (cmt_regexp_node_set* father);
210 
211  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
212
213  void dump () const;
214};
215//----------------------------------------------------------
216
217//----------------------------------------------------------
218cmt_regexp_node& cmt_regexp_node::null ()
219{
220  static cmt_regexp_node null_instance;
221 
222  return (null_instance);
223}
224//----------------------------------------------------------
225
226//----------------------------------------------------------
227class cmt_many_node : public cmt_regexp_node
228{
229public:
230  bool is_many_node () const;
231  void install (cmt_and_node& other, int index);
232  void reduce ();
233
234  void dump () const;
235 
236protected:
237  cmt_many_node (cmt_regexp_node* n);
238  virtual ~cmt_many_node ();
239  cmt_regexp_node* _node;
240  cmt_and_node _follower;
241};
242//----------------------------------------------------------
243
244//----------------------------------------------------------
245class cmt_zero_more : public cmt_many_node
246{
247public:
248  cmt_zero_more (cmt_regexp_node* n);
249 
250  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
251
252  void dump () const;
253};
254//----------------------------------------------------------
255
256//----------------------------------------------------------
257class cmt_one_more : public cmt_many_node
258{
259public:
260  cmt_one_more (cmt_regexp_node* n);
261
262  const cmt_regexp::iterator match (const cmt_string& text, int pos) const;
263
264  void dump () const;
265};
266//----------------------------------------------------------
267
268
269//----------------------------------------------------------
270//
271//  Implementation
272//
273//----------------------------------------------------------
274
275//----------------------------------------------------------
276cmt_regexp_node::cmt_regexp_node ()
277{
278  _node_count++;
279}
280
281cmt_regexp_node::~cmt_regexp_node ()
282{
283  _node_count--;
284}
285
286int cmt_regexp_node::node_count ()
287{
288  return (_node_count);
289}
290
291const cmt_regexp::iterator cmt_regexp_node::match (const cmt_string& /*text*/, 
292                                                   int /*pos*/) const
293{
294  return (cmt_regexp::iterator::null());
295}
296
297bool cmt_regexp_node::is_char () const
298{
299  return (false);
300}
301
302bool cmt_regexp_node::is_many_node () const
303{
304  return (false);
305}
306
307void cmt_regexp_node::dump () const
308{
309}
310
311int cmt_regexp_node::_node_count = 0;
312//----------------------------------------------------------
313
314//----------------------------------------------------------
315cmt_char_node::cmt_char_node (char c)
316{
317  _c = c;
318}
319
320const cmt_regexp::iterator cmt_char_node::match (const cmt_string& text, 
321                                                 int pos) const
322{
323  if ((pos < 0) || (pos > text.size ())) 
324    {
325      return (cmt_regexp::iterator::null ());
326    }
327
328  char c = text[pos];
329
330  if (c == _c)
331    {
332      return (cmt_regexp::iterator (pos, 1));
333    }
334 
335  return (cmt_regexp::iterator::null ());
336}
337
338bool cmt_char_node::is_char () const
339{
340  return (true);
341}
342
343cmt_char_node::operator char ()
344{
345  return (_c);
346}
347
348void cmt_char_node::dump () const
349{
350  tab (); cerr << "char>(" << this << ") c=" << _c << endl;
351}
352
353//----------------------------------------------------------
354
355//----------------------------------------------------------
356cmt_string_node::cmt_string_node (const cmt_string& s)
357{
358  _s = s;
359}
360
361const cmt_regexp::iterator cmt_string_node::match (const cmt_string& text, 
362                                                   int pos) const
363{
364  if ((pos < 0) || (pos > text.size ())) 
365    {
366      return (cmt_regexp::iterator::null ());
367    }
368
369  int length = _s.size ();
370 
371  cmt_string s = text.substr (pos, length);
372 
373  if ((length == 0) || (s == _s))
374    {
375      return (cmt_regexp::iterator (pos, length));
376    }
377 
378  return (cmt_regexp::iterator::null ());
379}
380
381void cmt_string_node::dump () const
382{
383  tab (); cerr << "string (" << this << ") s=[" << _s << "]" << endl;
384}
385
386//----------------------------------------------------------
387
388//----------------------------------------------------------
389cmt_char_list_node::cmt_char_list_node (cmt_string list)
390{
391  _list = list;
392 
393  _choices = "";
394 
395  char c;
396  int i;
397 
398  for (i = 0; i < list.size (); i++)
399    {
400      c = list[i];
401     
402      switch (c)
403        {
404        case '-':
405          i++;
406          {
407            char c1 = _choices[_choices.size () - 1];
408            char c2 = list[i];
409            int j;
410            int j0 = (c1 < c2) ? c1 : c2;
411            int j1 = (c1 > c2) ? c1 : c2;
412            for (j = j0; j <= j1; j++)
413              {
414                _choices += j;
415              }
416          }
417          break;
418        case '\\':
419          i++;
420          c = list[i];
421          switch (c)
422            {
423            case '[':
424            case ']':
425            case '(':
426            case ')':
427            case '.':
428            case '*':
429            case '?':
430            case '^':
431            case '$':
432            case '\\':
433              c = '\\';
434              break;
435            case 'r':
436              c = '\r';
437              break;
438            case 't':
439              c = '\t';
440              break;
441            case 'n':
442              c = '\n';
443              break;
444            default:
445              break;
446            }
447        default:
448          _choices += c;
449          break;
450        }
451    }
452}
453
454const cmt_regexp::iterator cmt_char_list_node::match (const cmt_string& text, 
455                                                      int pos) const
456{
457  if ((pos < 0) || (pos > text.size ())) 
458    {
459      return (cmt_regexp::iterator::null ());
460    }
461
462  char c = text[pos];
463
464  int i;
465 
466  for (i = 0; i < _choices.size (); i++)
467    {
468      if (c == _choices[i]) return (cmt_regexp::iterator (pos, 1));
469    }
470 
471  return (cmt_regexp::iterator::null ());
472}
473
474void cmt_char_list_node::dump () const
475{
476  tab (); cerr << "char_list (" << this << ") list=[" << _list << "] choices=[" << _choices << "]" << endl;
477}
478
479//----------------------------------------------------------
480
481//----------------------------------------------------------
482cmt_not_char_list_node::cmt_not_char_list_node (cmt_string list) : 
483  cmt_char_list_node (list)
484{
485}
486
487const cmt_regexp::iterator cmt_not_char_list_node::match (const cmt_string& text, 
488                                                          int pos) const
489{
490  if ((pos < 0) || (pos > text.size ())) 
491    {
492      return (cmt_regexp::iterator::null ());
493    }
494
495  char c = text[pos];
496
497  int i;
498
499  for (i = 0; i < _choices.size (); i++)
500    {
501      if (c == _choices[i]) return (cmt_regexp::iterator::null ());
502    }
503 
504  return (cmt_regexp::iterator (pos, 1));
505}
506
507void cmt_not_char_list_node::dump () const
508{
509  tab (); cerr << "not_char_list (" << this << ") list=[" << _list << "] choices=[" << _choices << "]" << endl;
510}
511
512
513//----------------------------------------------------------
514
515//----------------------------------------------------------
516const cmt_regexp::iterator cmt_any_node::match (const cmt_string& text, 
517                                                int pos) const
518{
519  if ((pos < 0) | (pos >= text.size ())) 
520    {
521      return (cmt_regexp::iterator::null ());
522    }
523 
524  return (cmt_regexp::iterator (pos, 1));
525}
526
527void cmt_any_node::dump () const
528{
529  tab (); cerr << "any (" << this << ") " << endl;
530}
531
532//----------------------------------------------------------
533
534//----------------------------------------------------------
535cmt_zero_one::cmt_zero_one (cmt_regexp_node* n) : _node (n)
536{
537}
538
539cmt_zero_one::~cmt_zero_one ()
540{
541  delete _node;
542}
543
544const cmt_regexp::iterator cmt_zero_one::match (const cmt_string& text, 
545                                                int pos) const
546{
547  if ((pos < 0) || (pos > text.size ())) 
548    {
549      return (cmt_regexp::iterator::null ());
550    }
551
552  int total = 0;
553
554  if (pos < text.size ())
555    {
556      const cmt_regexp::iterator it = _node->match (text, pos);
557      if (it != cmt_regexp::iterator::null ())
558        {
559          total += it._length;
560          pos += it._length;
561        }
562    }
563 
564  return (cmt_regexp::iterator (pos, total));
565}
566
567void cmt_zero_one::dump () const
568{
569  tab (); cerr << "zero_one (" << this << ") " << endl;
570
571  if (_node != 0)
572    {
573      tab_level++;
574      _node->dump ();
575      tab_level--;
576    }
577}
578
579//----------------------------------------------------------
580
581//----------------------------------------------------------
582cmt_many_node::cmt_many_node (cmt_regexp_node* n) : _node (n)
583{
584}
585
586bool cmt_many_node::is_many_node () const
587{
588  return (true);
589}
590
591cmt_many_node::~cmt_many_node ()
592{
593  delete _node;
594}
595
596void cmt_many_node::install (cmt_and_node& other, int start_index)
597{
598  _follower.fill (other, start_index);
599}
600
601void cmt_many_node::reduce ()
602{
603  _follower.reduce ();
604}
605
606void cmt_many_node::dump () const
607{
608  tab (); cerr << "many (" << this << ") " << endl;
609
610  if (_node != 0) 
611    {
612      tab_level++;
613      _node->dump ();
614      tab_level--;
615    }
616
617  tab_level++;
618  _follower.dump ();
619  tab_level--;
620}
621
622//----------------------------------------------------------
623
624
625
626//----------------------------------------------------------
627cmt_zero_more::cmt_zero_more (cmt_regexp_node* n) : cmt_many_node (n)
628{
629}
630
631const cmt_regexp::iterator cmt_zero_more::match (const cmt_string& text, 
632                                                 int pos) const
633{
634  if ((pos < 0) || (pos > text.size ())) 
635    {
636      return (cmt_regexp::iterator::null ());
637    }
638
639  int total = 0;
640
641  //
642  // we are at : x*y
643  //
644
645  int saved_pos = -1;
646  int saved_total = -1;
647
648  do
649    {
650      const cmt_regexp::iterator itx = _node->match (text, pos);
651      const cmt_regexp::iterator ity = _follower.match (text, pos);
652
653      if ((itx == cmt_regexp::iterator::null ()) &&
654          (ity == cmt_regexp::iterator::null ())) 
655        {
656          //
657          // There is neither x nor y. We move back to the last
658          // succesful match for y.
659          //
660          if (saved_pos >= 0)
661            {
662              //
663              // We had once a y.
664              //
665              pos = saved_pos;
666              total = saved_total;
667            }
668          else
669            {
670              //
671              // We never had any y !
672              //
673              return (cmt_regexp::iterator::null ());
674            }
675
676          break;
677        }
678
679      if (itx == cmt_regexp::iterator::null ())
680        {
681          //
682          // There is a y but no x anymore, fine, we can quit.
683          //
684          total += ity._length;
685          pos += ity._length;
686          break;
687        }
688
689      if (ity != cmt_regexp::iterator::null ())
690        {
691          //
692          //  We have both x and y. We save the current pos and total,
693          // and then skip this x.
694          //
695          saved_total = total + ity._length;
696          saved_pos = pos + ity._length;
697        }
698      total += itx._length;
699      pos += itx._length;
700    } while (true);
701 
702  return (cmt_regexp::iterator (pos, total));
703}
704
705void cmt_zero_more::dump () const
706{
707  tab (); cerr << "zero_more (" << this << ") " << endl;
708
709  if (_node != 0)
710    {
711      tab_level++;
712      _node->dump ();
713      tab_level--;
714    }
715
716  _follower.dump ();
717}
718
719//----------------------------------------------------------
720
721//----------------------------------------------------------
722cmt_one_more::cmt_one_more (cmt_regexp_node* n) : cmt_many_node (n)
723{
724}
725
726const cmt_regexp::iterator cmt_one_more::match (const cmt_string& text, 
727                                                int pos) const
728{
729  if ((pos < 0) || (pos > text.size ())) 
730    {
731      return (cmt_regexp::iterator::null ());
732    }
733
734  int total = 0;
735
736  //
737  // we are at : x+y
738  //
739
740  int saved_pos = -1;
741  int saved_total = -1;
742  bool at_least_one = false;
743
744  do
745    {
746      const cmt_regexp::iterator itx = _node->match (text, pos);
747      const cmt_regexp::iterator ity = _follower.match (text, pos);
748
749      if ((itx == cmt_regexp::iterator::null ()) &&
750          (ity == cmt_regexp::iterator::null ())) 
751        {
752          //
753          // There is neither x nor y. We move back to the last
754          // succesful match for y.
755          //
756          if (saved_pos >= 0)
757            {
758              //
759              // We had once a y.
760              //
761              pos = saved_pos;
762              total = saved_total;
763            }
764          else
765            {
766              //
767              // We never had any y !
768              //
769              return (cmt_regexp::iterator::null ());
770            }
771
772          break;
773        }
774
775      if (itx == cmt_regexp::iterator::null ())
776        {
777          //
778          // There is a y but no x anymore, fine, we can quit.
779          //
780          total += ity._length;
781          pos += ity._length;
782          break;
783        }
784
785      if (ity != cmt_regexp::iterator::null ())
786        {
787          //
788          //  We have both x and y. We save the current pos and total,
789          // and then skip this x.
790          //
791          saved_total = total + ity._length;
792          saved_pos = pos + ity._length;
793        }
794
795      total += itx._length;
796      pos += itx._length;
797
798      at_least_one = true;
799    } while (true);
800 
801  if (!at_least_one) return (cmt_regexp::iterator::null ());
802 
803  return (cmt_regexp::iterator (pos, total));
804}
805
806void cmt_one_more::dump () const
807{
808  tab (); cerr << "one_more (" << this << ") " << endl;
809
810  if (_node != 0)
811    {
812      tab_level++;
813      _node->dump ();
814      tab_level--;
815    }
816
817  tab_level++;
818  _follower.dump ();
819  tab_level--;
820}
821
822//----------------------------------------------------------
823
824
825
826//----------------------------------------------------------
827const cmt_regexp::iterator cmt_begin_node::match (const cmt_string& /*text*/, 
828                                                  int pos) const
829{
830  if (pos == 0) return (cmt_regexp::iterator (pos, 0));
831  return (cmt_regexp::iterator::null ());
832}
833
834void cmt_begin_node::dump () const
835{
836  tab (); cerr << "begin (" << this << ") " << endl;
837}
838//----------------------------------------------------------
839
840//----------------------------------------------------------
841const cmt_regexp::iterator cmt_end_node::match (const cmt_string& text,
842                                                int pos) const
843{
844  if (pos == text.size ()) return (cmt_regexp::iterator (pos, 0));
845  return (cmt_regexp::iterator::null ());
846}
847
848void cmt_end_node::dump () const
849{
850  tab (); cerr << "end (" << this << ") " << endl;
851}
852//----------------------------------------------------------
853
854//----------------------------------------------------------
855cmt_regexp_node_set::cmt_regexp_node_set () : _father (0)
856{
857  _parentheses = false;
858}
859
860cmt_regexp_node_set::cmt_regexp_node_set (cmt_regexp_node_set* father) : _father (father)
861{
862  if (father != 0) father->push (this);
863  _parentheses = false;
864}
865
866cmt_regexp_node_set::~cmt_regexp_node_set ()
867{
868  clear ();
869}
870
871cmt_regexp_node_set* cmt_regexp_node_set::father ()
872{
873  return (_father);
874}
875
876void cmt_regexp_node_set::clear ()
877{
878  int i;
879 
880  for (i = 0; i < _nodes.size (); i++)
881    {
882      cmt_regexp_node* n = _nodes[i];
883      delete n;
884    }
885  _nodes.clear ();
886}
887
888void cmt_regexp_node_set::push (cmt_regexp_node* n)
889{
890  _nodes.push_back (n);
891}
892
893cmt_regexp_node* cmt_regexp_node_set::pop ()
894{
895  if (_nodes.size () == 0) return (&cmt_regexp_node::null ());
896 
897  int index = _nodes.size () - 1;
898 
899  cmt_regexp_node* n = _nodes[index];
900  _nodes.erase (index);
901 
902  return (n);
903}
904
905cmt_regexp_node* cmt_regexp_node_set::top () const
906{
907  if (_nodes.size () == 0) return (&cmt_regexp_node::null ());
908 
909  int index = _nodes.size () - 1;
910 
911  cmt_regexp_node* n = _nodes[index];
912 
913  return (n);
914}
915
916int cmt_regexp_node_set::nodes () const
917{
918  return (_nodes.size ());
919}
920
921const cmt_regexp_node* cmt_regexp_node_set::nodeAt (int index) const
922{
923  return (_nodes[index]);
924}
925
926bool cmt_regexp_node_set::parentheses () const
927{
928  return (_parentheses);
929}
930
931void cmt_regexp_node_set::set_parentheses (bool value)
932{
933  _parentheses = value;
934}
935
936void cmt_regexp_node_set::reduce ()
937{
938}
939
940void cmt_regexp_node_set::dump () const
941{
942  tab (); cerr << "regexp_node_set (" << this << ") " << endl;
943}
944
945void cmt_regexp_node_set::dump (const cmt_string& title) const
946{
947  tab (); cerr << "Set (" << this << ") father=" << _father << " pars=" << _parentheses << endl;
948
949  for (int i = 0; i < _nodes.size (); i++)
950    {
951      cmt_regexp_node* n = _nodes[i];
952      if (n != 0)
953        {
954          if (i > 0)
955            {
956              tab (); cerr << title << endl;
957            }
958          tab_level++;
959          n->dump ();
960          tab_level--;
961        }
962    }
963
964  tab (); cerr << "EndSet (" << this << ")" << endl;
965}
966//----------------------------------------------------------
967
968//----------------------------------------------------------
969cmt_and_node::cmt_and_node () : cmt_regexp_node_set ()
970{
971}
972
973cmt_and_node::cmt_and_node (cmt_regexp_node_set* father) : cmt_regexp_node_set (father)
974{
975}
976
977const cmt_regexp::iterator cmt_and_node::match (const cmt_string& text, 
978                                                int pos) const
979{
980  if ((pos < 0) || (pos > text.size ())) 
981    {
982      return (cmt_regexp::iterator::null ());
983    }
984
985  if (_nodes.size () == 0) return (cmt_regexp::iterator (pos, 0));
986
987  int i;
988  int total = 0;
989  int p = pos;
990 
991  bool dbg = false;
992  if (Cmt::get_debug ()) dbg = CmtSystem::testenv ("CMTTESTREGEXP");
993
994  if (dbg) {tab (); cerr << "match and (" << this << ") pos=" << pos << endl;}
995
996  for (i = 0; i < _nodes.size (); i++)
997    {
998      cmt_regexp_node* n = _nodes[i];
999
1000      if (dbg) tab_level++;
1001      const cmt_regexp::iterator it = n->match (text, p);
1002      if (dbg) tab_level--;
1003
1004      if (dbg) {tab (); cerr << "  -> it(" << n << ") p=" << it._pos << " l=" << it._length << endl;}
1005     
1006      if (it == cmt_regexp::iterator::null ()) return (it);
1007     
1008      total += it._length;
1009      p += it._length;
1010    }
1011
1012  // All nodes match
1013 
1014  return (cmt_regexp::iterator (pos, total));
1015}
1016
1017void cmt_and_node::reduce ()
1018{
1019  if (_nodes.size () < 2) return;
1020 
1021  char c = ' ';
1022  cmt_string s = "";
1023  cmt_vector<cmt_regexp_node*> new_nodes;
1024
1025  //
1026  // We loop once too much in order to finish the possibly accumulated
1027  // string at the end.
1028  //
1029  for (int i = 0; i <= _nodes.size (); i++)
1030    {
1031      cmt_regexp_node* n = 0;
1032
1033      if (i < _nodes.size ()) n = _nodes[i];
1034
1035      if ((i >= _nodes.size ()) || (!n->is_char ()))
1036        {
1037          if (s.size () == 1)
1038            {
1039              //
1040              // Too bad there was only one char node to consider
1041              // let's put it back as a char node !
1042              //
1043              new_nodes.push_back (new cmt_char_node (c));
1044              s = "";
1045            }
1046          else if (s.size () > 1)
1047            {
1048              //
1049              // We have real reduction here sonce there was several
1050              // consecutive char nodes.
1051              //
1052              new_nodes.push_back (new cmt_string_node (s));
1053              s = "";
1054            }
1055
1056          if (i >= _nodes.size ()) break;
1057        }
1058
1059      if (n->is_char ())
1060        {
1061          //
1062          // We are now trying to compact those char nodes.
1063          //
1064          cmt_char_node& cn = *((cmt_char_node*) n);
1065          c = (char) cn;
1066          s += c;
1067          delete n;
1068          _nodes[i] = 0;
1069        }
1070      else if (n->is_many_node ())
1071        {
1072          cmt_many_node& mn = *((cmt_many_node*) n);
1073          mn.install (*this, i + 1);
1074          mn.reduce ();
1075          new_nodes.push_back (n);
1076          break;
1077        }
1078      else
1079        {
1080          new_nodes.push_back (n);
1081        }
1082    }
1083 
1084  _nodes = new_nodes;
1085}
1086
1087void cmt_and_node::fill (cmt_and_node& other, int start_index)
1088{
1089  if ((start_index < 0) || (start_index > other.nodes ())) return;
1090
1091  for (int i = start_index; i < other.nodes (); i++)
1092    {
1093      cmt_regexp_node* n = other._nodes[i];
1094      push (n);
1095    }
1096}
1097
1098void cmt_and_node::dump () const
1099{
1100  cmt_regexp_node_set::dump ("and");
1101}
1102
1103//----------------------------------------------------------
1104
1105//----------------------------------------------------------
1106cmt_or_node::cmt_or_node (cmt_regexp_node_set* father) : cmt_regexp_node_set (father)
1107{
1108}
1109
1110const cmt_regexp::iterator cmt_or_node::match (const cmt_string& text, 
1111                                               int pos) const
1112{
1113  if ((pos < 0) || (pos >= text.size ())) 
1114    {
1115      return (cmt_regexp::iterator::null ());
1116    }
1117
1118  if (_nodes.size () == 0) return (cmt_regexp::iterator (pos, 0));
1119 
1120  bool dbg = false;
1121  if (Cmt::get_debug ()) dbg = CmtSystem::testenv ("CMTTESTREGEXP");
1122
1123  if (dbg) {tab (); cerr << "match or (" << this << ") pos=" << pos << endl;}
1124
1125  int i;
1126
1127  int longest = 0;
1128
1129  cmt_regexp::iterator result = cmt_regexp::iterator::null ();
1130 
1131  for (i = 0; i < _nodes.size (); i++)
1132    {
1133      const cmt_regexp_node* n = _nodes[i];
1134     
1135      if (dbg) tab_level++;
1136      const cmt_regexp::iterator it = n->match (text, pos);
1137      if (dbg) tab_level--;
1138
1139      if (it._length > longest)
1140        {
1141          longest = it._length;
1142          result = it;
1143        }
1144
1145      //        at least one or-ed expression matches
1146      // if (it != cmt_regexp::iterator::null ()) return (it);
1147    }
1148 
1149  return (result);
1150}
1151
1152void cmt_or_node::dump () const
1153{
1154  cmt_regexp_node_set::dump ("or");
1155}
1156
1157//----------------------------------------------------------
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171//----------------------------------------------------------
1172cmt_regexp::cmt_regexp ()
1173{
1174  _root = 0;
1175}
1176
1177//----------------------------------------------------------
1178cmt_regexp::cmt_regexp (const cmt_string& expression)
1179{
1180  _root = 0;
1181  set (expression);
1182}
1183
1184//----------------------------------------------------------
1185void cmt_regexp::set (const cmt_string& expression)
1186{
1187  if (_root != 0)
1188    {
1189      delete _root;
1190      _root = 0;
1191    }
1192
1193  //
1194  // The root is the cmt_or_node which will be returned. It is
1195  // the top of the hierarchy.
1196  //
1197  //  top is the running cmt_and_node.
1198  //
1199  cmt_regexp_node_set* or_root = 0;
1200  cmt_regexp_node_set* top_and = 0;
1201 
1202  // abcd
1203  // ab|cd
1204  // a|b|cd
1205  // a|b*|cd
1206  // a|b*|cd?e
1207  //
1208  // exp     : and
1209  //         | exp '|' and
1210  //
1211  // and     : unary
1212  //         | unary and
1213  //
1214  // unary   : primary '*'
1215  //         | primary '?'
1216  //
1217  // primary : '[' opt_begin opt_chars opt_end ']'
1218  //         | '^'
1219  //         | '$'
1220  //         | char
1221  //         | '(' exp ')'
1222  //
1223 
1224  {
1225    //
1226    // First we build an cmt_or_node (corresponding to the
1227    // first grammatical rule)
1228    //
1229    //  Then cmt_and_nodes are pushed into it.
1230    //  and standard nodes are pushed into the running (top_and) cmt_and_node
1231    //
1232    or_root = new cmt_or_node (0);
1233    top_and = new cmt_and_node (or_root);
1234  }
1235 
1236  int i;
1237 
1238  for (i = 0; i < expression.size (); i++)
1239    {
1240      char c = expression[i];
1241      switch (c)
1242        {
1243        case '[':
1244          {
1245            //
1246            // The case is
1247            //
1248            //  exp   : '['     char ... ']'
1249            //  exp   : '[' '^' char ... ']'
1250            //
1251
1252            if (i >= expression.size ()) 
1253              {
1254                // syntax error : unbalanced '['
1255                delete or_root;
1256                return;
1257              }
1258            i++;
1259           
1260            int i0 = i;
1261           
1262            bool done = false;
1263            bool has_not = false;
1264           
1265            cmt_string choices = "";
1266           
1267            for (; i < expression.size (); i++)
1268              {
1269                c = expression[i];
1270                switch (c)
1271                  {
1272                  case ']':
1273                    done = true;
1274                    break;
1275                  case '^':
1276                    if (i == i0) has_not = true;
1277                    else choices += c;
1278                    break;
1279                  case '\\':
1280                    choices += c;
1281                    if (i >= expression.size ())
1282                      {
1283                        // syntax error : unbalanced '[' and unfinished
1284                        // escape sequence
1285                        delete or_root;
1286                        return;
1287                      }
1288                    i++;
1289                    c = expression[i];
1290                    choices += c;
1291                    break;
1292                  default:
1293                    choices += c;
1294                    break;
1295                  }
1296                if (done) break;
1297              }
1298           
1299            if (!done)
1300              {
1301                // syntax error : unbalanced '['
1302                delete or_root;
1303                return;
1304              }
1305            if (has_not)
1306              top_and->push (new cmt_not_char_list_node (choices));
1307            else       
1308              top_and->push (new cmt_char_list_node (choices));
1309          }
1310          break;
1311        case '*':
1312          {
1313            //
1314            //  exp : exp '*'
1315            //
1316            if (top_and->nodes () == 0)
1317              {
1318                // Syntax error : '*' is not preceded by an expression
1319                delete or_root;
1320                return;
1321              }
1322           
1323            cmt_regexp_node* n = top_and->pop ();
1324            top_and->push (new cmt_zero_more (n));
1325          }
1326          break;
1327        case '+':
1328          {
1329            //
1330            //  exp : exp '+'
1331            //
1332            if (top_and->nodes () == 0)
1333              {
1334                // Syntax error : '+' is not preceded by an expression
1335                delete or_root;
1336                return;
1337              }
1338           
1339            cmt_regexp_node* n = top_and->pop ();
1340            top_and->push (new cmt_one_more (n));
1341          }
1342          break;
1343        case '?':
1344          {
1345            //
1346            //  exp : exp '?'
1347            //
1348            if (top_and->nodes () == 0)
1349              {
1350                // Syntax error : '?' is not preceded by an expression
1351                delete or_root;
1352                return;
1353              }
1354           
1355            cmt_regexp_node* n = top_and->pop ();
1356            top_and->push (new cmt_zero_one (n));
1357          }
1358          break;
1359        case '.':
1360          //
1361          //  exp : '.'
1362          //
1363          top_and->push (new cmt_any_node ());
1364          break;
1365        case '(':
1366          {
1367            //
1368            //  exp : '(' exp ')'
1369            //
1370            if (top_and->parentheses ())
1371              {
1372                // This should never happen.
1373                delete or_root;
1374                return;
1375              }
1376           
1377            top_and->set_parentheses (true);
1378           
1379            //
1380            // A new complete expression is started.
1381            //  -> do as for top_and parsing.
1382            //
1383           
1384            top_and = new cmt_and_node (new cmt_or_node (top_and));
1385          }
1386          break;
1387        case ')':
1388          {
1389            //
1390            //  exp : '(' exp ')'
1391            //
1392           
1393            // top_and is the cmt_and_node into which new nodes are pushed.
1394            cmt_regexp_node_set* or_node = top_and->father ();
1395            if (or_node == 0) 
1396              {
1397                // This should never happen : top_and should always be
1398                // at least an cmt_and_node hanging at an cmt_or_node
1399                delete or_root;
1400                return;
1401              }
1402           
1403            //
1404            // The last cmt_and_node was empty, thus we had either '()' or '(...|)'
1405            //
1406           
1407            if (top_and->nodes () == 0) 
1408              {
1409                delete (or_node->pop ());
1410              }
1411            else
1412              {
1413                top_and->reduce ();
1414              }
1415           
1416            top_and = or_node->father ();
1417           
1418            if (top_and == 0)
1419              {
1420                // Syntax error : too many ')'
1421                delete or_root;
1422                return;
1423              }
1424           
1425            //
1426            // top_and is now the previous running cmt_and_node where the '('
1427            // was originally met its top_and node contains the parenthesized
1428            // sub expression  If this one is empty, (due to an empty '()'
1429            // expression) then it may simply be discarded.
1430            //
1431           
1432            if (!top_and->parentheses ())
1433              {
1434                // Syntax error : too many ')'
1435                delete or_root;
1436                return;
1437              }
1438           
1439            top_and->set_parentheses (false);
1440           
1441            cmt_regexp_node* unique = 0;
1442            if (or_node->nodes () == 1)
1443              {
1444                cmt_regexp_node_set* and_node = (cmt_regexp_node_set*) or_node->top ();
1445                if (and_node->nodes () == 1)
1446                  {
1447                    unique = and_node->pop ();
1448                    delete (or_node->pop ());
1449                  }
1450                else if (and_node->nodes () == 0)
1451                  {
1452                    delete (or_node->pop ());
1453                  }
1454              }
1455           
1456            if (or_node->nodes () == 0) delete (top_and->pop ());
1457            if (unique != 0) top_and->push (unique);
1458          }
1459         
1460          break;
1461        case '|':
1462          {
1463            //
1464            //  exp : exp '|' exp
1465            //
1466
1467            cmt_regexp_node_set* or_node = top_and->father ();
1468           
1469            top_and->reduce ();
1470           
1471            //
1472            // or is the father cmt_or_node, which only contains cmt_and_nodes
1473            //
1474           
1475            const cmt_regexp_node_set* and_node = (cmt_regexp_node_set*) or_node->top ();
1476            if (and_node->nodes () == 0)
1477              {
1478                // the previous node was empty.
1479                // we may discard it
1480                or_node->pop ();
1481              }
1482           
1483            top_and = new cmt_and_node (or_node);
1484          }
1485          break;
1486        case '^':
1487          //
1488          //  exp : '^'
1489          //
1490          top_and->push (new cmt_begin_node ());
1491          break;
1492        case '$':
1493          //
1494          //  exp : '$'
1495          //
1496          top_and->push (new cmt_end_node ());
1497          break;
1498        case '\\':
1499          if (i >= expression.size ())
1500            {
1501              delete or_root;
1502              return;
1503            }
1504          i++;
1505          c = expression[i];
1506          switch (c)
1507            {
1508            case '[':
1509            case ']':
1510            case '(':
1511            case ')':
1512            case '.':
1513            case '*':
1514            case '?':
1515            case '^':
1516            case '$':
1517            case '\\':
1518              break;
1519            case 'r':
1520              c = '\r';
1521              break;
1522            case 't':
1523              c = '\t';
1524              break;
1525            case 'n':
1526              c = '\n';
1527              break;
1528            default:
1529              break;
1530            }
1531        default:
1532          top_and->push (new cmt_char_node (c));
1533          break;
1534        }
1535    }
1536 
1537  if (or_root != 0)
1538    {
1539      cmt_regexp_node_set* and_node = (cmt_regexp_node_set*) or_root->top ();
1540     
1541      if (or_root->nodes () == 1)
1542        {
1543          //
1544          // Check whether there is at least one non-empty
1545          // cmt_and_node
1546          //
1547          if (and_node->nodes () == 0)
1548            {
1549              delete or_root;
1550              return;
1551            }
1552        }
1553     
1554      if (and_node != 0)
1555        {
1556          and_node->reduce ();
1557         
1558          if (and_node->parentheses ())
1559            {
1560              delete or_root;
1561              return;
1562            }
1563        }
1564    }
1565 
1566  _root = or_root;
1567
1568  bool dbg = false;
1569  if (Cmt::get_debug ()) dbg = CmtSystem::testenv ("CMTTESTREGEXP");
1570
1571  if (dbg)
1572    {
1573      if (_root != 0)
1574        {
1575          _root->dump ();
1576        }
1577    }
1578}
1579
1580cmt_regexp::~cmt_regexp ()
1581{
1582  if (_root != 0)
1583    {
1584      delete _root;
1585    }
1586}
1587
1588//----------------------------------------------------------
1589void cmt_regexp::clear ()
1590{
1591  if (_root != 0)
1592    {
1593      delete _root;
1594      _root = 0;
1595    }
1596}
1597
1598//----------------------------------------------------------
1599bool cmt_regexp::is_valid () const
1600{
1601  if (_root != 0) return (true);
1602  else return (false);
1603}
1604
1605cmt_regexp::iterator cmt_regexp::begin (const cmt_string& text, int pos)
1606{
1607  if (_root != 0)
1608    {
1609      int i;
1610     
1611      for (i = pos; i < text.size (); i++)
1612        {
1613          cmt_regexp::iterator it = _root->match (text, i);
1614          if (it != end ()) return (it);
1615        }
1616    }
1617 
1618  return (end ());
1619}
1620
1621cmt_regexp::iterator cmt_regexp::end ()
1622{
1623  return (cmt_regexp::iterator::null ());
1624}
1625
1626cmt_regexp::iterator cmt_regexp::begin (const cmt_string& text, int pos) const
1627{
1628  if (_root != 0)
1629    {
1630      int i;
1631     
1632      for (i = pos; i < text.size (); i++)
1633        {
1634          cmt_regexp::iterator it = _root->match (text, i);
1635          if (it != end ()) return (it);
1636        }
1637    }
1638 
1639  return (end ());
1640}
1641
1642cmt_regexp::iterator cmt_regexp::end () const
1643{
1644  return (cmt_regexp::iterator::null ());
1645}
1646
1647bool cmt_regexp::match (const cmt_string& text) const
1648{
1649  iterator it = begin (text);
1650  if (it == end ()) return (false);
1651  else return (true);
1652}
1653//----------------------------------------------------------
1654
1655//----------------------------------------------------------
1656const cmt_regexp::iterator cmt_regexp::iterator::null ()
1657{
1658  static const iterator null_instance (-1, -1);
1659 
1660  return (null_instance);
1661}
1662
1663cmt_regexp::iterator::iterator ()
1664{
1665  _pos = 0;
1666  _length = 0;
1667}
1668
1669cmt_regexp::iterator::iterator (int pos, int length)
1670{
1671  _pos = pos;
1672  _length = length;
1673}
1674
1675cmt_regexp::iterator::iterator (const iterator& other)
1676{
1677  _pos = other._pos;
1678  _length = other._length;
1679}
1680
1681int cmt_regexp::iterator::operator != (const iterator& other) const
1682{
1683  return ((this->_pos != other._pos) ||
1684          (this->_length != other._length));
1685}
1686
1687int cmt_regexp::iterator::operator == (const iterator& other) const
1688{
1689  return ((this->_pos == other._pos) &&
1690          (this->_length == other._length));
1691}
1692
1693int cmt_regexp::iterator::operator < (const iterator& other) const
1694{
1695  if (_pos == -1) return (0);
1696  if (other._pos == -1) return (0);
1697
1698  return (_pos < other._pos);
1699}
1700
1701cmt_string cmt_regexp::iterator::operator () (const cmt_string& text) const
1702{
1703  if (_pos == -1) return ("");
1704  if (_length <= 0) return ("");
1705
1706  return (text.substr (_pos, _length));
1707}
1708
1709//----------------------------------------------------------
1710
Note: See TracBrowser for help on using the repository browser.