home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gawk213s.lzh / GAWK213S / AWK.Y < prev    next >
Text File  |  1993-07-29  |  39KB  |  1,744 lines

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