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