home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gawk-2.15.6-base.tgz / gawk-2.15.6-base.tar / fsf / gawk / awk.y < prev    next >
Text File  |  1995-03-09  |  44KB  |  1,983 lines

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