home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 6 / FreshFish_September1994.bin / bbs / gnu / gawk-2.15.5-src.lha / GNU / src / amiga / gawk-2.15.5 / awk.y < prev    next >
Encoding:
Text File  |  1994-05-12  |  40.5 KB  |  1,869 lines

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