source: CMT/v1r16p20040901/src/cmt_regexp.cxx @ 1

Last change on this file since 1 was 1, checked in by arnault, 19 years ago

Import all tags

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