home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 11 / AUCD11B.iso / LANGUAGES / WraithSet / AwkStuff / MawkSrc / c / scan < prev    next >
Text File  |  1996-07-28  |  21KB  |  1,081 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 1.8  1996/07/28 21:47:05  mike
  16.  * gnuish patch
  17.  *
  18.  * Revision 1.7  1995/06/18  19:42:24  mike
  19.  * Remove some redundant declarations and add some prototypes
  20.  *
  21.  * Revision 1.6  1995/06/10  16:57:52  mike
  22.  * silently exit(0) if no program
  23.  * always add a '\n' on eof in scan_fillbuff()
  24.  *
  25.  * Revision 1.5  1995/06/06  00:18:33  mike
  26.  * change mawk_exit(1) to mawk_exit(2)
  27.  *
  28.  * Revision 1.4  1994/09/23  00:20:04  mike
  29.  * minor bug fix: handle \ in eat_nl()
  30.  *
  31.  * Revision 1.3  1993/07/17  00:45:21  mike
  32.  * indent
  33.  *
  34.  * Revision 1.2     1993/07/04  12:52:09  mike
  35.  * start on autoconfig changes
  36.  *
  37.  * Revision 1.1.1.1  1993/07/03     18:58:20  mike
  38.  * move source to cvs
  39.  *
  40.  * Revision 5.6     1993/02/13  21:57:33  mike
  41.  * merge patch3
  42.  *
  43.  * Revision 5.5     1993/01/01  21:30:48  mike
  44.  * split new_STRING() into new_STRING and new_STRING0
  45.  *
  46.  * Revision 5.4.1.1  1993/01/15     03:33:50  mike
  47.  * patch3: safer double to int conversion
  48.  *
  49.  * Revision 5.4     1992/11/29  18:57:50  mike
  50.  * field expressions convert to long so 16 bit and 32 bit
  51.  * systems behave the same
  52.  *
  53.  * Revision 5.3     1992/07/08  15:43:41  brennan
  54.  * patch2: length returns.  I am a wimp
  55.  *
  56.  * Revision 5.2     1992/02/21  14:16:53  brennan
  57.  * fix:     getline <=
  58.  *
  59.  * Revision 5.1     91/12/05  07:56:27  brennan
  60.  * 1.1 pre-release
  61.  *
  62. */
  63.  
  64.  
  65. #include  "mawk.h"
  66. #include  "scan.h"
  67. #include  "memory.h"
  68. #include  "field.h"
  69. #include  "init.h"
  70. #include  "fin.h"
  71. #include  "repl.h"
  72. #include  "code.h"
  73.  
  74. #ifndef      NO_FCNTL_H
  75. #include  <fcntl.h>
  76. #endif
  77.  
  78. #include  "files.h"
  79.  
  80.  
  81. /* static functions */
  82. static void PROTO(scan_fillbuff, (void)) ;
  83. static void PROTO(scan_open, (void)) ;
  84. static int PROTO(slow_next, (void)) ;
  85. static void PROTO(eat_comment, (void)) ;
  86. static void PROTO(eat_semi_colon, (void)) ;
  87. static double PROTO(collect_decimal, (int, int *)) ;
  88. static int PROTO(collect_string, (void)) ;
  89. static int PROTO(collect_RE, (void)) ;
  90.  
  91.  
  92. /*-----------------------------
  93.   program file management
  94.  *----------------------------*/
  95.  
  96. char *pfile_name ;
  97. STRING *program_string ;
  98. PFILE *pfile_list ;
  99. static unsigned char *buffer ;
  100. static unsigned char *buffp ;
  101.  /* unsigned so it works with 8 bit chars */
  102. static int program_fd ;
  103. static int eof_flag ;
  104.  
  105. void
  106. scan_init(cmdline_program)
  107.    char *cmdline_program ;
  108. {
  109.    if (cmdline_program)
  110.    {
  111.       program_fd = -1 ;         /* command line program */
  112.       program_string = new_STRING0(strlen(cmdline_program) + 1) ;
  113.       strcpy(program_string->str, cmdline_program) ;
  114.       /* simulate file termination */
  115.       program_string->str[program_string->len - 1] = '\n' ;
  116.       buffp = (unsigned char *) program_string->str ;
  117.       eof_flag = 1 ;
  118.    }
  119.    else     /* program from file[s] */
  120.    {
  121.       scan_open() ;
  122.       buffp = buffer = (unsigned char *) zmalloc(BUFFSZ + 1) ;
  123.       scan_fillbuff() ;
  124.    }
  125.  
  126. #ifdef OS2  /* OS/2 "extproc" is similar to #! */
  127.    if (strnicmp(buffp, "extproc ", 8) == 0)
  128.      eat_comment();
  129. #endif
  130.    eat_nl() ;             /* scan to first token */
  131.    if (next() == 0)
  132.    {
  133.       /* no program */
  134.       mawk_exit(0) ;
  135.    }
  136.  
  137.    un_next() ;
  138.  
  139. }
  140.  
  141. static void
  142. scan_open()            /* open pfile_name */
  143. {
  144.    if (pfile_name[0] == '-' && pfile_name[1] == 0)
  145.    {
  146.       program_fd = 0 ;
  147.    }
  148.    else if ((program_fd = open(pfile_name, O_RDONLY, 0)) == -1)
  149.    {
  150.       errmsg(errno, "cannot open %s", pfile_name) ;
  151.       mawk_exit(2) ;
  152.    }
  153. }
  154.  
  155. void
  156. scan_cleanup()
  157. {
  158.    if (program_fd >= 0)     zfree(buffer, BUFFSZ + 1) ;
  159.    else     free_STRING(program_string) ;
  160.  
  161.    if (program_fd > 0)    close(program_fd) ;
  162.  
  163.    /* redefine SPACE as [ \t\n] */
  164.  
  165.    scan_code['\n'] = posix_space_flag && rs_shadow.type != SEP_MLR
  166.       ? SC_UNEXPECTED : SC_SPACE ;
  167.    scan_code['\f'] = SC_UNEXPECTED ;     /*value doesn't matter */
  168.    scan_code['\013'] = SC_UNEXPECTED ;     /* \v not space */
  169.    scan_code['\r'] = SC_UNEXPECTED ;
  170. }
  171.  
  172. /*--------------------------------
  173.   global variables shared by yyparse() and yylex()
  174.   and used for error messages too
  175.  *-------------------------------*/
  176.  
  177. int current_token = -1 ;
  178. unsigned token_lineno ;
  179. unsigned compile_error_count ;
  180. int NR_flag ;             /* are we tracking NR */
  181. int paren_cnt ;
  182. int brace_cnt ;
  183. int print_flag ;         /* changes meaning of '>' */
  184. int getline_flag ;         /* changes meaning of '<' */
  185.  
  186.  
  187. /*----------------------------------------
  188.  file reading functions
  189.  next() and un_next(c) are macros in scan.h
  190.  
  191.  *---------------------*/
  192.  
  193. static unsigned lineno = 1 ;
  194.  
  195.  
  196. static void
  197. scan_fillbuff()
  198. {
  199.    unsigned r ;
  200.  
  201.    r = fillbuff(program_fd, (char *) buffer, BUFFSZ) ;
  202.    if (r < BUFFSZ)
  203.    {
  204.       eof_flag = 1 ;
  205.       /* make sure eof is terminated */
  206.       buffer[r] = '\n' ;
  207.       buffer[r + 1] = 0 ;
  208.    }
  209. }
  210.  
  211. /* read one character -- slowly */
  212. static int
  213. slow_next()
  214. {
  215.  
  216.    while (*buffp == 0)
  217.    {
  218.       if (!eof_flag)
  219.       {
  220.      buffp = buffer ;
  221.      scan_fillbuff() ;
  222.       }
  223.       else if (pfile_list /* open another program file */ )
  224.       {
  225.      PFILE *q ;
  226.  
  227.      if (program_fd > 0)  close(program_fd) ;
  228.      eof_flag = 0 ;
  229.      pfile_name = pfile_list->fname ;
  230.      q = pfile_list ;
  231.      pfile_list = pfile_list->link ;
  232.      ZFREE(q) ;
  233.      scan_open() ;
  234.      token_lineno = lineno = 1 ;
  235.       }
  236.       else  break /* real eof */ ;
  237.    }
  238.  
  239.    return *buffp++ ;         /* note can un_next() , eof which is zero */
  240. }
  241.  
  242. static void
  243. eat_comment()
  244. {
  245.    register int c ;
  246.  
  247.    while ((c = next()) != '\n' && scan_code[c]) ;
  248.    un_next() ;
  249. }
  250.  
  251. /* this is how we handle extra semi-colons that are
  252.    now allowed to separate pattern-action blocks
  253.  
  254.    A proof that they are useless clutter to the language:
  255.    we throw them away
  256. */
  257.  
  258. static void
  259. eat_semi_colon()
  260. /* eat one semi-colon on the current line */
  261. {
  262.    register int c ;
  263.  
  264.    while (scan_code[c = next()] == SC_SPACE) ;
  265.    if (c != ';')  un_next() ;
  266. }
  267.  
  268. void
  269. eat_nl()            /* eat all space including newlines */
  270. {
  271.    while (1)
  272.       switch (scan_code[next()])
  273.       {
  274.      case SC_COMMENT:
  275.         eat_comment() ;
  276.         break ;
  277.  
  278.      case SC_NL:
  279.         lineno++ ;
  280.         /* fall thru  */
  281.  
  282.      case SC_SPACE:
  283.         break ;
  284.  
  285.      case SC_ESCAPE:
  286.         /* bug fix - surprised anyone did this,
  287.            a csh user with backslash dyslexia.(Not a joke)
  288.         */
  289.         {
  290.            unsigned c ;
  291.  
  292.            while (scan_code[c = next()] == SC_SPACE) ;
  293.            if (c == '\n')
  294.           token_lineno = ++lineno ;
  295.            else if (c == 0)  
  296.            {
  297.           un_next() ;
  298.           return ;
  299.            }
  300.            else /* error */
  301.            {
  302.           un_next() ;
  303.           /* can't un_next() twice so deal with it */
  304.           yylval.ival = '\\' ;
  305.           unexpected_char() ;
  306.           if( ++compile_error_count == MAX_COMPILE_ERRORS )
  307.              mawk_exit(2) ;
  308.           return ;
  309.            }
  310.         }
  311.         break ;
  312.          
  313.      default:
  314.         un_next() ;
  315.         return ;
  316.       }
  317. }
  318.  
  319. int
  320. yylex()
  321. {
  322.    register int c ;
  323.  
  324.    token_lineno = lineno ;
  325.  
  326. reswitch:
  327.  
  328.    switch (scan_code[c = next()])
  329.    {
  330.       case 0:
  331.      ct_ret(EOF) ;
  332.  
  333.       case SC_SPACE:
  334.      goto reswitch ;
  335.  
  336.       case SC_COMMENT:
  337.      eat_comment() ;
  338.      goto reswitch ;
  339.  
  340.       case SC_NL:
  341.      lineno++ ;
  342.      eat_nl() ;
  343.      ct_ret(NL) ;
  344.  
  345.       case SC_ESCAPE:
  346.      while (scan_code[c = next()] == SC_SPACE) ;
  347.      if (c == '\n')
  348.      {
  349.         token_lineno = ++lineno ;
  350.         goto reswitch ;
  351.      }
  352.  
  353.      if (c == 0)  ct_ret(EOF) ;
  354.      un_next() ;
  355.      yylval.ival = '\\' ;
  356.      ct_ret(UNEXPECTED) ;
  357.  
  358.  
  359.       case SC_SEMI_COLON:
  360.      eat_nl() ;
  361.      ct_ret(SEMI_COLON) ;
  362.  
  363.       case SC_LBRACE:
  364.      eat_nl() ;
  365.      brace_cnt++ ;
  366.      ct_ret(LBRACE) ;
  367.  
  368.       case SC_PLUS:
  369.      switch (next())
  370.      {
  371.         case '+':
  372.            yylval.ival = '+' ;
  373.            string_buff[0] =
  374.           string_buff[1] = '+' ;
  375.            string_buff[2] = 0 ;
  376.            ct_ret(INC_or_DEC) ;
  377.  
  378.         case '=':
  379.            ct_ret(ADD_ASG) ;
  380.  
  381.         default:
  382.            un_next() ;
  383.            ct_ret(PLUS) ;
  384.      }
  385.  
  386.       case SC_MINUS:
  387.      switch (next())
  388.      {
  389.         case '-':
  390.            yylval.ival = '-' ;
  391.            string_buff[0] =
  392.           string_buff[1] = '-' ;
  393.            string_buff[2] = 0 ;
  394.            ct_ret(INC_or_DEC) ;
  395.  
  396.         case '=':
  397.            ct_ret(SUB_ASG) ;
  398.  
  399.         default:
  400.            un_next() ;
  401.            ct_ret(MINUS) ;
  402.      }
  403.  
  404.       case SC_COMMA:
  405.      eat_nl() ;
  406.      ct_ret(COMMA) ;
  407.  
  408.       case SC_MUL:
  409.      test1_ret('=', MUL_ASG, MUL) ;
  410.  
  411.       case SC_DIV:
  412.      {
  413.         static int can_precede_div[] =
  414.         {DOUBLE, STRING_, RPAREN, ID, D_ID, RE, RBOX, FIELD,
  415.          GETLINE, INC_or_DEC, -1} ;
  416.  
  417.         int *p = can_precede_div ;
  418.  
  419.         do
  420.         {
  421.            if (*p == current_token)
  422.            {
  423.           if (*p != INC_or_DEC)     test1_ret('=', DIV_ASG, DIV) ;
  424.  
  425.           if (next() == '=')
  426.           {
  427.              un_next() ;
  428.              ct_ret(collect_RE()) ;
  429.           }
  430.            }
  431.         }
  432.         while (*++p != -1) ;
  433.  
  434.         ct_ret(collect_RE()) ;
  435.      }
  436.  
  437.       case SC_MOD:
  438.      test1_ret('=', MOD_ASG, MOD) ;
  439.  
  440.       case SC_POW:
  441.      test1_ret('=', POW_ASG, POW) ;
  442.  
  443.       case SC_LPAREN:
  444.      paren_cnt++ ;
  445.      ct_ret(LPAREN) ;
  446.  
  447.       case SC_RPAREN:
  448.      if (--paren_cnt < 0)
  449.      {
  450.         compile_error("extra ')'") ;
  451.         paren_cnt = 0 ;
  452.         goto reswitch ;
  453.      }
  454.  
  455.      ct_ret(RPAREN) ;
  456.  
  457.       case SC_LBOX:
  458.      ct_ret(LBOX) ;
  459.  
  460.       case SC_RBOX:
  461.      ct_ret(RBOX) ;
  462.  
  463.       case SC_MATCH:
  464.      string_buff[0] = '~' ;
  465.      string_buff[0] = 0 ;
  466.      yylval.ival = 1 ;
  467.      ct_ret(MATCH) ;
  468.  
  469.       case SC_EQUAL:
  470.      test1_ret('=', EQ, ASSIGN) ;
  471.  
  472.       case SC_NOT:        /* !  */
  473.      if ((c = next()) == '~')
  474.      {
  475.         string_buff[0] = '!' ;
  476.         string_buff[1] = '~' ;
  477.         string_buff[2] = 0 ;
  478.         yylval.ival = 0 ;
  479.         ct_ret(MATCH) ;
  480.      }
  481.      else if (c == '=')  ct_ret(NEQ) ;
  482.  
  483.      un_next() ;
  484.      ct_ret(NOT) ;
  485.  
  486.  
  487.       case SC_LT:        /* '<' */
  488.      if (next() == '=')  ct_ret(LTE) ;
  489.      else  un_next() ;
  490.  
  491.      if (getline_flag)
  492.      {
  493.         getline_flag = 0 ;
  494.         ct_ret(IO_IN) ;
  495.      }
  496.      else  ct_ret(LT) ;
  497.  
  498.       case SC_GT:        /* '>' */
  499.      if (print_flag && paren_cnt == 0)
  500.      {
  501.         print_flag = 0 ;
  502.         /* there are 3 types of IO_OUT
  503.            -- build the error string in string_buff */
  504.         string_buff[0] = '>' ;
  505.         if (next() == '>')
  506.         {
  507.            yylval.ival = F_APPEND ;
  508.            string_buff[1] = '>' ;
  509.            string_buff[2] = 0 ;
  510.         }
  511.         else
  512.         {
  513.            un_next() ;
  514.            yylval.ival = F_TRUNC ;
  515.            string_buff[1] = 0 ;
  516.         }
  517.         return current_token = IO_OUT ;
  518.      }
  519.  
  520.      test1_ret('=', GTE, GT) ;
  521.  
  522.       case SC_OR:
  523.      if (next() == '|')
  524.      {
  525.         eat_nl() ;
  526.         ct_ret(OR) ;
  527.      }
  528.      else
  529.      {
  530.         un_next() ;
  531.  
  532.         if (print_flag && paren_cnt == 0)
  533.         {
  534.            print_flag = 0 ;
  535.            yylval.ival = PIPE_OUT ;
  536.            string_buff[0] = '|' ;
  537.            string_buff[1] = 0 ;
  538.            ct_ret(IO_OUT) ;
  539.         }
  540.         else  ct_ret(PIPE) ;
  541.      }
  542.  
  543.       case SC_AND:
  544.      if (next() == '&')
  545.      {
  546.         eat_nl() ;
  547.         ct_ret(AND) ;
  548.      }
  549.      else
  550.      {
  551.         un_next() ;
  552.         yylval.ival = '&' ;
  553.         ct_ret(UNEXPECTED) ;
  554.      }
  555.  
  556.       case SC_QMARK:
  557.      ct_ret(QMARK) ;
  558.  
  559.       case SC_COLON:
  560.      ct_ret(COLON) ;
  561.  
  562.       case SC_RBRACE:
  563.      if (--brace_cnt < 0)
  564.      {
  565.         compile_error("extra '}'") ;
  566.         eat_semi_colon() ;
  567.         brace_cnt = 0 ;
  568.         goto reswitch ;
  569.      }
  570.  
  571.      if ((c = current_token) == NL || c == SEMI_COLON
  572.          || c == SC_FAKE_SEMI_COLON || c == RBRACE)
  573.      {
  574.         /* if the brace_cnt is zero , we've completed
  575.            a pattern action block. If the user insists
  576.            on adding a semi-colon on the same line
  577.            we will eat it.    Note what we do below:
  578.            physical law -- conservation of semi-colons */
  579.  
  580.         if (brace_cnt == 0)     eat_semi_colon() ;
  581.         eat_nl() ;
  582.         ct_ret(RBRACE) ;
  583.      }
  584.  
  585.      /* supply missing semi-colon to statement that
  586.          precedes a '}' */
  587.      brace_cnt++ ;
  588.      un_next() ;
  589.      current_token = SC_FAKE_SEMI_COLON ;
  590.      return SEMI_COLON ;
  591.  
  592.       case SC_DIGIT:
  593.       case SC_DOT:
  594.      {
  595.         double d;
  596.         int flag ;
  597.         static double double_zero = 0.0 ;
  598.         static double double_one = 1.0 ;
  599.  
  600.         if ((d = collect_decimal(c, &flag)) == 0.0)
  601.         {
  602.            if (flag)  ct_ret(flag) ;
  603.            else  yylval.ptr = (PTR) & double_zero ;
  604.         }
  605.         else if (d == 1.0)
  606.         {
  607.            yylval.ptr = (PTR) & double_one ;
  608.         }
  609.         else
  610.         {
  611.            yylval.ptr = (PTR) ZMALLOC(double) ;
  612.            *(double *) yylval.ptr = d ;
  613.         }
  614.         ct_ret(DOUBLE) ;
  615.      }
  616.  
  617.       case SC_DOLLAR:        /* '$' */
  618.      {
  619.         double d;
  620.         int flag ;
  621.  
  622.         while (scan_code[c = next()] == SC_SPACE) ;
  623.         if (scan_code[c] != SC_DIGIT &&
  624.         scan_code[c] != SC_DOT)
  625.         {
  626.            un_next() ;
  627.            ct_ret(DOLLAR) ;
  628.         }
  629.  
  630.         /* compute field address at compile time */
  631.         if ((d = collect_decimal(c, &flag)) == 0.0)
  632.         {
  633.            if (flag)  ct_ret(flag) ; /* an error */
  634.            else  yylval.cp = &field[0] ;
  635.         }
  636.         else
  637.         {
  638.            if (d > MAX_FIELD)
  639.            {
  640.           compile_error(
  641.              "$%g exceeds maximum field(%d)", d, MAX_FIELD) ;
  642.           d = MAX_FIELD ;
  643.            }
  644.            yylval.cp = field_ptr((int) d) ;
  645.         }
  646.  
  647.         ct_ret(FIELD) ;
  648.      }
  649.  
  650.       case SC_DQUOTE:
  651.      return current_token = collect_string() ;
  652.  
  653.       case SC_IDCHAR:        /* collect an identifier */
  654.      {
  655.         unsigned char *p =
  656.         (unsigned char *) string_buff + 1 ;
  657.         SYMTAB *stp ;
  658.  
  659.         string_buff[0] = c ;
  660.  
  661.         while (
  662.              (c = scan_code[*p++ = next()]) == SC_IDCHAR ||
  663.              c == SC_DIGIT) ;
  664.  
  665.         un_next() ;
  666.         *--p = 0 ;
  667.  
  668.         switch ((stp = find(string_buff))->type)
  669.         {
  670.            case ST_NONE:
  671.           /* check for function call before defined */
  672.           if (next() == '(')
  673.           {
  674.              stp->type = ST_FUNCT ;
  675.              stp->stval.fbp = (FBLOCK *)
  676.             zmalloc(sizeof(FBLOCK)) ;
  677.              stp->stval.fbp->name = stp->name ;
  678.              stp->stval.fbp->code = (INST *) 0 ;
  679.              yylval.fbp = stp->stval.fbp ;
  680.              current_token = FUNCT_ID ;
  681.           }
  682.           else
  683.           {
  684.              yylval.stp = stp ;
  685.              current_token =
  686.             current_token == DOLLAR ? D_ID : ID ;
  687.           }
  688.           un_next() ;
  689.           break ;
  690.  
  691.            case ST_NR:
  692.           NR_flag = 1 ;
  693.           stp->type = ST_VAR ;
  694.           /* fall thru */
  695.  
  696.            case ST_VAR:
  697.            case ST_ARRAY:
  698.            case ST_LOCAL_NONE:
  699.            case ST_LOCAL_VAR:
  700.            case ST_LOCAL_ARRAY:
  701.  
  702.           yylval.stp = stp ;
  703.           current_token =
  704.              current_token == DOLLAR ? D_ID : ID ;
  705.           break ;
  706.  
  707.            case ST_ENV:
  708.           stp->type = ST_ARRAY ;
  709.           stp->stval.array = new_ARRAY() ;
  710.           load_environ(stp->stval.array) ;
  711.           yylval.stp = stp ;
  712.           current_token =
  713.              current_token == DOLLAR ? D_ID : ID ;
  714.           break ;
  715.  
  716.            case ST_FUNCT:
  717.           yylval.fbp = stp->stval.fbp ;
  718.           current_token = FUNCT_ID ;
  719.           break ;
  720.  
  721.            case ST_KEYWORD:
  722.           current_token = stp->stval.kw ;
  723.           break ;
  724.  
  725.            case ST_BUILTIN:
  726.           yylval.bip = stp->stval.bip ;
  727.           current_token = BUILTIN ;
  728.           break ;
  729.  
  730.            case ST_LENGTH:
  731.  
  732.           yylval.bip = stp->stval.bip ;
  733.  
  734.           /* check for length alone, this is an ugly
  735.              hack */
  736.           while (scan_code[c = next()] == SC_SPACE) ;
  737.           un_next() ;
  738.  
  739.           current_token = c == '(' ? BUILTIN : LENGTH ;
  740.           break ;
  741.  
  742.            case ST_FIELD:
  743.           yylval.cp = stp->stval.cp ;
  744.           current_token = FIELD ;
  745.           break ;
  746.  
  747.            default:
  748.           bozo("find returned bad st type") ;
  749.         }
  750.         return current_token ;
  751.      }
  752.  
  753.  
  754.       case SC_UNEXPECTED:
  755.      yylval.ival = c & 0xff ;
  756.      ct_ret(UNEXPECTED) ;
  757.    }
  758.    return 0 ;             /* never get here make lint happy */
  759. }
  760.  
  761. /* collect a decimal constant in temp_buff.
  762.    Return the value and error conditions by reference */
  763.  
  764. static double
  765. collect_decimal(c, flag)
  766.    int c ;
  767.    int *flag ;
  768. {
  769.    register unsigned char *p = (unsigned char *) string_buff + 1 ;
  770.    unsigned char *endp ;
  771.    double d;
  772.  
  773.    *flag = 0 ;
  774.    string_buff[0] = c ;
  775.  
  776.    if (c == '.')
  777.    {
  778.       if (scan_code[*p++ = next()] != SC_DIGIT)
  779.       {
  780.      *flag = UNEXPECTED ;
  781.      yylval.ival = '.' ;
  782.      return 0.0 ;
  783.       }
  784.    }
  785.    else
  786.    {
  787.       while (scan_code[*p++ = next()] == SC_DIGIT) ;
  788.       if (p[-1] != '.')
  789.       {
  790.      un_next() ;
  791.      p-- ;
  792.       }
  793.    }
  794.    /* get rest of digits after decimal point */
  795.    while (scan_code[*p++ = next()] == SC_DIGIT) ;
  796.  
  797.    /* check for exponent */
  798.    if (p[-1] != 'e' && p[-1] != 'E')
  799.    {
  800.       un_next() ;
  801.       *--p = 0 ;
  802.    }
  803.    else     /* get the exponent */
  804.    {
  805.       if (scan_code[*p = next()] != SC_DIGIT &&
  806.       *p != '-' && *p != '+')
  807.       {
  808.      *++p = 0 ;
  809.      *flag = BAD_DECIMAL ;
  810.      return 0.0 ;
  811.       }
  812.       else  /* get the rest of the exponent */
  813.       {
  814.      p++ ;
  815.      while (scan_code[*p++ = next()] == SC_DIGIT) ;
  816.      un_next() ;
  817.      *--p = 0 ;
  818.       }
  819.    }
  820.  
  821.    errno = 0 ;             /* check for overflow/underflow */
  822.    d = strtod(string_buff, (char **) &endp) ;
  823.  
  824. #ifndef     STRTOD_UNDERFLOW_ON_ZERO_BUG
  825.    if (errno)  compile_error("%s : decimal %sflow", string_buff,
  826.             d == 0.0 ? "under" : "over") ;
  827. #else /* ! sun4 bug */
  828.    if (errno && d != 0.0)
  829.       compile_error("%s : decimal overflow", string_buff) ;
  830. #endif
  831.  
  832.    if (endp < p)
  833.    {
  834.       *flag = BAD_DECIMAL ;
  835.       return 0.0 ;
  836.    }
  837.    return d ;
  838. }
  839.  
  840. /*----------  process escape characters ---------------*/
  841.  
  842. static char hex_val['f' - 'A' + 1] =
  843. {
  844.    10, 11, 12, 13, 14, 15, 0, 0,
  845.    0, 0, 0, 0, 0, 0, 0, 0,
  846.    0, 0, 0, 0, 0, 0, 0, 0,
  847.    0, 0, 0, 0, 0, 0, 0, 0,
  848.    10, 11, 12, 13, 14, 15} ;
  849.  
  850. #define isoctal(x)  ((x)>='0'&&(x)<='7')
  851.  
  852. #define     hex_value(x)    hex_val[(x)-'A']
  853.  
  854. #define ishex(x) (scan_code[x] == SC_DIGIT ||\
  855.           'A' <= (x) && (x) <= 'f' && hex_value(x))
  856.  
  857. static int PROTO(octal, (char **)) ;
  858. static int PROTO(hex, (char **)) ;
  859.  
  860. /* process one , two or three octal digits
  861.    moving a pointer forward by reference */
  862. static int
  863. octal(start_p)
  864.    char **start_p ;
  865. {
  866.    register char *p = *start_p ;
  867.    register unsigned x ;
  868.  
  869.    x = *p++ - '0' ;
  870.    if (isoctal(*p))
  871.    {
  872.       x = (x << 3) + *p++ - '0' ;
  873.       if (isoctal(*p))    x = (x << 3) + *p++ - '0' ;
  874.    }
  875.    *start_p = p ;
  876.    return x & 0xff ;
  877. }
  878.  
  879. /* process one or two hex digits
  880.    moving a pointer forward by reference */
  881.  
  882. static int
  883. hex(start_p)
  884.    char **start_p ;
  885. {
  886.    register unsigned char *p = (unsigned char *) *start_p ;
  887.    register unsigned x ;
  888.    unsigned t ;
  889.  
  890.    if (scan_code[*p] == SC_DIGIT)  x = *p++ - '0' ;
  891.    else     x = hex_value(*p++) ;
  892.  
  893.    if (scan_code[*p] == SC_DIGIT)  x = (x << 4) + *p++ - '0' ;
  894.    else if ('A' <= *p && *p <= 'f' && (t = hex_value(*p)))
  895.    {
  896.       x = (x << 4) + t ;
  897.       p++ ;
  898.    }
  899.  
  900.    *start_p = (char *) p ;
  901.    return x ;
  902. }
  903.  
  904. #define     ET_END        9
  905.  
  906. static struct
  907. {
  908.    char in, out ;
  909. }
  910. escape_test[ET_END + 1] =
  911. {
  912.    'n', '\n',
  913.    't', '\t',
  914.    'f', '\f',
  915.    'b', '\b',
  916.    'r', '\r',
  917.    'a', '\07',
  918.    'v', '\013',
  919.    '\\', '\\',
  920.    '\"', '\"',
  921.    0, 0
  922. } ;
  923.  
  924.  
  925. /* process the escape characters in a string, in place . */
  926.  
  927. char *
  928. rm_escape(s)
  929.    char *s ;
  930. {
  931.    register char *p, *q ;
  932.    char *t ;
  933.    int i ;
  934.  
  935.    q = p = s ;
  936.  
  937.    while (*p)
  938.    {
  939.       if (*p == '\\')
  940.       {
  941.      escape_test[ET_END].in = *++p ; /* sentinal */
  942.      i = 0 ;
  943.      while (escape_test[i].in != *p)  i++ ;
  944.  
  945.      if (i != ET_END)    /* in table */
  946.      {
  947.         p++ ;
  948.         *q++ = escape_test[i].out ;
  949.      }
  950.      else if (isoctal(*p))
  951.      {
  952.         t = p ;
  953.         *q++ = octal(&t) ;
  954.         p = t ;
  955.      }
  956.      else if (*p == 'x' && ishex(*(unsigned char *) (p + 1)))
  957.      {
  958.         t = p + 1 ;
  959.         *q++ = hex(&t) ;
  960.         p = t ;
  961.      }
  962.      else if (*p == 0)    /* can only happen with command line assign */
  963.         *q++ = '\\' ;
  964.      else  /* not an escape sequence */
  965.      {
  966.         *q++ = '\\' ;
  967.         *q++ = *p++ ;
  968.      }
  969.       }
  970.       else  *q++ = *p++ ;
  971.    }
  972.  
  973.    *q = 0 ;
  974.    return s ;
  975. }
  976.  
  977. static int
  978. collect_string()
  979. {
  980.    register unsigned char *p = (unsigned char *) string_buff ;
  981.    int c ;
  982.    int e_flag = 0 ;         /* on if have an escape char */
  983.  
  984.    while (1)
  985.       switch (scan_code[*p++ = next()])
  986.       {
  987.      case SC_DQUOTE:    /* done */
  988.         *--p = 0 ;
  989.         goto out ;
  990.  
  991.      case SC_NL:
  992.         p[-1] = 0 ;
  993.         /* fall thru */
  994.  
  995.      case 0:        /* unterminated string */
  996.         compile_error(
  997.                 "runaway string constant \"%.10s ...",
  998.                 string_buff, token_lineno) ;
  999.         mawk_exit(2) ;
  1000.  
  1001.      case SC_ESCAPE:
  1002.         if ((c = next()) == '\n')
  1003.         {
  1004.            p-- ;
  1005.            lineno++ ;
  1006.         }
  1007.         else if (c == 0)  un_next() ;
  1008.         else
  1009.         {
  1010.            *p++ = c ;
  1011.            e_flag = 1 ;
  1012.         }
  1013.  
  1014.         break ;
  1015.  
  1016.      default:
  1017.         break ;
  1018.       }
  1019.  
  1020. out:
  1021.    yylval.ptr = (PTR) new_STRING(
  1022.                    e_flag ? rm_escape(string_buff)
  1023.                    : string_buff) ;
  1024.    return STRING_ ;
  1025. }
  1026.  
  1027.  
  1028. static int
  1029. collect_RE()
  1030. {
  1031.    register unsigned char *p = (unsigned char *) string_buff ;
  1032.    int c ;
  1033.    STRING *sval ;
  1034.  
  1035.    while (1)
  1036.       switch (scan_code[*p++ = next()])
  1037.       {
  1038.      case SC_DIV:        /* done */
  1039.         *--p = 0 ;
  1040.         goto out ;
  1041.  
  1042.      case SC_NL:
  1043.         p[-1] = 0 ;
  1044.         /* fall thru */
  1045.  
  1046.      case 0:        /* unterminated re */
  1047.         compile_error(
  1048.                 "runaway regular expression /%.10s ...",
  1049.                 string_buff, token_lineno) ;
  1050.         mawk_exit(2) ;
  1051.  
  1052.      case SC_ESCAPE:
  1053.         switch (c = next())
  1054.         {
  1055.            case '/':
  1056.           p[-1] = '/' ;
  1057.           break ;
  1058.  
  1059.            case '\n':
  1060.           p-- ;
  1061.           break ;
  1062.  
  1063.            case 0:
  1064.           un_next() ;
  1065.           break ;
  1066.  
  1067.            default:
  1068.           *p++ = c ;
  1069.           break ;
  1070.         }
  1071.         break ;
  1072.       }
  1073.  
  1074. out:
  1075.    /* now we've got the RE, so compile it */
  1076.    sval = new_STRING(string_buff) ;
  1077.    yylval.ptr = re_compile(sval) ;
  1078.    free_STRING(sval) ;
  1079.    return RE ;
  1080. }
  1081.