home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / m / mawk11as.zip / REXP / REXP0.C < prev    next >
C/C++ Source or Header  |  1992-01-21  |  11KB  |  459 lines

  1.  
  2. /********************************************
  3. rexp0.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /*$Log:    rexp0.c,v $
  14.  * Revision 3.6  92/01/21  17:32:51  brennan
  15.  * added some casts so that character classes work with signed chars
  16.  * 
  17.  * Revision 3.5  91/10/29  10:53:57  brennan
  18.  * SIZE_T
  19.  * 
  20.  * Revision 3.4  91/08/13  09:10:05  brennan
  21.  * VERSION .9994
  22.  * 
  23.  * Revision 3.3  91/07/19  07:29:24  brennan
  24.  * backslash at end of regular expression now stands for backslash
  25.  * 
  26.  * Revision 3.2  91/07/19  06:58:23  brennan
  27.  * removed small bozo in processing of escape characters
  28.  * 
  29.  * Revision 3.1  91/06/07  10:33:20  brennan
  30.  * VERSION 0.995
  31.  * 
  32.  * Revision 1.2  91/06/05  08:59:36  brennan
  33.  * changed RE_free to free
  34.  * 
  35.  * Revision 1.1  91/06/03  07:10:15  brennan
  36.  * Initial revision
  37.  * 
  38. */
  39.  
  40. /*  lexical scanner  */
  41.  
  42. #include  "rexp.h"
  43.  
  44. /* static functions */
  45. static int  PROTO( do_str, (int, char **, MACHINE *) ) ;
  46. static int  PROTO( do_class, (char **, MACHINE *) ) ;
  47. static int  PROTO( escape, (char **) ) ;
  48. static BV   *PROTO( store_bvp, (BV *) ) ;
  49. static int  PROTO( ctohex, (int) ) ;
  50.  
  51.  
  52. #ifndef  EG  /* if EG make next array visible */
  53. static
  54. #endif
  55. char  RE_char2token[ '|' + 1 ] = {
  56. 0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  57. 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,9,13,13,13,
  58. 6,7,3,4,13,13,10,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  59. 13,13,5,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  60. 13,13,13,13,13,13,13,13,13,13,11,12,13,8,13,13,13,13,13,13,
  61. 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  62. 13,13,13,13,1} ;
  63.  
  64. #define  char2token(x) ( (unsigned char)(x) > '|' ? T_CHAR : RE_char2token[x] )
  65.  
  66. #define NOT_STARTED    (-1)
  67.  
  68. static  int  prev  ;
  69. static  char   *lp  ;     /*  ptr to reg exp string  */
  70. static  unsigned re_len ;
  71.  
  72.  
  73. void  RE_lex_init( re )
  74.   char *re ;
  75.   lp = re ;
  76.   re_len = strlen(re) + 1  ;
  77.   prev = NOT_STARTED ;
  78.   RE_run_stack_init() ;
  79. }
  80.   
  81.  
  82. int   RE_lex( mp )
  83.   MACHINE  *mp ;
  84. { register int c ;
  85.  
  86.   switch( c = char2token(*lp) )
  87.    {
  88.      case T_OR :
  89.      case T_PLUS :
  90.      case T_STAR :
  91.      case T_Q :
  92.      case T_RP :
  93.            lp++ ;  return  prev = c ;
  94.      case T_SLASH :
  95.            break ;
  96.  
  97.      case 0   :   return 0 ;
  98.      
  99.      case T_LP :
  100.            switch( prev )
  101.            { 
  102.              case T_CHAR :
  103.              case T_STR  :
  104.              case T_ANY :
  105.              case T_CLASS :
  106.              case T_START :
  107.              case T_RP :
  108.              case T_PLUS :
  109.              case T_STAR :
  110.              case T_Q :
  111.              case T_U :
  112.                   return prev = T_CAT ;
  113.              default  :
  114.                   lp++ ;
  115.                   return prev = T_LP ;
  116.            }
  117.    }
  118.  
  119.   /*  *lp  is  an operand, but implicit cat op is possible   */
  120.   switch( prev )
  121.    { case  NOT_STARTED :
  122.      case  T_OR :
  123.      case  T_LP :
  124.      case T_CAT :
  125.  
  126.           switch( c )
  127.            { case  T_ANY : 
  128.              { static plus_is_star_flag = 0 ;
  129.  
  130.                   if ( * ++lp == '*' )
  131.                   { lp++ ;  *mp = RE_u() ;
  132.                     return  prev = T_U ; }
  133.                   else
  134.                   if ( *lp == '+' )
  135.                       if ( plus_is_star_flag )
  136.                       { lp++ ;  *mp = RE_u() ;
  137.                         plus_is_star_flag = 0 ;
  138.                         return prev = T_U ;
  139.                       }
  140.                       else
  141.                       { plus_is_star_flag = 1 ;
  142.                         lp-- ; *mp = RE_any() ;
  143.                         return prev = T_ANY ;
  144.                       }
  145.                   else  
  146.                   { *mp = RE_any() ;
  147.                     prev = T_ANY ;
  148.                   }
  149.               }
  150.               break ;
  151.                     
  152.              case  T_SLASH :
  153.                   lp++ ; c = escape(&lp) ;
  154.                   prev = do_str(c, &lp, mp) ;
  155.                   break ;
  156.  
  157.              case  T_CHAR  :
  158.                   c = *lp++ ;
  159.                   prev = do_str(c, &lp, mp) ;
  160.                   break ;
  161.  
  162.              case T_CLASS : prev = do_class(&lp, mp) ;
  163.                             break ;
  164.  
  165.              case T_START : *mp = RE_start() ; lp++ ;
  166.                             prev = T_START ;
  167.                             break ;
  168.  
  169.              case T_END :  
  170.                      lp++ ; *mp = RE_end() ;
  171.                      return  prev = T_END ;
  172.  
  173.              default :
  174.                      RE_panic("bad switch in RE_lex") ;
  175.            }
  176.            break ;
  177.  
  178.      default : /* don't advance the pointer, return T_CAT */
  179.           return prev = T_CAT ;
  180.     }
  181.     /* check for end character */
  182.     if ( *lp == '$' )
  183.     { mp->start->type += END_ON ; lp++ ; }
  184.     return prev ;
  185. }
  186.  
  187. static  int  do_str( c, pp, mp)
  188.   int c ; /* the first character */
  189.   char **pp ;  /* where to put the re_char pointer on exit */
  190.   MACHINE  *mp ;  /* where to put the string machine */
  191. { register char *p , *s ;
  192.   char *str ;
  193.   unsigned len ;
  194.  
  195.  
  196.   p = *pp ;
  197.   s = str = RE_malloc( re_len ) ;
  198.   *s++ = c ;  len = 1 ;
  199.  
  200.   while ( 1 )
  201.   { char *save ;
  202.   
  203.     switch( char2token(*p) )
  204.     {
  205.       case  T_CHAR :  *s++ = *p++ ;
  206.                       break ;
  207.       case  T_SLASH :
  208.                       save = ++p ;
  209.                       *s++ = escape(&save) ;
  210.                       p = save ;
  211.                       break ;
  212.  
  213.       default  :  goto  out ;
  214.     }
  215.     len++ ;
  216.   }
  217. out:
  218.   /* if len > 1 and we failed on a ? + or * , need to back up */
  219.   if ( len > 1 && (*p == '*' || *p == '+' || *p == '?' ) )
  220.   { len-- ; p-- ; s-- ; }
  221.  
  222.   *s = 0 ;
  223.   *pp = p ;
  224.   *mp = RE_str((char *) RE_realloc(str, len+1) , len) ;
  225.   return  T_STR ;
  226. }
  227.  
  228.  
  229. /*--------------------------------------------
  230.   BUILD A CHARACTER CLASS
  231.  *---------------------------*/
  232.  
  233. #define  on( b, x)  ( (b)[((unsigned char)(x))>>3] |= ( 1 << ((x)&7) ))
  234.  
  235. static  void  PROTO(block_on, (BV,int,int) ) ;
  236.  
  237. static  void  block_on( b, x, y)
  238.   BV b ; int x, y ; 
  239. { int lo = (x&0xff) >> 3 ;
  240.   int hi = (y&0xff) >> 3 ;
  241.   int  i, j, bit  ;
  242.  
  243.   if ( lo == hi )
  244.     { j = x&7 ; bit =  1 << j ; i = (y&7) - j + 1 ;
  245.       for ( ; i ; i-- , bit <<= 1 )  b[lo] |= bit ; }
  246.   else
  247.     { for ( i = lo + 1 ; i <= hi - 1 ; i++ )  b[i] = 0xff ;
  248.       b[lo] |= ( 0xff << (x&7) ) ;
  249.       b[hi] |= ~( 0xff << ((y&7)+1)) ;
  250.     }
  251. }
  252.  
  253. /* build a BV for a character class.
  254.    *start points at the '['
  255.    on exit:   *start points at the character after ']'
  256.               mp points at a machine that recognizes the class
  257. */
  258.  
  259. static int  do_class( start, mp)
  260.   char **start ; MACHINE  *mp ;
  261. { register char *p ;
  262.   register BV   *bvp ;
  263.   int  prev ;
  264.   char *q , *t;
  265.   int  cnt ;
  266.   int comp_flag ;
  267.  
  268.   p = (*start) + 1 ;
  269.   if ( *p == ']' || *p == '^' && *(p+1) == ']' )
  270.          RE_error_trap(-E3) ;
  271.   while ( 1 )  /* find the back of the class */
  272.     { if ( ! (q = strchr(p,']')) )  /* no closing bracket */
  273.          RE_error_trap(-E3) ;
  274.       p = q-1 ;
  275.       cnt = 0 ;
  276.       while ( *p == '\\') { cnt++ ; p-- ; }
  277.       if ( (cnt & 1) == 0 )  /* even number of \ */  break ;
  278.       p = q+1 ;
  279.     }
  280.   /*  q  now  pts at the back of the class   */
  281.   p = (*start) + 1 ;
  282.   *start = q + 1 ;
  283.  
  284.   bvp = (BV *) RE_malloc( sizeof(BV) ) ;
  285.   (void) memset( bvp, 0, SIZE_T(sizeof(BV)) ) ;
  286.  
  287.   comp_flag = *p == '^' ? (p++ , 1) : 0 ;
  288.   prev = -1 ;  /* indicates  -  cannot be part of a range  */
  289.  
  290.   while ( p < q )
  291.   {
  292.      switch( *p )
  293.       { case '\\' :
  294.           t = ++p ;
  295.           prev = escape(&t) ;
  296.           on(*bvp, prev) ;
  297.           p = t ;
  298.           continue ;
  299.  
  300.         case '-' :
  301.           if ( prev == -1 || p+1 == q || prev > *(unsigned char*)(p+1) )
  302.              { prev = '-' ; on(*bvp, '-') ; }
  303.           else
  304.              { p++ ;
  305.                block_on(*bvp, prev, *p) ;
  306.                prev = -1 ;
  307.              }
  308.           break ;
  309.  
  310.         default :
  311.           prev = *(unsigned char*)p ;
  312.           on(*bvp, *p) ;
  313.           break ;
  314.       }
  315.       p++ ;
  316.   }
  317.  
  318.   if ( comp_flag )
  319.     for ( p = (char *) bvp ; p < (char *) bvp + sizeof(BV) ; p++)  *p = ~*p ;
  320.  
  321.   /* make sure zero is off */
  322.   (*bvp)[0] &= 0xfe ;
  323.  
  324.   *mp = RE_class( store_bvp( bvp ) ) ;
  325.   return  T_CLASS ;
  326. }
  327.  
  328.  
  329. /* storage for bit vectors so they can be reused ,
  330.    stored in an unsorted linear array 
  331.    the array grows as needed
  332. */
  333.  
  334. #define         BV_GROWTH       6
  335.  
  336. static BV *store_bvp( bvp )
  337.   BV *bvp ;
  338. {
  339.   static BV **bv_base, **bv_limit ;
  340.   static BV **bv_next ; /* next empty slot in the array */
  341.  
  342.   register BV **p ;
  343.   unsigned t ;
  344.  
  345.  
  346.   if ( bv_next == bv_limit ) /* need to grow */
  347.   {
  348.     if ( ! bv_base )  /* first growth */
  349.     {  t = 0 ; bv_base = (BV**)RE_malloc(BV_GROWTH*sizeof(BV*)) ; }
  350.     else 
  351.     { t = bv_next - bv_base ;
  352.       bv_base = (BV**) RE_realloc(bv_base, (t+BV_GROWTH)*sizeof(BV*)) ;
  353.     }
  354.  
  355.     bv_next = bv_base + t ;
  356.     bv_limit = bv_next + BV_GROWTH ;
  357.   }
  358.  
  359.   /* put bvp in bv_next as a sentinal */
  360.   *bv_next = bvp ;
  361.   p = bv_base ;
  362.   while ( memcmp(*p, bvp, SIZE_T(sizeof(BV))) )  p++ ;
  363.  
  364.   if ( p == bv_next )  /* it is new */
  365.         bv_next++ ;
  366.   else  /* we already have it */  free(bvp) ;
  367.  
  368.   return *p ;
  369. }
  370.   
  371.  
  372. /* ----------   convert escape sequences  -------------*/
  373.  
  374. #define isoctal(x)  ((x)>='0'&&(x)<='7')
  375.  
  376. #define  NOT_HEX        16
  377. static char hex_val['f' - 'A' + 1] = {
  378. 10,11,12,13,14,15, 0, 0,
  379.  0, 0, 0, 0, 0, 0, 0, 0,
  380.  0, 0, 0, 0, 0, 0, 0, 0,
  381.  0, 0, 0, 0, 0, 0, 0, 0,
  382. 10,11,12,13,14,15 } ;
  383.  
  384. /* interpret 1 character as hex */
  385. static int ctohex( c )
  386.   register int c ;
  387. { int t ;
  388.  
  389.   if ( c >= '0' && c <= '9' )  return c - '0' ;
  390.  
  391.   if ( c >= 'A' && c <= 'f' && ( t = hex_val[c-'A'] ))  return t ;
  392.  
  393.   return NOT_HEX ;
  394. }
  395.  
  396. #define  ET_END     7
  397.  
  398. static struct { char in , out ; } escape_test[ET_END+1] = {
  399. 'n' , '\n',
  400. 't' , '\t',
  401. 'f' , '\f',
  402. 'b' , '\b',
  403. 'r' , '\r',
  404. 'a' , '\07',
  405. 'v' , '\013',
  406. 0 , 0 } ;
  407.  
  408.  
  409. /*-----------------
  410.   return the char 
  411.   and move the pointer forward
  412.   on entry *s -> at the character after the slash
  413.  *-------------------*/
  414.  
  415. static int escape(start_p)
  416.   char **start_p ;
  417. { register char *p = *start_p ;
  418.   register unsigned x ;
  419.   unsigned xx ;
  420.   int i ;
  421.  
  422.   
  423.   escape_test[ET_END].in = *p ;
  424.   i = 0 ;
  425.   while ( escape_test[i].in != *p ) i++ ;
  426.   if ( i != ET_END )  /* in table */
  427.   { *start_p = p + 1 ;
  428.     return  escape_test[i].out ;
  429.   }
  430.  
  431.   if ( isoctal(*p) )
  432.   { x = *p++ - '0' ;
  433.     if ( isoctal(*p) )
  434.     { x = (x<<3) + *p++ - '0' ;
  435.       if ( isoctal(*p) )
  436.          x = (x<<3) + *p++ - '0' ;
  437.     }
  438.     *start_p = p ;
  439.     return  x & 0xff ;
  440.   }
  441.  
  442.   if ( *p == 0 )  return '\\' ;
  443.  
  444.   if ( *p++ == 'x' ) /* might be a hex digit */
  445.   {  if ( (x = ctohex(*p)) == NOT_HEX ) 
  446.      { *start_p  = p ;  return 'x' ; }
  447.  
  448.      /* look for another hex digit */
  449.      if ( (xx = ctohex(* ++p)) != NOT_HEX )
  450.      { x = (x<<4) + xx ; p++ ; }
  451.  
  452.      *start_p = p ; return x ;
  453.   }
  454.   /* anything else \c -> c */
  455.   *start_p = p ;
  456.   return p[-1]  ;
  457. }
  458.