home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mawk.lzh / mawk.6 < prev   
Text File  |  1991-05-19  |  58KB  |  2,327 lines

  1.                           else\
  2.                           { stackp->m=mx;stackp->s=sx;stackp->u=ux;}
  3. #endif
  4.  
  5.  
  6. #define   CASE_UANY(x)  case  x + U_OFF :  case  x + U_ON
  7.  
  8.  
  9. int  REtest( str, machine)
  10.   char *str ;
  11.   VOID *machine ;
  12. { register STATE *m = (STATE *) machine ;
  13.   register char *s = str ;
  14.   register RT_STATE *stackp ;
  15.   int u_flag ;
  16.   char *str_end ;
  17.   char *ts ; /*convenient temps */
  18.   STATE *tm ;
  19.  
  20.   /* handle the easy case quickly */
  21.   if ( (m+1)->type == M_ACCEPT && m->type == M_STR )
  22.         return  (int ) str_str(s, m->data.str, m->len) ;
  23.   else
  24.   { u_flag = U_ON ; str_end = (char *) 0 ;
  25.     stackp = RE_run_stack_base - 1 ;
  26.     goto  reswitch ;
  27.   }
  28.  
  29. refill :
  30.   if ( stackp < RE_run_stack_base )  return  0 ;
  31.   m = stackp->m ;
  32.   s = stackp->s ;
  33.   u_flag  = stackp-- -> u ;
  34.  
  35.  
  36. reswitch  :
  37.  
  38.   switch( m->type + u_flag )
  39.   {
  40.     case M_STR + U_OFF + END_OFF :
  41.             if ( strncmp(s, m->data.str, m->len) ) goto refill ;
  42.             s += m->len ;  m++ ;
  43.             goto reswitch ;
  44.  
  45.     case M_STR + U_OFF + END_ON :
  46.             if ( strcmp(s, m->data.str) ) goto refill ;
  47.             s += m->len ;  m++ ;
  48.             goto reswitch ;
  49.  
  50.     case M_STR + U_ON + END_OFF :
  51.             if ( !(s = str_str(s, m->data.str, m->len)) ) goto refill ;
  52.             push(m, s+1, U_ON) ;
  53.             s += m->len ; m++ ; u_flag = U_OFF ;
  54.             goto reswitch ;
  55.  
  56.     case M_STR + U_ON + END_ON :
  57.             if ( !str_end )  str_end = strchr(s, 0) ;
  58.             ts = str_end - m->len ;
  59.             if (ts < s || memcmp(ts,m->data.str,m->len+1)) goto refill ; 
  60.             s = str_end ; m++ ; u_flag = U_OFF ;
  61.             goto reswitch ;
  62.  
  63.     case M_CLASS + U_OFF + END_OFF :
  64.             if ( !ison(*m->data.bvp, s[0] ) )  goto refill ;
  65.             s++ ; m++ ;
  66.             goto reswitch ;
  67.  
  68.     case M_CLASS + U_OFF + END_ON :
  69.             if ( s[1] || !ison(*m->data.bvp,s[0]) )  goto refill ;
  70.             s++ ; m++ ;
  71.             goto reswitch ;
  72.  
  73.     case M_CLASS + U_ON + END_OFF :
  74.             while ( !ison(*m->data.bvp,s[0]) )
  75.                 if ( s[0] == 0 )  goto refill ;
  76.                 else  s++ ;
  77.             s++ ;
  78.             push(m, s, U_ON) ;
  79.             m++ ; u_flag = U_OFF ;
  80.             goto reswitch ;
  81.  
  82.     case M_CLASS + U_ON + END_ON :
  83.             if ( ! str_end )  str_end = strchr(s,0) ;
  84.             if ( ! ison(*m->data.bvp, str_end[-1]) ) goto refill ;
  85.             s = str_end ; m++ ; u_flag = U_OFF ;
  86.             goto reswitch ;
  87.  
  88.     case M_ANY + U_OFF + END_OFF :
  89.             if ( s[0] == 0 )  goto refill ;
  90.             s++ ; m++ ;
  91.             goto  reswitch ;
  92.  
  93.     case M_ANY + U_OFF + END_ON :
  94.             if ( s[0] == 0 || s[1] != 0 )  goto refill ;
  95.             s++ ; m++ ;
  96.             goto reswitch ;
  97.  
  98.     case M_ANY + U_ON + END_OFF :
  99.             if ( s[0] == 0 )  goto refill ;
  100.             s++ ; 
  101.             push(m, s, U_ON) ;
  102.             m++ ; u_flag = U_OFF ;
  103.             goto  reswitch ;
  104.  
  105.     case M_ANY + U_ON + END_ON :
  106.             if ( s[0] == 0 )  goto refill ;
  107.             if ( ! str_end )  str_end = strchr(s,0) ;
  108.             s = str_end ; m++ ; u_flag = U_OFF ;
  109.             goto reswitch ;
  110.  
  111.     case  M_START + U_OFF + END_OFF :
  112.     case  M_START + U_ON  + END_OFF :
  113.             if ( s != str )  goto  refill ;
  114.             m++ ;  u_flag = U_OFF ;
  115.             goto  reswitch ;
  116.  
  117.     case  M_START + U_OFF + END_ON :
  118.     case  M_START + U_ON  + END_ON :
  119.             if ( s != str || s[0] != 0 )  goto  refill ;
  120.             m++ ; u_flag = U_OFF ;
  121.             goto  reswitch ;
  122.  
  123.     case  M_END + U_OFF  :
  124.             if ( s[0]  != 0 )  goto  refill ;
  125.             m++ ; goto reswitch ;
  126.  
  127.     case  M_END + U_ON :
  128.             s = strchr(s, 0) ;
  129.             m++ ; u_flag = U_OFF ;
  130.             goto reswitch ;
  131.  
  132.     CASE_UANY(M_U) :
  133.             u_flag = U_ON ; m++ ;
  134.             goto reswitch ;
  135.  
  136.     CASE_UANY(M_1J) :
  137.             m += m->data.jump ;
  138.             goto reswitch ;
  139.  
  140.     CASE_UANY(M_2JA) : /* take the non jump branch */
  141.             /* don't stack an ACCEPT */
  142.             if ( (tm = m + m->data.jump)->type == M_ACCEPT ) return 1 ;
  143.             push(tm, s, u_flag) ;
  144.             m++ ;
  145.             goto reswitch ;
  146.  
  147.     CASE_UANY(M_2JB) : /* take the jump branch */
  148.             /* don't stack an ACCEPT */
  149.             if ( (tm = m + 1)->type == M_ACCEPT ) return 1 ;
  150.             push(tm, s, u_flag) ;
  151.             m += m->data.jump ;
  152.             goto reswitch ;
  153.  
  154.     CASE_UANY(M_ACCEPT) :
  155.             return 1 ;
  156.  
  157.     default :
  158.             RE_panic("unexpected case in REtest") ;
  159.   }
  160. }
  161.  
  162.   
  163.  
  164. #ifdef  MAWK
  165.  
  166. char *is_string_split( p, lenp )
  167.   register STATE *p ;
  168.   unsigned *lenp ;
  169. {
  170.   if ( p[0].type == M_STR && p[1].type == M_ACCEPT )
  171.   { *lenp = p->len ;
  172.     return  p->data.str ;
  173.   }
  174.   else   return  (char *) 0 ;
  175. }
  176. #else /* mawk provides its own str_str */
  177.  
  178. char *str_str(target, key, klen)
  179.   register char *target ;
  180.   register char *key ;
  181.   unsigned klen ;
  182. { int c = key[0] ;
  183.  
  184.   switch( klen )
  185.   { case 0 :  return (char *) 0 ;
  186.     case 1 :  return strchr(target, c) ;
  187.     case 2 :  
  188.               while ( target = strchr(target, c) )
  189.                     if ( target[1] == key[1] ) return target ;
  190.                     else target++ ;
  191.               break ;
  192.  
  193.     default :
  194.               klen-- ; key++ ;
  195.               while ( target = strchr(target, c) )
  196.                     if ( memcmp(target+1,key,klen) == 0 ) return target ;
  197.                     else target++ ;
  198.               break ;
  199.   }
  200.   return (char *) 0 ;
  201. }
  202.               
  203.  
  204. #endif  /* MAWK */
  205. @//E*O*F mawk0.97/rexp/rexp2.c//
  206. chmod u=rw,g=r,o=r mawk0.97/rexp/rexp2.c
  207.  
  208. echo x - mawk0.97/rexp/rexp3.c
  209. sed 's/^@//' > "mawk0.97/rexp/rexp3.c" <<'@//E*O*F mawk0.97/rexp/rexp3.c//'
  210.  
  211. /********************************************
  212. rexp3.c
  213. copyright 1991, Michael D. Brennan
  214.  
  215. This is a source file for mawk an implementation of
  216. the Awk programming language as defined in
  217. Aho, Kernighan and Weinberger, The AWK Programming Language,
  218. Addison-Wesley, 1988.
  219.  
  220. See the accompaning file, LIMITATIONS, for restrictions
  221. regarding modification and redistribution of this
  222. program in source or binary form.
  223. ********************************************/
  224.  
  225. /*  rexp3.c   */
  226.  
  227. /*  match a string against a machine   */
  228.  
  229. #include "rexp.h"
  230. #include <string.h>
  231.  
  232.  
  233. /*  check that a bit is on  */
  234. #define  ison(b,x) ( (b)[(x)>>3] & ( 1 << ((x)&7)  ))
  235.  
  236.  
  237. extern RT_STATE *RE_run_stack_base; 
  238. extern RT_STATE *RE_run_stack_limit ;
  239. RT_STATE  *RE_new_run_stack() ;
  240.  
  241.  
  242. #define  push(mx,sx,ssx,ux)   if (++stackp == RE_run_stack_limit)\
  243.                                 stackp = RE_new_run_stack() ;\
  244.                stackp->m=mx;stackp->s=sx;stackp->ss=ssx;stackp->u=ux;
  245.  
  246.  
  247. #define   CASE_UANY(x)  case  x + U_OFF :  case  x + U_ON
  248.  
  249. /* returns start of first longest match and the length by
  250.    reference.  If no match returns NULL and length zero */
  251.  
  252. char *REmatch(str, machine, lenp)
  253.   char *str ;
  254.   VOID   *machine ;
  255.   unsigned *lenp ;
  256. { register STATE *m = (STATE *) machine ;
  257.   register char *s = str ;
  258.   char *ss ;
  259.   register RT_STATE *stackp ;
  260.   int u_flag ;
  261.   char *str_end, *ts ;
  262.  
  263.   /* state of current best match stored here */
  264.   char *cb_ss ;  /* the start */
  265.   char *cb_e  ;  /* the end , pts at first char not matched */
  266.  
  267.   *lenp = 0 ;
  268.  
  269.   /* check for the easy case */
  270.   if ( (m+1)->type == M_ACCEPT && m->type == M_STR )
  271.   { if ( ts = str_str(s, m->data.str, m->len) ) *lenp = m->len ;
  272.     return ts ;
  273.   }
  274.     
  275.   u_flag = U_ON ; cb_ss = ss = str_end = (char *) 0 ;
  276.   stackp = RE_run_stack_base - 1 ;
  277.   goto  reswitch ;
  278.  
  279. refill :
  280.   if ( stackp < RE_run_stack_base )  /* empty stack */
  281.   { if ( cb_ss )  *lenp = cb_e - cb_ss ;
  282.     return cb_ss ;
  283.   }
  284.   ss = stackp->ss ;
  285.   s = stackp-- -> s ;
  286.   if ( cb_ss )  /* does new state start too late ? */
  287.       if ( ss )
  288.       { if ( cb_ss < ss )  goto refill ; }
  289.       else
  290.       if ( cb_ss < s ) goto refill ;
  291.  
  292.   m = (stackp+1)->m ;
  293.   u_flag  = (stackp+1)->u ;
  294.  
  295.  
  296. reswitch  :
  297.  
  298.   switch( m->type + u_flag )
  299.   {
  300.     case M_STR + U_OFF + END_OFF :
  301.             if ( strncmp(s, m->data.str, m->len) ) goto refill ;
  302.         if ( !ss )  
  303.             if ( cb_ss && s > cb_ss ) goto refill ;
  304.         else ss = s ;
  305.             s += m->len ;  m++ ;
  306.             goto reswitch ;
  307.  
  308.     case M_STR + U_OFF + END_ON :
  309.             if ( strcmp(s, m->data.str) ) goto refill ;
  310.         if ( !ss )  
  311.             if ( cb_ss && s > cb_ss ) goto refill ;
  312.         else ss = s ;
  313.             s += m->len ;  m++ ;
  314.             goto reswitch ;
  315.  
  316.     case M_STR + U_ON + END_OFF :
  317.             if ( !(s = str_str(s, m->data.str, m->len)) ) goto refill ;
  318.             push(m, s+1,ss, U_ON) ;
  319.         if ( !ss )  
  320.             if ( cb_ss && s > cb_ss ) goto refill ;
  321.         else ss = s ;
  322.             s += m->len ; m++ ; u_flag = U_OFF ;
  323.             goto reswitch ;
  324.  
  325.     case M_STR + U_ON + END_ON :
  326.             if ( !str_end )  str_end = strchr(s, 0) ;
  327.             ts = str_end - m->len ;
  328.             if (ts < s || memcmp(ts,m->data.str,m->len+1)) goto refill ; 
  329.         if ( !ss )  
  330.         if ( cb_ss && ts > cb_ss )  goto refill ;
  331.         else  ss = ts ;
  332.             s = str_end ; m++ ; u_flag = U_OFF ;
  333.             goto reswitch ;
  334.  
  335.     case M_CLASS + U_OFF + END_OFF :
  336.             if ( !ison(*m->data.bvp, s[0] ) )  goto refill ;
  337.         if ( !ss )
  338.         if ( cb_ss && s > cb_ss )  goto refill ;
  339.         else  ss = s ;
  340.             s++ ; m++ ;
  341.             goto reswitch ;
  342.  
  343.     case M_CLASS + U_OFF + END_ON :
  344.             if ( s[1] || !ison(*m->data.bvp,s[0]) )  goto refill ;
  345.         if ( !ss )
  346.         if ( cb_ss && s > cb_ss )  goto refill ;
  347.         else  ss = s ;
  348.             s++ ; m++ ;
  349.             goto reswitch ;
  350.  
  351.     case M_CLASS + U_ON + END_OFF :
  352.             while ( !ison(*m->data.bvp,s[0]) )
  353.                 if ( s[0] == 0 )  goto refill ;
  354.                 else  s++ ;
  355.  
  356.             s++ ;
  357.             push(m, s, ss, U_ON) ;
  358.         if ( !ss )
  359.         if ( cb_ss && s-1 > cb_ss )  goto refill ;
  360.         else  ss = s-1 ;
  361.             m++ ; u_flag = U_OFF ;
  362.             goto reswitch ;
  363.  
  364.     case M_CLASS + U_ON + END_ON :
  365.             if ( ! str_end )  str_end = strchr(s,0) ;
  366.             if ( ! ison(*m->data.bvp, str_end[-1]) ) goto refill ;
  367.         if ( !ss )
  368.         if ( cb_ss && str_end-1 > cb_ss )  goto refill ;
  369.         else  ss = str_end-1 ;
  370.             s = str_end ; m++ ; u_flag = U_OFF ;
  371.             goto reswitch ;
  372.  
  373.     case M_ANY + U_OFF + END_OFF :
  374.             if ( s[0] == 0 )  goto refill ;
  375.         if ( !ss )
  376.         if ( cb_ss && s > cb_ss )  goto refill ;
  377.         else ss = s ;
  378.             s++ ; m++ ;
  379.             goto  reswitch ;
  380.  
  381.     case M_ANY + U_OFF + END_ON :
  382.             if ( s[0] == 0 || s[1] != 0 )  goto refill ;
  383.         if ( !ss )
  384.         if ( cb_ss && s > cb_ss )  goto refill ;
  385.         else ss = s ;
  386.             s++ ; m++ ;
  387.             goto reswitch ;
  388.  
  389.     case M_ANY + U_ON + END_OFF :
  390.             if ( s[0] == 0 )  goto refill ;
  391.             s++ ; 
  392.             push(m, s, ss, U_ON) ;
  393.         if ( !ss )
  394.         if ( cb_ss && s-1 > cb_ss )  goto refill ;
  395.         else  ss = s-1 ;
  396.             m++ ; u_flag = U_OFF ;
  397.             goto  reswitch ;
  398.  
  399.     case M_ANY + U_ON + END_ON :
  400.             if ( s[0] == 0 )  goto refill ;
  401.             if ( ! str_end )  str_end = strchr(s,0) ;
  402.         if ( !ss )
  403.         if ( cb_ss && str_end-1 > cb_ss )  goto refill ;
  404.         else  ss = str_end - 1 ;
  405.             s = str_end ; m++ ; u_flag = U_OFF ;
  406.             goto reswitch ;
  407.  
  408.     case  M_START + U_OFF + END_OFF :
  409.     case  M_START + U_ON  + END_OFF :
  410.             if ( s != str )  goto  refill ;
  411.         ss = s ;
  412.             m++ ;  u_flag = U_OFF ;
  413.             goto  reswitch ;
  414.  
  415.     case  M_START + U_OFF + END_ON :
  416.     case  M_START + U_ON  + END_ON :
  417.             if ( s != str || s[0] != 0 )  goto  refill ;
  418.         ss = s ;
  419.             m++ ; u_flag = U_OFF ;
  420.             goto  reswitch ;
  421.  
  422.     case  M_END + U_OFF  :
  423.             if ( s[0]  != 0 )  goto  refill ;
  424.         if ( !ss ) 
  425.         if ( cb_ss && s > cb_ss )  goto refill ;
  426.         else  ss = s ;
  427.             m++ ; goto reswitch ;
  428.  
  429.     case  M_END + U_ON :
  430.         s = str_end ? str_end : (str_end =  strchr(s,0)) ;
  431.         if ( !ss ) 
  432.         if ( cb_ss && s > cb_ss )  goto refill ;
  433.         else  ss = s ;
  434.             m++ ; u_flag = U_OFF ;
  435.             goto reswitch ;
  436.  
  437.     CASE_UANY(M_U) :
  438.         if ( !ss ) 
  439.         if ( cb_ss && s > cb_ss )  goto refill ;
  440.         else  ss = s ;
  441.             u_flag = U_ON ; m++ ;
  442.             goto reswitch ;
  443.  
  444.     CASE_UANY(M_1J) :
  445.             m += m->data.jump ;
  446.             goto reswitch ;
  447.  
  448.     CASE_UANY(M_2JA) : /* take the non jump branch */
  449.             push(m+m->data.jump, s, ss, u_flag) ;
  450.             m++ ;
  451.             goto reswitch ;
  452.  
  453.     CASE_UANY(M_2JB) : /* take the jump branch */
  454.             push(m+1, s, ss, u_flag) ;
  455.             m += m->data.jump ;
  456.             goto reswitch ;
  457.  
  458.     case M_ACCEPT + U_OFF :
  459.         if ( !ss )  ss = s ;
  460.         if ( !cb_ss || ss < cb_ss || ss == cb_ss && s > cb_e )
  461.         { /* we have a new current best */
  462.           cb_ss = ss ; cb_e = s ;
  463.         }
  464.         goto  refill ;
  465.  
  466.     case  M_ACCEPT + U_ON :
  467.         if ( !ss )  ss = s ;
  468.         else
  469.         s = str_end ? str_end : (str_end = strchr(s,0)) ;
  470.  
  471.         if ( !cb_ss || ss < cb_ss || ss == cb_ss && s > cb_e )
  472.         { /* we have a new current best */
  473.           cb_ss = ss ; cb_e = s ;
  474.         }
  475.         goto  refill ;
  476.  
  477.     default :
  478.             RE_panic("unexpected case in REmatch") ;
  479.   }
  480. }
  481.  
  482. @//E*O*F mawk0.97/rexp/rexp3.c//
  483. chmod u=rw,g=r,o=r mawk0.97/rexp/rexp3.c
  484.  
  485. echo x - mawk0.97/rexp/rexpdb.c
  486. sed 's/^@//' > "mawk0.97/rexp/rexpdb.c" <<'@//E*O*F mawk0.97/rexp/rexpdb.c//'
  487.  
  488. /********************************************
  489. rexpdb.c
  490. copyright 1991, Michael D. Brennan
  491.  
  492. This is a source file for mawk an implementation of
  493. the Awk programming language as defined in
  494. Aho, Kernighan and Weinberger, The AWK Programming Language,
  495. Addison-Wesley, 1988.
  496.  
  497. See the accompaning file, LIMITATIONS, for restrictions
  498. regarding modification and redistribution of this
  499. program in source or binary form.
  500. ********************************************/
  501.  
  502.  
  503. /* rexpdb.c */
  504.  
  505.  
  506. #include "rexp.h"
  507. #include <ctype.h>
  508.  
  509. /*  print a machine for debugging  */
  510.  
  511. static  char *xlat[] = {
  512. "M_STR"  ,
  513. "M_CLASS" ,
  514. "M_ANY" ,
  515. "M_START" ,
  516. "M_END" ,
  517. "M_U",
  518. "M_1J" ,
  519. "M_2JA" ,
  520. "M_2JB" ,
  521. "M_ACCEPT" } ;
  522.  
  523. void  REmprint(m, f)
  524.   VOID *m ; FILE *f ;
  525. { register STATE *p = (STATE *) m ;
  526.   char *end_on_string ;
  527.  
  528.   while ( 1 )
  529.   { 
  530.     if ( p->type >= END_ON ) 
  531.     { p->type -= END_ON ; end_on_string = "$" ; }
  532.     else end_on_string = "" ;
  533.  
  534.     if ( p->type < 0 || p->type >= END_ON )
  535.     { fprintf(f, "unknown STATE type\n") ; return ; }
  536.  
  537.     fprintf(f, "%-10s" , xlat[p->type]) ;
  538.     switch( p->type )
  539.     {
  540.      case M_STR : fprintf(f, "%s", p->data.str ) ;
  541.                   break ;
  542.  
  543.      case M_1J:
  544.      case M_2JA:  
  545.      case M_2JB : fprintf(f, "%d", p->data.jump) ;
  546.                  break ;
  547.      case M_CLASS:
  548.           { unsigned char *q = (unsigned char *) p->data.bvp ;
  549.             unsigned char *r = q +  sizeof(BV) ;
  550.             while ( q < r )  fprintf(f, "%x " , *q++) ;
  551.           }
  552.           break ;
  553.     }
  554.     fprintf(f, "%s\n" , end_on_string) ;
  555.     if ( end_on_string[0] )  p->type += END_ON ;
  556.     if ( p->type == M_ACCEPT )  return ;
  557.     p++ ;
  558.    }
  559. }
  560.  
  561. @//E*O*F mawk0.97/rexp/rexpdb.c//
  562. chmod u=rw,g=r,o=r mawk0.97/rexp/rexpdb.c
  563.  
  564. echo mkdir - mawk0.97/test
  565. mkdir mawk0.97/test
  566. chmod u=rwx,g=rx,o=rx mawk0.97/test
  567.  
  568. echo x - mawk0.97/test/README
  569. sed 's/^@//' > "mawk0.97/test/README" <<'@//E*O*F mawk0.97/test/README//'
  570.  
  571. Some benchmarks of Mawk and other (new) awks are in the file
  572. benchmarks.
  573.  
  574. Most of the programs are one liners, but a few are interesting
  575. and duplicated in examples directory.
  576.  
  577. To run these tests or others yourself, use the
  578. shell script test.sh
  579.  
  580. ----------------------------------------------------
  581.  
  582. One area mawk needs to improve is array[expr] access when
  583. expr is numeric (see primes and qsort).
  584. Mawk always converts numeric expressions to string for
  585. array access which leads to a lot of redundant conversions.
  586. Better array access will be added for release 1.0.
  587.  
  588. -------------------------------------------
  589.  
  590. run wfrq0.awk or words0.awk to see how much RS as a 
  591. regular expression can speed up some programs
  592.  
  593. @//E*O*F mawk0.97/test/README//
  594. chmod u=r,g=r,o=r mawk0.97/test/README
  595.  
  596. echo x - mawk0.97/test/benchmarks
  597. sed 's/^@//' > "mawk0.97/test/benchmarks" <<'@//E*O*F mawk0.97/test/benchmarks//'
  598. The following are some timing tests of Mawk versus three
  599. other (new) awks.  Times are user + sys in seconds. First
  600. col is mawk time, second col is other awk time and last
  601. col is the ratio.
  602.  
  603.  
  604. Mawk vs.  Awk  on Stardent 3000, SysV 3.0
  605.     cat           4.0    4.8   1.20
  606.     wc            8.1    6.1   0.75
  607.     fields       20.8   26.3   1.26
  608.     reg0          4.7    6.0   1.28
  609.     reg1          5.6    6.0   1.07
  610.     reg2         18.1    6.0   0.33
  611.     loops         6.0   12.6   2.10
  612.     words        18.1   18.4   1.02
  613.     newton *      0.9    1.7   1.89
  614.     concat       14.1   15.0   1.06
  615.     primes *      2.6    3.1   1.19
  616.     squeeze       5.3    2.9   0.55
  617.     qsort         6.8   21.3   3.13
  618.     wfrq          8.9   10.0   1.12
  619.     deps **       3.1    5.2   1.68
  620.                    1.15 #
  621.  
  622. Mawk vs.  Gawk 2.11.1  on Sun3, SunOS 4.0
  623.     cat           6.1    8.1   1.33
  624.     wc           12.6   40.6   3.22
  625.     fields       35.7  117.6   3.29
  626.     reg0          6.7   11.0   1.64
  627.     reg1          8.5   12.6   1.48
  628.     reg2         34.3   55.5   1.62
  629.     loops        40.4  214.6   5.31
  630.     words        31.3  110.8   3.54
  631.     newton        6.7   25.4   3.79
  632.     concat       20.9   65.7   3.14
  633.     primes       38.8   28.3   0.73
  634.     squeeze       2.2    4.6   2.09
  635.     qsort        36.1   42.3   1.17
  636.     wfrq         66.5  199.4   3.00
  637.     deps         16.2   42.9   2.65
  638.                    2.24 #
  639.  
  640. Mawk vs.  Nawk  on  VAX  3600  Ultrix 4.1
  641.     cat           5.7    7.7   1.35
  642.     wc           12.8   12.4   0.97
  643.     fields       34.1   58.9   1.73
  644.     reg0          7.1    8.6   1.21
  645.     reg1          8.9   21.8   2.45
  646.     reg2         36.7   58.4   1.59
  647.     loops        30.5  117.7   3.86
  648.     words        31.0   58.7   1.89
  649.     newton        5.6   11.9   2.12
  650.     concat       21.3   28.9   1.36
  651.     primes       36.3   17.2   0.47
  652.     squeeze       2.2    3.1   1.41
  653.     qsort        39.3   29.5   0.75
  654.     wfrq         76.2  173.9   2.28
  655.     deps         18.1   32.4   1.79
  656.                    1.50 #
  657.  
  658. * newton , primes and loops take no input. 
  659. Newton computed the square roots of 1 to 1000 by Newtons method 
  660. and primes was a sieve for primes < 5000.  Loops was three nested
  661. loops 100 x 50 x 50 with a sum on the inside.
  662.  
  663. ** deps input was *.c on mawk source
  664.  
  665. The other programs read a file of 20000+ C source lines.
  666. The input files were blownup by 4 (80000+) on the Stardent.
  667.  
  668. # geometric mean of col 3 --  (a1 * a2 * ... an ) ^ (1/n) .
  669.  
  670. @//E*O*F mawk0.97/test/benchmarks//
  671. chmod u=r,g=r,o=r mawk0.97/test/benchmarks
  672.  
  673. echo x - mawk0.97/test/cat.awk
  674. sed 's/^@//' > "mawk0.97/test/cat.awk" <<'@//E*O*F mawk0.97/test/cat.awk//'
  675. { print } 
  676. @//E*O*F mawk0.97/test/cat.awk//
  677. chmod u=r,g=r,o=r mawk0.97/test/cat.awk
  678.  
  679. echo x - mawk0.97/test/concat.awk
  680. sed 's/^@//' > "mawk0.97/test/concat.awk" <<'@//E*O*F mawk0.97/test/concat.awk//'
  681.  
  682.  
  683. # test concatenation
  684. #
  685.  
  686. { print $NF  $( (NF+1)/2 )  $1 }
  687. @//E*O*F mawk0.97/test/concat.awk//
  688. chmod u=r,g=r,o=r mawk0.97/test/concat.awk
  689.  
  690. echo x - mawk0.97/test/fields.awk
  691. sed 's/^@//' > "mawk0.97/test/fields.awk" <<'@//E*O*F mawk0.97/test/fields.awk//'
  692.  
  693. # print each field
  694. # one per line
  695. #
  696.  
  697. { for(i=1;i<=NF;i++) print $i}
  698. @//E*O*F mawk0.97/test/fields.awk//
  699. chmod u=r,g=r,o=r mawk0.97/test/fields.awk
  700.  
  701. echo x - mawk0.97/test/loops.awk
  702. sed 's/^@//' > "mawk0.97/test/loops.awk" <<'@//E*O*F mawk0.97/test/loops.awk//'
  703.  
  704. # test looping speed
  705. #
  706.  
  707. BEGIN {
  708.  
  709. for(i=1; i<=100 ; i++)
  710.   j = i ;
  711.   while ( j >= 0 ) 
  712.   {
  713.     k = 0 
  714.     do  
  715.     { sum += k + j + i
  716.       k++
  717.     }
  718.     while ( k <= j )
  719.     j--
  720.   }
  721. }
  722.  
  723. print sum
  724. }
  725. @//E*O*F mawk0.97/test/loops.awk//
  726. chmod u=r,g=r,o=r mawk0.97/test/loops.awk
  727.  
  728. echo x - mawk0.97/test/newton.awk
  729. sed 's/^@//' > "mawk0.97/test/newton.awk" <<'@//E*O*F mawk0.97/test/newton.awk//'
  730.  
  731.  
  732. # compute square root by newton's method
  733. #
  734. function SQRT(x)
  735. { new = x/2
  736.   do  
  737.   { old = new
  738.     new = (old*old+x)/(2*old)
  739.   }
  740.   while ( abs(new-old) > 1e-6 )
  741.  
  742.   return  (new+old)/2
  743. }
  744.  
  745. function abs(x)
  746. { return x>=0?x:-x }
  747.  
  748.   
  749. BEGIN {
  750.   for(i = 1 ; i <= 1000 ; i++) print i, SQRT(i)
  751. }
  752. @//E*O*F mawk0.97/test/newton.awk//
  753. chmod u=r,g=r,o=r mawk0.97/test/newton.awk
  754.  
  755. echo x - mawk0.97/test/primes.awk
  756. sed 's/^@//' > "mawk0.97/test/primes.awk" <<'@//E*O*F mawk0.97/test/primes.awk//'
  757.  
  758. # find all primes 
  759. #  <= ARGV[1]
  760. #
  761. BEGIN {  stop = ARGV[1]
  762.    prime[ p_cnt = 1 ] =  3
  763.  
  764. # keep track of integer part of square root by adding
  765. # odd integers 
  766.    odd = test = 5
  767.    root = 2
  768.    squares = 9
  769.  
  770.    
  771. while ( test <= stop )
  772. {
  773.    if ( test >= squares )
  774.    { root++
  775.      odd += 2
  776.      squares += odd 
  777.    }
  778.  
  779.    flag = 1
  780.    for ( i = 1 ; prime[i] <= root ; i++ )
  781.        if ( test % prime[i] == 0 )  #  not prime
  782.     { flag = 0 ; break }
  783.  
  784.    if ( flag )  prime[ ++p_cnt ] = test
  785.  
  786.    test += 2
  787. }
  788.  
  789. prime[0] = 2
  790.  
  791. for(i = 0 ; i <= p_cnt ; i++ )  print prime[i]
  792.  
  793. }
  794.  
  795.  
  796.      
  797. @//E*O*F mawk0.97/test/primes.awk//
  798. chmod u=r,g=r,o=r mawk0.97/test/primes.awk
  799.  
  800. echo x - mawk0.97/test/qsort.awk
  801. sed 's/^@//' > "mawk0.97/test/qsort.awk" <<'@//E*O*F mawk0.97/test/qsort.awk//'
  802.  
  803.  
  804. # qsort text files
  805. #
  806.  
  807. function middle(x,y,z)  #return middle of 3
  808. {
  809.   if ( x <= y )  
  810.   { if ( z >= y )  return y
  811.     if ( z <  x )  return x
  812.     return z
  813.   }
  814.  
  815.   if ( z >= x )  return x
  816.   if ( z <  y )  return y
  817.   return z
  818. }
  819.  
  820.  
  821. function  isort(A , n,    i, j, hold)
  822. {
  823.   # if needed a sentinal at A[0] will be created
  824.  
  825.   for( i = 2 ; i <= n ; i++)
  826.   {
  827.     hold = A[ j = i ]
  828.     while ( A[j-1] > hold )
  829.     { j-- ; A[j+1] = A[j] }
  830.  
  831.     A[j] = hold
  832.   }
  833. }
  834.  
  835.  
  836. # recursive quicksort
  837. function  qsort(A, left, right    ,i , j, pivot, hold)
  838. {
  839.   
  840.   pivot = middle(A[left], A[int((left+right)/2)], A[right])
  841.  
  842.   i = left
  843.   j = right
  844.  
  845.   while ( i <= j )
  846.   {
  847.     while ( A[i] < pivot )  i++ 
  848.     while ( A[j] > pivot )  j--
  849.  
  850.     if ( i <= j )
  851.     { hold = A[i]
  852.       A[i++] = A[j]
  853.       A[j--] = hold
  854.     }
  855.   }
  856.  
  857.   if ( j - left > BLOCK )  qsort(A,left,j)
  858.   if ( right - i > BLOCK )  qsort(A,i,right)
  859. }
  860.  
  861. BEGIN { BLOCK = 5 }
  862.  
  863.  
  864. { line[NR] = $0 ""   # sort as string
  865. }
  866.  
  867. END  {
  868.  
  869.   if ( NR > BLOCK )  qsort(line, 1, NR)
  870.  
  871.   isort(line, NR)
  872.  
  873.   for(i = 1 ; i <= NR ; i++) print line[i]
  874. }
  875.   
  876.  
  877.  
  878.  
  879.     
  880. @//E*O*F mawk0.97/test/qsort.awk//
  881. chmod u=r,g=r,o=r mawk0.97/test/qsort.awk
  882.  
  883. echo x - mawk0.97/test/reg0.awk
  884. sed 's/^@//' > "mawk0.97/test/reg0.awk" <<'@//E*O*F mawk0.97/test/reg0.awk//'
  885.  
  886. /return/ {cnt++}  END{print cnt}
  887. @//E*O*F mawk0.97/test/reg0.awk//
  888. chmod u=r,g=r,o=r mawk0.97/test/reg0.awk
  889.  
  890. echo x - mawk0.97/test/reg1.awk
  891. sed 's/^@//' > "mawk0.97/test/reg1.awk" <<'@//E*O*F mawk0.97/test/reg1.awk//'
  892.  
  893. /return|switch/ {cnt++}  END{print cnt}
  894. @//E*O*F mawk0.97/test/reg1.awk//
  895. chmod u=r,g=r,o=r mawk0.97/test/reg1.awk
  896.  
  897. echo x - mawk0.97/test/reg2.awk
  898. sed 's/^@//' > "mawk0.97/test/reg2.awk" <<'@//E*O*F mawk0.97/test/reg2.awk//'
  899.  
  900. /[A-Za-z_][A-Za-z0-9_]*\[.*\][ \t]*=/ {cnt++}  END{print cnt}
  901. @//E*O*F mawk0.97/test/reg2.awk//
  902. chmod u=r,g=r,o=r mawk0.97/test/reg2.awk
  903.  
  904. echo x - mawk0.97/test/sample
  905. sed 's/^@//' > "mawk0.97/test/sample" <<'@//E*O*F mawk0.97/test/sample//'
  906. dump  cat.awk  ../TB  mawk gawk awk
  907. out   wc.awk ../TB  mawk gawk awk
  908. dump  fields.awk ../TB mawk gawk awk
  909. out  reg0.awk ../TB mawk gawk awk
  910. out  reg1.awk ../TB mawk gawk awk
  911. out  reg2.awk ../TB mawk gawk awk
  912. out  words0.awk  ../TB  mawk gawk
  913. out  words1.awk  ../TB  mawk
  914. dump newton.awk  /dev/null  mawk  gawk
  915. dump concat.awk  ../TB  mawk gawk awk
  916. dump primes.awk  5000   mawk gawk
  917. dump squeeze.awk  ../parse.y mawk gawk
  918. dump qsort.awk  ../parse.y  mawk  gawk
  919. @//E*O*F mawk0.97/test/sample//
  920. chmod u=r,g=r,o=r mawk0.97/test/sample
  921.  
  922. echo x - mawk0.97/test/squeeze.awk
  923. sed 's/^@//' > "mawk0.97/test/squeeze.awk" <<'@//E*O*F mawk0.97/test/squeeze.awk//'
  924.  
  925. # test gsub
  926. #
  927. # squeeze space to single space
  928.  
  929.  
  930. { gsub( /[ \t]+/, " ") ; print }
  931. @//E*O*F mawk0.97/test/squeeze.awk//
  932. chmod u=r,g=r,o=r mawk0.97/test/squeeze.awk
  933.  
  934. echo x - mawk0.97/test/test.sh
  935. sed 's/^@//' > "mawk0.97/test/test.sh" <<'@//E*O*F mawk0.97/test/test.sh//'
  936. #! /bin/sh
  937.  
  938. ###############
  939. #  shell script for timing mawk and other awks
  940. #
  941. #  reads input file of the form
  942. #  dump_or_not  program_file  input_file  list of awks
  943. #
  944. #  usage:  test.sh < input_file
  945. #
  946.  
  947.  
  948. if [ $# != 0 ]
  949. then
  950.   name=`basename $0`
  951.   echo "usage: $name < input_file"  1>&2
  952.   exit 1
  953. fi
  954.  
  955.  
  956. while  read  direct program file  awk_list
  957. do
  958.  
  959. echo 
  960. echo
  961.  
  962. if [ $direct = dump ]
  963. then
  964. for i in $awk_list
  965. do
  966. echo "$i -f $program $file"
  967. /bin/time $i -f $program $file >/dev/null
  968. done
  969.  
  970. else
  971. for i in $awk_list
  972. do
  973. echo "$i -f $program $file"
  974. /bin/time $i -f $program $file 
  975. done
  976. fi
  977.  
  978. done   2>&1    # send the timing to stdout
  979. @//E*O*F mawk0.97/test/test.sh//
  980. chmod u=rx,g=rx,o=rx mawk0.97/test/test.sh
  981.  
  982. echo x - mawk0.97/test/wc.awk
  983. sed 's/^@//' > "mawk0.97/test/wc.awk" <<'@//E*O*F mawk0.97/test/wc.awk//'
  984.  
  985. {sum += NF}
  986. END{ print NR, sum}
  987. @//E*O*F mawk0.97/test/wc.awk//
  988. chmod u=r,g=r,o=r mawk0.97/test/wc.awk
  989.  
  990. echo x - mawk0.97/test/wfrq.awk
  991. sed 's/^@//' > "mawk0.97/test/wfrq.awk" <<'@//E*O*F mawk0.97/test/wfrq.awk//'
  992.  
  993.  
  994. # wfrq.awk 
  995. # find the twenty most frequent words in a document
  996. # counts words in   array   cnt[ word ]
  997. #
  998. # uses a heap to select the twenty most frequent
  999. #
  1000. #
  1001.  
  1002.  
  1003. BEGIN { FS = "[^a-zA-Z]+" ;  BIG = 999999 }
  1004.  
  1005. { for( i = 1 ; i <= NF ; i++ )  cnt[$i]++ }
  1006.  
  1007. END { delete  cnt[ "" ]
  1008.  
  1009. # load twenty values
  1010. # into the heap   word[1..20] and count[1..20]
  1011. #
  1012. #   heap condition --
  1013. #   count[i] <= count[2*i] and count[i] <= count[2*i+1]
  1014.  
  1015. j = 1
  1016.  
  1017. # remove twenty values from cnt[] , put in the heap
  1018.  
  1019. for( i in cnt )
  1020. {
  1021.   word[j] = i  ; count[j] = cnt[i] 
  1022.   delete cnt[i] ;
  1023.   if ( ++j == 21 )  break ;
  1024. }
  1025.  
  1026. # make some sentinals
  1027. # to stop down_heap()
  1028. #
  1029.  
  1030. for( i = j ; i < 43 ; i++ )  count[i] = BIG
  1031.  
  1032. h_empty = j  # save the first empty slot
  1033. # make a heap with the smallest in slot 1
  1034. for( i = h_empty - 1 ; i > 0 ; i-- )  down_heap(i) 
  1035.  
  1036. # examine the rest of the values
  1037. for ( i in cnt )
  1038.   if ( (j = cnt[i]) > count[1] )
  1039.   { # its bigger
  1040.     # take the smallest out of the heap and readjust
  1041.     word[1] = i ; count[1] = j
  1042.     down_heap(1)
  1043.   }
  1044.  
  1045. h_empty-- ;
  1046.  
  1047. # what's left are the twenty largest
  1048. # smallest at the top
  1049. #
  1050.  
  1051. i = 20
  1052. while ( h_empty > 1 )
  1053. {
  1054.   buffer[i--] = sprintf ("%3d %s"  , count[1], word[1])
  1055.   count[1] = count[h_empty] ; word[1] = word[h_empty]
  1056.   count[h_empty] = BIG
  1057.   down_heap(1)
  1058.   h_empty--
  1059. }
  1060.   buffer[i--] = sprintf ("%3d %s"  , count[1], word[1])
  1061.  
  1062.   for(j = 1 ; j <= 20 ; j++ )  print buffer[j]
  1063. }
  1064.  
  1065. # let the i th element drop to its correct position
  1066.  
  1067. function down_heap(i,       k) 
  1068. {
  1069.   while ( 1 )
  1070.   {
  1071.       if ( count[2*i] <= count[2*i+1] )  k = 2*i
  1072.       else  k = 2*i + 1 
  1073.  
  1074.       if ( count[i] <= count[k] )  return
  1075.  
  1076.       hold = word[k] ; word[k] = word[i] ; word[i] = hold
  1077.       hold = count[k] ; count[k] = count[i] ; count[i] = hold
  1078.       i = k
  1079.    }
  1080. }
  1081.  
  1082. @//E*O*F mawk0.97/test/wfrq.awk//
  1083. chmod u=r,g=r,o=r mawk0.97/test/wfrq.awk
  1084.  
  1085. echo x - mawk0.97/test/wfrq0.awk
  1086. sed 's/^@//' > "mawk0.97/test/wfrq0.awk" <<'@//E*O*F mawk0.97/test/wfrq0.awk//'
  1087.  
  1088. #  this program is the same as wfrq.awk except it runs
  1089. #  about twice as fast because it uses RS as a regular 
  1090. #  expression
  1091. #
  1092.  
  1093. function down_heap(i,  k) 
  1094. {
  1095.   while ( 1 )
  1096.   {
  1097.       if ( count[2*i] <= count[2*i+1] )  k = 2*i
  1098.       else  k = 2*i + 1 
  1099.  
  1100.       if ( count[i] <= count[k] )  return
  1101.  
  1102.       hold = word[k] ; word[k] = word[i] ; word[i] = hold
  1103.       hold = count[k] ; count[k] = count[i] ; count[i] = hold
  1104.       i = k
  1105.    }
  1106. }
  1107.  
  1108.  
  1109. BEGIN { RS = "[^a-zA-Z]+" ;  BIG = 999999 }
  1110.  
  1111. { cnt[$0]++ }
  1112.  
  1113. END { delete  cnt[ "" ]
  1114.  
  1115. # load twenty values
  1116. j = 1
  1117. for( i in cnt )
  1118. {
  1119.   word[j] = i  ; count[j] = cnt[i] 
  1120.   delete cnt[i] ;
  1121.   if ( ++j == 21 )  break ;
  1122. }
  1123.  
  1124. # make some sentinals
  1125. for( i = j ; i < 43 ; i++ )  count[i] = BIG
  1126.  
  1127. h_empty = j  # save the first empty slot
  1128. # make a heap with the smallest in slot 1
  1129. for( i = h_empty - 1 ; i > 0 ; i-- )  down_heap(i) 
  1130.  
  1131. # examine the rest of the values
  1132. for ( i in cnt )
  1133.   if ( (j = cnt[i]) > count[1] )
  1134.   { # its bigger
  1135.     # take the smallest out of the heap and readjust
  1136.     word[1] = i ; count[1] = j
  1137.     down_heap(1)
  1138.   }
  1139.  
  1140. h_empty-- ;
  1141.  
  1142. # what's left are the twenty largest
  1143. # smallest at the top
  1144. #
  1145.  
  1146. i = 20
  1147. while ( h_empty > 1 )
  1148. {
  1149.   buffer[i--] = sprintf ("%3d %s"  , count[1], word[1])
  1150.   count[1] = count[h_empty] ; word[1] = word[h_empty]
  1151.   count[h_empty] = BIG
  1152.   down_heap(1)
  1153.   h_empty--
  1154. }
  1155.   buffer[i--] = sprintf ("%3d %s"  , count[1], word[1])
  1156.  
  1157.   for(j = 1 ; j <= 20 ; j++ )  print buffer[j]
  1158. }
  1159. @//E*O*F mawk0.97/test/wfrq0.awk//
  1160. chmod u=r,g=r,o=r mawk0.97/test/wfrq0.awk
  1161.  
  1162. echo x - mawk0.97/test/words.awk
  1163. sed 's/^@//' > "mawk0.97/test/words.awk" <<'@//E*O*F mawk0.97/test/words.awk//'
  1164.  
  1165. # words0.awk
  1166.  
  1167. # find real words
  1168. # i.e contigous letters
  1169.  
  1170. BEGIN { FS = "[^A-Za-z]+" } # split fields on not letters
  1171.  
  1172. {
  1173. # $1 and $NF  might be  empty
  1174.  
  1175.   if ( NF > 0 )
  1176.   {
  1177.     cnt += NF
  1178.  
  1179.     if ( $NF == "" )  cnt--
  1180.     if ( NF > 1 && $1 == "" ) cnt--
  1181.   }
  1182. }
  1183.  
  1184. END { print cnt}
  1185.  
  1186.  
  1187. @//E*O*F mawk0.97/test/words.awk//
  1188. chmod u=r,g=r,o=r mawk0.97/test/words.awk
  1189.  
  1190. echo x - mawk0.97/test/words0.awk
  1191. sed 's/^@//' > "mawk0.97/test/words0.awk" <<'@//E*O*F mawk0.97/test/words0.awk//'
  1192.  
  1193.  
  1194. # use non letters as RS
  1195. #
  1196. #
  1197.  
  1198. BEGIN { RS = "[^A-Za-z][^A-Za-z]*" 
  1199.     getline
  1200.     if ( $0 == "" )  NR = 0
  1201. }
  1202.  
  1203. END { print NR }
  1204. @//E*O*F mawk0.97/test/words0.awk//
  1205. chmod u=r,g=r,o=r mawk0.97/test/words0.awk
  1206.  
  1207. echo mkdir - mawk0.97/examples
  1208. mkdir mawk0.97/examples
  1209. chmod u=rwx,g=rx,o=rx mawk0.97/examples
  1210.  
  1211. echo x - mawk0.97/examples/decl.awk
  1212. sed 's/^@//' > "mawk0.97/examples/decl.awk" <<'@//E*O*F mawk0.97/examples/decl.awk//'
  1213.  
  1214. # parse a C declaration by recursive descent
  1215. # based on a C program in KR ANSI edition
  1216. #
  1217. # run on a C file it finds the declarations
  1218. #
  1219. # restrictions: one declaration per line
  1220. #               doesn't understand struct {...}
  1221. #               makes assumptions about type names
  1222. #
  1223. #
  1224. #  some awks need double escapes on strings used as
  1225. #  regular expressions.  If not run on mawk, use gdecl.awk
  1226.  
  1227.  
  1228. ################################################
  1229. #   lexical scanner -- gobble()
  1230. #   input : string s -- treated as a regular expression
  1231. #   gobble eats SPACE, then eats longest match of s off front
  1232. #   of global variable line.
  1233. #   Cuts the matched part off of line
  1234. #
  1235.  
  1236.  
  1237. function gobble(s,  x)  
  1238. {
  1239.   sub( /^ /, "", line)  # eat SPACE if any
  1240.  
  1241.   # surround s with parenthesis to make sure ^ acts on the
  1242.   # whole thing
  1243.  
  1244.   match(line, "^" "(" s ")")
  1245.   x = substr(line, 1, RLENGTH)
  1246.   line = substr(line, RLENGTH+1)
  1247.   return x 
  1248. }
  1249.  
  1250.  
  1251. function ptr_to(n,  x)  # print "pointer to" , n times
  1252. { n = int(n)
  1253.   if ( n <= 0 )  return ""
  1254.   x = "pointer to" ; n--
  1255.   while ( n-- )  x = x " pointer to"
  1256.   return x
  1257. }
  1258.  
  1259.  
  1260. #recursively get a decl
  1261. # returns an english description of the declaration or
  1262. # "" if not a C declaration.
  1263.  
  1264. function  decl(   x, t, ptr_part)
  1265. {
  1266.  
  1267.   x = gobble("[* ]+")   # get list of *** ...
  1268.   gsub(/ /, "", x)   # remove all SPACES
  1269.   ptr_part = ptr_to( length(x) )
  1270.  
  1271.   # We expect to see either an identifier or '('
  1272.   #
  1273.  
  1274.   if ( gobble("\(") )
  1275.   { 
  1276.     # this is the recursive descent part
  1277.     # we expect to match a declaration and closing ')'
  1278.     # If not return "" to indicate  failure
  1279.  
  1280.       if ( (x = decl()) == "" || gobble( "\)" ) == "" ) return ""
  1281.  
  1282.   }
  1283.   else  #  expecting an identifier
  1284.   {
  1285.     if ( (x = gobble(id)) == "" )  return ""
  1286.     x = x ":"
  1287.   }
  1288.  
  1289.   # finally look for ()
  1290.   # or  [ opt_size ]
  1291.  
  1292.   while ( 1 )
  1293.      if ( gobble( funct_mark ) )  x = x " function returning"
  1294.      else
  1295.      if ( t = gobble( array_mark ) )
  1296.      { gsub(/ /, "", t)
  1297.        x = x " array" t " of"
  1298.      }
  1299.      else  break
  1300.  
  1301.  
  1302.    x = x " "  ptr_part
  1303.    return x
  1304. }
  1305.     
  1306.  
  1307. BEGIN { id = "[_A-Za-z][_A-Za-z0-9]*" 
  1308.         funct_mark = "\([ \t]*\)"
  1309.     array_mark = "\[[ \t]*[_A-Za-z0-9]*[ \t]*\]"
  1310.  
  1311. # I've assumed types are keywords or all CAPS or end in _t
  1312. # Other conventions could be added.
  1313.  
  1314.     type0 = "int|char|short|long|double|float|void" 
  1315.     type1 = "[_A-Z][_A-Z0-9]*"  #  types are CAPS
  1316.     type2 = "[_A-Za-z][_A-Za-z0-9]*_t"  # end in _t
  1317.  
  1318.     types = "(" type0 "|" type1 "|" type2 ")"
  1319. }
  1320.  
  1321.  
  1322. {   
  1323.  
  1324.     gsub( "/\*([^*]|\*[^/])*(\*/|$)" , " ") # remove comments
  1325.     gsub( /[ \t]+/, " ")  # squeeze white space to a single space
  1326.  
  1327.  
  1328.     line = $0
  1329.  
  1330.     scope = gobble( "extern|static" )
  1331.  
  1332.     if ( type = gobble("(struct|union|enum) ") )
  1333.             type = type gobble(id)  #  get the tag
  1334.     else
  1335.     {
  1336.  
  1337.        type = gobble("(un)?signed ") gobble( types )
  1338.  
  1339.     }
  1340.     
  1341.     if ( ! type )  next
  1342.     
  1343.     if ( (x = decl()) && gobble( ";") )
  1344.     {
  1345.       x  =  x " " type
  1346.       if ( scope )  x = x " (" scope ")"
  1347.       gsub( /  +/, " ", x)  # 
  1348.       print x
  1349.     }
  1350.  
  1351. }
  1352.  
  1353.  
  1354.  
  1355.  
  1356. @//E*O*F mawk0.97/examples/decl.awk//
  1357. chmod u=rx,g=rx,o=rx mawk0.97/examples/decl.awk
  1358.  
  1359. echo x - mawk0.97/examples/deps.awk
  1360. sed 's/^@//' > "mawk0.97/examples/deps.awk" <<'@//E*O*F mawk0.97/examples/deps.awk//'
  1361.  
  1362. # find include dependencies in C source
  1363. #
  1364. # mawk -f deps.awk  C_source_files
  1365. #         -- prints a dependency list suitable for make
  1366. #         -- ignores   #include <   >
  1367. #
  1368.  
  1369.  
  1370. BEGIN {  stack_index = 0 # stack[] holds the input files
  1371.  
  1372.   for(i = 1 ; i < ARGC ; i++)
  1373.   { 
  1374.     file = ARGV[i]
  1375.     if ( file !~ /\.c$/ )  continue  # skip it
  1376.     outfile = substr(file, 1, length(file)-2) ".o"
  1377.  
  1378.     # INCLUDED[] stores the set of included files
  1379.     # -- start with the empty set
  1380.     for( j in INCLUDED ) delete INCLUDED[j]
  1381.  
  1382.     while ( 1 )
  1383.     {
  1384.         if ( getline line < file <= 0 )  # no open or EOF
  1385.     { close(file)
  1386.       if ( stack_index == 0 )  break # empty stack
  1387.       else  
  1388.       { file = stack[ stack_index-- ]
  1389.         continue
  1390.       }
  1391.         }
  1392.  
  1393.     if ( line ~ /^#include[ \t]+".*"/ )
  1394.     {
  1395.       split(line, X, "\"")  # filename is in X[2]
  1396.  
  1397.       if ( X[2] in INCLUDED ) # we've already included it
  1398.         continue
  1399.  
  1400.       #push current file 
  1401.       stack[ ++stack_index ] = file
  1402.       INCLUDED[ file = X[2] ] = ""
  1403.         }
  1404.     }  # end of while
  1405.     
  1406.    # test if INCLUDED is empty
  1407.    flag = 0 # on once the front is printed 
  1408.    for( j in INCLUDED )
  1409.       if ( ! flag )  
  1410.       { printf "%s : %s" , outfile, j ; flag = 1 }
  1411.       else  printf " %s" , j
  1412.  
  1413.    if ( flag )  print ""
  1414.  
  1415.   }# end of loop over files in ARGV[i]
  1416.  
  1417. }
  1418. @//E*O*F mawk0.97/examples/deps.awk//
  1419. chmod u=rx,g=rx,o=rx mawk0.97/examples/deps.awk
  1420.  
  1421. echo x - mawk0.97/examples/gdecl.awk
  1422. sed 's/^@//' > "mawk0.97/examples/gdecl.awk" <<'@//E*O*F mawk0.97/examples/gdecl.awk//'
  1423.  
  1424. # parse a C declaration by recursive descent
  1425. #  decl.awk with extra escapes \
  1426.  
  1427. ################################################
  1428. ############################################
  1429.  
  1430.  
  1431. #   lexical scanner -- gobble()
  1432. #   input : string s -- treated as a regular expression
  1433. #   gobble eats SPACE, then eats longest match of s off front
  1434. #   of global variable line.
  1435. #   Cuts the matched part off of line
  1436. #
  1437.  
  1438.  
  1439. function gobble(s,  x)  
  1440. {
  1441.   sub( /^ /, "", line)  # eat SPACE if any
  1442.  
  1443.   # surround s with parenthesis to make sure ^ acts on the
  1444.   # whole thing
  1445.  
  1446.   match(line, "^" "(" s ")")
  1447.   x = substr(line, 1, RLENGTH)
  1448.   line = substr(line, RLENGTH+1)
  1449.   return x 
  1450. }
  1451.  
  1452.  
  1453. function ptr_to(n,  x)  # print "pointer to" , n times
  1454. { n = int(n)
  1455.   if ( n <= 0 )  return ""
  1456.   x = "pointer to" ; n--
  1457.   while ( n-- )  x = x " pointer to"
  1458.   return x
  1459. }
  1460.  
  1461.  
  1462. #recursively get a decl
  1463. # returns an english description of the declaration or
  1464. # "" if not a C declaration.
  1465.  
  1466. function  decl(   x, t, ptr_part)
  1467. {
  1468.  
  1469.   x = gobble("[* ]+")   # get list of *** ...
  1470.   gsub(/ /, "", x)   # remove all SPACES
  1471.   ptr_part = ptr_to( length(x) )
  1472.  
  1473.   # We expect to see either an identifier or '('
  1474.   #
  1475.  
  1476.   if ( gobble("\\(") )
  1477.   { 
  1478.     # this is the recursive descent part
  1479.     # we expect to match a declaration and closing ')'
  1480.     # If not return "" to indicate  failure
  1481.  
  1482.       if ( (x = decl()) == "" || gobble( "\\)" ) == "" ) return ""
  1483.  
  1484.   }
  1485.   else  #  expecting an identifier
  1486.   {
  1487.     if ( (x = gobble(id)) == "" )  return ""
  1488.     x = x ":"
  1489.   }
  1490.  
  1491.   # finally look for ()
  1492.   # or  [ opt_size ]
  1493.  
  1494.   while ( 1 )
  1495.      if ( gobble( funct_mark ) )  x = x " function returning"
  1496.      else
  1497.      if ( t = gobble( array_mark ) )
  1498.      { gsub(/ /, "", t)
  1499.        x = x " array" t " of"
  1500.      }
  1501.      else  break
  1502.  
  1503.  
  1504.    x = x " "  ptr_part
  1505.    return x
  1506. }
  1507.     
  1508.  
  1509. BEGIN { id = "[_A-Za-z][_A-Za-z0-9]*" 
  1510.         funct_mark = "\\([ \t]*\\)"
  1511.     array_mark = "\\[[ \t]*[_A-Za-z0-9]*[ \t]*\\]"
  1512.  
  1513. # I've assumed types are keywords or all CAPS or end in _t
  1514. # Other conventions could be added.
  1515.  
  1516.     type0 = "int|char|short|long|double|float|void" 
  1517.     type1 = "[_A-Z][_A-Z0-9]*"  #  types are CAPS
  1518.     type2 = "[_A-Za-z][_A-Za-z0-9]*_t"  # end in _t
  1519.  
  1520.     types = "(" type0 "|" type1 "|" type2 ")"
  1521. }
  1522.  
  1523.  
  1524. {   
  1525.  
  1526.     gsub( /\/\*([^*]|\*[^\/])*(\*\/|$)/ , " ") # remove comments
  1527.     gsub( /[ \t]+/, " ")  # squeeze white space to a single space
  1528.  
  1529.  
  1530.     line = $0
  1531.  
  1532.     scope = gobble( "extern|static" )
  1533.  
  1534.     if ( type = gobble("(struct|union|enum) ") )
  1535.             type = type gobble(id)  #  get the tag
  1536.     else
  1537.     {
  1538.  
  1539.        type = gobble("(un)?signed ") gobble( types )
  1540.  
  1541.     }
  1542.     
  1543.     if ( ! type )  next
  1544.     
  1545.     if ( (x = decl()) && gobble( ";") )
  1546.     {
  1547.       x  =  x " " type
  1548.       if ( scope )  x = x " (" scope ")"
  1549.       gsub( /  +/, " ", x)  # 
  1550.       print x
  1551.     }
  1552.  
  1553. }
  1554.  
  1555.  
  1556.  
  1557.  
  1558. @//E*O*F mawk0.97/examples/gdecl.awk//
  1559. chmod u=rx,g=rx,o=rx mawk0.97/examples/gdecl.awk
  1560.  
  1561. echo x - mawk0.97/examples/nocomment.awk
  1562. sed 's/^@//' > "mawk0.97/examples/nocomment.awk" <<'@//E*O*F mawk0.97/examples/nocomment.awk//'
  1563.  
  1564. # remove C comments
  1565. #
  1566.  
  1567. BEGIN {
  1568.  RS = "/\*([^*]|\*[^/])*\*/"
  1569.  ORS = " "
  1570.  getline hold
  1571. }
  1572.  
  1573. { # hold one record because we don't want ORS on the last
  1574.   # record
  1575.  
  1576.   print hold
  1577.   hold = $0
  1578. }
  1579.  
  1580. END { printf "%s", hold }
  1581. @//E*O*F mawk0.97/examples/nocomment.awk//
  1582. chmod u=r,g=r,o=r mawk0.97/examples/nocomment.awk
  1583.  
  1584. echo mkdir - mawk0.97/msdos
  1585. mkdir mawk0.97/msdos
  1586. chmod u=rwx,g=rx,o=rx mawk0.97/msdos
  1587.  
  1588. echo x - mawk0.97/msdos/INSTALL
  1589. sed 's/^@//' > "mawk0.97/msdos/INSTALL" <<'@//E*O*F mawk0.97/msdos/INSTALL//'
  1590.  
  1591. how to make mawk under MsDOS
  1592. ---------------------------
  1593.  
  1594. Read the DOS section in the manual first.
  1595.  
  1596. In addition to a C compiler, you will need an
  1597. assembler and a yacc compatable parser generator.
  1598.  
  1599. Assuming you keep the same directory structure:
  1600.  
  1601. 1)  run  mklib.bat in this directory to create msdos.lib
  1602.  
  1603. 2)  move the makefile and mawk.dep  to ..
  1604.     ( The supplied dos makefile is for Borland's make.  I used to
  1605.       make mawk with MS make -- which make you use is no big deal.)
  1606.  
  1607. 3)  If you want a Unix style command line for mawk, you'll need to
  1608.     write a function called reargv(int *, char ***) which passes
  1609.     mawk the modified argc and argv.  Compile and add to
  1610.     msdos.lib.
  1611.  
  1612.     The supplied reargv.c works with POLYSHELL by Polytron; for a
  1613.     different shell you could use it as an example.
  1614.  
  1615.     If this made sense and all went well, go to machine.h
  1616.     and
  1617.       #define  HAVE_REARGV   1
  1618.  
  1619.     If ! (sense || well ) , don't worry HAVE_REARGV is 0 by
  1620.     default.
  1621.  
  1622. 4)  YACC --
  1623. On the PC I use bison.1.14, it works fine and is easy to find.
  1624. Surely easier to get than mawk.  Unfortunately I cannot distribute
  1625. the generated parse.c file.
  1626.  
  1627.     If you use bison, I suggest #if 0  in parse.c
  1628.     on the part that grows the parser stack.
  1629.     Then you won't need alloca().
  1630.     ( For mawk programs if the parser stack needs to grow, something
  1631.       is fatally wrong.)
  1632.     Also unless you are debugging the grammar, you don't need
  1633.     the tables yyrhs[] or yyprhs[] -- cut them out and save some data
  1634.     space.
  1635.  
  1636. You can make parse.c under unix with bison or another yacc and
  1637. move it to dos.
  1638.  
  1639. 5)  The rand48.asm is hardwired for small model.  I've never made
  1640. a large model mawk, but as far as I can tell I think the only problem
  1641. is in rand48.asm.  The stack machine instructions (INST) assume a
  1642. pointer is a pointer is a pointer, so if you change to far data
  1643. pointers you'll also need to change to far code pointers.
  1644.  
  1645. Rand48 is overkill, you could use another random number generator
  1646. although the one supplied with your compiler is a near 
  1647. certainty to be poor.
  1648.  
  1649. On small model, you have about 40K of free data space which is plenty
  1650. except for programs that hold a medium or larger data file entirely
  1651. in memory.
  1652.  
  1653. ==================================================================
  1654.  
  1655. The reason system() and pipes are missing is I haven't decided
  1656. entirely how to handle the runaway loop problem.  Dos makes
  1657. asynchronous termination of a program difficult, because DOS
  1658. itself might not be able to handle exit().
  1659.  
  1660. Hooking int 0x1a forces me to deal with cleanup and makes ^C
  1661. a pain.  What is the effect of my 0x1a on children? (That's why
  1662. no system() or pipes yet).  What do I have to check after a child
  1663. terminates, children can muck up the state of the parent process.
  1664.  
  1665.  
  1666. I have used mawk as is on DOS for about 6 months, what's missing
  1667. I rarely use  except to emit error messages and I use
  1668. errmsg() for that.  If I stall about fixing this stuff, DOS
  1669. might go away and I'll never have to deal with it.
  1670. @//E*O*F mawk0.97/msdos/INSTALL//
  1671. chmod u=r,g=r,o=r mawk0.97/msdos/INSTALL
  1672.  
  1673. echo x - mawk0.97/msdos/makefile
  1674. sed 's/^@//' > "mawk0.97/msdos/makefile" <<'@//E*O*F mawk0.97/msdos/makefile//'
  1675.  
  1676. #  this is a makefile for mawk 
  1677. #  using Borland's make v3.0
  1678. #  and CFLAGS for TurboC
  1679.  
  1680. @.SWAP
  1681.  
  1682. CFLAGS = -c -ms -f -wnod -wpro -A
  1683. LINKFLAGS = /c/m
  1684.  
  1685. !if $d(DEBUG)
  1686. CFLAGS = $(CFLAGS) -DDEBUG
  1687. LINKFLAGS = $(LINKFLAGS)/v
  1688. !else
  1689. #  optimize
  1690. CFLAGS = $(CFLAGS) -v- -O -DHAVE_REARGV=1
  1691. !endif
  1692.  
  1693.  
  1694. ####################
  1695. #  user tuned macros
  1696. ####################
  1697.  
  1698. # location of your C library
  1699. CLIB=c:\lib
  1700.  
  1701. # if you have a 80x87 coprocessor
  1702. #FLOATLIB=fp87
  1703. # otherwise
  1704. FLOATLIB=emu
  1705.  
  1706. #take this out if you don't need it, i.e.,
  1707. # if you have a reargv()
  1708. WILDARGS=\lib\wildargs.obj  #expand filenames
  1709.  
  1710. #  You'll need a yacc like parser
  1711. YACC = bison -dyv
  1712.  
  1713. ######################  end of tuneable macros
  1714.  
  1715.  
  1716. OBS = parse.obj \
  1717. array.obj \
  1718. bi_funct.obj \
  1719. bi_vars.obj \
  1720. cast.obj \
  1721. code.obj \
  1722. da.obj \
  1723. error.obj \
  1724. execute.obj \
  1725. fcall.obj \
  1726. field.obj \
  1727. files.obj \
  1728. fin.obj \
  1729. hash.obj \
  1730. init.obj \
  1731. jmp.obj \
  1732. kw.obj \
  1733. main.obj \
  1734. matherr.obj \
  1735. memory.obj \
  1736. print.obj \
  1737. re_cmpl.obj \
  1738. scan.obj \
  1739. scancode.obj \
  1740. split.obj \
  1741. zmalloc.obj
  1742.  
  1743. REXP_C = rexp\rexp.c \
  1744. rexp\rexp0.c \
  1745. rexp\rexp1.c \
  1746. rexp\rexp2.c  \
  1747. rexp\rexpdb.c
  1748.  
  1749.  
  1750. LIBS = msdos\msdos.lib \
  1751. rexp\rexp.lib \
  1752. $(CLIB)\$(FLOATLIB) \
  1753. $(CLIB)\maths \
  1754. $(CLIB)\cs
  1755.  
  1756. mawk.exe : $(OBS)  rexp\rexp.lib
  1757.     tlink $(LINKFLAGS) @&&!
  1758.     $(CLIB)\c0s $(WILDARGS) $(OBS)
  1759.     mawk,mawk
  1760.     $(LIBS)
  1761. !
  1762.  
  1763. rexp\rexp.lib : $(REXP_C)
  1764.     cd rexp
  1765.     del *.obj
  1766.     make
  1767.  
  1768. @.c.obj :
  1769.     tcc $(CFLAGS) $*.c 
  1770.  
  1771. parse.c :  parse.y
  1772.     $(YACC)  parse.y
  1773.     rename y_tab.c parse.c
  1774.     rename  y_tab.h parse.h
  1775.  
  1776. scancode.c :  makescan.c  scan.h
  1777.     tcc makescan.c
  1778.     makescan.exe > scancode.c
  1779.     rm makescan.obj  makescan.exe
  1780.  
  1781.  
  1782.  
  1783. # the dependencies of the obj's on h's
  1784. # you can make this with mawk -f deps.awk *.c
  1785.  
  1786. array.o : bi_vars.h sizes.h zmalloc.h memory.h types.h machine.h mawk.h symtype.h
  1787. bi_funct.o : fin.h bi_vars.h sizes.h memory.h zmalloc.h regexp.h types.h machine.h field.h repl.h files.h bi_funct.h mawk.h symtype.h init.h
  1788. bi_vars.o : bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h mawk.h symtype.h init.h
  1789. cast.o : parse.h sizes.h memory.h zmalloc.h types.h machine.h field.h scan.h repl.h mawk.h symtype.h
  1790. code.o : sizes.h memory.h zmalloc.h types.h machine.h code.h mawk.h init.h
  1791. da.o : sizes.h memory.h zmalloc.h types.h machine.h field.h repl.h code.h bi_funct.h mawk.h symtype.h
  1792. error.o : parse.h bi_vars.h sizes.h types.h machine.h scan.h mawk.h symtype.h
  1793. execute.o : sizes.h memory.h zmalloc.h regexp.h types.h machine.h field.h code.h repl.h bi_funct.h mawk.h symtype.h
  1794. fcall.o : sizes.h memory.h zmalloc.h types.h machine.h code.h mawk.h symtype.h
  1795. field.o : parse.h bi_vars.h sizes.h memory.h zmalloc.h regexp.h types.h machine.h field.h scan.h repl.h mawk.h symtype.h init.h
  1796. files.o : fin.h sizes.h memory.h zmalloc.h types.h machine.h files.h mawk.h
  1797. fin.o : parse.h fin.h bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h scan.h mawk.h symtype.h
  1798. hash.o : sizes.h memory.h zmalloc.h types.h machine.h mawk.h symtype.h
  1799. init.o : bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h code.h mawk.h symtype.h init.h
  1800. jmp.o : sizes.h memory.h zmalloc.h types.h machine.h code.h jmp.h mawk.h init.h
  1801. kw.o : parse.h sizes.h types.h machine.h mawk.h symtype.h init.h
  1802. main.o : fin.h bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h code.h files.h mawk.h init.h
  1803. makescan.o : parse.h scan.h symtype.h
  1804. matherr.o : sizes.h types.h machine.h mawk.h
  1805. memory.o : sizes.h memory.h zmalloc.h types.h machine.h mawk.h
  1806. parse.o : bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h code.h files.h bi_funct.h mawk.h jmp.h symtype.h
  1807. print.o : bi_vars.h parse.h sizes.h memory.h zmalloc.h types.h machine.h field.h scan.h files.h bi_funct.h mawk.h symtype.h
  1808. re_cmpl.o : parse.h sizes.h memory.h zmalloc.h regexp.h types.h machine.h scan.h repl.h mawk.h symtype.h
  1809. scan.o : parse.h fin.h sizes.h memory.h zmalloc.h types.h machine.h field.h scan.h repl.h files.h mawk.h symtype.h init.h
  1810. split.o : bi_vars.h parse.h sizes.h memory.h zmalloc.h regexp.h types.h machine.h field.h scan.h bi_funct.h mawk.h symtype.h
  1811. zmalloc.o : sizes.h zmalloc.h types.h machine.h mawk.h
  1812. @//E*O*F mawk0.97/msdos/makefile//
  1813. chmod u=r,g=r,o=r mawk0.97/msdos/makefile
  1814.  
  1815. echo x - mawk0.97/msdos/mklib.bat
  1816. sed 's/^@//' > "mawk0.97/msdos/mklib.bat" <<'@//E*O*F mawk0.97/msdos/mklib.bat//'
  1817.  
  1818. masm /mx /z  rand48.asm ;
  1819. tcc -c -f -O -v-  rand48_0.c
  1820.  
  1821. lib  msdos.lib  -+rand48.obj -+rand48_0.obj  ;
  1822.  
  1823.  
  1824.  
  1825. @//E*O*F mawk0.97/msdos/mklib.bat//
  1826. chmod u=r,g=r,o=r mawk0.97/msdos/mklib.bat
  1827.  
  1828. echo x - mawk0.97/msdos/rand48.asm
  1829. sed 's/^@//' > "mawk0.97/msdos/rand48.asm" <<'@//E*O*F mawk0.97/msdos/rand48.asm//'
  1830.  
  1831. ;**************************************************
  1832. ;  rand.asm
  1833. ;  PC versions of the rand48 family
  1834. ;  1988 Michael D. Brennan
  1835. ;  
  1836. ;
  1837. ;  rand.asm  and rand0.c  are the source files
  1838. ;     for rand.lib  (see also rand48.h)
  1839. ;**************************************************
  1840.  
  1841.  
  1842. public   _srand48, _seed48 , _lcong48
  1843. public     _mrand48, _jrand48 ; uniform on [0,2^32)
  1844. public   _lrand48, _nrand48 ; uniform on [0,2^31)
  1845. public   _urand48, _vrand48 ; uniform on [0,2^16)
  1846.  
  1847. ;  rand.asm
  1848.  
  1849. standard_scale0 = 0e66dh
  1850. standard_scale1 = 0deech
  1851. standard_scale2 = 5h
  1852. standard_shift  = 0bh
  1853.  
  1854. @.model  small
  1855.  
  1856. @.data
  1857. prod   dw   3 dup(?)  ;  build  scale*seed here
  1858. seed   dw   3 dup(?)  ;  default seed storage for drand, lrand etc
  1859. scale  dw   standard_scale0
  1860.        dw   standard_scale1
  1861.        dw   standard_scale2
  1862. shift  dw   standard_shift
  1863. seedbuf    dw    3 dup(?)  ;  place old seed  for seed48()
  1864.  
  1865. @.code
  1866.  
  1867.  
  1868. ;****************************************
  1869. ;  rgen -- the basic linear congruence
  1870. ;  call with  bx->the seed
  1871. ;*************************************
  1872.  
  1873. rgen    proc    near
  1874.      ;   seed <- scale * seed + shift  with overflow
  1875.  
  1876.      ;  first get  scale*seed into prod
  1877.  
  1878.     mov    ax, scale   ;  0,0
  1879.     mul    word ptr [bx]
  1880.     mov    prod, ax
  1881.     mov    cx, dx     ;   save the overflow in cx
  1882.  
  1883.     mov    ax, scale+2    ; 1,0
  1884.     mul    word ptr [bx]
  1885.     add    ax, cx
  1886.     adc    dx, 0
  1887.     mov    prod+2, ax
  1888.     mov    cx, dx
  1889.  
  1890.     mov    ax, scale+4   ;  2,0
  1891.     mul    word ptr [bx]
  1892.     add    ax, cx
  1893.     mov    prod+4, ax
  1894.  
  1895.     mov    ax, scale     ;  0,1
  1896.     mul    word ptr [bx+2]
  1897.     add    ax, prod+2
  1898.     adc    dx, 0
  1899.     mov    prod+2, ax
  1900.     mov    cx, dx
  1901.  
  1902.     mov    ax, scale+2   ;   1,1
  1903.     mul    word ptr [bx+2]
  1904.     add    ax, cx
  1905.     add    prod+4, ax
  1906.  
  1907.     mov    ax, scale   ;  0,2
  1908.     mul    word ptr [bx+4]
  1909.     add     ax, prod+4
  1910.                      ;  move product to seed
  1911.     mov    word ptr [bx+4], ax
  1912.     mov    ax, prod+2
  1913.     mov    word ptr [bx+2], ax
  1914.     mov    ax, prod
  1915.     mov    word ptr [bx], ax
  1916.               ;   add shift to seed
  1917.     mov    ax, shift
  1918.     add    word ptr [bx], ax
  1919.     adc    word ptr [bx+2], 0
  1920.     adc    word ptr [bx+4], 0
  1921.  
  1922.     ret
  1923. rgen    endp
  1924.  
  1925. set_scale    proc   near ;  set scale and shift to standard
  1926.     mov    scale, standard_scale0
  1927.     mov    scale+2, standard_scale1
  1928.     mov    scale+4, standard_scale2
  1929.     mov    shift, standard_shift
  1930.     ret
  1931. set_scale    endp
  1932.  
  1933. ;  void  srand48(long seedval)
  1934.  
  1935. _srand48    proc    near
  1936.     push    bp
  1937.     mov    bp, sp
  1938.     mov    seed, 330eh ;
  1939.     mov    ax, [bp+4]
  1940.     mov    seed+2, ax
  1941.     mov    ax, [bp+6]
  1942.     mov    seed+4, ax
  1943.     call    set_scale
  1944.     pop    bp
  1945.     ret
  1946. _srand48    endp
  1947.  
  1948.  
  1949. ;  short  *seed48( short  newseed[3] )
  1950.  
  1951. _seed48        proc   near
  1952.     push    bp
  1953.     mov    bp, sp
  1954.     push    si
  1955.     push    di
  1956.     push    ds
  1957.     pop    es
  1958.     cld
  1959.     mov    di, offset seedbuf  ;  save old seed
  1960.     mov    si, offset seed
  1961.     mov    cx, 3
  1962.     rep    movsw
  1963.     mov    si, [bp+4]   ;  load the new seed
  1964.     mov    di, offset seed
  1965.     mov    cx, 3
  1966.     rep    movsw
  1967.     call    set_scale
  1968.     mov    ax, offset seedbuf
  1969.     pop    di
  1970.     pop    si
  1971.     pop    bp
  1972.     ret
  1973. _seed48    endp
  1974.  
  1975.  
  1976. ;  long  mrand48()
  1977. ;  long  jrand48(short seed[3])
  1978.  
  1979. _mrand48    proc    near
  1980.     mov    bx, offset seed
  1981.     call    rgen
  1982.     mov    dx, seed+4
  1983.     mov    ax, seed+2
  1984.     ret
  1985. _mrand48    endp
  1986.  
  1987. _jrand48    proc    near
  1988.     push    bp
  1989.     mov    bp, sp
  1990.     mov    bx, [bp+4]
  1991.     call    rgen
  1992.     mov    dx, word ptr [bx+4]
  1993.     mov    ax, word ptr [bx+2]
  1994.     pop    bp
  1995.     ret
  1996. _jrand48    endp
  1997.  
  1998. _nrand48    proc     near
  1999.     push    bp
  2000.     mov    bp, sp
  2001.     mov    bx, [bp+4]
  2002.     call    rgen
  2003.     mov    dx, [bx+4]
  2004.     mov    ax, [bx+2]
  2005.     shr    dx, 1
  2006.     rcr    ax, 1
  2007.     pop    bp
  2008.     ret
  2009. _nrand48    endp
  2010.  
  2011. _lrand48    proc    near
  2012.     mov    bx, offset seed
  2013.     call    rgen
  2014.     mov    dx, seed+4
  2015.     mov    ax, seed+2
  2016.     shr     dx, 1
  2017.     rcr     ax, 1
  2018.     ret
  2019. _lrand48    endp
  2020.  
  2021. _vrand48    proc   near
  2022.     push    bp
  2023.     mov    bp, sp
  2024.     mov    bx, [bp+4]
  2025.     call    rgen
  2026.     mov    ax, [bx+4]
  2027.     pop    bp
  2028.     ret
  2029. _vrand48    endp
  2030.  
  2031. _urand48    proc    near
  2032.     mov    bx, offset seed
  2033.     call    rgen
  2034.     mov    ax, seed+4
  2035.     ret
  2036. _urand48    endp
  2037.  
  2038. _lcong48    proc     near
  2039.     push    bp
  2040.     mov    bp, sp
  2041.     push    si
  2042.     push    di
  2043.     push    ds
  2044.     pop    es
  2045.     cld
  2046.     mov    si, [bp+4]
  2047.     mov    di, offset seed
  2048.     mov    cx, 7
  2049.     rep    movsw
  2050.     pop    di
  2051.     pop    si
  2052.     pop    bp
  2053.     ret
  2054. _lcong48    endp
  2055.  
  2056. end
  2057. @//E*O*F mawk0.97/msdos/rand48.asm//
  2058. chmod u=r,g=r,o=r mawk0.97/msdos/rand48.asm
  2059.  
  2060. echo x - mawk0.97/msdos/rand48.h
  2061. sed 's/^@//' > "mawk0.97/msdos/rand48.h" <<'@//E*O*F mawk0.97/msdos/rand48.h//'
  2062.  
  2063. /*  rand48.h  */
  2064. /*  see Unix drand(3) for expansive discussion */
  2065.  
  2066. double  drand48(void) ;
  2067. double  erand48(unsigned short[3]) ;
  2068.  
  2069. long   mrand48(void) ;
  2070. long   jrand48(unsigned short[3]) ;
  2071. /* uniform on [-2^31, 2^31)  or
  2072.    [0,2^32)  depending on how you interpret the sign bit */
  2073.  
  2074. long  lrand48(void) ;
  2075. long  nrand48(unsigned short[3]) ;
  2076. /* uniform on [0,2^31)
  2077.    lrand48() == mrand48()>>1   */
  2078.  
  2079. unsigned  urand48(void) ;
  2080. unsigned  vrand48(unsigned short[3]) ;
  2081. /*  for 16bit machines uniform on [0,2^16)  */
  2082.  
  2083. /* SEEDING  */
  2084. void  srand48(long seedval) ;
  2085. unsigned short *seed48(unsigned short seedv[3]) ;
  2086. void  lcong(unsigned short[7] ) ;
  2087.  
  2088.  
  2089. void  srand48() ;
  2090. long  mrand48(), jrand48(), lrand48(), nrand48() ;
  2091. unsigned urand48(), vrand48() ;
  2092. double  drand48(), erand48() ;
  2093. @//E*O*F mawk0.97/msdos/rand48.h//
  2094. chmod u=r,g=r,o=r mawk0.97/msdos/rand48.h
  2095.  
  2096. echo x - mawk0.97/msdos/rand48_0.c
  2097. sed 's/^@//' > "mawk0.97/msdos/rand48_0.c" <<'@//E*O*F mawk0.97/msdos/rand48_0.c//'
  2098.  
  2099.  
  2100. /*   rand0.c    */
  2101.  
  2102. unsigned long  mrand48() ;
  2103. unsigned long  jrand48(short [3]) ;
  2104.  
  2105. double  drand48()
  2106. { return  (double) mrand48() / 4294967296.0 ; }
  2107.  
  2108. double  erand48(short x[3])
  2109. { return  (double) jrand48(x) /  4294967296.0 ; }
  2110. @//E*O*F mawk0.97/msdos/rand48_0.c//
  2111. chmod u=r,g=r,o=r mawk0.97/msdos/rand48_0.c
  2112.  
  2113. echo x - mawk0.97/msdos/reargv.c
  2114. sed 's/^@//' > "mawk0.97/msdos/reargv.c" <<'@//E*O*F mawk0.97/msdos/reargv.c//'
  2115.  
  2116. /*  reargv.c
  2117.     --  set arguments via POLYSHELL
  2118.     --  no errors, don't change anything if
  2119.     --  it seems shell is not activated   */
  2120.  
  2121. char *strchr(), *getenv() ;
  2122.  
  2123. static  char *basename(char *s)
  2124. /* strip path and extension , upcase the rest */
  2125.   register char *p ;
  2126.  
  2127.   for ( p = strchr(s,0) ; p > s ; p-- )
  2128.     switch( p[-1] )
  2129.      { case '\\' :
  2130.        case ':'  :
  2131.        case '/'  :  return p ;
  2132.        case '.'  :  p[-1] = 0 ;  break ;
  2133.        default   :
  2134.         if ( p[-1] >= 'a' && p[-1] <= 'z' )   p[-1] -= 32 ;
  2135.         break ;
  2136.      }
  2137.  
  2138.   return  p ;
  2139. }
  2140.  
  2141. /*---------------------
  2142.   reargv  --  recompute  argc and argv for PolyShell
  2143.     if not under shell do nothing
  2144.  *-------------------------------  */
  2145.  
  2146. extern  char *progname ;
  2147. extern  unsigned char _osmajor ;
  2148.  
  2149. void  reargv(int *argcp , char ***argvp)
  2150. { register char *p ;
  2151.   char **v , *q, *cmdline, **vx ;
  2152.   int cnt, cntx ;
  2153.  
  2154.   if ( _osmajor == 2 )  /* ugh */
  2155.      (*argvp)[0] = progname ;
  2156.   else { (*argvp)[0] = basename( (*argvp)[0] ) ;
  2157.      progname = (*argvp)[0] ; }
  2158.  
  2159.   if ( ! (cmdline = getenv("CMDLINE")) )  return ;
  2160.  
  2161.   if ( *(q = strchr(cmdline,0) - 1) != 0xff )
  2162.       return ;  /*  shexpand set wrong */
  2163.  
  2164.   for ( *q = 0, cnt = 1 , p = cmdline ; p < q ; p++ )
  2165.      if ( *p == 0xff ) { cnt++ ; *p = 0 ; }
  2166.  
  2167.   if ( ! (v = (char **) malloc((cnt+1)*sizeof(char*))) )
  2168.        return ;  /* shouldn't happen */
  2169.  
  2170.   p = cmdline ;
  2171.   vx = v ; cntx = cnt ;
  2172.   while ( cnt )
  2173.    { *v++ = p ;
  2174.      cnt-- ;
  2175.      while ( *p )  p++ ;
  2176.      p++ ;
  2177.    }
  2178.   *v = (char *) 0 ;
  2179.   v = vx ;
  2180.  
  2181.   v[0] = basename( v[0] ) ;
  2182.   if ( strcmp(v[0], (*argvp)[0]) )  return  ;/* running under command
  2183.     and sh earlier  */
  2184.   /* running under PolyShell  */
  2185.   *argcp = cntx ;  *argvp = v ;
  2186.   progname = v[0] ;
  2187. }
  2188. @//E*O*F mawk0.97/msdos/reargv.c//
  2189. chmod u=r,g=r,o=r mawk0.97/msdos/reargv.c
  2190.  
  2191. echo Inspecting for damage in transit...
  2192. temp=/tmp/shar$$; dtemp=/tmp/.shar$$
  2193. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  2194. cat > $temp <<\!!!
  2195.      110     194    1897 packing.list
  2196.       21      66     407 README
  2197.       38     203    1246 LIMITATIONS
  2198.       78     450    3560 Makefile
  2199.      639    3453   20668 mawk.manual
  2200.      235    1062    5676 array.c
  2201.      781    2886   17818 bi_funct.c
  2202.       68     279    1720 bi_funct.h
  2203.       87     284    1910 bi_vars.c
  2204.       61     193    1374 bi_vars.h
  2205.      354    1074    7389 cast.c
  2206.      102     361    2538 code.c
  2207.      141     407    3421 code.h
  2208.      386    1119    9666 da.c
  2209.      345    1188    7739 error.c
  2210.      927    3424   26735 execute.c
  2211.      365    1360    9733 fcall.c
  2212.      404    1378    9426 field.c
  2213.       65     199    1432 field.h
  2214.      299    1085    7060 files.c
  2215.       41     132    1006 files.h
  2216.      368    1464    8781 fin.c
  2217.       48     185    1167 fin.h
  2218.      169     622    3566 hash.c
  2219.      202     718    4475 init.c
  2220.       44     160    1143 init.h
  2221.      217     864    5679 jmp.c
  2222.       35     122     876 jmp.h
  2223.       83     270    1572 kw.c
  2224.      160     584    4357 machine.h
  2225.      151     453    3001 main.c
  2226.      107     378    2495 makescan.c
  2227.      106     285    2019 matherr.c
  2228.      142     567    3652 mawk.h
  2229.       95     312    2268 memory.c
  2230.       50     129    1088 memory.h
  2231.     1076    3677   30281 parse.y
  2232.      285    1176    7197 print.c
  2233.      321    1215    7100 re_cmpl.c
  2234.       32     112     793 regexp.h
  2235.       37     128     898 repl.h
  2236.      694    2586   18298 scan.c
  2237.      107     315    2906 scan.h
  2238.       23      36     832 scancode.c
  2239.       56     201    1446 sizes.h
  2240.      174     644    3952 split.c
  2241.      162     633    4106 symtype.h
  2242.      112     344    2840 types.h
  2243.      129     537    3196 zmalloc.c
  2244.       44     118     905 zmalloc.h
  2245.       26      72     446 Makefile
  2246.      186     815    5015 rexp.c
  2247.      153     565    3636 rexp.h
  2248.      423    1718   10188 rexp0.c
  2249.      183     708    3987 rexp1.c
  2250.      282    1139    7507 rexp2.c
  2251.      272    1335    7457 rexp3.c
  2252.       74     252    1649 rexpdb.c
  2253.       23     106     710 README
  2254.       72     343    2430 benchmarks
  2255.        1       3      11 cat.awk
  2256.        6      12      59 concat.awk
  2257.        6      13      69 fields.awk
  2258.       23      49     201 loops.awk
  2259.       22      53     286 newton.awk
  2260.       40     129     564 primes.awk
  2261.       78     234    1076 qsort.awk
  2262.        2       4      34 reg0.awk
  2263.        2       4      41 reg1.awk
  2264.        2       5      63 reg2.awk
  2265.       13      71     461 sample
  2266.        7      19      82 squeeze.awk
  2267.       43     111     621 test.sh
  2268.        3       7      33 wc.awk
  2269.       91     363    1765 wfrq.awk
  2270.       72     297    1433 wfrq0.awk
  2271.       23      64     275 words.awk
  2272.       12      29     127 words0.awk
  2273.      143     546    3030 decl.awk
  2274.       57     241    1284 deps.awk
  2275.      136     493    2776 gdecl.awk
  2276.       18      44     213 nocomment.awk
  2277.       80     522    3002 INSTALL
  2278.      137     553    4067 makefile
  2279.        8      16     107 mklib.bat
  2280.      227     620    3670 rand48.asm
  2281.       31     106     774 rand48.h
  2282.       12      33     231 rand48_0.c
  2283.       74     333    1727 reargv.c
  2284.    13839   51659  344417 total
  2285. !!!
  2286. wc mawk0.97/packing.list mawk0.97/README mawk0.97/LIMITATIONS \
  2287.  mawk0.97/Makefile mawk0.97/mawk.manual mawk0.97/array.c \
  2288.  mawk0.97/bi_funct.c mawk0.97/bi_funct.h mawk0.97/bi_vars.c \
  2289.  mawk0.97/bi_vars.h mawk0.97/cast.c mawk0.97/code.c \
  2290.  mawk0.97/code.h mawk0.97/da.c mawk0.97/error.c mawk0.97/execute.c \
  2291.  mawk0.97/fcall.c mawk0.97/field.c mawk0.97/field.h \
  2292.  mawk0.97/files.c mawk0.97/files.h mawk0.97/fin.c mawk0.97/fin.h \
  2293.  mawk0.97/hash.c mawk0.97/init.c mawk0.97/init.h mawk0.97/jmp.c \
  2294.  mawk0.97/jmp.h mawk0.97/kw.c mawk0.97/machine.h mawk0.97/main.c \
  2295.  mawk0.97/makescan.c mawk0.97/matherr.c mawk0.97/mawk.h \
  2296.  mawk0.97/memory.c mawk0.97/memory.h mawk0.97/parse.y \
  2297.  mawk0.97/print.c mawk0.97/re_cmpl.c mawk0.97/regexp.h \
  2298.  mawk0.97/repl.h mawk0.97/scan.c mawk0.97/scan.h mawk0.97/scancode.c \
  2299.  mawk0.97/sizes.h mawk0.97/split.c mawk0.97/symtype.h \
  2300.  mawk0.97/types.h mawk0.97/zmalloc.c mawk0.97/zmalloc.h \
  2301.  mawk0.97/rexp/Makefile mawk0.97/rexp/rexp.c mawk0.97/rexp/rexp.h \
  2302.  mawk0.97/rexp/rexp0.c mawk0.97/rexp/rexp1.c mawk0.97/rexp/rexp2.c \
  2303.  mawk0.97/rexp/rexp3.c mawk0.97/rexp/rexpdb.c mawk0.97/test/README \
  2304.  mawk0.97/test/benchmarks mawk0.97/test/cat.awk mawk0.97/test/concat.awk \
  2305.  mawk0.97/test/fields.awk mawk0.97/test/loops.awk mawk0.97/test/newton.awk \
  2306.  mawk0.97/test/primes.awk mawk0.97/test/qsort.awk mawk0.97/test/reg0.awk \
  2307.  mawk0.97/test/reg1.awk mawk0.97/test/reg2.awk mawk0.97/test/sample \
  2308.  mawk0.97/test/squeeze.awk mawk0.97/test/test.sh mawk0.97/test/wc.awk \
  2309.  mawk0.97/test/wfrq.awk mawk0.97/test/wfrq0.awk mawk0.97/test/words.awk \
  2310.  mawk0.97/test/words0.awk mawk0.97/examples/decl.awk \
  2311.  mawk0.97/examples/deps.awk mawk0.97/examples/gdecl.awk \
  2312.  mawk0.97/examples/nocomment.awk mawk0.97/msdos/INSTALL \
  2313.  mawk0.97/msdos/makefile mawk0.97/msdos/mklib.bat mawk0.97/msdos/rand48.asm \
  2314.  mawk0.97/msdos/rand48.h mawk0.97/msdos/rand48_0.c mawk0.97/msdos/reargv.c \
  2315.  | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  2316. if [ -s $dtemp ]
  2317. then echo "Ouch [diff of wc output]:" ; cat $dtemp
  2318. else echo "No problems found."
  2319. fi
  2320. exit 0
  2321.  
  2322.  
  2323.