home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnuawk.zip / awk.y < prev    next >
Text File  |  1997-05-11  |  55KB  |  2,435 lines

  1. /*
  2.  * awk.y --- yacc/bison parser
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1997 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Programming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  24.  */
  25.  
  26. %{
  27. #ifdef DEBUG
  28. #define YYDEBUG 12
  29. #endif
  30.  
  31. #include "awk.h"
  32.  
  33. #define CAN_FREE    TRUE
  34. #define DONT_FREE    FALSE
  35.  
  36. #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
  37. static void yyerror(const char *m, ...) ;
  38. #else
  39. static void yyerror(); /* va_alist */
  40. #endif
  41. static char *get_src_buf P((void));
  42. static int yylex P((void));
  43. static NODE *node_common P((NODETYPE op));
  44. static NODE *snode P((NODE *subn, NODETYPE op, int sindex));
  45. static NODE *mkrangenode P((NODE *cpair));
  46. static NODE *make_for_loop P((NODE *init, NODE *cond, NODE *incr));
  47. static NODE *append_right P((NODE *list, NODE *new));
  48. static void func_install P((NODE *params, NODE *def));
  49. static void pop_var P((NODE *np, int freeit));
  50. static void pop_params P((NODE *params));
  51. static NODE *make_param P((char *name));
  52. static NODE *mk_rexp P((NODE *exp));
  53. static int dup_parms P((NODE *func));
  54. static void param_sanity P((NODE *arglist));
  55. static int isnoeffect P((NODETYPE t));
  56. static int isassignable P((NODE *n));
  57.  
  58. enum defref { FUNC_DEFINE, FUNC_USE };
  59. static void func_use P((char *name, enum defref how));
  60. static void check_funcs P((void));
  61.  
  62. static int want_assign;        /* lexical scanning kludge */
  63. static int want_regexp;        /* lexical scanning kludge */
  64. static int can_return;        /* lexical scanning kludge */
  65. static int io_allowed = TRUE;    /* lexical scanning kludge */
  66. static char *lexptr;        /* pointer to next char during parsing */
  67. static char *lexend;
  68. static char *lexptr_begin;    /* keep track of where we were for error msgs */
  69. static char *lexeme;        /* beginning of lexeme for debugging */
  70. static char *thisline = NULL;
  71. #define YYDEBUG_LEXER_TEXT (lexeme)
  72. static int param_counter;
  73. static char *tokstart = NULL;
  74. static char *tok = NULL;
  75. static char *tokend;
  76.  
  77. #define HASHSIZE    1021    /* this constant only used here */
  78. NODE *variables[HASHSIZE];
  79.  
  80. extern char *source;
  81. extern int sourceline;
  82. extern struct src *srcfiles;
  83. extern int numfiles;
  84. extern int errcount;
  85. extern NODE *begin_block;
  86. extern NODE *end_block;
  87. %}
  88.  
  89. %union {
  90.     long lval;
  91.     AWKNUM fval;
  92.     NODE *nodeval;
  93.     NODETYPE nodetypeval;
  94.     char *sval;
  95.     NODE *(*ptrval)();
  96. }
  97.  
  98. %type <nodeval> function_prologue function_body
  99. %type <nodeval> rexp exp start program rule simp_exp
  100. %type <nodeval> non_post_simp_exp
  101. %type <nodeval> pattern 
  102. %type <nodeval>    action variable param_list
  103. %type <nodeval>    rexpression_list opt_rexpression_list
  104. %type <nodeval>    expression_list opt_expression_list
  105. %type <nodeval>    statements statement if_statement opt_param_list 
  106. %type <nodeval> opt_exp opt_variable regexp 
  107. %type <nodeval> input_redir output_redir
  108. %type <nodetypeval> print
  109. %type <sval> func_name
  110. %type <lval> lex_builtin
  111.  
  112. %token <sval> FUNC_CALL NAME REGEXP
  113. %token <lval> ERROR
  114. %token <nodeval> YNUMBER YSTRING
  115. %token <nodetypeval> RELOP APPEND_OP
  116. %token <nodetypeval> ASSIGNOP MATCHOP NEWLINE CONCAT_OP
  117. %token <nodetypeval> LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
  118. %token <nodetypeval> LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
  119. %token <nodetypeval> LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
  120. %token <nodetypeval> LEX_GETLINE LEX_NEXTFILE
  121. %token <nodetypeval> LEX_IN
  122. %token <lval> LEX_AND LEX_OR INCREMENT DECREMENT
  123. %token <lval> LEX_BUILTIN LEX_LENGTH
  124.  
  125. /* these are just yylval numbers */
  126.  
  127. /* Lowest to highest */
  128. %right ASSIGNOP
  129. %right '?' ':'
  130. %left LEX_OR
  131. %left LEX_AND
  132. %left LEX_GETLINE
  133. %nonassoc LEX_IN
  134. %left FUNC_CALL LEX_BUILTIN LEX_LENGTH
  135. %nonassoc ','
  136. %nonassoc MATCHOP
  137. %nonassoc RELOP '<' '>' '|' APPEND_OP
  138. %left CONCAT_OP
  139. %left YSTRING YNUMBER
  140. %left '+' '-'
  141. %left '*' '/' '%'
  142. %right '!' UNARY
  143. %right '^'
  144. %left INCREMENT DECREMENT
  145. %left '$'
  146. %left '(' ')'
  147. %%
  148.  
  149. start
  150.     : opt_nls program opt_nls
  151.         {
  152.             expression_value = $2;
  153.             check_funcs();
  154.         }
  155.     ;
  156.  
  157. program
  158.     : rule
  159.         { 
  160.             if ($1 != NULL)
  161.                 $$ = $1;
  162.             else
  163.                 $$ = NULL;
  164.             yyerrok;
  165.         }
  166.     | program rule
  167.         /* add the rule to the tail of list */
  168.         {
  169.             if ($2 == NULL)
  170.                 $$ = $1;
  171.             else if ($1 == NULL)
  172.                 $$ = $2;
  173.             else {
  174.                 if ($1->type != Node_rule_list)
  175.                     $1 = node($1, Node_rule_list,
  176.                         (NODE*) NULL);
  177.                 $$ = append_right($1,
  178.                    node($2, Node_rule_list, (NODE *) NULL));
  179.             }
  180.             yyerrok;
  181.         }
  182.     | error    { $$ = NULL; }
  183.     | program error { $$ = NULL; }
  184.     | /* empty */ { $$ = NULL; }
  185.     ;
  186.  
  187. rule
  188.     : LEX_BEGIN { io_allowed = FALSE; }
  189.       action
  190.       {
  191.         if (begin_block != NULL) {
  192.             if (begin_block->type != Node_rule_list)
  193.                 begin_block = node(begin_block, Node_rule_list,
  194.                     (NODE *) NULL);
  195.             (void) append_right(begin_block, node(
  196.                 node((NODE *) NULL, Node_rule_node, $3),
  197.                 Node_rule_list, (NODE *) NULL) );
  198.         } else
  199.             begin_block = node((NODE *) NULL, Node_rule_node, $3);
  200.         $$ = NULL;
  201.         io_allowed = TRUE;
  202.         yyerrok;
  203.       }
  204.     | LEX_END { io_allowed = FALSE; }
  205.       action
  206.       {
  207.         if (end_block != NULL) {
  208.             if (end_block->type != Node_rule_list)
  209.                 end_block = node(end_block, Node_rule_list,
  210.                     (NODE *) NULL);
  211.             (void) append_right (end_block, node(
  212.                 node((NODE *) NULL, Node_rule_node, $3),
  213.                 Node_rule_list, (NODE *) NULL));
  214.         } else
  215.             end_block = node((NODE *) NULL, Node_rule_node, $3);
  216.         $$ = NULL;
  217.         io_allowed = TRUE;
  218.         yyerrok;
  219.       }
  220.     | LEX_BEGIN statement_term
  221.       {
  222.         warning("BEGIN blocks must have an action part");
  223.         errcount++;
  224.         yyerrok;
  225.       }
  226.     | LEX_END statement_term
  227.       {
  228.         warning("END blocks must have an action part");
  229.         errcount++;
  230.         yyerrok;
  231.       }
  232.     | pattern action
  233.         { $$ = node($1, Node_rule_node, $2); yyerrok; }
  234.     | action
  235.         { $$ = node((NODE *) NULL, Node_rule_node, $1); yyerrok; }
  236.     | pattern statement_term
  237.         {
  238.           $$ = node($1,
  239.                  Node_rule_node,
  240.                  node(node(node(make_number(0.0),
  241.                         Node_field_spec,
  242.                         (NODE *) NULL),
  243.                     Node_expression_list,
  244.                     (NODE *) NULL),
  245.                   Node_K_print,
  246.                   (NODE *) NULL));
  247.           yyerrok;
  248.         }
  249.     | function_prologue function_body
  250.         {
  251.             func_install($1, $2);
  252.             $$ = NULL;
  253.             yyerrok;
  254.         }
  255.     ;
  256.  
  257. func_name
  258.     : NAME
  259.         { $$ = $1; }
  260.     | FUNC_CALL
  261.         { $$ = $1; }
  262.     | lex_builtin
  263.       {
  264.         yyerror("%s() is a built-in function, it cannot be redefined",
  265.             tokstart);
  266.         errcount++;
  267.         /* yyerrok; */
  268.       }
  269.     ;
  270.  
  271. lex_builtin
  272.     : LEX_BUILTIN
  273.     | LEX_LENGTH
  274.     ;
  275.         
  276. function_prologue
  277.     : LEX_FUNCTION 
  278.         {
  279.             param_counter = 0;
  280.         }
  281.       func_name '(' opt_param_list r_paren opt_nls
  282.         {
  283.             NODE *t;
  284.  
  285.             t = make_param($3);
  286.             t->flags |= FUNC;
  287.             $$ = append_right(t, $5);
  288.             can_return = TRUE;
  289.             /* check for duplicate parameter names */
  290.             if (dup_parms($$))
  291.                 errcount++;
  292.         }
  293.     ;
  294.  
  295. function_body
  296.     : l_brace statements r_brace opt_semi
  297.       {
  298.         $$ = $2;
  299.         can_return = FALSE;
  300.       }
  301.     | l_brace r_brace opt_semi opt_nls
  302.       {
  303.         $$ = node((NODE *) NULL, Node_K_return, (NODE *) NULL);
  304.         can_return = FALSE;
  305.       }
  306.     ;
  307.  
  308.  
  309. pattern
  310.     : exp
  311.         { $$ = $1; }
  312.     | exp ',' exp
  313.         { $$ = mkrangenode(node($1, Node_cond_pair, $3)); }
  314.     ;
  315.  
  316. regexp
  317.     /*
  318.      * In this rule, want_regexp tells yylex that the next thing
  319.      * is a regexp so it should read up to the closing slash.
  320.      */
  321.     : '/'
  322.         { ++want_regexp; }
  323.       REGEXP '/'
  324.         {
  325.           NODE *n;
  326.           size_t len;
  327.  
  328.           getnode(n);
  329.           n->type = Node_regex;
  330.           len = strlen($3);
  331.           n->re_exp = make_string($3, len);
  332.           n->re_reg = make_regexp($3, len, FALSE, TRUE);
  333.           n->re_text = NULL;
  334.           n->re_flags = CONST;
  335.           n->re_cnt = 1;
  336.           $$ = n;
  337.         }
  338.     ;
  339.  
  340. action
  341.     : l_brace statements r_brace opt_semi opt_nls
  342.         { $$ = $2; }
  343.     | l_brace r_brace opt_semi opt_nls
  344.         { $$ = NULL; }
  345.     ;
  346.  
  347. statements
  348.     : statement
  349.         {
  350.             $$ = $1;
  351.             if (do_lint && isnoeffect($$->type))
  352.                 warning("statement may have no effect");
  353.         }
  354.     | statements statement
  355.         {
  356.             if ($1 == NULL || $1->type != Node_statement_list)
  357.                 $1 = node($1, Node_statement_list, (NODE *) NULL);
  358.                 $$ = append_right($1,
  359.                 node($2, Node_statement_list, (NODE *)   NULL));
  360.                 yyerrok;
  361.         }
  362.     | error
  363.         { $$ = NULL; }
  364.     | statements error
  365.         { $$ = NULL; }
  366.     ;
  367.  
  368. statement_term
  369.     : nls
  370.     | semi opt_nls
  371.     ;
  372.  
  373. statement
  374.     : semi opt_nls
  375.         { $$ = NULL; }
  376.     | l_brace r_brace
  377.         { $$ = NULL; }
  378.     | l_brace statements r_brace
  379.         { $$ = $2; }
  380.     | if_statement
  381.         { $$ = $1; }
  382.     | LEX_WHILE '(' exp r_paren opt_nls statement
  383.         { $$ = node($3, Node_K_while, $6); }
  384.     | LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
  385.         { $$ = node($6, Node_K_do, $3); }
  386.     | LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement
  387.       {
  388.         $$ = node($8, Node_K_arrayfor,
  389.             make_for_loop(variable($3, CAN_FREE, Node_var),
  390.             (NODE *) NULL, variable($5, CAN_FREE, Node_var_array)));
  391.       }
  392.     | LEX_FOR '(' opt_exp semi exp semi opt_exp r_paren opt_nls statement
  393.       {
  394.         $$ = node($10, Node_K_for, (NODE *) make_for_loop($3, $5, $7));
  395.       }
  396.     | LEX_FOR '(' opt_exp semi semi opt_exp r_paren opt_nls statement
  397.       {
  398.         $$ = node($9, Node_K_for,
  399.             (NODE *) make_for_loop($3, (NODE *) NULL, $6));
  400.       }
  401.     | LEX_BREAK statement_term
  402.        /* for break, maybe we'll have to remember where to break to */
  403.         { $$ = node((NODE *) NULL, Node_K_break, (NODE *) NULL); }
  404.     | LEX_CONTINUE statement_term
  405.        /* similarly */
  406.         { $$ = node((NODE *) NULL, Node_K_continue, (NODE *) NULL); }
  407.     | print '(' expression_list r_paren output_redir statement_term
  408.         { $$ = node($3, $1, $5); }
  409.     | print opt_rexpression_list output_redir statement_term
  410.         {
  411.             if ($1 == Node_K_print && $2 == NULL) {
  412.                 static int warned = FALSE;
  413.  
  414.                 $2 = node(node(make_number(0.0),
  415.                            Node_field_spec,
  416.                            (NODE *) NULL),
  417.                       Node_expression_list,
  418.                       (NODE *) NULL);
  419.  
  420.                 if (do_lint && ! io_allowed && ! warned) {
  421.                     warned = TRUE;
  422.                     warning(
  423.     "plain `print' in BEGIN or END rule should probably be `print \"\"'");
  424.                 }
  425.             }
  426.  
  427.             $$ = node($2, $1, $3);
  428.         }
  429.     | LEX_NEXT opt_exp statement_term
  430.         { NODETYPE type;
  431.  
  432.           if ($2) {
  433.             if ($2 == lookup("file")) {
  434.                 static int warned = FALSE;
  435.  
  436.                 if (! warned) {
  437.                     warned = TRUE;
  438.                     warning("`next file' is obsolete; use `nextfile'");
  439.                 }
  440.                 if (do_lint)
  441.                     warning("`next file' is a gawk extension");
  442.                 if (do_traditional) {
  443.                     /*
  444.                      * can't use yyerror, since may have overshot
  445.                      * the source line
  446.                      */
  447.                     errcount++;
  448.                     error("`next file' is a gawk extension");
  449.                 }
  450.                 if (! io_allowed) {
  451.                     /* same thing */
  452.                     errcount++;
  453.                     error("`next file' used in BEGIN or END action");
  454.                 }
  455.                 type = Node_K_nextfile;
  456.             } else {
  457.                 errcount++;
  458.                 error("illegal expression after `next'");
  459.                 type = Node_K_next;    /* sanity */
  460.             }
  461.           } else {
  462.             if (! io_allowed)
  463.                 yyerror("`next' used in BEGIN or END action");
  464.             type = Node_K_next;
  465.           }
  466.           $$ = node((NODE *) NULL, type, (NODE *) NULL);
  467.         }
  468.     | LEX_NEXTFILE statement_term
  469.         {
  470.           if (do_lint)
  471.             warning("`nextfile' is a gawk extension");
  472.           if (do_traditional) {
  473.             /*
  474.              * can't use yyerror, since may have overshot
  475.              * the source line
  476.              */
  477.             errcount++;
  478.             error("`nextfile' is a gawk extension");
  479.           }
  480.           if (! io_allowed) {
  481.             /* same thing */
  482.             errcount++;
  483.             error("`nextfile' used in BEGIN or END action");
  484.           }
  485.           $$ = node((NODE *) NULL, Node_K_nextfile, (NODE *) NULL);
  486.         }
  487.     | LEX_EXIT opt_exp statement_term
  488.         { $$ = node($2, Node_K_exit, (NODE *) NULL); }
  489.     | LEX_RETURN
  490.         {
  491.           if (! can_return)
  492.             yyerror("`return' used outside function context");
  493.         }
  494.       opt_exp statement_term
  495.         { $$ = node($3, Node_K_return, (NODE *) NULL); }
  496.     | LEX_DELETE NAME '[' expression_list ']' statement_term
  497.         { $$ = node(variable($2, CAN_FREE, Node_var_array), Node_K_delete, $4); }
  498.     | LEX_DELETE NAME  statement_term
  499.         {
  500.           if (do_lint)
  501.             warning("`delete array' is a gawk extension");
  502.           if (do_traditional) {
  503.             /*
  504.              * can't use yyerror, since may have overshot
  505.              * the source line
  506.              */
  507.             errcount++;
  508.             error("`delete array' is a gawk extension");
  509.           }
  510.           $$ = node(variable($2, CAN_FREE, Node_var_array), Node_K_delete, (NODE *) NULL);
  511.         }
  512.     | exp statement_term
  513.         { $$ = $1; }
  514.     ;
  515.  
  516. print
  517.     : LEX_PRINT
  518.         { $$ = $1; }
  519.     | LEX_PRINTF
  520.         { $$ = $1; }
  521.     ;
  522.  
  523. if_statement
  524.     : LEX_IF '(' exp r_paren opt_nls statement
  525.       {
  526.         $$ = node($3, Node_K_if, 
  527.             node($6, Node_if_branches, (NODE *) NULL));
  528.       }
  529.     | LEX_IF '(' exp r_paren opt_nls statement
  530.          LEX_ELSE opt_nls statement
  531.         { $$ = node($3, Node_K_if,
  532.                 node($6, Node_if_branches, $9)); }
  533.     ;
  534.  
  535. nls
  536.     : NEWLINE
  537.         { want_assign = FALSE; }
  538.     | nls NEWLINE
  539.     ;
  540.  
  541. opt_nls
  542.     : /* empty */
  543.     | nls
  544.     ;
  545.  
  546. input_redir
  547.     : /* empty */
  548.         { $$ = NULL; }
  549.     | '<' simp_exp
  550.         { $$ = node($2, Node_redirect_input, (NODE *) NULL); }
  551.     ;
  552.  
  553. output_redir
  554.     : /* empty */
  555.         { $$ = NULL; }
  556.     | '>' exp
  557.         { $$ = node($2, Node_redirect_output, (NODE *) NULL); }
  558.     | APPEND_OP exp
  559.         { $$ = node($2, Node_redirect_append, (NODE *) NULL); }
  560.     | '|' exp
  561.         { $$ = node($2, Node_redirect_pipe, (NODE *) NULL); }
  562.     ;
  563.  
  564. opt_param_list
  565.     : /* empty */
  566.         { $$ = NULL; }
  567.     | param_list
  568.         { $$ = $1; }
  569.     ;
  570.  
  571. param_list
  572.     : NAME
  573.         { $$ = make_param($1); }
  574.     | param_list comma NAME
  575.         { $$ = append_right($1, make_param($3)); yyerrok; }
  576.     | error
  577.         { $$ = NULL; }
  578.     | param_list error
  579.         { $$ = NULL; }
  580.     | param_list comma error
  581.         { $$ = NULL; }
  582.     ;
  583.  
  584. /* optional expression, as in for loop */
  585. opt_exp
  586.     : /* empty */
  587.         { $$ = NULL; }
  588.     | exp
  589.         { $$ = $1; }
  590.     ;
  591.  
  592. opt_rexpression_list
  593.     : /* empty */
  594.         { $$ = NULL; }
  595.     | rexpression_list
  596.         { $$ = $1; }
  597.     ;
  598.  
  599. rexpression_list
  600.     : rexp
  601.         { $$ = node($1, Node_expression_list, (NODE *) NULL); }
  602.     | rexpression_list comma rexp
  603.       {
  604.         $$ = append_right($1,
  605.             node($3, Node_expression_list, (NODE *) NULL));
  606.         yyerrok;
  607.       }
  608.     | error
  609.         { $$ = NULL; }
  610.     | rexpression_list error
  611.         { $$ = NULL; }
  612.     | rexpression_list error rexp
  613.         { $$ = NULL; }
  614.     | rexpression_list comma error
  615.         { $$ = NULL; }
  616.     ;
  617.  
  618. opt_expression_list
  619.     : /* empty */
  620.         { $$ = NULL; }
  621.     | expression_list
  622.         { $$ = $1; }
  623.     ;
  624.  
  625. expression_list
  626.     : exp
  627.         { $$ = node($1, Node_expression_list, (NODE *) NULL); }
  628.     | expression_list comma exp
  629.         {
  630.             $$ = append_right($1,
  631.                 node($3, Node_expression_list, (NODE *) NULL));
  632.             yyerrok;
  633.         }
  634.     | error
  635.         { $$ = NULL; }
  636.     | expression_list error
  637.         { $$ = NULL; }
  638.     | expression_list error exp
  639.         { $$ = NULL; }
  640.     | expression_list comma error
  641.         { $$ = NULL; }
  642.     ;
  643.  
  644. /* Expressions, not including the comma operator.  */
  645. exp    : variable ASSIGNOP 
  646.         { want_assign = FALSE; }
  647.       exp
  648.         {
  649.           if (do_lint && $4->type == Node_regex)
  650.             warning("Regular expression on left of assignment.");
  651.           $$ = node($1, $2, $4);
  652.         }
  653.     | '(' expression_list r_paren LEX_IN NAME
  654.         { $$ = node(variable($5, CAN_FREE, Node_var_array), Node_in_array, $2); }
  655.     | exp '|' LEX_GETLINE opt_variable
  656.         {
  657.           $$ = node($4, Node_K_getline,
  658.              node($1, Node_redirect_pipein, (NODE *) NULL));
  659.         }
  660.     | LEX_GETLINE opt_variable input_redir
  661.         {
  662.           if (do_lint && ! io_allowed && $3 == NULL)
  663.             warning("non-redirected getline undefined inside BEGIN or END action");
  664.           $$ = node($2, Node_K_getline, $3);
  665.         }
  666.     | exp LEX_AND exp
  667.         { $$ = node($1, Node_and, $3); }
  668.     | exp LEX_OR exp
  669.         { $$ = node($1, Node_or, $3); }
  670.     | exp MATCHOP exp
  671.         {
  672.           if ($1->type == Node_regex)
  673.             warning("Regular expression on left of MATCH operator.");
  674.           $$ = node($1, $2, mk_rexp($3));
  675.         }
  676.     | regexp
  677.         {
  678.           $$ = $1;
  679.           if (do_lint && tokstart[0] == '*') {
  680.             /* possible C comment */
  681.             int n = strlen(tokstart) - 1;
  682.             if (tokstart[n] == '*')
  683.                 warning("regexp looks like a C comment, but is not");
  684.           }
  685.         }
  686.     | '!' regexp %prec UNARY
  687.         {
  688.           $$ = node(node(make_number(0.0),
  689.                  Node_field_spec,
  690.                  (NODE *) NULL),
  691.                     Node_nomatch,
  692.                 $2);
  693.         }
  694.     | exp LEX_IN NAME
  695.         { $$ = node(variable($3, CAN_FREE, Node_var_array), Node_in_array, $1); }
  696.     | exp RELOP exp
  697.         {
  698.           if (do_lint && $3->type == Node_regex)
  699.             warning("Regular expression on left of comparison.");
  700.           $$ = node($1, $2, $3);
  701.         }
  702.     | exp '<' exp
  703.         { $$ = node($1, Node_less, $3); }
  704.     | exp '>' exp
  705.         { $$ = node($1, Node_greater, $3); }
  706.     | exp '?' exp ':' exp
  707.         { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
  708.     | simp_exp
  709.         { $$ = $1; }
  710.     | exp simp_exp %prec CONCAT_OP
  711.         { $$ = node($1, Node_concat, $2); }
  712.     ;
  713.  
  714. rexp    
  715.     : variable ASSIGNOP 
  716.         { want_assign = FALSE; }
  717.       rexp
  718.         { $$ = node($1, $2, $4); }
  719.     | rexp LEX_AND rexp
  720.         { $$ = node($1, Node_and, $3); }
  721.     | rexp LEX_OR rexp
  722.         { $$ = node($1, Node_or, $3); }
  723.     | LEX_GETLINE opt_variable input_redir
  724.         {
  725.           if (do_lint && ! io_allowed && $3 == NULL)
  726.             warning("non-redirected getline undefined inside BEGIN or END action");
  727.           $$ = node($2, Node_K_getline, $3);
  728.         }
  729.     | regexp
  730.         { $$ = $1; } 
  731.     | '!' regexp %prec UNARY
  732.         { $$ = node((NODE *) NULL, Node_nomatch, $2); }
  733.     | rexp MATCHOP rexp
  734.          { $$ = node($1, $2, mk_rexp($3)); }
  735.     | rexp LEX_IN NAME
  736.         { $$ = node(variable($3, CAN_FREE, Node_var_array), Node_in_array, $1); }
  737.     | rexp RELOP rexp
  738.         { $$ = node($1, $2, $3); }
  739.     | rexp '?' rexp ':' rexp
  740.         { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
  741.     | simp_exp
  742.         { $$ = $1; }
  743.     | rexp simp_exp %prec CONCAT_OP
  744.         { $$ = node($1, Node_concat, $2); }
  745.     ;
  746.  
  747. simp_exp
  748.     : non_post_simp_exp
  749.     /* Binary operators in order of decreasing precedence.  */
  750.     | simp_exp '^' simp_exp
  751.         { $$ = node($1, Node_exp, $3); }
  752.     | simp_exp '*' simp_exp
  753.         { $$ = node($1, Node_times, $3); }
  754.     | simp_exp '/' simp_exp
  755.         { $$ = node($1, Node_quotient, $3); }
  756.     | simp_exp '%' simp_exp
  757.         { $$ = node($1, Node_mod, $3); }
  758.     | simp_exp '+' simp_exp
  759.         { $$ = node($1, Node_plus, $3); }
  760.     | simp_exp '-' simp_exp
  761.         { $$ = node($1, Node_minus, $3); }
  762.     | variable INCREMENT
  763.         { $$ = node($1, Node_postincrement, (NODE *) NULL); }
  764.     | variable DECREMENT
  765.         { $$ = node($1, Node_postdecrement, (NODE *) NULL); }
  766.     ;
  767.  
  768. non_post_simp_exp
  769.     : '!' simp_exp %prec UNARY
  770.         { $$ = node($2, Node_not, (NODE *) NULL); }
  771.     | '(' exp r_paren
  772.         { $$ = $2; }
  773.     | LEX_BUILTIN
  774.       '(' opt_expression_list r_paren
  775.         { $$ = snode($3, Node_builtin, (int) $1); }
  776.     | LEX_LENGTH '(' opt_expression_list r_paren
  777.         { $$ = snode($3, Node_builtin, (int) $1); }
  778.     | LEX_LENGTH
  779.       {
  780.         if (do_lint)
  781.             warning("call of `length' without parentheses is not portable");
  782.         $$ = snode((NODE *) NULL, Node_builtin, (int) $1);
  783.         if (do_posix)
  784.             warning("call of `length' without parentheses is deprecated by POSIX");
  785.       }
  786.     | FUNC_CALL '(' opt_expression_list r_paren
  787.       {
  788.         $$ = node($3, Node_func_call, make_string($1, strlen($1)));
  789.         func_use($1, FUNC_USE);
  790.         param_sanity($3);
  791.         free($1);
  792.       }
  793.     | variable
  794.     | INCREMENT variable
  795.         { $$ = node($2, Node_preincrement, (NODE *) NULL); }
  796.     | DECREMENT variable
  797.         { $$ = node($2, Node_predecrement, (NODE *) NULL); }
  798.     | YNUMBER
  799.         { $$ = $1; }
  800.     | YSTRING
  801.         { $$ = $1; }
  802.  
  803.     | '-' simp_exp    %prec UNARY
  804.         {
  805.           if ($2->type == Node_val) {
  806.             $2->numbr = -(force_number($2));
  807.             $$ = $2;
  808.           } else
  809.             $$ = node($2, Node_unary_minus, (NODE *) NULL);
  810.         }
  811.     | '+' simp_exp    %prec UNARY
  812.         {
  813.           /*
  814.            * was: $$ = $2
  815.            * POSIX semantics: force a conversion to numeric type
  816.            */
  817.           $$ = node (make_number(0.0), Node_plus, $2);
  818.         }
  819.     ;
  820.  
  821. opt_variable
  822.     : /* empty */
  823.         { $$ = NULL; }
  824.     | variable
  825.         { $$ = $1; }
  826.     ;
  827.  
  828. variable
  829.     : NAME
  830.         { $$ = variable($1, CAN_FREE, Node_var); }
  831.     | NAME '[' expression_list ']'
  832.         {
  833.         if ($3->rnode == NULL) {
  834.             $$ = node(variable($1, CAN_FREE, Node_var_array), Node_subscript, $3->lnode);
  835.             freenode($3);
  836.         } else
  837.             $$ = node(variable($1, CAN_FREE, Node_var_array), Node_subscript, $3);
  838.         }
  839.     | '$' non_post_simp_exp
  840.         { $$ = node($2, Node_field_spec, (NODE *) NULL); }
  841.     ;
  842.  
  843. l_brace
  844.     : '{' opt_nls
  845.     ;
  846.  
  847. r_brace
  848.     : '}' opt_nls    { yyerrok; }
  849.     ;
  850.  
  851. r_paren
  852.     : ')' { yyerrok; }
  853.     ;
  854.  
  855. opt_semi
  856.     : /* empty */
  857.     | semi
  858.     ;
  859.  
  860. semi
  861.     : ';'    { yyerrok; want_assign = FALSE; }
  862.     ;
  863.  
  864. comma    : ',' opt_nls    { yyerrok; }
  865.     ;
  866.  
  867. %%
  868.  
  869. struct token {
  870.     const char *operator;        /* text to match */
  871.     NODETYPE value;        /* node type */
  872.     int class;        /* lexical class */
  873.     unsigned flags;        /* # of args. allowed and compatability */
  874. #    define    ARGS    0xFF    /* 0, 1, 2, 3 args allowed (any combination */
  875. #    define    A(n)    (1<<(n))
  876. #    define    VERSION    0xFF00    /* old awk is zero */
  877. #    define    NOT_OLD        0x0100    /* feature not in old awk */
  878. #    define    NOT_POSIX    0x0200    /* feature not in POSIX */
  879. #    define    GAWKX        0x0400    /* gawk extension */
  880. #    define    RESX        0x0800    /* Bell Labs Research extension */
  881.     NODE *(*ptr)();        /* function that implements this keyword */
  882. };
  883.  
  884. extern NODE
  885.     *do_exp(),    *do_getline(),    *do_index(),    *do_length(),
  886.     *do_sqrt(),    *do_log(),    *do_sprintf(),    *do_substr(),
  887.     *do_split(),    *do_system(),    *do_int(),    *do_close(),
  888.     *do_atan2(),    *do_sin(),    *do_cos(),    *do_rand(),
  889.     *do_srand(),    *do_match(),    *do_tolower(),    *do_toupper(),
  890.     *do_sub(),    *do_gsub(),    *do_strftime(),    *do_systime(),
  891.     *do_fflush();
  892.  
  893. /* Tokentab is sorted ascii ascending order, so it can be binary searched. */
  894.  
  895. static struct token tokentab[] = {
  896. {"BEGIN",    Node_illegal,     LEX_BEGIN,    0,        0},
  897. {"END",        Node_illegal,     LEX_END,    0,        0},
  898. #ifdef BITOPS
  899. {"and",        Node_builtin,    LEX_BUILTIN,    GAWKX|A(2),    do_and},
  900. #endif /* BITOPS */
  901. {"atan2",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2),    do_atan2},
  902. {"break",    Node_K_break,     LEX_BREAK,    0,        0},
  903. {"close",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_close},
  904. #ifdef BITOPS
  905. {"compl",    Node_builtin,    LEX_BUILTIN,    GAWKX|A(1),    do_compl},
  906. #endif /* BITOPS */
  907. {"continue",    Node_K_continue, LEX_CONTINUE,    0,        0},
  908. {"cos",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_cos},
  909. {"delete",    Node_K_delete,     LEX_DELETE,    NOT_OLD,    0},
  910. {"do",        Node_K_do,     LEX_DO,    NOT_OLD,    0},
  911. {"else",    Node_illegal,     LEX_ELSE,    0,        0},
  912. {"exit",    Node_K_exit,     LEX_EXIT,    0,        0},
  913. {"exp",        Node_builtin,     LEX_BUILTIN,    A(1),        do_exp},
  914. {"fflush",    Node_builtin,     LEX_BUILTIN,    RESX|A(0)|A(1), do_fflush},
  915. {"for",        Node_K_for,     LEX_FOR,    0,        0},
  916. {"func",    Node_K_function, LEX_FUNCTION,    NOT_POSIX|NOT_OLD,    0},
  917. {"function",    Node_K_function, LEX_FUNCTION,    NOT_OLD,    0},
  918. {"gensub",    Node_builtin,     LEX_BUILTIN,    GAWKX|A(3)|A(4), do_gensub},
  919. {"getline",    Node_K_getline,     LEX_GETLINE,    NOT_OLD,    0},
  920. {"gsub",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2)|A(3), do_gsub},
  921. {"if",        Node_K_if,     LEX_IF,    0,        0},
  922. {"in",        Node_illegal,     LEX_IN,    0,        0},
  923. {"index",    Node_builtin,     LEX_BUILTIN,    A(2),        do_index},
  924. {"int",        Node_builtin,     LEX_BUILTIN,    A(1),        do_int},
  925. {"length",    Node_builtin,     LEX_LENGTH,    A(0)|A(1),    do_length},
  926. {"log",        Node_builtin,     LEX_BUILTIN,    A(1),        do_log},
  927. #ifdef BITOPS
  928. {"lshift",    Node_builtin,    LEX_BUILTIN,    GAWKX|A(2),    do_lshift},
  929. #endif /* BITOPS */
  930. {"match",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2),    do_match},
  931. {"next",    Node_K_next,     LEX_NEXT,    0,        0},
  932. {"nextfile",    Node_K_nextfile, LEX_NEXTFILE,    GAWKX,        0},
  933. #ifdef BITOPS
  934. {"or",        Node_builtin,    LEX_BUILTIN,    GAWKX|A(2),    do_or},
  935. #endif /* BITOPS */
  936. {"print",    Node_K_print,     LEX_PRINT,    0,        0},
  937. {"printf",    Node_K_printf,     LEX_PRINTF,    0,        0},
  938. {"rand",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(0),    do_rand},
  939. {"return",    Node_K_return,     LEX_RETURN,    NOT_OLD,    0},
  940. #ifdef BITOPS
  941. {"rshift",    Node_builtin,    LEX_BUILTIN,    GAWKX|A(2),    do_rshift},
  942. #endif /* BITOPS */
  943. {"sin",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_sin},
  944. {"split",    Node_builtin,     LEX_BUILTIN,    A(2)|A(3),    do_split},
  945. {"sprintf",    Node_builtin,     LEX_BUILTIN,    0,        do_sprintf},
  946. {"sqrt",    Node_builtin,     LEX_BUILTIN,    A(1),        do_sqrt},
  947. {"srand",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(0)|A(1), do_srand},
  948. {"strftime",    Node_builtin,     LEX_BUILTIN,    GAWKX|A(0)|A(1)|A(2), do_strftime},
  949. #ifdef BITOPS
  950. {"strtonum",    Node_builtin,    LEX_BUILTIN,    GAWKX|A(1),    do_strtonum},
  951. #endif /* BITOPS */
  952. {"sub",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2)|A(3), do_sub},
  953. {"substr",    Node_builtin,     LEX_BUILTIN,    A(2)|A(3),    do_substr},
  954. {"system",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_system},
  955. {"systime",    Node_builtin,     LEX_BUILTIN,    GAWKX|A(0),    do_systime},
  956. {"tolower",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_tolower},
  957. {"toupper",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_toupper},
  958. {"while",    Node_K_while,     LEX_WHILE,    0,        0},
  959. #ifdef BITOPS
  960. {"xor",        Node_builtin,    LEX_BUILTIN,    GAWKX|A(2),    do_xor},
  961. #endif /* BITOPS */
  962. };
  963.  
  964. /* yyerror --- print a syntax error message, show where */
  965.  
  966. #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
  967. static void
  968. yyerror(const char *m, ...)
  969. #else
  970. /* VARARGS0 */
  971. static void
  972. yyerror(va_alist)
  973. va_dcl
  974. #endif
  975. {
  976.     va_list args;
  977.     const char *mesg = NULL;
  978.     register char *bp, *cp;
  979.     char *scan;
  980.     char buf[120];
  981.     static char end_of_file_line[] = "(END OF FILE)";
  982.  
  983.     errcount++;
  984.     /* Find the current line in the input file */
  985.     if (lexptr && lexeme) {
  986.         if (thisline == NULL) {
  987.             cp = lexeme;
  988.             if (*cp == '\n') {
  989.                 cp--;
  990.                 mesg = "unexpected newline";
  991.             }
  992.             for (; cp != lexptr_begin && *cp != '\n'; --cp)
  993.                 continue;
  994.             if (*cp == '\n')
  995.                 cp++;
  996.             thisline = cp;
  997.         }
  998.         /* NL isn't guaranteed */
  999.         bp = lexeme;
  1000.         while (bp < lexend && *bp && *bp != '\n')
  1001.             bp++;
  1002.     } else {
  1003.         thisline = end_of_file_line;
  1004.         bp = thisline + strlen(thisline);
  1005.     }
  1006.     msg("%.*s", (int) (bp - thisline), thisline);
  1007.     bp = buf;
  1008.     cp = buf + sizeof(buf) - 24;    /* 24 more than longest msg. input */
  1009.     if (lexptr != NULL) {
  1010.         scan = thisline;
  1011.         while (bp < cp && scan < lexeme)
  1012.             if (*scan++ == '\t')
  1013.                 *bp++ = '\t';
  1014.             else
  1015.                 *bp++ = ' ';
  1016.         *bp++ = '^';
  1017.         *bp++ = ' ';
  1018.     }
  1019. #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
  1020.     va_start(args, m);
  1021.     if (mesg == NULL)
  1022.         mesg = m;
  1023. #else
  1024.     va_start(args);
  1025.     if (mesg == NULL)
  1026.         mesg = va_arg(args, char *);
  1027. #endif
  1028.     strcpy(bp, mesg);
  1029.     err("", buf, args);
  1030.     va_end(args);
  1031. }
  1032.  
  1033. /* get_src_buf --- read the next buffer of source program */
  1034.  
  1035. static char *
  1036. get_src_buf()
  1037. {
  1038.     static int samefile = FALSE;
  1039.     static int nextfile = 0;
  1040.     static char *buf = NULL;
  1041.     static int fd;
  1042.     int n;
  1043.     register char *scan;
  1044.     static int len = 0;
  1045.     static int did_newline = FALSE;
  1046.     int newfile;
  1047.     struct stat sbuf;
  1048.  
  1049. #    define    SLOP    128    /* enough space to hold most source lines */
  1050.  
  1051. again:
  1052.     newfile = FALSE;
  1053.     if (nextfile > numfiles)
  1054.         return NULL;
  1055.  
  1056.     if (srcfiles[nextfile].stype == CMDLINE) {
  1057.         if (len == 0) {
  1058.             len = strlen(srcfiles[nextfile].val);
  1059.             if (len == 0) {
  1060.                 /*
  1061.                  * Yet Another Special case:
  1062.                  *    gawk '' /path/name
  1063.                  * Sigh.
  1064.                  */
  1065.                 static int warned = FALSE;
  1066.  
  1067.                 if (do_lint && ! warned) {
  1068.                     warned = TRUE;
  1069.                     warning("empty program text on command line");
  1070.                 }
  1071.                 ++nextfile;
  1072.                 goto again;
  1073.             }
  1074.             sourceline = 1;
  1075.             lexptr = lexptr_begin = srcfiles[nextfile].val;
  1076.             lexend = lexptr + len;
  1077.         } else if (! did_newline && *(lexptr-1) != '\n') {
  1078.             /*
  1079.              * The following goop is to ensure that the source
  1080.              * ends with a newline and that the entire current
  1081.              * line is available for error messages.
  1082.              */
  1083.             int offset;
  1084.  
  1085.             did_newline = TRUE;
  1086.             offset = lexptr - lexeme;
  1087.             for (scan = lexeme; scan > lexptr_begin; scan--)
  1088.                 if (*scan == '\n') {
  1089.                     scan++;
  1090.                     break;
  1091.                 }
  1092.             len = lexptr - scan;
  1093.             emalloc(buf, char *, len+1, "get_src_buf");
  1094.             memcpy(buf, scan, len);
  1095.             thisline = buf;
  1096.             lexptr = buf + len;
  1097.             *lexptr = '\n';
  1098.             lexeme = lexptr - offset;
  1099.             lexptr_begin = buf;
  1100.             lexend = lexptr + 1;
  1101.         } else {
  1102.             len = 0;
  1103.             lexeme = lexptr = lexptr_begin = NULL;
  1104.         }
  1105.         if (lexptr == NULL && ++nextfile <= numfiles)
  1106.             goto again;
  1107.         return lexptr;
  1108.     }
  1109.     if (! samefile) {
  1110.         source = srcfiles[nextfile].val;
  1111.         if (source == NULL) {
  1112.             if (buf != NULL) {
  1113.                 free(buf);
  1114.                 buf = NULL;
  1115.             }
  1116.             len = 0;
  1117.             return lexeme = lexptr = lexptr_begin = NULL;
  1118.         }
  1119.         fd = pathopen(source);
  1120.         if (fd <= INVALID_HANDLE) {
  1121.             char *in;
  1122.  
  1123.             /* suppress file name and line no. in error mesg */
  1124.             in = source;
  1125.             source = NULL;
  1126.             fatal("can't open source file \"%s\" for reading (%s)",
  1127.                 in, strerror(errno));
  1128.         }
  1129.         len = optimal_bufsize(fd, & sbuf);
  1130.         newfile = TRUE;
  1131.         if (buf != NULL)
  1132.             free(buf);
  1133.         emalloc(buf, char *, len + SLOP, "get_src_buf");
  1134.         lexptr_begin = buf + SLOP;
  1135.         samefile = TRUE;
  1136.         sourceline = 1;
  1137.     } else {
  1138.         /*
  1139.          * Here, we retain the current source line (up to length SLOP)
  1140.          * in the beginning of the buffer that was overallocated above
  1141.          */
  1142.         int offset;
  1143.         int linelen;
  1144.  
  1145.         offset = lexptr - lexeme;
  1146.         for (scan = lexeme; scan > lexptr_begin; scan--)
  1147.             if (*scan == '\n') {
  1148.                 scan++;
  1149.                 break;
  1150.             }
  1151.         linelen = lexptr - scan;
  1152.         if (linelen > SLOP)
  1153.             linelen = SLOP;
  1154.         thisline = buf + SLOP - linelen;
  1155.         memcpy(thisline, scan, linelen);
  1156.         lexeme = buf + SLOP - offset;
  1157.         lexptr_begin = thisline;
  1158.     }
  1159.     n = read(fd, buf + SLOP, len);
  1160.     if (n == -1)
  1161.         fatal("can't read sourcefile \"%s\" (%s)",
  1162.             source, strerror(errno));
  1163.     if (n == 0) {
  1164.         if (newfile) {
  1165.             static int warned = FALSE;
  1166.  
  1167.             if (do_lint && ! warned) {
  1168.                 warned = TRUE;
  1169.                 warning("source file `%s' is empty", source);
  1170.             }
  1171.         }
  1172.         close(fd);
  1173.         samefile = FALSE;
  1174.         nextfile++;
  1175.         if (lexeme)
  1176.             *lexeme = '\0';
  1177.         len = 0;
  1178.         goto again;
  1179.     }
  1180.     lexptr = buf + SLOP;
  1181.     lexend = lexptr + n;
  1182.     return buf;
  1183. }
  1184.  
  1185. /* tokadd --- add a character to the token buffer */
  1186.  
  1187. #define    tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok)
  1188.  
  1189. /* tokexpand --- grow the token buffer */
  1190.  
  1191. char *
  1192. tokexpand()
  1193. {
  1194.     static int toksize = 60;
  1195.     int tokoffset;
  1196.  
  1197.     tokoffset = tok - tokstart;
  1198.     toksize *= 2;
  1199.     if (tokstart != NULL)
  1200.         erealloc(tokstart, char *, toksize, "tokexpand");
  1201.     else
  1202.         emalloc(tokstart, char *, toksize, "tokexpand");
  1203.     tokend = tokstart + toksize;
  1204.     tok = tokstart + tokoffset;
  1205.     return tok;
  1206. }
  1207.  
  1208. /* nextc --- get the next input character */
  1209.  
  1210. #if DEBUG
  1211. int
  1212. nextc()
  1213. {
  1214.     int c;
  1215.  
  1216.     if (lexptr && lexptr < lexend)
  1217.         c = *lexptr++;
  1218.     else if (get_src_buf())
  1219.         c = *lexptr++;
  1220.     else
  1221.         c = EOF;
  1222.  
  1223.     return c;
  1224. }
  1225. #else
  1226. #define    nextc()    ((lexptr && lexptr < lexend) ? \
  1227.             *lexptr++ : \
  1228.             (get_src_buf() ? *lexptr++ : EOF) \
  1229.         )
  1230. #endif
  1231.  
  1232. /* pushback --- push a character back on the input */
  1233.  
  1234. #define pushback() (lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr)
  1235.  
  1236. /* allow_newline --- allow newline after &&, ||, ? and : */
  1237.  
  1238. static void
  1239. allow_newline()
  1240. {
  1241.     int c;
  1242.  
  1243.     for (;;) {
  1244.         c = nextc();
  1245.         if (c == EOF)
  1246.             break;
  1247.         if (c == '#') {
  1248.             while ((c = nextc()) != '\n' && c != EOF)
  1249.                 continue;
  1250.             if (c == EOF)
  1251.                 break;
  1252.         }
  1253.         if (c == '\n')
  1254.             sourceline++;
  1255.         if (! isspace(c)) {
  1256.             pushback();
  1257.             break;
  1258.         }
  1259.     }
  1260. }
  1261.  
  1262. /* yylex --- Read the input and turn it into tokens. */
  1263.  
  1264. static int
  1265. yylex()
  1266. {
  1267.     register int c, c1;
  1268.     int seen_e = FALSE;        /* These are for numbers */
  1269.     int seen_point = FALSE;
  1270.     int esc_seen;        /* for literal strings */
  1271.     int low, mid, high;
  1272.     static int did_newline = FALSE;
  1273.     char *tokkey;
  1274.     static int lasttok = 0, eof_warned = FALSE;
  1275.     int inhex = FALSE;
  1276.  
  1277.     if (nextc() == EOF) {
  1278.         if (lasttok != NEWLINE) {
  1279.             lasttok = NEWLINE;
  1280.             if (do_lint && ! eof_warned) {
  1281.                 warning("source file does not end in newline");
  1282.                 eof_warned = TRUE;
  1283.             }
  1284.             return NEWLINE;    /* fake it */
  1285.         }
  1286.         return 0;
  1287.     }
  1288.     pushback();
  1289. #ifdef OS2
  1290.     /*
  1291.      * added for OS/2's extproc feature of cmd.exe
  1292.      * (like #! in BSD sh)
  1293.      */
  1294.     if (strncasecmp(lexptr, "extproc ", 8) == 0) {
  1295.         while (*lexptr && *lexptr != '\n')
  1296.             lexptr++;
  1297.     }
  1298. #endif
  1299.     lexeme = lexptr;
  1300.     thisline = NULL;
  1301.     if (want_regexp) {
  1302.         int in_brack = 0;    /* count brackets, [[:alnum:]] allowed */
  1303.         /*
  1304.          * Counting brackets is non-trivial. [[] is ok,
  1305.          * and so is [\]], with a point being that /[/]/ as a regexp
  1306.          * constant has to work.
  1307.          *
  1308.          * Do not count [ or ] if either one is preceded by a \.
  1309.          * A `[' should be counted if
  1310.          *  a) it is the first one so far (in_brack == 0)
  1311.          *  b) it is the `[' in `[:'
  1312.          * A ']' should be counted if not preceded by a \, since
  1313.          * it is either closing `:]' or just a plain list.
  1314.          * According to POSIX, []] is how you put a ] into a set.
  1315.          * Try to handle that too.
  1316.          *
  1317.          * The code for \ handles \[ and \].
  1318.          */
  1319.  
  1320.         want_regexp = FALSE;
  1321.         tok = tokstart;
  1322.         for (;;) {
  1323.             c = nextc();
  1324.             switch (c) {
  1325.             case '[':
  1326.                 /* one day check for `.' and `=' too */
  1327.                 if ((c1 = nextc()) == ':' || in_brack == 0)
  1328.                     in_brack++;
  1329.                 pushback();
  1330.                 break;
  1331.             case ']':
  1332.                 if (tokstart[0] == '['
  1333.                     && (tok == tokstart + 1
  1334.                     || (tok == tokstart + 2
  1335.                         && tokstart[1] == '^')))
  1336.                     /* do nothing */;
  1337.                 else
  1338.                     in_brack--;
  1339.                 break;
  1340.             case '\\':
  1341.                 if ((c = nextc()) == EOF) {
  1342.                     yyerror("unterminated regexp ends with \\ at end of file");
  1343.                     return lasttok = REGEXP; /* kludge */
  1344.                 } else if (c == '\n') {
  1345.                     sourceline++;
  1346.                     continue;
  1347.                 } else {
  1348.                     tokadd('\\');
  1349.                     tokadd(c);
  1350.                     continue;
  1351.                 }
  1352.                 break;
  1353.             case '/':    /* end of the regexp */
  1354.                 if (in_brack > 0)
  1355.                     break;
  1356.  
  1357.                 pushback();
  1358.                 tokadd('\0');
  1359.                 yylval.sval = tokstart;
  1360.                 return lasttok = REGEXP;
  1361.             case '\n':
  1362.                 pushback();
  1363.                 yyerror("unterminated regexp");
  1364.                 return lasttok = REGEXP;    /* kludge */
  1365.             case EOF:
  1366.                 yyerror("unterminated regexp at end of file");
  1367.                 return lasttok = REGEXP;    /* kludge */
  1368.             }
  1369.             tokadd(c);
  1370.         }
  1371.     }
  1372. retry:
  1373.     while ((c = nextc()) == ' ' || c == '\t')
  1374.         continue;
  1375.  
  1376.     lexeme = lexptr ? lexptr - 1 : lexptr;
  1377.     thisline = NULL;
  1378.     tok = tokstart;
  1379.     yylval.nodetypeval = Node_illegal;
  1380.  
  1381.     switch (c) {
  1382.     case EOF:
  1383.         if (lasttok != NEWLINE) {
  1384.             lasttok = NEWLINE;
  1385.             if (do_lint && ! eof_warned) {
  1386.                 warning("source file does not end in newline");
  1387.                 eof_warned = TRUE;
  1388.             }
  1389.             return NEWLINE;    /* fake it */
  1390.         }
  1391.         return 0;
  1392.  
  1393.     case '\n':
  1394.         sourceline++;
  1395.         return lasttok = NEWLINE;
  1396.  
  1397.     case '#':        /* it's a comment */
  1398.         while ((c = nextc()) != '\n') {
  1399.             if (c == EOF) {
  1400.                 if (lasttok != NEWLINE) {
  1401.                     lasttok = NEWLINE;
  1402.                     if (do_lint && ! eof_warned) {
  1403.                         warning(
  1404.                 "source file does not end in newline");
  1405.                         eof_warned = TRUE;
  1406.                     }
  1407.                     return NEWLINE;    /* fake it */
  1408.                 }
  1409.                 return 0;
  1410.             }
  1411.         }
  1412.         sourceline++;
  1413.         return lasttok = NEWLINE;
  1414.  
  1415.     case '\\':
  1416. #ifdef RELAXED_CONTINUATION
  1417.         /*
  1418.          * This code puports to allow comments and/or whitespace
  1419.          * after the `\' at the end of a line used for continuation.
  1420.          * Use it at your own risk. We think it's a bad idea, which
  1421.          * is why it's not on by default.
  1422.          */
  1423.         if (! do_traditional) {
  1424.             /* strip trailing white-space and/or comment */
  1425.             while ((c = nextc()) == ' ' || c == '\t')
  1426.                 continue;
  1427.             if (c == '#') {
  1428.                 if (do_lint)
  1429.                     warning(
  1430.         "use of `\\ #...' line continuation is not portable");
  1431.                 while ((c = nextc()) != '\n')
  1432.                     if (c == EOF)
  1433.                         break;
  1434.             }
  1435.             pushback();
  1436.         }
  1437. #endif /* RELAXED_CONTINUATION */
  1438.         if (nextc() == '\n') {
  1439.             sourceline++;
  1440.             goto retry;
  1441.         } else {
  1442.             yyerror("backslash not last character on line");
  1443.             exit(1);
  1444.         }
  1445.         break;
  1446.  
  1447.     case '$':
  1448.         want_assign = TRUE;
  1449.         return lasttok = '$';
  1450.  
  1451.     case ':':
  1452.     case '?':
  1453.         allow_newline();
  1454.         /* fall through */
  1455.     case ')':
  1456.     case ']':
  1457.     case '(':    
  1458.     case '[':
  1459.     case ';':
  1460.     case '{':
  1461.     case ',':
  1462.         return lasttok = c;
  1463.  
  1464.     case '*':
  1465.         if ((c = nextc()) == '=') {
  1466.             yylval.nodetypeval = Node_assign_times;
  1467.             return lasttok = ASSIGNOP;
  1468.         } else if (do_posix) {
  1469.             pushback();
  1470.             return lasttok = '*';
  1471.         } else if (c == '*') {
  1472.             /* make ** and **= aliases for ^ and ^= */
  1473.             static int did_warn_op = FALSE, did_warn_assgn = FALSE;
  1474.  
  1475.             if (nextc() == '=') {
  1476.                 if (do_lint && ! did_warn_assgn) {
  1477.                     did_warn_assgn = TRUE;
  1478.                     warning("**= is not allowed by POSIX");
  1479.                     warning("operator `**=' is not supported in old awk");
  1480.                 }
  1481.                 yylval.nodetypeval = Node_assign_exp;
  1482.                 return ASSIGNOP;
  1483.             } else {
  1484.                 pushback();
  1485.                 if (do_lint && ! did_warn_op) {
  1486.                     did_warn_op = TRUE;
  1487.                     warning("** is not allowed by POSIX");
  1488.                     warning("operator `**' is not supported in old awk");
  1489.                 }
  1490.                 return lasttok = '^';
  1491.             }
  1492.         }
  1493.         pushback();
  1494.         return lasttok = '*';
  1495.  
  1496.     case '/':
  1497.         if (want_assign) {
  1498.             if (nextc() == '=') {
  1499.                 yylval.nodetypeval = Node_assign_quotient;
  1500.                 return lasttok = ASSIGNOP;
  1501.             }
  1502.             pushback();
  1503.         }
  1504.         return lasttok = '/';
  1505.  
  1506.     case '%':
  1507.         if (nextc() == '=') {
  1508.             yylval.nodetypeval = Node_assign_mod;
  1509.             return lasttok = ASSIGNOP;
  1510.         }
  1511.         pushback();
  1512.         return lasttok = '%';
  1513.  
  1514.     case '^':
  1515.     {
  1516.         static int did_warn_op = FALSE, did_warn_assgn = FALSE;
  1517.  
  1518.         if (nextc() == '=') {
  1519.             if (do_lint && ! did_warn_assgn) {
  1520.                 did_warn_assgn = TRUE;
  1521.                 warning("operator `^=' is not supported in old awk");
  1522.             }
  1523.             yylval.nodetypeval = Node_assign_exp;
  1524.             return lasttok = ASSIGNOP;
  1525.         }
  1526.         pushback();
  1527.         if (do_lint && ! did_warn_op) {
  1528.             did_warn_op = TRUE;
  1529.             warning("operator `^' is not supported in old awk");
  1530.         }
  1531.         return lasttok = '^';
  1532.     }
  1533.  
  1534.     case '+':
  1535.         if ((c = nextc()) == '=') {
  1536.             yylval.nodetypeval = Node_assign_plus;
  1537.             return lasttok = ASSIGNOP;
  1538.         }
  1539.         if (c == '+')
  1540.             return lasttok = INCREMENT;
  1541.         pushback();
  1542.         return lasttok = '+';
  1543.  
  1544.     case '!':
  1545.         if ((c = nextc()) == '=') {
  1546.             yylval.nodetypeval = Node_notequal;
  1547.             return lasttok = RELOP;
  1548.         }
  1549.         if (c == '~') {
  1550.             yylval.nodetypeval = Node_nomatch;
  1551.             want_assign = FALSE;
  1552.             return lasttok = MATCHOP;
  1553.         }
  1554.         pushback();
  1555.         return lasttok = '!';
  1556.  
  1557.     case '<':
  1558.         if (nextc() == '=') {
  1559.             yylval.nodetypeval = Node_leq;
  1560.             return lasttok = RELOP;
  1561.         }
  1562.         yylval.nodetypeval = Node_less;
  1563.         pushback();
  1564.         return lasttok = '<';
  1565.  
  1566.     case '=':
  1567.         if (nextc() == '=') {
  1568.             yylval.nodetypeval = Node_equal;
  1569.             return lasttok = RELOP;
  1570.         }
  1571.         yylval.nodetypeval = Node_assign;
  1572.         pushback();
  1573.         return lasttok = ASSIGNOP;
  1574.  
  1575.     case '>':
  1576.         if ((c = nextc()) == '=') {
  1577.             yylval.nodetypeval = Node_geq;
  1578.             return lasttok = RELOP;
  1579.         } else if (c == '>') {
  1580.             yylval.nodetypeval = Node_redirect_append;
  1581.             return lasttok = APPEND_OP;
  1582.         }
  1583.         yylval.nodetypeval = Node_greater;
  1584.         pushback();
  1585.         return lasttok = '>';
  1586.  
  1587.     case '~':
  1588.         yylval.nodetypeval = Node_match;
  1589.         want_assign = FALSE;
  1590.         return lasttok = MATCHOP;
  1591.  
  1592.     case '}':
  1593.         /*
  1594.          * Added did newline stuff.  Easier than
  1595.          * hacking the grammar.
  1596.          */
  1597.         if (did_newline) {
  1598.             did_newline = FALSE;
  1599.             return lasttok = c;
  1600.         }
  1601.         did_newline++;
  1602.         --lexptr;    /* pick up } next time */
  1603.         return lasttok = NEWLINE;
  1604.  
  1605.     case '"':
  1606.         esc_seen = FALSE;
  1607.         while ((c = nextc()) != '"') {
  1608.             if (c == '\n') {
  1609.                 pushback();
  1610.                 yyerror("unterminated string");
  1611.                 exit(1);
  1612.             }
  1613.             if (c == '\\') {
  1614.                 c = nextc();
  1615.                 if (c == '\n') {
  1616.                     sourceline++;
  1617.                     continue;
  1618.                 }
  1619.                 esc_seen = TRUE;
  1620.                 tokadd('\\');
  1621.             }
  1622.             if (c == EOF) {
  1623.                 pushback();
  1624.                 yyerror("unterminated string");
  1625.                 exit(1);
  1626.             }
  1627.             tokadd(c);
  1628.         }
  1629.         yylval.nodeval = make_str_node(tokstart,
  1630.                     tok - tokstart, esc_seen ? SCAN : 0);
  1631.         yylval.nodeval->flags |= PERM;
  1632.         return lasttok = YSTRING;
  1633.  
  1634.     case '-':
  1635.         if ((c = nextc()) == '=') {
  1636.             yylval.nodetypeval = Node_assign_minus;
  1637.             return lasttok = ASSIGNOP;
  1638.         }
  1639.         if (c == '-')
  1640.             return lasttok = DECREMENT;
  1641.         pushback();
  1642.         return lasttok = '-';
  1643.  
  1644.     case '.':
  1645.         c = nextc();
  1646.         pushback();
  1647.         if (! isdigit(c))
  1648.             return lasttok = '.';
  1649.         else
  1650.             c = '.';
  1651.         /* FALL THROUGH */
  1652.     case '0':
  1653.     case '1':
  1654.     case '2':
  1655.     case '3':
  1656.     case '4':
  1657.     case '5':
  1658.     case '6':
  1659.     case '7':
  1660.     case '8':
  1661.     case '9':
  1662.         /* It's a number */
  1663.         for (;;) {
  1664.             int gotnumber = FALSE;
  1665.  
  1666.             tokadd(c);
  1667.             switch (c) {
  1668. #ifdef BITOPS
  1669.             case 'x':
  1670.             case 'X':
  1671.                 if (do_traditional)
  1672.                     goto done;
  1673.                 if (tok == tokstart + 2)
  1674.                     inhex = TRUE;
  1675.                 break;
  1676. #endif /* BITOTS */
  1677.             case '.':
  1678.                 if (seen_point) {
  1679.                     gotnumber = TRUE;
  1680.                     break;
  1681.                 }
  1682.                 seen_point = TRUE;
  1683.                 break;
  1684.             case 'e':
  1685.             case 'E':
  1686.                 if (inhex)
  1687.                     break;
  1688.                 if (seen_e) {
  1689.                     gotnumber = TRUE;
  1690.                     break;
  1691.                 }
  1692.                 seen_e = TRUE;
  1693.                 if ((c = nextc()) == '-' || c == '+')
  1694.                     tokadd(c);
  1695.                 else
  1696.                     pushback();
  1697.                 break;
  1698. #ifdef BITOPS
  1699.             case 'a':
  1700.             case 'A':
  1701.             case 'b':
  1702.             case 'B':
  1703.             case 'c':
  1704.             case 'C':
  1705.             case 'D':
  1706.             case 'd':
  1707.             case 'f':
  1708.             case 'F':
  1709.                 if (do_traditional || ! inhex)
  1710.                     goto done;
  1711.                 /* fall through */
  1712. #endif
  1713.             case '0':
  1714.             case '1':
  1715.             case '2':
  1716.             case '3':
  1717.             case '4':
  1718.             case '5':
  1719.             case '6':
  1720.             case '7':
  1721.             case '8':
  1722.             case '9':
  1723.                 break;
  1724.             default:
  1725.             done:
  1726.                 gotnumber = TRUE;
  1727.             }
  1728.             if (gotnumber)
  1729.                 break;
  1730.             c = nextc();
  1731.         }
  1732.         if (c != EOF)
  1733.             pushback();
  1734.         else if (do_lint && ! eof_warned) {
  1735.             warning("source file does not end in newline");
  1736.             eof_warned = TRUE;
  1737.         }
  1738.         tokadd('\0');
  1739. #ifdef BITOPS
  1740.         if (! do_traditional && isnondecimal(tokstart))
  1741.             yylval.nodeval = make_number(nondec2awknum(tokstart, strlen(tokstart)));
  1742.         else
  1743. #endif /* BITOPS */
  1744.         yylval.nodeval = make_number(atof(tokstart));
  1745.         yylval.nodeval->flags |= PERM;
  1746.         return lasttok = YNUMBER;
  1747.  
  1748.     case '&':
  1749.         if ((c = nextc()) == '&') {
  1750.             yylval.nodetypeval = Node_and;
  1751.             allow_newline();
  1752.             want_assign = FALSE;
  1753.             return lasttok = LEX_AND;
  1754.         }
  1755.         pushback();
  1756.         return lasttok = '&';
  1757.  
  1758.     case '|':
  1759.         if ((c = nextc()) == '|') {
  1760.             yylval.nodetypeval = Node_or;
  1761.             allow_newline();
  1762.             want_assign = FALSE;
  1763.             return lasttok = LEX_OR;
  1764.         }
  1765.         pushback();
  1766.         return lasttok = '|';
  1767.     }
  1768.  
  1769.     if (c != '_' && ! isalpha(c)) {
  1770.         yyerror("Invalid char '%c' in expression\n", c);
  1771.         exit(1);
  1772.     }
  1773.  
  1774.     /* it's some type of name-type-thing.  Find its length. */
  1775.     tok = tokstart;
  1776.     while (is_identchar(c)) {
  1777.         tokadd(c);
  1778.         c = nextc();
  1779.     }
  1780.     tokadd('\0');
  1781.     emalloc(tokkey, char *, tok - tokstart, "yylex");
  1782.     memcpy(tokkey, tokstart, tok - tokstart);
  1783.     if (c != EOF)
  1784.         pushback();
  1785.     else if (do_lint && ! eof_warned) {
  1786.         warning("source file does not end in newline");
  1787.         eof_warned = TRUE;
  1788.     }
  1789.  
  1790.     /* See if it is a special token. */
  1791.     low = 0;
  1792.     high = (sizeof(tokentab) / sizeof(tokentab[0])) - 1;
  1793.     while (low <= high) {
  1794.         int i;
  1795.  
  1796.         mid = (low + high) / 2;
  1797.         c = *tokstart - tokentab[mid].operator[0];
  1798.         i = c ? c : strcmp(tokstart, tokentab[mid].operator);
  1799.  
  1800.         if (i < 0)        /* token < mid */
  1801.             high = mid - 1;
  1802.         else if (i > 0)        /* token > mid */
  1803.             low = mid + 1;
  1804.         else {
  1805.             if (do_lint) {
  1806.                 if (tokentab[mid].flags & GAWKX)
  1807.                     warning("%s() is a gawk extension",
  1808.                         tokentab[mid].operator);
  1809.                 if (tokentab[mid].flags & RESX)
  1810.                     warning("%s() is a Bell Labs extension",
  1811.                         tokentab[mid].operator);
  1812.                 if (tokentab[mid].flags & NOT_POSIX)
  1813.                     warning("POSIX does not allow %s",
  1814.                         tokentab[mid].operator);
  1815.             }
  1816.             if (do_lint_old && (tokentab[mid].flags & NOT_OLD))
  1817.                 warning("%s is not supported in old awk",
  1818.                         tokentab[mid].operator);
  1819.             if ((do_traditional && (tokentab[mid].flags & GAWKX))
  1820.                 || (do_posix && (tokentab[mid].flags & NOT_POSIX)))
  1821.                 break;
  1822.             if (tokentab[mid].class == LEX_BUILTIN
  1823.                 || tokentab[mid].class == LEX_LENGTH
  1824.                )
  1825.                 yylval.lval = mid;
  1826.             else
  1827.                 yylval.nodetypeval = tokentab[mid].value;
  1828.  
  1829.             free(tokkey);
  1830.             return lasttok = tokentab[mid].class;
  1831.         }
  1832.     }
  1833.  
  1834.     yylval.sval = tokkey;
  1835.     if (*lexptr == '(')
  1836.         return lasttok = FUNC_CALL;
  1837.     else {
  1838.         want_assign = TRUE;
  1839.         return lasttok = NAME;
  1840.     }
  1841. }
  1842.  
  1843. /* node_common --- common code for allocating a new node */
  1844.  
  1845. static NODE *
  1846. node_common(op)
  1847. NODETYPE op;
  1848. {
  1849.     register NODE *r;
  1850.  
  1851.     getnode(r);
  1852.     r->type = op;
  1853.     r->flags = MALLOC;
  1854.     /* if lookahead is NL, lineno is 1 too high */
  1855.     if (lexeme && *lexeme == '\n')
  1856.         r->source_line = sourceline - 1;
  1857.     else
  1858.         r->source_line = sourceline;
  1859.     r->source_file = source;
  1860.     return r;
  1861. }
  1862.  
  1863. /* node --- allocates a node with defined lnode and rnode. */
  1864.  
  1865. NODE *
  1866. node(left, op, right)
  1867. NODE *left, *right;
  1868. NODETYPE op;
  1869. {
  1870.     register NODE *r;
  1871.  
  1872.     r = node_common(op);
  1873.     r->lnode = left;
  1874.     r->rnode = right;
  1875.     return r;
  1876. }
  1877.  
  1878. /* snode ---    allocate a node with defined subnode and proc for builtin
  1879.         functions. Checks for arg. count and supplies defaults where
  1880.         possible. */
  1881.  
  1882. static NODE *
  1883. snode(subn, op, idx)
  1884. NODETYPE op;
  1885. int idx;
  1886. NODE *subn;
  1887. {
  1888.     register NODE *r;
  1889.     register NODE *n;
  1890.     int nexp = 0;
  1891.     int args_allowed;
  1892.  
  1893.     r = node_common(op);
  1894.  
  1895.     /* traverse expression list to see how many args. given */
  1896.     for (n = subn; n != NULL; n = n->rnode) {
  1897.         nexp++;
  1898.         if (nexp > 3)
  1899.             break;
  1900.     }
  1901.  
  1902.     /* check against how many args. are allowed for this builtin */
  1903.     args_allowed = tokentab[idx].flags & ARGS;
  1904.     if (args_allowed && (args_allowed & A(nexp)) == 0)
  1905.         fatal("%s() cannot have %d argument%c",
  1906.             tokentab[idx].operator, nexp, nexp == 1 ? ' ' : 's');
  1907.  
  1908.     r->proc = tokentab[idx].ptr;
  1909.  
  1910.     /* special case processing for a few builtins */
  1911.     /*
  1912.      * FIXME: go through these to make sure that everything done
  1913.      *      here is really right. Move anything that's not into
  1914.      *      the corresponding routine.
  1915.      */
  1916.     if (nexp == 0 && r->proc == do_length) {
  1917.         subn = node(node(make_number(0.0), Node_field_spec, (NODE *) NULL),
  1918.                     Node_expression_list,
  1919.                 (NODE *) NULL);
  1920.     } else if (r->proc == do_match) {
  1921.         if (subn->rnode->lnode->type != Node_regex)
  1922.             subn->rnode->lnode = mk_rexp(subn->rnode->lnode);
  1923.     } else if (r->proc == do_sub || r->proc == do_gsub) {
  1924.         if (subn->lnode->type != Node_regex)
  1925.             subn->lnode = mk_rexp(subn->lnode);
  1926.         if (nexp == 2)
  1927.             append_right(subn, node(node(make_number(0.0),
  1928.                              Node_field_spec,
  1929.                              (NODE *) NULL),
  1930.                             Node_expression_list,
  1931.                         (NODE *) NULL));
  1932.         else if (subn->rnode->rnode->lnode->type == Node_val) {
  1933.             if (do_lint)
  1934.                 warning("string literal as last arg of substitute");
  1935.         } else if (! isassignable(subn->rnode->rnode->lnode))
  1936.             yyerror("%s third parameter is not a changeable object",
  1937.                 r->proc == do_sub ? "sub" : "gsub");
  1938.     } else if (r->proc == do_gensub) {
  1939.         if (subn->lnode->type != Node_regex)
  1940.             subn->lnode = mk_rexp(subn->lnode);
  1941.         if (nexp == 3)
  1942.             append_right(subn, node(node(make_number(0.0),
  1943.                              Node_field_spec,
  1944.                              (NODE *) NULL),
  1945.                             Node_expression_list,
  1946.                         (NODE *) NULL));
  1947.     } else if (r->proc == do_split) {
  1948.         if (nexp == 2)
  1949.             append_right(subn,
  1950.                 node(FS_node, Node_expression_list, (NODE *) NULL));
  1951.         n = subn->rnode->rnode->lnode;
  1952.         if (n->type != Node_regex)
  1953.             subn->rnode->rnode->lnode = mk_rexp(n);
  1954.         if (nexp == 2)
  1955.             subn->rnode->rnode->lnode->re_flags |= FS_DFLT;
  1956.     }
  1957.  
  1958.     r->subnode = subn;
  1959.     return r;
  1960. }
  1961.  
  1962. /*
  1963.  * mkrangenode:
  1964.  * This allocates a Node_line_range node with defined condpair and
  1965.  * zeroes the trigger word to avoid the temptation of assuming that calling
  1966.  * 'node( foo, Node_line_range, 0)' will properly initialize 'triggered'. 
  1967.  * Otherwise like node().
  1968.  */
  1969.  
  1970. static NODE *
  1971. mkrangenode(cpair)
  1972. NODE *cpair;
  1973. {
  1974.     register NODE *r;
  1975.  
  1976.     getnode(r);
  1977.     r->type = Node_line_range;
  1978.     r->condpair = cpair;
  1979.     r->triggered = FALSE;
  1980.     return r;
  1981. }
  1982.  
  1983. /* make_for_loop --- build a for loop */
  1984.  
  1985. static NODE *
  1986. make_for_loop(init, cond, incr)
  1987. NODE *init, *cond, *incr;
  1988. {
  1989.     register FOR_LOOP_HEADER *r;
  1990.     NODE *n;
  1991.  
  1992.     emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop");
  1993.     getnode(n);
  1994.     n->type = Node_illegal;
  1995.     r->init = init;
  1996.     r->cond = cond;
  1997.     r->incr = incr;
  1998.     n->sub.nodep.r.hd = r;
  1999.     return n;
  2000. }
  2001.  
  2002. /* dup_parms --- return TRUE if there are duplicate parameters */
  2003.  
  2004. static int
  2005. dup_parms(func)
  2006. NODE *func;
  2007. {
  2008.     register NODE *np;
  2009.     char *fname, **names;
  2010.     int count, i, j, dups;
  2011.     NODE *params;
  2012.  
  2013.     if (func == NULL)    /* error earlier */
  2014.         return TRUE;
  2015.  
  2016.     fname = func->param;
  2017.     count = func->param_cnt;
  2018.     params = func->rnode;
  2019.  
  2020.     if (count == 0)        /* no args, no problem */
  2021.         return FALSE;
  2022.  
  2023.     if (params == NULL)    /* error earlier */
  2024.         return TRUE;
  2025.  
  2026.     emalloc(names, char **, count * sizeof(char *), "dup_parms");
  2027.  
  2028.     i = 0;
  2029.     for (np = params; np != NULL; np = np->rnode) {
  2030.         if (np->param == NULL) { /* error earlier, give up, go home */
  2031.             free(names);
  2032.             return TRUE;
  2033.         }
  2034.         names[i++] = np->param;
  2035.     }
  2036.  
  2037.     dups = 0;
  2038.     for (i = 1; i < count; i++) {
  2039.         for (j = 0; j < i; j++) {
  2040.             if (strcmp(names[i], names[j]) == 0) {
  2041.                 dups++;
  2042.                 error(
  2043.     "function `%s': parameter #%d, `%s', duplicates parameter #%d",
  2044.                     fname, i+1, names[j], j+1);
  2045.             }
  2046.         }
  2047.     }
  2048.  
  2049.     free(names);
  2050.     return (dups > 0 ? TRUE : FALSE);
  2051. }
  2052.  
  2053. /*
  2054.  * install:
  2055.  * Install a name in the symbol table, even if it is already there.
  2056.  * Caller must check against redefinition if that is desired. 
  2057.  */
  2058.  
  2059. NODE *
  2060. install(name, value)
  2061. char *name;
  2062. NODE *value;
  2063. {
  2064.     register NODE *hp;
  2065.     register size_t len;
  2066.     register int bucket;
  2067.  
  2068.     len = strlen(name);
  2069.     bucket = hash(name, len, (unsigned long) HASHSIZE);
  2070.     getnode(hp);
  2071.     hp->type = Node_hashnode;
  2072.     hp->hnext = variables[bucket];
  2073.     variables[bucket] = hp;
  2074.     hp->hlength = len;
  2075.     hp->hvalue = value;
  2076.     hp->hname = name;
  2077.     hp->hvalue->vname = name;
  2078.     return hp->hvalue;
  2079. }
  2080.  
  2081. /* lookup --- find the most recent hash node for name installed by install */
  2082.  
  2083. NODE *
  2084. lookup(name)
  2085. const char *name;
  2086. {
  2087.     register NODE *bucket;
  2088.     register size_t len;
  2089.  
  2090.     len = strlen(name);
  2091.     for (bucket = variables[hash(name, len, (unsigned long) HASHSIZE)];
  2092.             bucket != NULL; bucket = bucket->hnext)
  2093.         if (bucket->hlength == len && STREQN(bucket->hname, name, len))
  2094.             return bucket->hvalue;
  2095.  
  2096.     return NULL;
  2097. }
  2098.  
  2099. /*
  2100.  * append_right:
  2101.  * Add new to the rightmost branch of LIST.  This uses n^2 time, so we make
  2102.  * a simple attempt at optimizing it.
  2103.  */
  2104.  
  2105. static NODE *
  2106. append_right(list, new)
  2107. NODE *list, *new;
  2108. {
  2109.     register NODE *oldlist;
  2110.     static NODE *savefront = NULL, *savetail = NULL;
  2111.  
  2112.     oldlist = list;
  2113.     if (savefront == oldlist) {
  2114.         savetail = savetail->rnode = new;
  2115.         return oldlist;
  2116.     } else
  2117.         savefront = oldlist;
  2118.     while (list->rnode != NULL)
  2119.         list = list->rnode;
  2120.     savetail = list->rnode = new;
  2121.     return oldlist;
  2122. }
  2123.  
  2124. /*
  2125.  * func_install:
  2126.  * check if name is already installed;  if so, it had better have Null value,
  2127.  * in which case def is added as the value. Otherwise, install name with def
  2128.  * as value. 
  2129.  */
  2130.  
  2131. static void
  2132. func_install(params, def)
  2133. NODE *params;
  2134. NODE *def;
  2135. {
  2136.     NODE *r;
  2137.  
  2138.     pop_params(params->rnode);
  2139.     pop_var(params, FALSE);
  2140.     r = lookup(params->param);
  2141.     if (r != NULL) {
  2142.         fatal("function name `%s' previously defined", params->param);
  2143.     } else
  2144.         (void) install(params->param, node(params, Node_func, def));
  2145.  
  2146.     func_use(params->param, FUNC_DEFINE);
  2147. }
  2148.  
  2149. /* pop_var --- remove a variable from the symbol table */
  2150.  
  2151. static void
  2152. pop_var(np, freeit)
  2153. NODE *np;
  2154. int freeit;
  2155. {
  2156.     register NODE *bucket, **save;
  2157.     register size_t len;
  2158.     char *name;
  2159.  
  2160.     name = np->param;
  2161.     len = strlen(name);
  2162.     save = &(variables[hash(name, len, (unsigned long) HASHSIZE)]);
  2163.     for (bucket = *save; bucket != NULL; bucket = bucket->hnext) {
  2164.         if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
  2165.             *save = bucket->hnext;
  2166.             freenode(bucket);
  2167.             if (freeit)
  2168.                 free(np->param);
  2169.             return;
  2170.         }
  2171.         save = &(bucket->hnext);
  2172.     }
  2173. }
  2174.  
  2175. /* pop_params --- remove list of function parameters from symbol table */
  2176.  
  2177. /*
  2178.  * pop parameters out of the symbol table. do this in reverse order to
  2179.  * avoid reading freed memory if there were duplicated parameters.
  2180.  */
  2181. static void
  2182. pop_params(params)
  2183. NODE *params;
  2184. {
  2185.     if (params == NULL)
  2186.         return;
  2187.     pop_params(params->rnode);
  2188.     pop_var(params, TRUE);
  2189. }
  2190.  
  2191. /* make_param --- make NAME into a function parameter */
  2192.  
  2193. static NODE *
  2194. make_param(name)
  2195. char *name;
  2196. {
  2197.     NODE *r;
  2198.  
  2199.     getnode(r);
  2200.     r->type = Node_param_list;
  2201.     r->rnode = NULL;
  2202.     r->param = name;
  2203.     r->param_cnt = param_counter++;
  2204.     return (install(name, r));
  2205. }
  2206.  
  2207. static struct fdesc {
  2208.     char *name;
  2209.     short used;
  2210.     short defined;
  2211.     struct fdesc *next;
  2212. } *ftable[HASHSIZE];
  2213.  
  2214. /* func_use --- track uses and definitions of functions */
  2215.  
  2216. static void
  2217. func_use(name, how)
  2218. char *name;
  2219. enum defref how;
  2220. {
  2221.     struct fdesc *fp;
  2222.     int len;
  2223.     int ind;
  2224.  
  2225.     len = strlen(name);
  2226.     ind = hash(name, len, HASHSIZE);
  2227.  
  2228.     for (fp = ftable[ind]; fp != NULL; fp = fp->next) {
  2229.         if (strcmp(fp->name, name) == 0) {
  2230.             if (how == FUNC_DEFINE)
  2231.                 fp->defined++;
  2232.             else
  2233.                 fp->used++;
  2234.             return;
  2235.         }
  2236.     }
  2237.  
  2238.     /* not in the table, fall through to allocate a new one */
  2239.  
  2240.     emalloc(fp, struct fdesc *, sizeof(struct fdesc), "func_use");
  2241.     memset(fp, '\0', sizeof(struct fdesc));
  2242.     emalloc(fp->name, char *, len + 1, "func_use");
  2243.     strcpy(fp->name, name);
  2244.     if (how == FUNC_DEFINE)
  2245.         fp->defined++;
  2246.     else
  2247.         fp->used++;
  2248.     fp->next = ftable[ind];
  2249.     ftable[ind] = fp;
  2250. }
  2251.  
  2252. /* check_funcs --- verify functions that are called but not defined */
  2253.  
  2254. static void
  2255. check_funcs()
  2256. {
  2257.     struct fdesc *fp, *next;
  2258.     int i;
  2259.  
  2260.     for (i = 0; i < HASHSIZE; i++) {
  2261.         for (fp = ftable[i]; fp != NULL; fp = fp->next) {
  2262. #ifdef REALLYMEAN
  2263.             /* making this the default breaks old code. sigh. */
  2264.             if (fp->defined == 0) {
  2265.                 error(
  2266.         "function `%s' called but never defined", fp->name);
  2267.                 errcount++;
  2268.             }
  2269. #else
  2270.             if (do_lint && fp->defined == 0)
  2271.                 warning(
  2272.         "function `%s' called but never defined", fp->name);
  2273. #endif
  2274.             if (do_lint && fp->used == 0) {
  2275.                 warning("function `%s' defined but never called",
  2276.                     fp->name);
  2277.             }
  2278.         }
  2279.     }
  2280.  
  2281.     /* now let's free all the memory */
  2282.     for (i = 0; i < HASHSIZE; i++) {
  2283.         for (fp = ftable[i]; fp != NULL; fp = next) {
  2284.             next = fp->next;
  2285.             free(fp->name);
  2286.             free(fp);
  2287.         }
  2288.     }
  2289. }
  2290.  
  2291. /* param_sanity --- look for parameters that are regexp constants */
  2292.  
  2293. static void
  2294. param_sanity(arglist)
  2295. NODE *arglist;
  2296. {
  2297.     NODE *argp, *arg;
  2298.     int i;
  2299.  
  2300.     for (i = 1, argp = arglist; argp != NULL; argp = argp->rnode, i++) {
  2301.         arg = argp->lnode;
  2302.         if (arg->type == Node_regex)
  2303.             warning("regexp constant for parameter #%d yields boolean value", i);
  2304.     }
  2305. }
  2306.  
  2307. /* variable --- make sure NAME is in the symbol table */
  2308.  
  2309. NODE *
  2310. variable(name, can_free, type)
  2311. char *name;
  2312. int can_free;
  2313. NODETYPE type;
  2314. {
  2315.     register NODE *r;
  2316.     static int env_loaded = FALSE;
  2317.  
  2318.     if (! env_loaded && STREQ(name, "ENVIRON")) {
  2319.         load_environ();
  2320.         env_loaded = TRUE;
  2321.     }
  2322.     if ((r = lookup(name)) == NULL)
  2323.         r = install(name, node(Nnull_string, type, (NODE *) NULL));
  2324.     else if (can_free)
  2325.         free(name);
  2326.     return r;
  2327. }
  2328.  
  2329. /* mk_rexp --- make a regular expression constant */
  2330.  
  2331. static NODE *
  2332. mk_rexp(exp)
  2333. NODE *exp;
  2334. {
  2335.     NODE *n;
  2336.  
  2337.     if (exp->type == Node_regex)
  2338.         return exp;
  2339.  
  2340.     getnode(n);
  2341.     n->type = Node_regex;
  2342.     n->re_exp = exp;
  2343.     n->re_text = NULL;
  2344.     n->re_reg = NULL;
  2345.     n->re_flags = 0;
  2346.     n->re_cnt = 1;
  2347.     return n;
  2348. }
  2349.  
  2350. /* isnoeffect --- when used as a statement, has no side effects */
  2351.  
  2352. /*
  2353.  * To be completely general, we should recursively walk the parse
  2354.  * tree, to make sure that all the subexpressions also have no effect.
  2355.  * Instead, we just weaken the actual warning that's printed, up above
  2356.  * in the grammar.
  2357.  */
  2358.  
  2359. static int
  2360. isnoeffect(type)
  2361. NODETYPE type;
  2362. {
  2363.     switch (type) {
  2364.     case Node_times:
  2365.     case Node_quotient:
  2366.     case Node_mod:
  2367.     case Node_plus:
  2368.     case Node_minus:
  2369.     case Node_subscript:
  2370.     case Node_concat:
  2371.     case Node_exp:
  2372.     case Node_unary_minus:
  2373.     case Node_field_spec:
  2374.     case Node_and:
  2375.     case Node_or:
  2376.     case Node_equal:
  2377.     case Node_notequal:
  2378.     case Node_less:
  2379.     case Node_greater:
  2380.     case Node_leq:
  2381.     case Node_geq:
  2382.     case Node_match:
  2383.     case Node_nomatch:
  2384.     case Node_not:
  2385.     case Node_val:
  2386.     case Node_in_array:
  2387.     case Node_NF:
  2388.     case Node_NR:
  2389.     case Node_FNR:
  2390.     case Node_FS:
  2391.     case Node_RS:
  2392.     case Node_FIELDWIDTHS:
  2393.     case Node_IGNORECASE:
  2394.     case Node_OFS:
  2395.     case Node_ORS:
  2396.     case Node_OFMT:
  2397.     case Node_CONVFMT:
  2398.         return TRUE;
  2399.     default:
  2400.         break;    /* keeps gcc -Wall happy */
  2401.     }
  2402.  
  2403.     return FALSE;
  2404. }
  2405.  
  2406. /* isassignable --- can this node be assigned to? */
  2407.  
  2408. static int
  2409. isassignable(n)
  2410. register NODE *n;
  2411. {
  2412.     switch (n->type) {
  2413.     case Node_var:
  2414.     case Node_FIELDWIDTHS:
  2415.     case Node_RS:
  2416.     case Node_FS:
  2417.     case Node_FNR:
  2418.     case Node_NR:
  2419.     case Node_NF:
  2420.     case Node_IGNORECASE:
  2421.     case Node_OFMT:
  2422.     case Node_CONVFMT:
  2423.     case Node_ORS:
  2424.     case Node_OFS:
  2425.     case Node_field_spec:
  2426.     case Node_subscript:
  2427.         return TRUE;
  2428.     case Node_param_list:
  2429.         return ((n->flags & FUNC) == 0);  /* ok if not func name */
  2430.     default:
  2431.         break;    /* keeps gcc -Wall happy */
  2432.     }
  2433.     return FALSE;
  2434. }
  2435.