home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / compcomp / gnuawk / awk.y < prev    next >
Encoding:
Text File  |  1989-11-06  |  36.1 KB  |  1,687 lines

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