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