home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / MPW / gawk 2.11.1r3 / Sources / awk.y < prev    next >
Encoding:
Text File  |  1991-06-01  |  37.4 KB  |  1,751 lines  |  [TEXT/MPS ]

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