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 / REXP2.C < prev    next >
C/C++ Source or Header  |  1992-01-21  |  10KB  |  351 lines

  1.  
  2. /********************************************
  3. rexp2.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:    rexp2.c,v $
  14.  * Revision 3.7  92/01/21  17:33:15  brennan
  15.  * added some casts so that character classes work with signed chars
  16.  * 
  17.  * Revision 3.6  91/10/29  10:54:03  brennan
  18.  * SIZE_T
  19.  * 
  20.  * Revision 3.5  91/08/13  09:10:15  brennan
  21.  * VERSION .9994
  22.  * 
  23.  * Revision 3.4  91/08/08  07:53:34  brennan
  24.  * work around for turboC realloc() bug
  25.  * 
  26.  * Revision 3.4  91/08/07  07:10:47  brennan
  27.  * work around for TurboC realloc() bug
  28.  * 
  29.  * Revision 3.3  91/08/04  15:45:57  brennan
  30.  * minor change for large model dos
  31.  * 
  32.  * Revision 3.2  91/06/10  16:18:14  brennan
  33.  * changes for V7
  34.  * 
  35.  * Revision 3.1  91/06/07  10:33:25  brennan
  36.  * VERSION 0.995
  37.  * 
  38.  * Revision 1.8  91/06/05  09:01:33  brennan
  39.  * changes to RE_new_run_stack
  40.  * 
  41.  * Revision 1.7  91/05/31  10:56:02  brennan
  42.  * stack_empty hack for DOS large model
  43.  * 
  44. */
  45.  
  46.  
  47.  
  48. /*  test a string against a machine   */
  49.  
  50. #include "rexp.h"
  51.  
  52. #define  STACKGROWTH    16
  53.  
  54. /* statics */
  55. static RT_STATE *PROTO(slow_push,(RT_STATE *,STATE*,char*,int)); 
  56.  
  57.  
  58.  
  59. RT_STATE *RE_run_stack_base; 
  60. RT_STATE *RE_run_stack_limit ;
  61.  
  62. /* Large model DOS segment arithemetic breaks the current stack.
  63.    This hack fixes it without rewriting the whole thing, 5/31/91 */
  64. RT_STATE *RE_run_stack_empty ;
  65.  
  66. /* for statistics and debug */
  67. static RT_STATE *stack_max ; 
  68.  
  69. void RE_run_stack_init()
  70. { if ( !RE_run_stack_base )
  71.   {
  72.     RE_run_stack_base = (RT_STATE *)
  73.                  RE_malloc(sizeof(RT_STATE) * STACKGROWTH ) ;
  74.     RE_run_stack_limit = RE_run_stack_base + STACKGROWTH ;
  75.     RE_run_stack_empty = stack_max = RE_run_stack_base-1 ;
  76.   }
  77. }
  78.  
  79. /* sometimes during REmatch(), this stack can grow pretty large.
  80.    In real life cases, the back tracking usually fails. Some
  81.    work is needed here to improve the algorithm.
  82.    I.e., figure out how not to stack useless paths.
  83. */
  84.  
  85. RT_STATE  *RE_new_run_stack()
  86. { int newsize = (RE_run_stack_limit - RE_run_stack_base) + STACKGROWTH ;
  87.  
  88. #ifdef  LMDOS   /* large model DOS */
  89.   /* have to worry about overflow on multiplication (ugh) */
  90.   if ( newsize >= 4096 ) RE_run_stack_base = (RT_STATE*) 0 ;
  91.   else
  92. #endif
  93.  
  94. #ifdef  __TURBOC__  
  95. /* turbo C's realloc() screws up when running out of mem  */
  96.   { RT_STATE *temp = (RT_STATE*)malloc(SIZE_T(newsize*sizeof(RT_STATE))) ;
  97.     if ( temp ) (void)memcpy(temp,RE_run_stack_base,
  98.         SIZE_T((newsize-STACKGROWTH)*sizeof(RT_STATE))) ;
  99.     free(RE_run_stack_base) ;
  100.     RE_run_stack_base = temp ;
  101.   }
  102. #else  /* normal case */
  103.   RE_run_stack_base = (RT_STATE *) realloc( RE_run_stack_base ,
  104.           SIZE_T(newsize * sizeof(RT_STATE)) ) ;
  105. #endif
  106.  
  107.   if ( ! RE_run_stack_base )
  108.   { fprintf(stderr, "out of memory for RE run time stack\n") ;
  109.     /* this is pretty unusual, I've only seen it happen on
  110.        weird input to REmatch() under 16bit DOS , the same
  111.        situation worked easily on 32bit machine.  */
  112.     exit(100) ;
  113.   }
  114.  
  115.   RE_run_stack_limit = RE_run_stack_base + newsize ;
  116.   RE_run_stack_empty = RE_run_stack_base - 1 ;
  117.   return  stack_max = RE_run_stack_base + newsize - STACKGROWTH ;
  118. }
  119.  
  120. static RT_STATE *slow_push(sp, m, s, u)
  121.   RT_STATE *sp ;
  122.   STATE *m ;
  123.   char *s ;
  124.   int   u ;
  125.   if ( sp > stack_max )
  126.      if ( (stack_max = sp) == RE_run_stack_limit )
  127.              sp = RE_new_run_stack() ;
  128.  
  129.   sp->m = m ; sp->s = s ; sp->u = u ;
  130.   return sp ;
  131. }
  132.  
  133. #ifdef   DEBUG
  134. void  print_max_stack(f)
  135.   FILE *f ;
  136. { fprintf(f, "stack_max = %d\n", stack_max-RE_run_stack_base+1) ; }
  137. #endif
  138.  
  139. #ifdef   DEBUG
  140. #define  push(mx,sx,ux)   stackp = slow_push(++stackp, mx, sx, ux)
  141. #else
  142. #define  push(mx,sx,ux)   if (++stackp == RE_run_stack_limit)\
  143.                                 stackp = slow_push(stackp,mx,sx,ux) ;\
  144.                           else\
  145.                           { stackp->m=mx;stackp->s=sx;stackp->u=ux;}
  146. #endif
  147.  
  148.  
  149. #define   CASE_UANY(x)  case  x + U_OFF :  case  x + U_ON
  150.  
  151. /* test if str ~ /machine/
  152. */
  153.  
  154. int  REtest( str, machine)
  155.   char *str ;
  156.   VOID *machine ;
  157. { register STATE *m = (STATE *) machine ;
  158.   register char *s = str ;
  159.   register RT_STATE *stackp ;
  160.   int u_flag ;
  161.   char *str_end ;
  162.   char *ts ; /*convenient temps */
  163.   STATE *tm ;
  164.  
  165.   /* handle the easy case quickly */
  166.   if ( (m+1)->type == M_ACCEPT && m->type == M_STR )
  167.         return  (int ) str_str(s, m->data.str, m->len) ;
  168.   else
  169.   { u_flag = U_ON ; str_end = (char *) 0 ;
  170.     stackp = RE_run_stack_empty ;
  171.     goto  reswitch ;
  172.   }
  173.  
  174. refill :
  175.   if ( stackp == RE_run_stack_empty )  return  0 ;
  176.   m = stackp->m ;
  177.   s = stackp->s ;
  178.   u_flag  = stackp-- -> u ;
  179.  
  180.  
  181. reswitch  :
  182.  
  183.   switch( m->type + u_flag )
  184.   {
  185.     case M_STR + U_OFF + END_OFF :
  186.             if ( strncmp(s, m->data.str, SIZE_T(m->len)) ) goto refill ;
  187.             s += m->len ;  m++ ;
  188.             goto reswitch ;
  189.  
  190.     case M_STR + U_OFF + END_ON :
  191.             if ( strcmp(s, m->data.str) ) goto refill ;
  192.             s += m->len ;  m++ ;
  193.             goto reswitch ;
  194.  
  195.     case M_STR + U_ON + END_OFF :
  196.             if ( !(s = str_str(s, m->data.str, m->len)) ) goto refill ;
  197.             push(m, s+1, U_ON) ;
  198.             s += m->len ; m++ ; u_flag = U_OFF ;
  199.             goto reswitch ;
  200.  
  201.     case M_STR + U_ON + END_ON :
  202.             if ( !str_end )  str_end = s + strlen(s) ;
  203.             ts = str_end - m->len ;
  204.             if (ts < s || memcmp(ts,m->data.str,SIZE_T(m->len+1))) goto refill ;
  205.             s = str_end ; m++ ; u_flag = U_OFF ;
  206.             goto reswitch ;
  207.  
  208.     case M_CLASS + U_OFF + END_OFF :
  209.             if ( !ison(*m->data.bvp, s[0] ) )  goto refill ;
  210.             s++ ; m++ ;
  211.             goto reswitch ;
  212.  
  213.     case M_CLASS + U_OFF + END_ON :
  214.             if ( s[1] || !ison(*m->data.bvp,s[0]) )  goto refill ;
  215.             s++ ; m++ ;
  216.             goto reswitch ;
  217.  
  218.     case M_CLASS + U_ON + END_OFF :
  219.             while ( !ison(*m->data.bvp,s[0]) )
  220.                 if ( s[0] == 0 )  goto refill ;
  221.                 else  s++ ;
  222.             s++ ;
  223.             push(m, s, U_ON) ;
  224.             m++ ; u_flag = U_OFF ;
  225.             goto reswitch ;
  226.  
  227.     case M_CLASS + U_ON + END_ON :
  228.             if ( ! str_end )  str_end = s + strlen(s) ;
  229.             if ( ! ison(*m->data.bvp, str_end[-1]) ) goto refill ;
  230.             s = str_end ; m++ ; u_flag = U_OFF ;
  231.             goto reswitch ;
  232.  
  233.     case M_ANY + U_OFF + END_OFF :
  234.             if ( s[0] == 0 )  goto refill ;
  235.             s++ ; m++ ;
  236.             goto  reswitch ;
  237.  
  238.     case M_ANY + U_OFF + END_ON :
  239.             if ( s[0] == 0 || s[1] != 0 )  goto refill ;
  240.             s++ ; m++ ;
  241.             goto reswitch ;
  242.  
  243.     case M_ANY + U_ON + END_OFF :
  244.             if ( s[0] == 0 )  goto refill ;
  245.             s++ ; 
  246.             push(m, s, U_ON) ;
  247.             m++ ; u_flag = U_OFF ;
  248.             goto  reswitch ;
  249.  
  250.     case M_ANY + U_ON + END_ON :
  251.             if ( s[0] == 0 )  goto refill ;
  252.             if ( ! str_end )  str_end = s + strlen(s) ;
  253.             s = str_end ; m++ ; u_flag = U_OFF ;
  254.             goto reswitch ;
  255.  
  256.     case  M_START + U_OFF + END_OFF :
  257.     case  M_START + U_ON  + END_OFF :
  258.             if ( s != str )  goto  refill ;
  259.             m++ ;  u_flag = U_OFF ;
  260.             goto  reswitch ;
  261.  
  262.     case  M_START + U_OFF + END_ON :
  263.     case  M_START + U_ON  + END_ON :
  264.             if ( s != str || s[0] != 0 )  goto  refill ;
  265.             m++ ; u_flag = U_OFF ;
  266.             goto  reswitch ;
  267.  
  268.     case  M_END + U_OFF  :
  269.             if ( s[0]  != 0 )  goto  refill ;
  270.             m++ ; goto reswitch ;
  271.  
  272.     case  M_END + U_ON :
  273.             s += strlen(s) ;
  274.             m++ ; u_flag = U_OFF ;
  275.             goto reswitch ;
  276.  
  277.     CASE_UANY(M_U) :
  278.             u_flag = U_ON ; m++ ;
  279.             goto reswitch ;
  280.  
  281.     CASE_UANY(M_1J) :
  282.             m += m->data.jump ;
  283.             goto reswitch ;
  284.  
  285.     CASE_UANY(M_2JA) : /* take the non jump branch */
  286.             /* don't stack an ACCEPT */
  287.             if ( (tm = m + m->data.jump)->type == M_ACCEPT ) return 1 ;
  288.             push(tm, s, u_flag) ;
  289.             m++ ;
  290.             goto reswitch ;
  291.  
  292.     CASE_UANY(M_2JB) : /* take the jump branch */
  293.             /* don't stack an ACCEPT */
  294.             if ( (tm = m + 1)->type == M_ACCEPT ) return 1 ;
  295.             push(tm, s, u_flag) ;
  296.             m += m->data.jump ;
  297.             goto reswitch ;
  298.  
  299.     CASE_UANY(M_ACCEPT) :
  300.             return 1 ;
  301.  
  302.     default :
  303.             RE_panic("unexpected case in REtest") ;
  304.   }
  305. }
  306.  
  307.   
  308.  
  309. #ifdef  MAWK
  310.  
  311. char *is_string_split( p, lenp )
  312.   register STATE *p ;
  313.   unsigned *lenp ;
  314. {
  315.   if ( p[0].type == M_STR && p[1].type == M_ACCEPT )
  316.   { *lenp = p->len ;
  317.     return  p->data.str ;
  318.   }
  319.   else   return  (char *) 0 ;
  320. }
  321. #else /* mawk provides its own str_str */
  322.  
  323. char *str_str(target, key, klen)
  324.   register char *target ;
  325.   register char *key ;
  326.   unsigned klen ;
  327. { int c = key[0] ;
  328.  
  329.   switch( klen )
  330.   { case 0 :  return (char *) 0 ;
  331.     case 1 :  return strchr(target, c) ;
  332.     case 2 :  
  333.               while ( target = strchr(target, c) )
  334.                     if ( target[1] == key[1] ) return target ;
  335.                     else target++ ;
  336.               break ;
  337.  
  338.     default :
  339.               klen-- ; key++ ;
  340.               while ( target = strchr(target, c) )
  341.                     if (memcmp(target+1,key,SIZE_T(klen)) == 0) return target ;
  342.                     else target++ ;
  343.               break ;
  344.   }
  345.   return (char *) 0 ;
  346. }
  347.               
  348.  
  349. #endif  /* MAWK */
  350.