home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / m / mawk11as.zip / SCAN.C < prev    next >
C/C++ Source or Header  |  1991-12-18  |  22KB  |  833 lines

  1.  
  2. /********************************************
  3. scan.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.  
  14. /* $Log:    scan.c,v $
  15.  * Revision 5.1  91/12/05  07:56:27  brennan
  16.  * 1.1 pre-release
  17.  * 
  18. */
  19.  
  20.  
  21. #include  "mawk.h"
  22. #include  "sizes.h"
  23. #include  "scan.h"
  24. #include  "memory.h"
  25. #include  "field.h"
  26. #include  "init.h"
  27. #include  "fin.h"
  28. #include  "repl.h"
  29. #include  "code.h"
  30.  
  31. #if HAVE_FCNTL_H
  32. #include  <fcntl.h>
  33. #endif
  34.  
  35. #include  "files.h"
  36.  
  37.  
  38. /* static functions */
  39. static void PROTO(scan_fillbuff, (void) ) ;
  40. static void PROTO(scan_open, (void) ) ;
  41. static int PROTO(slow_next, (void) ) ;
  42. static void PROTO(eat_comment, (void) ) ;
  43. static void PROTO(eat_semi_colon, (void) ) ;
  44. static double PROTO(collect_decimal, (int, int *) ) ;
  45. static int PROTO(collect_string, (void) ) ;
  46. static int  PROTO(collect_RE, (void) ) ;
  47.  
  48.  
  49. /*-----------------------------
  50.   program file management
  51.  *----------------------------*/
  52.  
  53. char *pfile_name ;
  54. STRING  *program_string ;
  55. PFILE *pfile_list ;
  56. static  unsigned char *buffer ;
  57. static  unsigned char *buffp ;  
  58.     /* unsigned so it works with 8 bit chars */
  59. static  int  program_fd   ; 
  60. static  int  eof_flag ;
  61.  
  62. void  scan_init(cmdline_program)
  63.   char * cmdline_program ;
  64.   if ( cmdline_program )
  65.   {
  66.     program_fd = -1 ; /* command line program */
  67.     program_string = new_STRING((char *)0, 
  68.                 strlen(cmdline_program) + 1 ) ;
  69.     (void) strcpy(program_string->str, cmdline_program) ;
  70.     /* simulate file termination */
  71.     program_string->str[program_string->len-1] = '\n' ;
  72.     buffp = (unsigned char *)  program_string->str ;
  73.     eof_flag = 1 ;
  74.   }
  75.   else /* program from file[s] */
  76.   {
  77.     scan_open() ;
  78.     buffp = buffer = (unsigned char *) zmalloc( BUFFSZ+1 ) ;
  79.     scan_fillbuff() ;
  80.   }
  81.  
  82.   eat_nl() ; /* scan to first token */
  83.   if ( next() == 0 ) { errmsg(0, "no program") ; mawk_exit(1) ; }
  84.   un_next() ;
  85.   
  86. }
  87.  
  88. static void  scan_open() /* open pfile_name */
  89. {
  90.   if ( pfile_name[0] == '-' && pfile_name[1] == 0 )
  91.         program_fd = 0 ;
  92.   else
  93.   if ( (program_fd = open(pfile_name, O_RDONLY, 0)) == -1 )
  94.   { errmsg( errno, "cannot open %s", pfile_name) ; mawk_exit(1) ; }
  95. }
  96.  
  97. void scan_cleanup()
  98.   if ( program_fd >= 0 ) zfree(buffer, BUFFSZ+1) ;
  99.   else  free_STRING(program_string) ;
  100.  
  101.   if ( program_fd > 0 )  (void) close(program_fd) ;
  102.  
  103.   /* redefine SPACE as [ \t\n] */
  104.  
  105.   scan_code['\n'] = posix_space_flag && rs_shadow.type != SEP_MLR
  106.             ? SC_UNEXPECTED : SC_SPACE ;
  107.   scan_code['\f'] = SC_UNEXPECTED ; /*value doesn't matter */
  108.   scan_code['\013'] = SC_UNEXPECTED ; /* \v not space */
  109.   scan_code['\r'] = SC_UNEXPECTED ;
  110. }
  111.  
  112. /*--------------------------------
  113.   global variables shared by yyparse() and yylex()
  114.   and used for error messages too
  115.  *-------------------------------*/
  116.  
  117. int  current_token = -1 ; 
  118. unsigned  token_lineno ;
  119. unsigned  compile_error_count ;
  120. int   NR_flag ; /* are we tracking NR */
  121. int   paren_cnt ;
  122. int   brace_cnt ;
  123. int   print_flag ;  /* changes meaning of '>' */
  124. int   getline_flag ; /* changes meaning of '<' */
  125.  
  126. extern  YYSTYPE  yylval ;
  127.  
  128. /*----------------------------------------
  129.  file reading functions
  130.  next() and un_next(c) are macros in scan.h
  131.  
  132.  *---------------------*/
  133.  
  134. static  unsigned lineno = 1 ;
  135.  
  136.  
  137. static  void scan_fillbuff()
  138. { unsigned r ;
  139.  
  140.   r = fillbuff(program_fd, (char *)buffer, BUFFSZ) ;
  141.   if ( r < BUFFSZ ) 
  142.   { eof_flag = 1 ;
  143.     /* check eof is terminated */
  144.     if ( r && buffer[r-1] != '\n' )
  145.     { buffer[r] = '\n' ; buffer[r+1] = 0 ; }
  146.   }
  147. }
  148.  
  149. /* read one character -- slowly */
  150. static int slow_next()
  151.    
  152.   while ( *buffp == 0 )
  153.   {
  154.     if ( !eof_flag ) 
  155.     { buffp = buffer ; scan_fillbuff() ; }
  156.     else
  157.     if ( pfile_list /* open another program file */ )
  158.     {
  159.       PFILE *q ;
  160.  
  161.       if ( program_fd > 0 ) (void) close(program_fd) ;
  162.       eof_flag = 0 ;
  163.       pfile_name = pfile_list->fname ;
  164.       q = pfile_list ;
  165.       pfile_list = pfile_list->link ;
  166.       ZFREE(q) ;
  167.       scan_open() ;
  168.       token_lineno = lineno = 1 ;
  169.     }
  170.     else  break /* real eof */ ;
  171.   }
  172.  
  173.   return *buffp++ ; /* note can un_next() , eof which is zero */
  174. }
  175.  
  176. static void eat_comment()
  177. { register int c ;
  178.  
  179.   while ( (c = next()) != '\n' && scan_code[c] ) ;
  180.   un_next() ;
  181. }
  182.  
  183. /* this is how we handle extra semi-colons that are
  184.    now allowed to separate pattern-action blocks
  185.  
  186.    A proof that they are useless clutter to the language:
  187.    we throw them away
  188. */
  189.  
  190. static  void  eat_semi_colon()
  191. /* eat one semi-colon on the current line */
  192. { register int c ;
  193.  
  194.   while ( scan_code[c = next()] == SC_SPACE )  ;
  195.   if ( c != ';' )  un_next() ;
  196. }
  197.  
  198. void eat_nl() /* eat all space including newlines */
  199. {
  200.   while ( 1 )
  201.     switch( scan_code[next()] )
  202.     { 
  203.       case SC_COMMENT : 
  204.          eat_comment() ;
  205.          break ;
  206.          
  207.       case  SC_NL  :   lineno++ ;
  208.       /* fall thru  */
  209.       case  SC_SPACE  :   break ;
  210.       default :  
  211.           un_next() ; return ;
  212.     }
  213. }
  214.  
  215. int yylex()
  216.   register int c ;
  217.  
  218.   token_lineno = lineno ;
  219.  
  220. reswitch:
  221.  
  222.     switch( scan_code[c = next()] )
  223.     {
  224.       case  0  :  
  225.           ct_ret(EOF) ;
  226.           
  227.       case  SC_SPACE  :   goto reswitch ;
  228.  
  229.       case  SC_COMMENT :
  230.           eat_comment() ; goto reswitch ;
  231.  
  232.       case  SC_NL  : 
  233.           lineno++ ; eat_nl() ;
  234.           ct_ret(NL) ;
  235.  
  236.       case SC_ESCAPE :
  237.           while ( scan_code[ c = next() ] == SC_SPACE ) ;
  238.           if ( c == '\n')
  239.           { token_lineno = ++lineno ; goto reswitch ; }
  240.           if ( c == 0 )  ct_ret(EOF) ;
  241.           un_next() ;
  242.           yylval.ival = '\\' ;
  243.           ct_ret(UNEXPECTED) ;
  244.  
  245.  
  246.       case  SC_SEMI_COLON  : 
  247.           eat_nl() ;
  248.           ct_ret(SEMI_COLON) ;
  249.  
  250.       case  SC_LBRACE :  
  251.           eat_nl() ; brace_cnt++ ;
  252.           ct_ret(LBRACE) ;
  253.  
  254.       case  SC_PLUS  :
  255.           switch( next() )
  256.           {
  257.             case '+' :  
  258.                 yylval.ival = '+' ;
  259.                 string_buff[0] = 
  260.                      string_buff[1] = '+' ;
  261.                 string_buff[2] = 0 ;
  262.                 ct_ret(INC_or_DEC) ;
  263.  
  264.             case  '=' :
  265.                 ct_ret(ADD_ASG) ;
  266.  
  267.             default :  un_next() ; ct_ret(PLUS) ;
  268.           }
  269.  
  270.       case  SC_MINUS :
  271.           switch( next() )
  272.           {
  273.             case '-' :  
  274.                 yylval.ival = '-' ;
  275.                 string_buff[0] = 
  276.                      string_buff[1] = '-' ;
  277.                 string_buff[2] = 0 ;
  278.                 ct_ret(INC_or_DEC) ;
  279.  
  280.             case  '=' :
  281.                 ct_ret(SUB_ASG) ;
  282.  
  283.             default :  un_next() ; ct_ret(MINUS) ;
  284.           }
  285.  
  286.       case  SC_COMMA :  eat_nl() ; ct_ret(COMMA) ;
  287.  
  288.       case  SC_MUL  :  test1_ret('=', MUL_ASG, MUL) ;
  289.       case  SC_DIV :   
  290.           { static int can_precede_div[] =
  291.         { DOUBLE, STRING_, RPAREN, ID, D_ID, RE, RBOX, FIELD,
  292.           GETLINE, INC_or_DEC, -1 } ;
  293.           
  294.           int *p = can_precede_div ;
  295.  
  296.             do
  297.                 if ( *p == current_token )
  298.         {
  299.           if ( *p != INC_or_DEC ) 
  300.             test1_ret('=', DIV_ASG, DIV) ;
  301.  
  302.           if ( next() == '=' )
  303.           { un_next() ; ct_ret( collect_RE() ) ;  }
  304.         }
  305.                  
  306.             while ( * ++p != -1 ) ;
  307.  
  308.             ct_ret( collect_RE() ) ;
  309.           }
  310.  
  311.       case  SC_MOD  :  test1_ret('=', MOD_ASG, MOD) ;
  312.       case  SC_POW :   test1_ret('=' , POW_ASG, POW) ;
  313.       case  SC_LPAREN : 
  314.           paren_cnt++ ;
  315.           ct_ret(LPAREN) ;
  316.  
  317.       case  SC_RPAREN : 
  318.           if ( --paren_cnt < 0 )
  319.           { compile_error( "extra ')'" ) ;
  320.             paren_cnt = 0 ;
  321.             goto reswitch ; }
  322.  
  323.           ct_ret(RPAREN) ;
  324.  
  325.       case  SC_LBOX   : ct_ret(LBOX) ;
  326.       case  SC_RBOX   : ct_ret(RBOX) ;
  327.  
  328.       case  SC_MATCH  : 
  329.       string_buff[0] = '~' ; string_buff[0] = 0 ;
  330.       yylval.ival = 1 ;
  331.       ct_ret(MATCH) ;
  332.  
  333.       case  SC_EQUAL  :
  334.           test1_ret( '=', EQ, ASSIGN ) ;
  335.  
  336.       case  SC_NOT : /* !  */
  337.       if ( (c = next()) == '~' )
  338.       {
  339.         string_buff[0] = '!' ;
  340.         string_buff[1] = '~' ;
  341.         string_buff[2] = 0 ;
  342.         yylval.ival = 0 ;
  343.         ct_ret(MATCH) ;
  344.       }
  345.       else
  346.       if ( c == '=' )  ct_ret(NEQ) ;
  347.  
  348.       un_next() ;
  349.       ct_ret(NOT) ;
  350.  
  351.  
  352.       case  SC_LT  :  /* '<' */
  353.           if ( getline_flag )
  354.           { getline_flag = 0 ; ct_ret(IO_IN) ; }
  355.           else
  356.             test1_ret('=', LTE, LT) ;
  357.  
  358.       case  SC_GT  :  /* '>' */
  359.           if ( print_flag && paren_cnt == 0 )
  360.           { print_flag = 0 ;
  361.             /* there are 3 types of IO_OUT 
  362.                -- build the error string in string_buff */
  363.             string_buff[0] = '>' ;
  364.             if ( next() == '>' ) 
  365.             { 
  366.               yylval.ival = F_APPEND ;
  367.               string_buff[1] = '>' ;
  368.               string_buff[2] =  0 ;
  369.             }
  370.             else
  371.             { un_next() ; 
  372.               yylval.ival = F_TRUNC ; 
  373.               string_buff[1] = 0 ;
  374.             }
  375.             return current_token = IO_OUT ;
  376.           }
  377.  
  378.           test1_ret('=', GTE, GT) ;
  379.  
  380.       case  SC_OR :
  381.           if ( next() == '|' ) 
  382.           { eat_nl() ; ct_ret(OR) ; }
  383.           else 
  384.           { un_next() ; 
  385.  
  386.             if ( print_flag && paren_cnt == 0 )
  387.             { print_flag = 0 ; 
  388.               yylval.ival = PIPE_OUT;
  389.               string_buff[0] = '|' ;
  390.               string_buff[1] = 0 ;
  391.               ct_ret(IO_OUT) ;
  392.             }
  393.             else  ct_ret(PIPE) ;
  394.           }
  395.  
  396.       case  SC_AND :
  397.           if ( next() == '&' )  
  398.           { eat_nl() ; ct_ret(AND) ; }
  399.           else 
  400.           { un_next() ; yylval.ival = '&' ; ct_ret(UNEXPECTED) ; }
  401.  
  402.       case  SC_QMARK  :  ct_ret(QMARK) ;
  403.       case  SC_COLON  :  ct_ret(COLON) ;
  404.       case  SC_RBRACE :
  405.           if ( --brace_cnt < 0 )
  406.           { compile_error("extra '}'" ) ;
  407.             eat_semi_colon() ;
  408.             brace_cnt = 0 ; goto reswitch ; }
  409.  
  410.           if ( (c = current_token) == NL || c == SEMI_COLON 
  411.                || c == SC_FAKE_SEMI_COLON  || c == RBRACE  )
  412.           { 
  413.             /* if the brace_cnt is zero , we've completed
  414.                a pattern action block. If the user insists
  415.                on adding a semi-colon on the same line
  416.                we will eat it.  Note what we do below:
  417.                physical law -- conservation of semi-colons */
  418.  
  419.             if ( brace_cnt == 0 )  eat_semi_colon() ;
  420.             eat_nl() ;
  421.             ct_ret(RBRACE) ;
  422.           }
  423.  
  424.           /* supply missing semi-colon to statement that
  425.              precedes a '}' */
  426.           brace_cnt++ ; un_next() ;
  427.           current_token = SC_FAKE_SEMI_COLON ;
  428.           return  SEMI_COLON ;
  429.  
  430.       case  SC_DIGIT  :
  431.       case  SC_DOT    :
  432.           { double d ;
  433.             int flag ;
  434.         static double double_zero = 0.0 ;
  435.         static double double_one = 1.0 ;
  436.  
  437.             if ( (d = collect_decimal(c, &flag)) == 0.0 )
  438.                 if ( flag )  ct_ret(flag) ;
  439.                 else  yylval.ptr = (PTR) &double_zero ;
  440.             else if ( d == 1.0 ) yylval.ptr = (PTR) &double_one ;
  441.             else 
  442.             { yylval.ptr = (PTR) ZMALLOC(double) ;
  443.           *(double*)yylval.ptr = d ;
  444.             }
  445.             ct_ret( DOUBLE ) ;
  446.           }
  447.  
  448.       case  SC_DOLLAR :  /* '$' */
  449.           { double d ;
  450.             int flag ;
  451.  
  452.             while ( scan_code[c = next()] == SC_SPACE )  ;
  453.             if ( scan_code[c] != SC_DIGIT &&
  454.                  scan_code[c] != SC_DOT )
  455.             { un_next() ; ct_ret(DOLLAR) ; }
  456.             /* compute field address at compile time */
  457.             if ( (d = collect_decimal(c, &flag)) == 0.0 )
  458.                 if ( flag )  ct_ret(flag) ; /* an error */
  459.                 else  yylval.cp = &field[0] ;
  460.             else
  461.             { int k = (int) d ;
  462.  
  463.               if ( k > MAX_FIELD )
  464.               { compile_error(
  465.                    "$%g exceeds maximum field(%d)" , d, MAX_FIELD) ;
  466.                 k = MAX_FIELD ;
  467.               }
  468.               yylval.cp = field_ptr(k) ;
  469.             }
  470.  
  471.             ct_ret(FIELD) ;
  472.           }
  473.  
  474.       case  SC_DQUOTE :
  475.           return current_token = collect_string() ;
  476.  
  477.       case  SC_IDCHAR : /* collect an identifier */
  478.             { unsigned char *p =
  479.                     (unsigned char *)string_buff + 1 ;
  480.               SYMTAB *stp ;
  481.  
  482.               string_buff[0] = c ;
  483.  
  484.               while ( 
  485.                 (c = scan_code[ *p++ = next()]) == SC_IDCHAR ||
  486.                        c == SC_DIGIT )  ;
  487.               
  488.               un_next() ; * --p = 0 ;
  489.  
  490.               switch( (stp = find(string_buff))->type )
  491.               { case ST_NONE :  
  492.                   /* check for function call before defined */
  493.                       if ( next() == '(' )
  494.                       { stp->type = ST_FUNCT ;
  495.                         stp->stval.fbp = (FBLOCK *)
  496.                                 zmalloc(sizeof(FBLOCK)) ;
  497.                         stp->stval.fbp->name = stp->name ;
  498.                         stp->stval.fbp->code = (INST *) 0 ;
  499.                         yylval.fbp = stp->stval.fbp ;
  500.                         current_token = FUNCT_ID ;
  501.                       }
  502.                       else
  503.                       { yylval.stp = stp ;
  504.                         current_token = 
  505.                             current_token == DOLLAR ? D_ID : ID ;
  506.                       }
  507.                       un_next() ;
  508.                       break ;
  509.  
  510.                 case  ST_NR  :
  511.               NR_flag = 1 ;
  512.                       stp->type = ST_VAR ;
  513.                       /* fall thru */
  514.                         
  515.                 case ST_VAR :
  516.                 case  ST_ARRAY :
  517.                 case  ST_LOCAL_NONE :
  518.                 case  ST_LOCAL_VAR :
  519.                 case  ST_LOCAL_ARRAY :
  520.  
  521.                       yylval.stp = stp ;
  522.                       current_token =
  523.                             current_token == DOLLAR ? D_ID : ID ;
  524.                       break ;
  525.  
  526.         case ST_ENV :
  527.               stp->type = ST_ARRAY ;
  528.               stp->stval.array = new_ARRAY() ;
  529.               load_environ(stp->stval.array) ;
  530.               yylval.stp = stp ;
  531.               current_token =
  532.               current_token == DOLLAR ? D_ID : ID ;
  533.               break ;
  534.  
  535.                 case ST_FUNCT :
  536.                       yylval.fbp = stp->stval.fbp ;
  537.                       current_token = FUNCT_ID ;
  538.                       break ;
  539.  
  540.                 case ST_KEYWORD :  
  541.                       current_token = stp->stval.kw ;
  542.                       break ;
  543.  
  544.                 case  ST_BUILTIN :
  545.                       yylval.bip = stp->stval.bip ;
  546.                       current_token = BUILTIN ;
  547.                       break ;
  548.  
  549.                 case  ST_FIELD  :
  550.                       yylval.cp = stp->stval.cp ;
  551.                       current_token = FIELD ;
  552.                       break ;
  553.  
  554.                 default : 
  555.                       bozo("find returned bad st type") ;
  556.               }
  557.               return  current_token  ;
  558.             }
  559.  
  560.  
  561.       case  SC_UNEXPECTED :
  562.             yylval.ival = c & 0xff ;
  563.             ct_ret(UNEXPECTED) ;
  564.     }
  565.     return  0 ; /* never get here make lint happy */
  566. }
  567.  
  568. /* collect a decimal constant in temp_buff.
  569.    Return the value and error conditions by reference */
  570.  
  571. static double collect_decimal(c, flag)
  572.   int c ; int *flag ;
  573. { register unsigned char *p = (unsigned char*) string_buff + 1;
  574.   unsigned char *endp ;
  575.   double d ;
  576.  
  577.   *flag = 0 ;
  578.   string_buff[0] = c ;
  579.  
  580.   if ( c == '.' )
  581.   { if ( scan_code[*p++ = next()] != SC_DIGIT )
  582.     { *flag = UNEXPECTED ; yylval.ival = '.' ;
  583.       return 0.0 ; }
  584.   }
  585.   else
  586.   {  while ( scan_code[*p++ = next()] == SC_DIGIT ) ;
  587.      if ( p[-1] != '.' )
  588.      { un_next() ; p-- ; }
  589.   }
  590.   /* get rest of digits after decimal point */
  591.   while ( scan_code[*p++ = next()] == SC_DIGIT )  ;
  592.  
  593.   /* check for exponent */
  594.   if ( p[-1] != 'e' && p[-1] != 'E' )
  595.   { un_next() ; * --p = 0 ; }
  596.   else  /* get the exponent */
  597.     if ( scan_code[*p = next()] != SC_DIGIT &&
  598.          *p != '-' && *p != '+' )
  599.     { *++p = 0 ; *flag = BAD_DECIMAL ;
  600.       return 0.0 ; }
  601.     else  /* get the rest of the exponent */
  602.     { p++ ;
  603.       while ( scan_code[*p++ = next()] == SC_DIGIT )  ;
  604.       un_next() ; * --p = 0 ;
  605.     }
  606.  
  607.   errno = 0 ; /* check for overflow/underflow */
  608.   d = strtod( string_buff, (char **)&endp ) ;
  609.  
  610. #ifndef  STRTOD_UNDERFLOW_ON_ZERO_BUG
  611.   if ( errno )
  612.       compile_error( "%s : decimal %sflow" , string_buff,
  613.         d == 0.0 ? "under" : "over") ;
  614. #else /* sun4 bug */
  615.   if ( errno && d != 0.0 )
  616.       compile_error( "%s : decimal overflow", string_buff) ;
  617. #endif
  618.  
  619.   if ( endp < p )
  620.   { *flag = BAD_DECIMAL ; return 0.0 ; }
  621.   return d ;
  622. }
  623.  
  624. /*----------  process escape characters ---------------*/
  625.  
  626. static char hex_val['f' - 'A' + 1] = {
  627. 10,11,12,13,14,15, 0, 0,
  628.  0, 0, 0, 0, 0, 0, 0, 0,
  629.  0, 0, 0, 0, 0, 0, 0, 0,
  630.  0, 0, 0, 0, 0, 0, 0, 0,
  631. 10,11,12,13,14,15 } ;
  632.  
  633. #define isoctal(x)  ((x)>='0'&&(x)<='7')
  634.  
  635. #define  hex_value(x)   hex_val[(x)-'A']
  636.  
  637. #define ishex(x) (scan_code[x] == SC_DIGIT ||\
  638.                   'A' <= (x) && (x) <= 'f' && hex_value(x))
  639.  
  640. static int PROTO(octal, (char **)) ;
  641. static int PROTO(hex, (char **)) ;
  642.  
  643. /* process one , two or three octal digits
  644.    moving a pointer forward by reference */
  645. static int octal( start_p )
  646.   char **start_p ;
  647. { register char *p = *start_p ;
  648.   register unsigned x ;
  649.  
  650.   x = *p++ - '0' ;
  651.   if ( isoctal(*p) )
  652.   {
  653.     x = (x<<3) + *p++ - '0' ;
  654.     if ( isoctal(*p) )   x = (x<<3) + *p++ - '0' ;
  655.   }
  656.   *start_p = p ;
  657.   return  x & 0xff ;
  658. }
  659.  
  660. /* process one or two hex digits
  661.    moving a pointer forward by reference */
  662.  
  663. static int  hex( start_p )
  664.   char **start_p ;
  665. { register unsigned char *p = (unsigned char*) *start_p ;
  666.   register unsigned x ;
  667.   unsigned t ;
  668.  
  669.   if ( scan_code[*p] == SC_DIGIT )
  670.         x = *p++ - '0' ;
  671.   else  x = hex_value(*p++) ;
  672.  
  673.   if ( scan_code[*p] == SC_DIGIT )
  674.         x = (x<<4) + *p++ - '0' ;
  675.   else
  676.   if ( 'A' <= *p && *p <= 'f' && (t = hex_value(*p)) )
  677.   { x = (x<<4) + t ; p++ ; }
  678.  
  679.   *start_p = (char *) p ;
  680.   return x ;
  681. }
  682.  
  683. #define  ET_END     9
  684.  
  685. static struct { char in , out ; } escape_test[ET_END+1] = {
  686. 'n' , '\n',
  687. 't' , '\t',
  688. 'f' , '\f',
  689. 'b' , '\b',
  690. 'r' , '\r',
  691. 'a' , '\07',
  692. 'v' , '\013',
  693. '\\', '\\',
  694. '\"', '\"',
  695. 0 , 0 } ;
  696.  
  697.  
  698. /* process the escape characters in a string, in place . */
  699.  
  700. char *rm_escape(s)
  701.   char *s ;
  702. { register char *p, *q ;
  703.   char *t ;
  704.   int i ;
  705.  
  706.   q = p = s ;
  707.  
  708.   while ( *p )
  709.       if ( *p == '\\' )
  710.       { 
  711.         escape_test[ET_END].in = * ++p ; /* sentinal */
  712.         i = 0 ;
  713.         while ( escape_test[i].in != *p )  i++ ;
  714.  
  715.         if ( i != ET_END )  /* in table */
  716.         { 
  717.           p++ ; *q++ = escape_test[i].out ;
  718.         }
  719.         else
  720.         if ( isoctal(*p) ) 
  721.         {
  722.           t = p ;  *q++ = octal(&t) ; p = t ;
  723.         }
  724.         else
  725.         if ( *p == 'x' && ishex(*(unsigned char*)(p+1)) )
  726.         {
  727.           t = p+1 ; *q++ = hex(&t) ; p = t ;
  728.         }
  729.         else
  730.         if ( *p == 0 ) /* can only happen with command line assign */
  731.             *q++ = '\\' ;
  732.         else  /* not an escape sequence */
  733.         { 
  734.           *q++ = '\\' ; *q++ = *p++ ;
  735.         }
  736.       }
  737.       else  *q++ = *p++ ;
  738.  
  739.   *q = 0 ;
  740.   return s ;
  741. }
  742.  
  743. static  int  collect_string()
  744. { register unsigned char *p = (unsigned char *)string_buff ;
  745.   int c ;
  746.   int e_flag = 0 ; /* on if have an escape char */
  747.  
  748.   while ( 1 )
  749.       switch( scan_code[ *p++ = next() ] )
  750.       { case  SC_DQUOTE : /* done */
  751.               * --p = 0 ;  goto out ;
  752.  
  753.         case  SC_NL :
  754.               p[-1] = 0 ;
  755.               /* fall thru */
  756.  
  757.         case  0 :   /* unterminated string */
  758.               compile_error(
  759.               "runaway string constant \"%.10s ..." ,
  760.               string_buff, token_lineno ) ;
  761.               mawk_exit(1) ;
  762.  
  763.         case SC_ESCAPE :
  764.               if ( (c = next()) == '\n' )
  765.               { p-- ; lineno++ ; }
  766.               else  
  767.                 if ( c == 0 )  un_next() ;   
  768.                 else 
  769.                 { *p++ = c ; e_flag = 1 ; }
  770.  
  771.               break ;
  772.  
  773.         default : break ;
  774.       }
  775.  
  776. out:
  777.     yylval.ptr = (PTR) new_STRING(
  778.          e_flag ? rm_escape( string_buff ) 
  779.                 : string_buff ) ;
  780.     return  STRING_ ;
  781. }
  782.  
  783.  
  784. static  int  collect_RE()
  785. { register unsigned char *p = (unsigned char*) string_buff ;
  786.   int c ;
  787.   STRING *sval ;
  788.  
  789.   while ( 1 )
  790.       switch( scan_code[ *p++ = next() ] )
  791.       { case  SC_DIV : /* done */
  792.               * --p = 0 ;  goto out ;
  793.  
  794.         case  SC_NL :
  795.               p[-1] = 0 ;
  796.               /* fall thru */
  797.  
  798.         case  0 :   /* unterminated re */
  799.               compile_error(
  800.               "runaway regular expression /%.10s ..." ,
  801.               string_buff, token_lineno ) ;
  802.               mawk_exit(1) ;
  803.  
  804.         case SC_ESCAPE :
  805.               switch( c = next() )
  806.               { case '/' :  
  807.                       p[-1] = '/' ; break ;
  808.  
  809.                 case '\n' :
  810.                       p-- ;  break ;
  811.  
  812.                 case  0   :
  813.                       un_next() ;  break ;
  814.  
  815.                 default :
  816.                       *p++ = c ; break ;
  817.               }
  818.               break ;
  819.       }
  820.  
  821. out:
  822.   /* now we've got the RE, so compile it */
  823.   sval = new_STRING( string_buff ) ;
  824.   yylval.ptr = re_compile(sval) ;
  825.   free_STRING(sval) ;
  826.   return RE ;
  827. }
  828.  
  829.