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