source: CMT/v1r25/source/cmt_regexp.cxx

Last change on this file was 607, checked in by rybkin, 12 years ago

See C.L. 482

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