* Add this nice filesystem testing tool that I've recently
[dragonfly.git] / contrib / awk / awk.y
1 /*
2  * awk.y --- yacc/bison parser
3  */
4
5 /* 
6  * Copyright (C) 1986, 1988, 1989, 1991-2000 the Free Software Foundation, Inc.
7  * 
8  * This file is part of GAWK, the GNU implementation of the
9  * AWK Programming 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 2 of the License, or
14  * (at your option) 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 this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
24  */
25
26 %{
27 #ifdef DEBUG
28 #define YYDEBUG 12
29 #endif
30
31 #include "awk.h"
32
33 #define CAN_FREE        TRUE
34 #define DONT_FREE       FALSE
35
36 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
37 static void yyerror(const char *m, ...) ;
38 #else
39 static void yyerror(); /* va_alist */
40 #endif
41 static char *get_src_buf P((void));
42 static int yylex P((void));
43 static NODE *node_common P((NODETYPE op));
44 static NODE *snode P((NODE *subn, NODETYPE op, int sindex));
45 static NODE *mkrangenode P((NODE *cpair));
46 static NODE *make_for_loop P((NODE *init, NODE *cond, NODE *incr));
47 static NODE *append_right P((NODE *list, NODE *new));
48 static void func_install P((NODE *params, NODE *def));
49 static void pop_var P((NODE *np, int freeit));
50 static void pop_params P((NODE *params));
51 static NODE *make_param P((char *name));
52 static NODE *mk_rexp P((NODE *exp));
53 static int dup_parms P((NODE *func));
54 static void param_sanity P((NODE *arglist));
55 static int isnoeffect P((NODETYPE t));
56 static int isassignable P((NODE *n));
57
58 enum defref { FUNC_DEFINE, FUNC_USE };
59 static void func_use P((char *name, enum defref how));
60 static void check_funcs P((void));
61
62 static int want_assign;         /* lexical scanning kludge */
63 static int want_regexp;         /* lexical scanning kludge */
64 static int can_return;          /* lexical scanning kludge */
65 static int io_allowed = TRUE;   /* lexical scanning kludge */
66 static char *lexptr;            /* pointer to next char during parsing */
67 static char *lexend;
68 static char *lexptr_begin;      /* keep track of where we were for error msgs */
69 static char *lexeme;            /* beginning of lexeme for debugging */
70 static char *thisline = NULL;
71 #define YYDEBUG_LEXER_TEXT (lexeme)
72 static int param_counter;
73 static char *tokstart = NULL;
74 static char *tok = NULL;
75 static char *tokend;
76
77 #define HASHSIZE        1021    /* this constant only used here */
78 NODE *variables[HASHSIZE];
79
80 extern char *source;
81 extern int sourceline;
82 extern struct src *srcfiles;
83 extern int numfiles;
84 extern int errcount;
85 extern NODE *begin_block;
86 extern NODE *end_block;
87 %}
88
89 %union {
90         long lval;
91         AWKNUM fval;
92         NODE *nodeval;
93         NODETYPE nodetypeval;
94         char *sval;
95         NODE *(*ptrval)();
96 }
97
98 %type <nodeval> function_prologue function_body
99 %type <nodeval> rexp exp start program rule simp_exp
100 %type <nodeval> non_post_simp_exp
101 %type <nodeval> pattern 
102 %type <nodeval> action variable param_list
103 %type <nodeval> rexpression_list opt_rexpression_list
104 %type <nodeval> expression_list opt_expression_list
105 %type <nodeval> statements statement if_statement opt_param_list 
106 %type <nodeval> opt_exp opt_variable regexp 
107 %type <nodeval> input_redir output_redir
108 %type <nodetypeval> print
109 %type <sval> func_name
110 %type <lval> lex_builtin
111
112 %token <sval> FUNC_CALL NAME REGEXP
113 %token <lval> ERROR
114 %token <nodeval> YNUMBER YSTRING
115 %token <nodetypeval> RELOP APPEND_OP
116 %token <nodetypeval> ASSIGNOP MATCHOP NEWLINE CONCAT_OP
117 %token <nodetypeval> LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
118 %token <nodetypeval> LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
119 %token <nodetypeval> LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
120 %token <nodetypeval> LEX_GETLINE LEX_NEXTFILE
121 %token <nodetypeval> LEX_IN
122 %token <lval> LEX_AND LEX_OR INCREMENT DECREMENT
123 %token <lval> LEX_BUILTIN LEX_LENGTH
124
125 /* these are just yylval numbers */
126
127 /* Lowest to highest */
128 %right ASSIGNOP
129 %right '?' ':'
130 %left LEX_OR
131 %left LEX_AND
132 %left LEX_GETLINE
133 %nonassoc LEX_IN
134 %left FUNC_CALL LEX_BUILTIN LEX_LENGTH
135 %nonassoc ','
136 %nonassoc MATCHOP
137 %nonassoc RELOP '<' '>' '|' APPEND_OP
138 %left CONCAT_OP
139 %left YSTRING YNUMBER
140 %left '+' '-'
141 %left '*' '/' '%'
142 %right '!' UNARY
143 %right '^'
144 %left INCREMENT DECREMENT
145 %left '$'
146 %left '(' ')'
147 %%
148
149 start
150         : opt_nls program opt_nls
151                 {
152                         expression_value = $2;
153                         check_funcs();
154                 }
155         ;
156
157 program
158         : rule
159                 { 
160                         if ($1 != NULL)
161                                 $$ = $1;
162                         else
163                                 $$ = NULL;
164                         yyerrok;
165                 }
166         | program rule
167                 /* add the rule to the tail of list */
168                 {
169                         if ($2 == NULL)
170                                 $$ = $1;
171                         else if ($1 == NULL)
172                                 $$ = $2;
173                         else {
174                                 if ($1->type != Node_rule_list)
175                                         $1 = node($1, Node_rule_list,
176                                                 (NODE*) NULL);
177                                 $$ = append_right($1,
178                                    node($2, Node_rule_list, (NODE *) NULL));
179                         }
180                         yyerrok;
181                 }
182         | error { $$ = NULL; }
183         | program error { $$ = NULL; }
184         | /* empty */ { $$ = NULL; }
185         ;
186
187 rule
188         : LEX_BEGIN { io_allowed = FALSE; }
189           action
190           {
191                 if (begin_block != NULL) {
192                         if (begin_block->type != Node_rule_list)
193                                 begin_block = node(begin_block, Node_rule_list,
194                                         (NODE *) NULL);
195                         (void) append_right(begin_block, node(
196                             node((NODE *) NULL, Node_rule_node, $3),
197                             Node_rule_list, (NODE *) NULL) );
198                 } else
199                         begin_block = node((NODE *) NULL, Node_rule_node, $3);
200                 $$ = NULL;
201                 io_allowed = TRUE;
202                 yyerrok;
203           }
204         | LEX_END { io_allowed = FALSE; }
205           action
206           {
207                 if (end_block != NULL) {
208                         if (end_block->type != Node_rule_list)
209                                 end_block = node(end_block, Node_rule_list,
210                                         (NODE *) NULL);
211                         (void) append_right (end_block, node(
212                             node((NODE *) NULL, Node_rule_node, $3),
213                             Node_rule_list, (NODE *) NULL));
214                 } else
215                         end_block = node((NODE *) NULL, Node_rule_node, $3);
216                 $$ = NULL;
217                 io_allowed = TRUE;
218                 yyerrok;
219           }
220         | LEX_BEGIN statement_term
221           {
222                 warning("BEGIN blocks must have an action part");
223                 errcount++;
224                 yyerrok;
225           }
226         | LEX_END statement_term
227           {
228                 warning("END blocks must have an action part");
229                 errcount++;
230                 yyerrok;
231           }
232         | pattern action
233                 { $$ = node($1, Node_rule_node, $2); yyerrok; }
234         | action
235                 { $$ = node((NODE *) NULL, Node_rule_node, $1); yyerrok; }
236         | pattern statement_term
237                 {
238                   $$ = node($1,
239                              Node_rule_node,
240                              node(node(node(make_number(0.0),
241                                             Node_field_spec,
242                                             (NODE *) NULL),
243                                         Node_expression_list,
244                                         (NODE *) NULL),
245                                   Node_K_print,
246                                   (NODE *) NULL));
247                   yyerrok;
248                 }
249         | function_prologue function_body
250                 {
251                         func_install($1, $2);
252                         $$ = NULL;
253                         yyerrok;
254                 }
255         ;
256
257 func_name
258         : NAME
259                 { $$ = $1; }
260         | FUNC_CALL
261                 { $$ = $1; }
262         | lex_builtin
263           {
264                 yyerror("%s() is a built-in function, it cannot be redefined",
265                         tokstart);
266                 errcount++;
267                 /* yyerrok; */
268           }
269         ;
270
271 lex_builtin
272         : LEX_BUILTIN
273         | LEX_LENGTH
274         ;
275                 
276 function_prologue
277         : LEX_FUNCTION 
278                 {
279                         param_counter = 0;
280                 }
281           func_name '(' opt_param_list r_paren opt_nls
282                 {
283                         NODE *t;
284
285                         t = make_param($3);
286                         t->flags |= FUNC;
287                         $$ = append_right(t, $5);
288                         can_return = TRUE;
289                         /* check for duplicate parameter names */
290                         if (dup_parms($$))
291                                 errcount++;
292                 }
293         ;
294
295 function_body
296         : l_brace statements r_brace opt_semi
297           {
298                 $$ = $2;
299                 can_return = FALSE;
300           }
301         | l_brace r_brace opt_semi opt_nls
302           {
303                 $$ = node((NODE *) NULL, Node_K_return, (NODE *) NULL);
304                 can_return = FALSE;
305           }
306         ;
307
308
309 pattern
310         : exp
311                 { $$ = $1; }
312         | exp ',' exp
313                 { $$ = mkrangenode(node($1, Node_cond_pair, $3)); }
314         ;
315
316 regexp
317         /*
318          * In this rule, want_regexp tells yylex that the next thing
319          * is a regexp so it should read up to the closing slash.
320          */
321         : '/'
322                 { ++want_regexp; }
323           REGEXP '/'
324                 {
325                   NODE *n;
326                   size_t len;
327
328                   getnode(n);
329                   n->type = Node_regex;
330                   len = strlen($3);
331                   n->re_exp = make_string($3, len);
332                   n->re_reg = make_regexp($3, len, FALSE, TRUE);
333                   n->re_text = NULL;
334                   n->re_flags = CONST;
335                   n->re_cnt = 1;
336                   $$ = n;
337                 }
338         ;
339
340 action
341         : l_brace statements r_brace opt_semi opt_nls
342                 { $$ = $2; }
343         | l_brace r_brace opt_semi opt_nls
344                 { $$ = NULL; }
345         ;
346
347 statements
348         : statement
349                 {
350                         $$ = $1;
351                         if (do_lint && isnoeffect($$->type))
352                                 warning("statement may have no effect");
353                 }
354         | statements statement
355                 {
356                         if ($1 == NULL || $1->type != Node_statement_list)
357                                 $1 = node($1, Node_statement_list, (NODE *) NULL);
358                         $$ = append_right($1,
359                                 node($2, Node_statement_list, (NODE *)   NULL));
360                         yyerrok;
361                 }
362         | error
363                 { $$ = NULL; }
364         | statements error
365                 { $$ = NULL; }
366         ;
367
368 statement_term
369         : nls
370         | semi opt_nls
371         ;
372
373 statement
374         : semi opt_nls
375                 { $$ = NULL; }
376         | l_brace r_brace
377                 { $$ = NULL; }
378         | l_brace statements r_brace
379                 { $$ = $2; }
380         | if_statement
381                 { $$ = $1; }
382         | LEX_WHILE '(' exp r_paren opt_nls statement
383                 { $$ = node($3, Node_K_while, $6); }
384         | LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
385                 { $$ = node($6, Node_K_do, $3); }
386         | LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement
387           {
388                 /*
389                  * Efficiency hack.  Recognize the special case of
390                  *
391                  *      for (iggy in foo)
392                  *              delete foo[iggy]
393                  *
394                  * and treat it as if it were
395                  *
396                  *      delete foo
397                  *
398                  * Check that the body is a `delete a[i]' statement,
399                  * and that both the loop var and array names match.
400                  */
401                 if ($8->type == Node_K_delete
402                     && $8->rnode != NULL
403                     && strcmp($3, $8->rnode->var_value->vname) == 0
404                     && strcmp($5, $8->lnode->vname) == 0) {
405                         $8->type = Node_K_delete_loop;
406                         $$ = $8;
407                 } else {
408                         $$ = node($8, Node_K_arrayfor,
409                                 make_for_loop(variable($3, CAN_FREE, Node_var),
410                                 (NODE *) NULL, variable($5, CAN_FREE, Node_var_array)));
411                 }
412           }
413         | LEX_FOR '(' opt_exp semi exp semi opt_exp r_paren opt_nls statement
414           {
415                 $$ = node($10, Node_K_for, (NODE *) make_for_loop($3, $5, $7));
416           }
417         | LEX_FOR '(' opt_exp semi semi opt_exp r_paren opt_nls statement
418           {
419                 $$ = node($9, Node_K_for,
420                         (NODE *) make_for_loop($3, (NODE *) NULL, $6));
421           }
422         | LEX_BREAK statement_term
423            /* for break, maybe we'll have to remember where to break to */
424                 { $$ = node((NODE *) NULL, Node_K_break, (NODE *) NULL); }
425         | LEX_CONTINUE statement_term
426            /* similarly */
427                 { $$ = node((NODE *) NULL, Node_K_continue, (NODE *) NULL); }
428         | print '(' expression_list r_paren output_redir statement_term
429                 { $$ = node($3, $1, $5); }
430         | print opt_rexpression_list output_redir statement_term
431                 {
432                         if ($1 == Node_K_print && $2 == NULL) {
433                                 static int warned = FALSE;
434
435                                 $2 = node(node(make_number(0.0),
436                                                Node_field_spec,
437                                                (NODE *) NULL),
438                                           Node_expression_list,
439                                           (NODE *) NULL);
440
441                                 if (do_lint && ! io_allowed && ! warned) {
442                                         warned = TRUE;
443                                         warning(
444         "plain `print' in BEGIN or END rule should probably be `print \"\"'");
445                                 }
446                         }
447
448                         $$ = node($2, $1, $3);
449                 }
450         | LEX_NEXT opt_exp statement_term
451                 { NODETYPE type;
452
453                   if ($2) {
454                         if ($2 == lookup("file")) {
455                                 static int warned = FALSE;
456
457                                 if (! warned) {
458                                         warned = TRUE;
459                                         warning("`next file' is obsolete; use `nextfile'");
460                                 }
461                                 if (do_lint)
462                                         warning("`next file' is a gawk extension");
463                                 if (do_traditional) {
464                                         /*
465                                          * can't use yyerror, since may have overshot
466                                          * the source line
467                                          */
468                                         errcount++;
469                                         error("`next file' is a gawk extension");
470                                 }
471                                 if (! io_allowed) {
472                                         /* same thing */
473                                         errcount++;
474                                         error("`next file' used in BEGIN or END action");
475                                 }
476                                 type = Node_K_nextfile;
477                         } else {
478                                 errcount++;
479                                 error("illegal expression after `next'");
480                                 type = Node_K_next;     /* sanity */
481                         }
482                   } else {
483                         if (! io_allowed)
484                                 yyerror("`next' used in BEGIN or END action");
485                         type = Node_K_next;
486                   }
487                   $$ = node((NODE *) NULL, type, (NODE *) NULL);
488                 }
489         | LEX_NEXTFILE statement_term
490                 {
491                   if (do_lint)
492                         warning("`nextfile' is a gawk extension");
493                   if (do_traditional) {
494                         /*
495                          * can't use yyerror, since may have overshot
496                          * the source line
497                          */
498                         errcount++;
499                         error("`nextfile' is a gawk extension");
500                   }
501                   if (! io_allowed) {
502                         /* same thing */
503                         errcount++;
504                         error("`nextfile' used in BEGIN or END action");
505                   }
506                   $$ = node((NODE *) NULL, Node_K_nextfile, (NODE *) NULL);
507                 }
508         | LEX_EXIT opt_exp statement_term
509                 { $$ = node($2, Node_K_exit, (NODE *) NULL); }
510         | LEX_RETURN
511                 {
512                   if (! can_return)
513                         yyerror("`return' used outside function context");
514                 }
515           opt_exp statement_term
516                 { $$ = node($3, Node_K_return, (NODE *) NULL); }
517         | LEX_DELETE NAME '[' expression_list ']' statement_term
518                 { $$ = node(variable($2, CAN_FREE, Node_var_array), Node_K_delete, $4); }
519         | LEX_DELETE NAME  statement_term
520                 {
521                   if (do_lint)
522                         warning("`delete array' is a gawk extension");
523                   if (do_traditional) {
524                         /*
525                          * can't use yyerror, since may have overshot
526                          * the source line
527                          */
528                         errcount++;
529                         error("`delete array' is a gawk extension");
530                   }
531                   $$ = node(variable($2, CAN_FREE, Node_var_array), Node_K_delete, (NODE *) NULL);
532                 }
533         | exp statement_term
534                 { $$ = $1; }
535         ;
536
537 print
538         : LEX_PRINT
539                 { $$ = $1; }
540         | LEX_PRINTF
541                 { $$ = $1; }
542         ;
543
544 if_statement
545         : LEX_IF '(' exp r_paren opt_nls statement
546           {
547                 $$ = node($3, Node_K_if, 
548                         node($6, Node_if_branches, (NODE *) NULL));
549           }
550         | LEX_IF '(' exp r_paren opt_nls statement
551              LEX_ELSE opt_nls statement
552                 { $$ = node($3, Node_K_if,
553                                 node($6, Node_if_branches, $9)); }
554         ;
555
556 nls
557         : NEWLINE
558                 { want_assign = FALSE; }
559         | nls NEWLINE
560         ;
561
562 opt_nls
563         : /* empty */
564         | nls
565         ;
566
567 input_redir
568         : /* empty */
569                 { $$ = NULL; }
570         | '<' simp_exp
571                 { $$ = node($2, Node_redirect_input, (NODE *) NULL); }
572         ;
573
574 output_redir
575         : /* empty */
576                 { $$ = NULL; }
577         | '>' exp
578                 { $$ = node($2, Node_redirect_output, (NODE *) NULL); }
579         | APPEND_OP exp
580                 { $$ = node($2, Node_redirect_append, (NODE *) NULL); }
581         | '|' exp
582                 { $$ = node($2, Node_redirect_pipe, (NODE *) NULL); }
583         ;
584
585 opt_param_list
586         : /* empty */
587                 { $$ = NULL; }
588         | param_list
589                 { $$ = $1; }
590         ;
591
592 param_list
593         : NAME
594                 { $$ = make_param($1); }
595         | param_list comma NAME
596                 { $$ = append_right($1, make_param($3)); yyerrok; }
597         | error
598                 { $$ = NULL; }
599         | param_list error
600                 { $$ = NULL; }
601         | param_list comma error
602                 { $$ = NULL; }
603         ;
604
605 /* optional expression, as in for loop */
606 opt_exp
607         : /* empty */
608                 { $$ = NULL; }
609         | exp
610                 { $$ = $1; }
611         ;
612
613 opt_rexpression_list
614         : /* empty */
615                 { $$ = NULL; }
616         | rexpression_list
617                 { $$ = $1; }
618         ;
619
620 rexpression_list
621         : rexp
622                 { $$ = node($1, Node_expression_list, (NODE *) NULL); }
623         | rexpression_list comma rexp
624           {
625                 $$ = append_right($1,
626                         node($3, Node_expression_list, (NODE *) NULL));
627                 yyerrok;
628           }
629         | error
630                 { $$ = NULL; }
631         | rexpression_list error
632                 { $$ = NULL; }
633         | rexpression_list error rexp
634                 { $$ = NULL; }
635         | rexpression_list comma error
636                 { $$ = NULL; }
637         ;
638
639 opt_expression_list
640         : /* empty */
641                 { $$ = NULL; }
642         | expression_list
643                 { $$ = $1; }
644         ;
645
646 expression_list
647         : exp
648                 { $$ = node($1, Node_expression_list, (NODE *) NULL); }
649         | expression_list comma exp
650                 {
651                         $$ = append_right($1,
652                                 node($3, Node_expression_list, (NODE *) NULL));
653                         yyerrok;
654                 }
655         | error
656                 { $$ = NULL; }
657         | expression_list error
658                 { $$ = NULL; }
659         | expression_list error exp
660                 { $$ = NULL; }
661         | expression_list comma error
662                 { $$ = NULL; }
663         ;
664
665 /* Expressions, not including the comma operator.  */
666 exp     : variable ASSIGNOP 
667                 { want_assign = FALSE; }
668           exp
669                 {
670                   if (do_lint && $4->type == Node_regex)
671                         warning("Regular expression on left of assignment.");
672                   $$ = node($1, $2, $4);
673                 }
674         | '(' expression_list r_paren LEX_IN NAME
675                 { $$ = node(variable($5, CAN_FREE, Node_var_array), Node_in_array, $2); }
676         | exp '|' LEX_GETLINE opt_variable
677                 {
678                   $$ = node($4, Node_K_getline,
679                          node($1, Node_redirect_pipein, (NODE *) NULL));
680                 }
681         | LEX_GETLINE opt_variable input_redir
682                 {
683                   if (do_lint && ! io_allowed && $3 == NULL)
684                         warning("non-redirected getline undefined inside BEGIN or END action");
685                   $$ = node($2, Node_K_getline, $3);
686                 }
687         | exp LEX_AND exp
688                 { $$ = node($1, Node_and, $3); }
689         | exp LEX_OR exp
690                 { $$ = node($1, Node_or, $3); }
691         | exp MATCHOP exp
692                 {
693                   if ($1->type == Node_regex)
694                         warning("Regular expression on left of MATCH operator.");
695                   $$ = node($1, $2, mk_rexp($3));
696                 }
697         | regexp
698                 {
699                   $$ = $1;
700                   if (do_lint && tokstart[0] == '*') {
701                         /* possible C comment */
702                         int n = strlen(tokstart) - 1;
703                         if (tokstart[n] == '*')
704                                 warning("regexp looks like a C comment, but is not");
705                   }
706                 }
707         | '!' regexp %prec UNARY
708                 {
709                   $$ = node(node(make_number(0.0),
710                                  Node_field_spec,
711                                  (NODE *) NULL),
712                             Node_nomatch,
713                             $2);
714                 }
715         | exp LEX_IN NAME
716                 { $$ = node(variable($3, CAN_FREE, Node_var_array), Node_in_array, $1); }
717         | exp RELOP exp
718                 {
719                   if (do_lint && $3->type == Node_regex)
720                         warning("Regular expression on left of comparison.");
721                   $$ = node($1, $2, $3);
722                 }
723         | exp '<' exp
724                 { $$ = node($1, Node_less, $3); }
725         | exp '>' exp
726                 { $$ = node($1, Node_greater, $3); }
727         | exp '?' exp ':' exp
728                 { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
729         | simp_exp
730                 { $$ = $1; }
731         | exp simp_exp %prec CONCAT_OP
732                 { $$ = node($1, Node_concat, $2); }
733         ;
734
735 rexp    
736         : variable ASSIGNOP 
737                 { want_assign = FALSE; }
738           rexp
739                 { $$ = node($1, $2, $4); }
740         | rexp LEX_AND rexp
741                 { $$ = node($1, Node_and, $3); }
742         | rexp LEX_OR rexp
743                 { $$ = node($1, Node_or, $3); }
744         | LEX_GETLINE opt_variable input_redir
745                 {
746                   if (do_lint && ! io_allowed && $3 == NULL)
747                         warning("non-redirected getline undefined inside BEGIN or END action");
748                   $$ = node($2, Node_K_getline, $3);
749                 }
750         | regexp
751                 { $$ = $1; } 
752         | '!' regexp %prec UNARY
753                 { $$ = node((NODE *) NULL, Node_nomatch, $2); }
754         | rexp MATCHOP rexp
755                  { $$ = node($1, $2, mk_rexp($3)); }
756         | rexp LEX_IN NAME
757                 { $$ = node(variable($3, CAN_FREE, Node_var_array), Node_in_array, $1); }
758         | rexp RELOP rexp
759                 { $$ = node($1, $2, $3); }
760         | rexp '?' rexp ':' rexp
761                 { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
762         | simp_exp
763                 { $$ = $1; }
764         | rexp simp_exp %prec CONCAT_OP
765                 { $$ = node($1, Node_concat, $2); }
766         ;
767
768 simp_exp
769         : non_post_simp_exp
770         /* Binary operators in order of decreasing precedence.  */
771         | simp_exp '^' simp_exp
772                 { $$ = node($1, Node_exp, $3); }
773         | simp_exp '*' simp_exp
774                 { $$ = node($1, Node_times, $3); }
775         | simp_exp '/' simp_exp
776                 { $$ = node($1, Node_quotient, $3); }
777         | simp_exp '%' simp_exp
778                 { $$ = node($1, Node_mod, $3); }
779         | simp_exp '+' simp_exp
780                 { $$ = node($1, Node_plus, $3); }
781         | simp_exp '-' simp_exp
782                 { $$ = node($1, Node_minus, $3); }
783         | variable INCREMENT
784                 { $$ = node($1, Node_postincrement, (NODE *) NULL); }
785         | variable DECREMENT
786                 { $$ = node($1, Node_postdecrement, (NODE *) NULL); }
787         ;
788
789 non_post_simp_exp
790         : '!' simp_exp %prec UNARY
791                 { $$ = node($2, Node_not, (NODE *) NULL); }
792         | '(' exp r_paren
793                 { $$ = $2; }
794         | LEX_BUILTIN
795           '(' opt_expression_list r_paren
796                 { $$ = snode($3, Node_builtin, (int) $1); }
797         | LEX_LENGTH '(' opt_expression_list r_paren
798                 { $$ = snode($3, Node_builtin, (int) $1); }
799         | LEX_LENGTH
800           {
801                 if (do_lint)
802                         warning("call of `length' without parentheses is not portable");
803                 $$ = snode((NODE *) NULL, Node_builtin, (int) $1);
804                 if (do_posix)
805                         warning("call of `length' without parentheses is deprecated by POSIX");
806           }
807         | FUNC_CALL '(' opt_expression_list r_paren
808           {
809                 $$ = node($3, Node_func_call, make_string($1, strlen($1)));
810                 func_use($1, FUNC_USE);
811                 param_sanity($3);
812                 free($1);
813           }
814         | variable
815         | INCREMENT variable
816                 { $$ = node($2, Node_preincrement, (NODE *) NULL); }
817         | DECREMENT variable
818                 { $$ = node($2, Node_predecrement, (NODE *) NULL); }
819         | YNUMBER
820                 { $$ = $1; }
821         | YSTRING
822                 { $$ = $1; }
823
824         | '-' simp_exp    %prec UNARY
825                 {
826                   if ($2->type == Node_val) {
827                         $2->numbr = -(force_number($2));
828                         $$ = $2;
829                   } else
830                         $$ = node($2, Node_unary_minus, (NODE *) NULL);
831                 }
832         | '+' simp_exp    %prec UNARY
833                 {
834                   /*
835                    * was: $$ = $2
836                    * POSIX semantics: force a conversion to numeric type
837                    */
838                   $$ = node (make_number(0.0), Node_plus, $2);
839                 }
840         ;
841
842 opt_variable
843         : /* empty */
844                 { $$ = NULL; }
845         | variable
846                 { $$ = $1; }
847         ;
848
849 variable
850         : NAME
851                 { $$ = variable($1, CAN_FREE, Node_var); }
852         | NAME '[' expression_list ']'
853                 {
854                 if ($3 == NULL) {
855                         fatal("invalid subscript expression");
856                 } else if ($3->rnode == NULL) {
857                         $$ = node(variable($1, CAN_FREE, Node_var_array), Node_subscript, $3->lnode);
858                         freenode($3);
859                 } else
860                         $$ = node(variable($1, CAN_FREE, Node_var_array), Node_subscript, $3);
861                 }
862         | '$' non_post_simp_exp
863                 { $$ = node($2, Node_field_spec, (NODE *) NULL); }
864         ;
865
866 l_brace
867         : '{' opt_nls
868         ;
869
870 r_brace
871         : '}' opt_nls   { yyerrok; }
872         ;
873
874 r_paren
875         : ')' { yyerrok; }
876         ;
877
878 opt_semi
879         : /* empty */
880         | semi
881         ;
882
883 semi
884         : ';'   { yyerrok; want_assign = FALSE; }
885         ;
886
887 comma   : ',' opt_nls   { yyerrok; }
888         ;
889
890 %%
891
892 struct token {
893         const char *operator;           /* text to match */
894         NODETYPE value;         /* node type */
895         int class;              /* lexical class */
896         unsigned flags;         /* # of args. allowed and compatability */
897 #       define  ARGS    0xFF    /* 0, 1, 2, 3 args allowed (any combination */
898 #       define  A(n)    (1<<(n))
899 #       define  VERSION 0xFF00  /* old awk is zero */
900 #       define  NOT_OLD         0x0100  /* feature not in old awk */
901 #       define  NOT_POSIX       0x0200  /* feature not in POSIX */
902 #       define  GAWKX           0x0400  /* gawk extension */
903 #       define  RESX            0x0800  /* Bell Labs Research extension */
904         NODE *(*ptr)();         /* function that implements this keyword */
905 };
906
907
908 /* Tokentab is sorted ascii ascending order, so it can be binary searched. */
909 /* Function pointers come from declarations in awk.h. */
910
911 static struct token tokentab[] = {
912 {"BEGIN",       Node_illegal,    LEX_BEGIN,     0,              0},
913 {"END",         Node_illegal,    LEX_END,       0,              0},
914 #ifdef ARRAYDEBUG
915 {"adump",       Node_builtin,    LEX_BUILTIN,   GAWKX|A(1),     do_adump},
916 #endif
917 #ifdef BITOPS
918 {"and",         Node_builtin,    LEX_BUILTIN,   GAWKX|A(2),     do_and},
919 #endif /* BITOPS */
920 {"atan2",       Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(2),   do_atan2},
921 {"break",       Node_K_break,    LEX_BREAK,     0,              0},
922 {"close",       Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(1),   do_close},
923 #ifdef BITOPS
924 {"compl",       Node_builtin,    LEX_BUILTIN,   GAWKX|A(1),     do_compl},
925 #endif /* BITOPS */
926 {"continue",    Node_K_continue, LEX_CONTINUE,  0,              0},
927 {"cos",         Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(1),   do_cos},
928 {"delete",      Node_K_delete,   LEX_DELETE,    NOT_OLD,        0},
929 {"do",          Node_K_do,       LEX_DO,        NOT_OLD,        0},
930 {"else",        Node_illegal,    LEX_ELSE,      0,              0},
931 {"exit",        Node_K_exit,     LEX_EXIT,      0,              0},
932 {"exp",         Node_builtin,    LEX_BUILTIN,   A(1),           do_exp},
933 {"fflush",      Node_builtin,    LEX_BUILTIN,   RESX|A(0)|A(1), do_fflush},
934 {"for",         Node_K_for,      LEX_FOR,       0,              0},
935 {"func",        Node_K_function, LEX_FUNCTION,  NOT_POSIX|NOT_OLD,      0},
936 {"function",    Node_K_function, LEX_FUNCTION,  NOT_OLD,        0},
937 {"gensub",      Node_builtin,    LEX_BUILTIN,   GAWKX|A(3)|A(4), do_gensub},
938 {"getline",     Node_K_getline,  LEX_GETLINE,   NOT_OLD,        0},
939 {"gsub",        Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(2)|A(3), do_gsub},
940 {"if",          Node_K_if,       LEX_IF,        0,              0},
941 {"in",          Node_illegal,    LEX_IN,        0,              0},
942 {"index",       Node_builtin,    LEX_BUILTIN,   A(2),           do_index},
943 {"int",         Node_builtin,    LEX_BUILTIN,   A(1),           do_int},
944 {"length",      Node_builtin,    LEX_LENGTH,    A(0)|A(1),      do_length},
945 {"log",         Node_builtin,    LEX_BUILTIN,   A(1),           do_log},
946 #ifdef BITOPS
947 {"lshift",      Node_builtin,    LEX_BUILTIN,   GAWKX|A(2),     do_lshift},
948 #endif /* BITOPS */
949 {"match",       Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(2),   do_match},
950 {"next",        Node_K_next,     LEX_NEXT,      0,              0},
951 {"nextfile",    Node_K_nextfile, LEX_NEXTFILE,  GAWKX,          0},
952 #ifdef BITOPS
953 {"or",          Node_builtin,    LEX_BUILTIN,   GAWKX|A(2),     do_or},
954 #endif /* BITOPS */
955 {"print",       Node_K_print,    LEX_PRINT,     0,              0},
956 {"printf",      Node_K_printf,   LEX_PRINTF,    0,              0},
957 {"rand",        Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(0),   do_rand},
958 {"return",      Node_K_return,   LEX_RETURN,    NOT_OLD,        0},
959 #ifdef BITOPS
960 {"rshift",      Node_builtin,    LEX_BUILTIN,   GAWKX|A(2),     do_rshift},
961 #endif /* BITOPS */
962 {"sin",         Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(1),   do_sin},
963 {"split",       Node_builtin,    LEX_BUILTIN,   A(2)|A(3),      do_split},
964 {"sprintf",     Node_builtin,    LEX_BUILTIN,   0,              do_sprintf},
965 {"sqrt",        Node_builtin,    LEX_BUILTIN,   A(1),           do_sqrt},
966 {"srand",       Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(0)|A(1), do_srand},
967 #ifdef ARRAYDEBUG
968 {"stopme",      Node_builtin,    LEX_BUILTIN,   GAWKX|A(0),     stopme},
969 #endif
970 {"strftime",    Node_builtin,    LEX_BUILTIN,   GAWKX|A(0)|A(1)|A(2), do_strftime},
971 #ifdef BITOPS
972 {"strtonum",    Node_builtin,    LEX_BUILTIN,   GAWKX|A(1),     do_strtonum},
973 #endif /* BITOPS */
974 {"sub",         Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(2)|A(3), do_sub},
975 {"substr",      Node_builtin,    LEX_BUILTIN,   A(2)|A(3),      do_substr},
976 {"system",      Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(1),   do_system},
977 {"systime",     Node_builtin,    LEX_BUILTIN,   GAWKX|A(0),     do_systime},
978 {"tolower",     Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(1),   do_tolower},
979 {"toupper",     Node_builtin,    LEX_BUILTIN,   NOT_OLD|A(1),   do_toupper},
980 {"while",       Node_K_while,    LEX_WHILE,     0,              0},
981 #ifdef BITOPS
982 {"xor",         Node_builtin,    LEX_BUILTIN,   GAWKX|A(2),     do_xor},
983 #endif /* BITOPS */
984 };
985
986 /* yyerror --- print a syntax error message, show where */
987
988 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
989 static void
990 yyerror(const char *m, ...)
991 #else
992 /* VARARGS0 */
993 static void
994 yyerror(va_alist)
995 va_dcl
996 #endif
997 {
998         va_list args;
999         const char *mesg = NULL;
1000         register char *bp, *cp;
1001         char *scan;
1002         char buf[120];
1003         static char end_of_file_line[] = "(END OF FILE)";
1004
1005         errcount++;
1006         /* Find the current line in the input file */
1007         if (lexptr && lexeme) {
1008                 if (thisline == NULL) {
1009                         cp = lexeme;
1010                         if (*cp == '\n') {
1011                                 cp--;
1012                                 mesg = "unexpected newline";
1013                         }
1014                         for (; cp != lexptr_begin && *cp != '\n'; --cp)
1015                                 continue;
1016                         if (*cp == '\n')
1017                                 cp++;
1018                         thisline = cp;
1019                 }
1020                 /* NL isn't guaranteed */
1021                 bp = lexeme;
1022                 while (bp < lexend && *bp && *bp != '\n')
1023                         bp++;
1024         } else {
1025                 thisline = end_of_file_line;
1026                 bp = thisline + strlen(thisline);
1027         }
1028         msg("%.*s", (int) (bp - thisline), thisline);
1029         bp = buf;
1030         cp = buf + sizeof(buf) - 24;    /* 24 more than longest msg. input */
1031         if (lexptr != NULL) {
1032                 scan = thisline;
1033                 while (bp < cp && scan < lexeme)
1034                         if (*scan++ == '\t')
1035                                 *bp++ = '\t';
1036                         else
1037                                 *bp++ = ' ';
1038                 *bp++ = '^';
1039                 *bp++ = ' ';
1040         }
1041 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
1042         va_start(args, m);
1043         if (mesg == NULL)
1044                 mesg = m;
1045 #else
1046         va_start(args);
1047         if (mesg == NULL)
1048                 mesg = va_arg(args, char *);
1049 #endif
1050         strcpy(bp, mesg);
1051         err("", buf, args);
1052         va_end(args);
1053 }
1054
1055 /* get_src_buf --- read the next buffer of source program */
1056
1057 static char *
1058 get_src_buf()
1059 {
1060         static int samefile = FALSE;
1061         static int nextfile = 0;
1062         static char *buf = NULL;
1063         static int fd;
1064         int n;
1065         register char *scan;
1066         static int len = 0;
1067         static int did_newline = FALSE;
1068         int newfile;
1069         struct stat sbuf;
1070
1071 #       define  SLOP    128     /* enough space to hold most source lines */
1072
1073 again:
1074         newfile = FALSE;
1075         if (nextfile > numfiles)
1076                 return NULL;
1077
1078         if (srcfiles[nextfile].stype == CMDLINE) {
1079                 if (len == 0) {
1080                         len = strlen(srcfiles[nextfile].val);
1081                         if (len == 0) {
1082                                 /*
1083                                  * Yet Another Special case:
1084                                  *      gawk '' /path/name
1085                                  * Sigh.
1086                                  */
1087                                 static int warned = FALSE;
1088
1089                                 if (do_lint && ! warned) {
1090                                         warned = TRUE;
1091                                         warning("empty program text on command line");
1092                                 }
1093                                 ++nextfile;
1094                                 goto again;
1095                         }
1096                         sourceline = 1;
1097                         lexptr = lexptr_begin = srcfiles[nextfile].val;
1098                         lexend = lexptr + len;
1099                 } else if (! did_newline && *(lexptr-1) != '\n') {
1100                         /*
1101                          * The following goop is to ensure that the source
1102                          * ends with a newline and that the entire current
1103                          * line is available for error messages.
1104                          */
1105                         int offset;
1106
1107                         did_newline = TRUE;
1108                         offset = lexptr - lexeme;
1109                         for (scan = lexeme; scan > lexptr_begin; scan--)
1110                                 if (*scan == '\n') {
1111                                         scan++;
1112                                         break;
1113                                 }
1114                         len = lexptr - scan;
1115                         emalloc(buf, char *, len+1, "get_src_buf");
1116                         memcpy(buf, scan, len);
1117                         thisline = buf;
1118                         lexptr = buf + len;
1119                         *lexptr = '\n';
1120                         lexeme = lexptr - offset;
1121                         lexptr_begin = buf;
1122                         lexend = lexptr + 1;
1123                 } else {
1124                         len = 0;
1125                         lexeme = lexptr = lexptr_begin = NULL;
1126                 }
1127                 if (lexptr == NULL && ++nextfile <= numfiles)
1128                         goto again;
1129                 return lexptr;
1130         }
1131         if (! samefile) {
1132                 source = srcfiles[nextfile].val;
1133                 if (source == NULL) {
1134                         if (buf != NULL) {
1135                                 free(buf);
1136                                 buf = NULL;
1137                         }
1138                         len = 0;
1139                         return lexeme = lexptr = lexptr_begin = NULL;
1140                 }
1141                 fd = pathopen(source);
1142                 if (fd <= INVALID_HANDLE) {
1143                         char *in;
1144
1145                         /* suppress file name and line no. in error mesg */
1146                         in = source;
1147                         source = NULL;
1148                         fatal("can't open source file \"%s\" for reading (%s)",
1149                                 in, strerror(errno));
1150                 }
1151                 len = optimal_bufsize(fd, & sbuf);
1152                 newfile = TRUE;
1153                 if (buf != NULL)
1154                         free(buf);
1155                 emalloc(buf, char *, len + SLOP, "get_src_buf");
1156                 lexptr_begin = buf + SLOP;
1157                 samefile = TRUE;
1158                 sourceline = 1;
1159         } else {
1160                 /*
1161                  * Here, we retain the current source line (up to length SLOP)
1162                  * in the beginning of the buffer that was overallocated above
1163                  */
1164                 int offset;
1165                 int linelen;
1166
1167                 offset = lexptr - lexeme;
1168                 for (scan = lexeme; scan > lexptr_begin; scan--)
1169                         if (*scan == '\n') {
1170                                 scan++;
1171                                 break;
1172                         }
1173                 linelen = lexptr - scan;
1174                 if (linelen > SLOP)
1175                         linelen = SLOP;
1176                 thisline = buf + SLOP - linelen;
1177                 memcpy(thisline, scan, linelen);
1178                 lexeme = buf + SLOP - offset;
1179                 lexptr_begin = thisline;
1180         }
1181         n = read(fd, buf + SLOP, len);
1182         if (n == -1)
1183                 fatal("can't read sourcefile \"%s\" (%s)",
1184                         source, strerror(errno));
1185         if (n == 0) {
1186                 if (newfile) {
1187                         static int warned = FALSE;
1188
1189                         if (do_lint && ! warned) {
1190                                 warned = TRUE;
1191                                 warning("source file `%s' is empty", source);
1192                         }
1193                 }
1194                 if (fileno(stdin) != fd)        /* safety */
1195                         close(fd);
1196                 samefile = FALSE;
1197                 nextfile++;
1198                 if (lexeme)
1199                         *lexeme = '\0';
1200                 len = 0;
1201                 goto again;
1202         }
1203         lexptr = buf + SLOP;
1204         lexend = lexptr + n;
1205         return buf;
1206 }
1207
1208 /* tokadd --- add a character to the token buffer */
1209
1210 #define tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok)
1211
1212 /* tokexpand --- grow the token buffer */
1213
1214 char *
1215 tokexpand()
1216 {
1217         static int toksize = 60;
1218         int tokoffset;
1219
1220         tokoffset = tok - tokstart;
1221         toksize *= 2;
1222         if (tokstart != NULL)
1223                 erealloc(tokstart, char *, toksize, "tokexpand");
1224         else
1225                 emalloc(tokstart, char *, toksize, "tokexpand");
1226         tokend = tokstart + toksize;
1227         tok = tokstart + tokoffset;
1228         return tok;
1229 }
1230
1231 /* nextc --- get the next input character */
1232
1233 #if DEBUG
1234 int
1235 nextc()
1236 {
1237         int c;
1238
1239         if (lexptr && lexptr < lexend)
1240                 c = (int) (unsigned char) *lexptr++;
1241         else if (get_src_buf())
1242                 c = (int) (unsigned char) *lexptr++;
1243         else
1244                 c = EOF;
1245
1246         return c;
1247 }
1248 #else
1249 #define nextc() ((lexptr && lexptr < lexend) ? \
1250                     ((int) (unsigned char) *lexptr++) : \
1251                     (get_src_buf() ? ((int) (unsigned char) *lexptr++) : EOF) \
1252                 )
1253 #endif
1254
1255 /* pushback --- push a character back on the input */
1256
1257 #define pushback() (lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr)
1258
1259 /* allow_newline --- allow newline after &&, ||, ? and : */
1260
1261 static void
1262 allow_newline()
1263 {
1264         int c;
1265
1266         for (;;) {
1267                 c = nextc();
1268                 if (c == EOF)
1269                         break;
1270                 if (c == '#') {
1271                         while ((c = nextc()) != '\n' && c != EOF)
1272                                 continue;
1273                         if (c == EOF)
1274                                 break;
1275                 }
1276                 if (c == '\n')
1277                         sourceline++;
1278                 if (! isspace(c)) {
1279                         pushback();
1280                         break;
1281                 }
1282         }
1283 }
1284
1285 /* yylex --- Read the input and turn it into tokens. */
1286
1287 static int
1288 yylex()
1289 {
1290         register int c, c1;
1291         int seen_e = FALSE;             /* These are for numbers */
1292         int seen_point = FALSE;
1293         int esc_seen;           /* for literal strings */
1294         int low, mid, high;
1295         static int did_newline = FALSE;
1296         char *tokkey;
1297         static int lasttok = 0, eof_warned = FALSE;
1298         int inhex = FALSE;
1299
1300         if (nextc() == EOF) {
1301                 if (lasttok != NEWLINE) {
1302                         lasttok = NEWLINE;
1303                         if (do_lint && ! eof_warned) {
1304                                 warning("source file does not end in newline");
1305                                 eof_warned = TRUE;
1306                         }
1307                         return NEWLINE; /* fake it */
1308                 }
1309                 return 0;
1310         }
1311         pushback();
1312 #ifdef OS2
1313         /*
1314          * added for OS/2's extproc feature of cmd.exe
1315          * (like #! in BSD sh)
1316          */
1317         if (strncasecmp(lexptr, "extproc ", 8) == 0) {
1318                 while (*lexptr && *lexptr != '\n')
1319                         lexptr++;
1320         }
1321 #endif
1322         lexeme = lexptr;
1323         thisline = NULL;
1324         if (want_regexp) {
1325                 int in_brack = 0;       /* count brackets, [[:alnum:]] allowed */
1326                 /*
1327                  * Counting brackets is non-trivial. [[] is ok,
1328                  * and so is [\]], with a point being that /[/]/ as a regexp
1329                  * constant has to work.
1330                  *
1331                  * Do not count [ or ] if either one is preceded by a \.
1332                  * A `[' should be counted if
1333                  *  a) it is the first one so far (in_brack == 0)
1334                  *  b) it is the `[' in `[:'
1335                  * A ']' should be counted if not preceded by a \, since
1336                  * it is either closing `:]' or just a plain list.
1337                  * According to POSIX, []] is how you put a ] into a set.
1338                  * Try to handle that too.
1339                  *
1340                  * The code for \ handles \[ and \].
1341                  */
1342
1343                 want_regexp = FALSE;
1344                 tok = tokstart;
1345                 for (;;) {
1346                         c = nextc();
1347                         switch (c) {
1348                         case '[':
1349                                 /* one day check for `.' and `=' too */
1350                                 if ((c1 = nextc()) == ':' || in_brack == 0)
1351                                         in_brack++;
1352                                 pushback();
1353                                 break;
1354                         case ']':
1355                                 if (tokstart[0] == '['
1356                                     && (tok == tokstart + 1
1357                                         || (tok == tokstart + 2
1358                                             && tokstart[1] == '^')))
1359                                         /* do nothing */;
1360                                 else
1361                                         in_brack--;
1362                                 break;
1363                         case '\\':
1364                                 if ((c = nextc()) == EOF) {
1365                                         yyerror("unterminated regexp ends with \\ at end of file");
1366                                         return lasttok = REGEXP; /* kludge */
1367                                 } else if (c == '\n') {
1368                                         sourceline++;
1369                                         continue;
1370                                 } else {
1371                                         tokadd('\\');
1372                                         tokadd(c);
1373                                         continue;
1374                                 }
1375                                 break;
1376                         case '/':       /* end of the regexp */
1377                                 if (in_brack > 0)
1378                                         break;
1379
1380                                 pushback();
1381                                 tokadd('\0');
1382                                 yylval.sval = tokstart;
1383                                 return lasttok = REGEXP;
1384                         case '\n':
1385                                 pushback();
1386                                 yyerror("unterminated regexp");
1387                                 return lasttok = REGEXP;        /* kludge */
1388                         case EOF:
1389                                 yyerror("unterminated regexp at end of file");
1390                                 return lasttok = REGEXP;        /* kludge */
1391                         }
1392                         tokadd(c);
1393                 }
1394         }
1395 retry:
1396         while ((c = nextc()) == ' ' || c == '\t')
1397                 continue;
1398
1399         lexeme = lexptr ? lexptr - 1 : lexptr;
1400         thisline = NULL;
1401         tok = tokstart;
1402         yylval.nodetypeval = Node_illegal;
1403
1404         switch (c) {
1405         case EOF:
1406                 if (lasttok != NEWLINE) {
1407                         lasttok = NEWLINE;
1408                         if (do_lint && ! eof_warned) {
1409                                 warning("source file does not end in newline");
1410                                 eof_warned = TRUE;
1411                         }
1412                         return NEWLINE; /* fake it */
1413                 }
1414                 return 0;
1415
1416         case '\n':
1417                 sourceline++;
1418                 return lasttok = NEWLINE;
1419
1420         case '#':               /* it's a comment */
1421                 while ((c = nextc()) != '\n') {
1422                         if (c == EOF) {
1423                                 if (lasttok != NEWLINE) {
1424                                         lasttok = NEWLINE;
1425                                         if (do_lint && ! eof_warned) {
1426                                                 warning(
1427                                 "source file does not end in newline");
1428                                                 eof_warned = TRUE;
1429                                         }
1430                                         return NEWLINE; /* fake it */
1431                                 }
1432                                 return 0;
1433                         }
1434                 }
1435                 sourceline++;
1436                 return lasttok = NEWLINE;
1437
1438         case '\\':
1439 #ifdef RELAXED_CONTINUATION
1440                 /*
1441                  * This code puports to allow comments and/or whitespace
1442                  * after the `\' at the end of a line used for continuation.
1443                  * Use it at your own risk. We think it's a bad idea, which
1444                  * is why it's not on by default.
1445                  */
1446                 if (! do_traditional) {
1447                         /* strip trailing white-space and/or comment */
1448                         while ((c = nextc()) == ' ' || c == '\t')
1449                                 continue;
1450                         if (c == '#') {
1451                                 if (do_lint)
1452                                         warning(
1453                 "use of `\\ #...' line continuation is not portable");
1454                                 while ((c = nextc()) != '\n')
1455                                         if (c == EOF)
1456                                                 break;
1457                         }
1458                         pushback();
1459                 }
1460 #endif /* RELAXED_CONTINUATION */
1461                 if (nextc() == '\n') {
1462                         sourceline++;
1463                         goto retry;
1464                 } else {
1465                         yyerror("backslash not last character on line");
1466                         exit(1);
1467                 }
1468                 break;
1469
1470         case '$':
1471                 want_assign = TRUE;
1472                 return lasttok = '$';
1473
1474         case ':':
1475         case '?':
1476                 allow_newline();
1477                 return lasttok = c;
1478
1479         case ')':
1480         case '(':       
1481         case ';':
1482         case '{':
1483         case ',':
1484                 want_assign = FALSE;
1485                 /* fall through */
1486         case '[':
1487         case ']':
1488                 return lasttok = c;
1489
1490         case '*':
1491                 if ((c = nextc()) == '=') {
1492                         yylval.nodetypeval = Node_assign_times;
1493                         return lasttok = ASSIGNOP;
1494                 } else if (do_posix) {
1495                         pushback();
1496                         return lasttok = '*';
1497                 } else if (c == '*') {
1498                         /* make ** and **= aliases for ^ and ^= */
1499                         static int did_warn_op = FALSE, did_warn_assgn = FALSE;
1500
1501                         if (nextc() == '=') {
1502                                 if (do_lint && ! did_warn_assgn) {
1503                                         did_warn_assgn = TRUE;
1504                                         warning("**= is not allowed by POSIX");
1505                                         warning("operator `**=' is not supported in old awk");
1506                                 }
1507                                 yylval.nodetypeval = Node_assign_exp;
1508                                 return ASSIGNOP;
1509                         } else {
1510                                 pushback();
1511                                 if (do_lint && ! did_warn_op) {
1512                                         did_warn_op = TRUE;
1513                                         warning("** is not allowed by POSIX");
1514                                         warning("operator `**' is not supported in old awk");
1515                                 }
1516                                 return lasttok = '^';
1517                         }
1518                 }
1519                 pushback();
1520                 return lasttok = '*';
1521
1522         case '/':
1523                 if (want_assign) {
1524                         if (nextc() == '=') {
1525                                 yylval.nodetypeval = Node_assign_quotient;
1526                                 return lasttok = ASSIGNOP;
1527                         }
1528                         pushback();
1529                 }
1530                 return lasttok = '/';
1531
1532         case '%':
1533                 if (nextc() == '=') {
1534                         yylval.nodetypeval = Node_assign_mod;
1535                         return lasttok = ASSIGNOP;
1536                 }
1537                 pushback();
1538                 return lasttok = '%';
1539
1540         case '^':
1541         {
1542                 static int did_warn_op = FALSE, did_warn_assgn = FALSE;
1543
1544                 if (nextc() == '=') {
1545                         if (do_lint && ! did_warn_assgn) {
1546                                 did_warn_assgn = TRUE;
1547                                 warning("operator `^=' is not supported in old awk");
1548                         }
1549                         yylval.nodetypeval = Node_assign_exp;
1550                         return lasttok = ASSIGNOP;
1551                 }
1552                 pushback();
1553                 if (do_lint && ! did_warn_op) {
1554                         did_warn_op = TRUE;
1555                         warning("operator `^' is not supported in old awk");
1556                 }
1557                 return lasttok = '^';
1558         }
1559
1560         case '+':
1561                 if ((c = nextc()) == '=') {
1562                         yylval.nodetypeval = Node_assign_plus;
1563                         return lasttok = ASSIGNOP;
1564                 }
1565                 if (c == '+')
1566                         return lasttok = INCREMENT;
1567                 pushback();
1568                 return lasttok = '+';
1569
1570         case '!':
1571                 if ((c = nextc()) == '=') {
1572                         yylval.nodetypeval = Node_notequal;
1573                         return lasttok = RELOP;
1574                 }
1575                 if (c == '~') {
1576                         yylval.nodetypeval = Node_nomatch;
1577                         want_assign = FALSE;
1578                         return lasttok = MATCHOP;
1579                 }
1580                 pushback();
1581                 return lasttok = '!';
1582
1583         case '<':
1584                 if (nextc() == '=') {
1585                         yylval.nodetypeval = Node_leq;
1586                         return lasttok = RELOP;
1587                 }
1588                 yylval.nodetypeval = Node_less;
1589                 pushback();
1590                 return lasttok = '<';
1591
1592         case '=':
1593                 if (nextc() == '=') {
1594                         yylval.nodetypeval = Node_equal;
1595                         return lasttok = RELOP;
1596                 }
1597                 yylval.nodetypeval = Node_assign;
1598                 pushback();
1599                 return lasttok = ASSIGNOP;
1600
1601         case '>':
1602                 if ((c = nextc()) == '=') {
1603                         yylval.nodetypeval = Node_geq;
1604                         return lasttok = RELOP;
1605                 } else if (c == '>') {
1606                         yylval.nodetypeval = Node_redirect_append;
1607                         return lasttok = APPEND_OP;
1608                 }
1609                 yylval.nodetypeval = Node_greater;
1610                 pushback();
1611                 return lasttok = '>';
1612
1613         case '~':
1614                 yylval.nodetypeval = Node_match;
1615                 want_assign = FALSE;
1616                 return lasttok = MATCHOP;
1617
1618         case '}':
1619                 /*
1620                  * Added did newline stuff.  Easier than
1621                  * hacking the grammar.
1622                  */
1623                 if (did_newline) {
1624                         did_newline = FALSE;
1625                         return lasttok = c;
1626                 }
1627                 did_newline++;
1628                 --lexptr;       /* pick up } next time */
1629                 return lasttok = NEWLINE;
1630
1631         case '"':
1632                 esc_seen = FALSE;
1633                 while ((c = nextc()) != '"') {
1634                         if (c == '\n') {
1635                                 pushback();
1636                                 yyerror("unterminated string");
1637                                 exit(1);
1638                         }
1639                         if (c == '\\') {
1640                                 c = nextc();
1641                                 if (c == '\n') {
1642                                         sourceline++;
1643                                         continue;
1644                                 }
1645                                 esc_seen = TRUE;
1646                                 tokadd('\\');
1647                         }
1648                         if (c == EOF) {
1649                                 pushback();
1650                                 yyerror("unterminated string");
1651                                 exit(1);
1652                         }
1653                         tokadd(c);
1654                 }
1655                 yylval.nodeval = make_str_node(tokstart,
1656                                         tok - tokstart, esc_seen ? SCAN : 0);
1657                 yylval.nodeval->flags |= PERM;
1658                 return lasttok = YSTRING;
1659
1660         case '-':
1661                 if ((c = nextc()) == '=') {
1662                         yylval.nodetypeval = Node_assign_minus;
1663                         return lasttok = ASSIGNOP;
1664                 }
1665                 if (c == '-')
1666                         return lasttok = DECREMENT;
1667                 pushback();
1668                 return lasttok = '-';
1669
1670         case '.':
1671                 c = nextc();
1672                 pushback();
1673                 if (! isdigit(c))
1674                         return lasttok = '.';
1675                 else
1676                         c = '.';
1677                 /* FALL THROUGH */
1678         case '0':
1679         case '1':
1680         case '2':
1681         case '3':
1682         case '4':
1683         case '5':
1684         case '6':
1685         case '7':
1686         case '8':
1687         case '9':
1688                 /* It's a number */
1689                 for (;;) {
1690                         int gotnumber = FALSE;
1691
1692                         tokadd(c);
1693                         switch (c) {
1694 #ifdef BITOPS
1695                         case 'x':
1696                         case 'X':
1697                                 if (do_traditional)
1698                                         goto done;
1699                                 if (tok == tokstart + 2)
1700                                         inhex = TRUE;
1701                                 break;
1702 #endif /* BITOTS */
1703                         case '.':
1704                                 if (seen_point) {
1705                                         gotnumber = TRUE;
1706                                         break;
1707                                 }
1708                                 seen_point = TRUE;
1709                                 break;
1710                         case 'e':
1711                         case 'E':
1712                                 if (inhex)
1713                                         break;
1714                                 if (seen_e) {
1715                                         gotnumber = TRUE;
1716                                         break;
1717                                 }
1718                                 seen_e = TRUE;
1719                                 if ((c = nextc()) == '-' || c == '+')
1720                                         tokadd(c);
1721                                 else
1722                                         pushback();
1723                                 break;
1724 #ifdef BITOPS
1725                         case 'a':
1726                         case 'A':
1727                         case 'b':
1728                         case 'B':
1729                         case 'c':
1730                         case 'C':
1731                         case 'D':
1732                         case 'd':
1733                         case 'f':
1734                         case 'F':
1735                                 if (do_traditional || ! inhex)
1736                                         goto done;
1737                                 /* fall through */
1738 #endif
1739                         case '0':
1740                         case '1':
1741                         case '2':
1742                         case '3':
1743                         case '4':
1744                         case '5':
1745                         case '6':
1746                         case '7':
1747                         case '8':
1748                         case '9':
1749                                 break;
1750                         default:
1751                         done:
1752                                 gotnumber = TRUE;
1753                         }
1754                         if (gotnumber)
1755                                 break;
1756                         c = nextc();
1757                 }
1758                 if (c != EOF)
1759                         pushback();
1760                 else if (do_lint && ! eof_warned) {
1761                         warning("source file does not end in newline");
1762                         eof_warned = TRUE;
1763                 }
1764                 tokadd('\0');
1765 #ifdef BITOPS
1766                 if (! do_traditional && isnondecimal(tokstart))
1767                         yylval.nodeval = make_number(nondec2awknum(tokstart, strlen(tokstart)));
1768                 else
1769 #endif /* BITOPS */
1770                 yylval.nodeval = make_number(atof(tokstart));
1771                 yylval.nodeval->flags |= PERM;
1772                 return lasttok = YNUMBER;
1773
1774         case '&':
1775                 if ((c = nextc()) == '&') {
1776                         yylval.nodetypeval = Node_and;
1777                         allow_newline();
1778                         want_assign = FALSE;
1779                         return lasttok = LEX_AND;
1780                 }
1781                 pushback();
1782                 return lasttok = '&';
1783
1784         case '|':
1785                 if ((c = nextc()) == '|') {
1786                         yylval.nodetypeval = Node_or;
1787                         allow_newline();
1788                         want_assign = FALSE;
1789                         return lasttok = LEX_OR;
1790                 }
1791                 pushback();
1792                 return lasttok = '|';
1793         }
1794
1795         if (c != '_' && ! isalpha(c)) {
1796                 yyerror("Invalid char '%c' in expression\n", c);
1797                 exit(1);
1798         }
1799
1800         /* it's some type of name-type-thing.  Find its length. */
1801         tok = tokstart;
1802         while (is_identchar(c)) {
1803                 tokadd(c);
1804                 c = nextc();
1805         }
1806         tokadd('\0');
1807         emalloc(tokkey, char *, tok - tokstart, "yylex");
1808         memcpy(tokkey, tokstart, tok - tokstart);
1809         if (c != EOF)
1810                 pushback();
1811         else if (do_lint && ! eof_warned) {
1812                 warning("source file does not end in newline");
1813                 eof_warned = TRUE;
1814         }
1815
1816         /* See if it is a special token. */
1817         low = 0;
1818         high = (sizeof(tokentab) / sizeof(tokentab[0])) - 1;
1819         while (low <= high) {
1820                 int i;
1821
1822                 mid = (low + high) / 2;
1823                 c = *tokstart - tokentab[mid].operator[0];
1824                 i = c ? c : strcmp(tokstart, tokentab[mid].operator);
1825
1826                 if (i < 0)              /* token < mid */
1827                         high = mid - 1;
1828                 else if (i > 0)         /* token > mid */
1829                         low = mid + 1;
1830                 else {
1831                         if (do_lint) {
1832                                 if (tokentab[mid].flags & GAWKX)
1833                                         warning("%s() is a gawk extension",
1834                                                 tokentab[mid].operator);
1835                                 if (tokentab[mid].flags & RESX)
1836                                         warning("%s() is a Bell Labs extension",
1837                                                 tokentab[mid].operator);
1838                                 if (tokentab[mid].flags & NOT_POSIX)
1839                                         warning("POSIX does not allow %s",
1840                                                 tokentab[mid].operator);
1841                         }
1842                         if (do_lint_old && (tokentab[mid].flags & NOT_OLD))
1843                                 warning("%s is not supported in old awk",
1844                                                 tokentab[mid].operator);
1845                         if ((do_traditional && (tokentab[mid].flags & GAWKX))
1846                             || (do_posix && (tokentab[mid].flags & NOT_POSIX)))
1847                                 break;
1848                         if (tokentab[mid].class == LEX_BUILTIN
1849                             || tokentab[mid].class == LEX_LENGTH
1850                            )
1851                                 yylval.lval = mid;
1852                         else
1853                                 yylval.nodetypeval = tokentab[mid].value;
1854
1855                         free(tokkey);
1856                         return lasttok = tokentab[mid].class;
1857                 }
1858         }
1859
1860         yylval.sval = tokkey;
1861         if (*lexptr == '(')
1862                 return lasttok = FUNC_CALL;
1863         else {
1864                 want_assign = TRUE;
1865                 return lasttok = NAME;
1866         }
1867 }
1868
1869 /* node_common --- common code for allocating a new node */
1870
1871 static NODE *
1872 node_common(op)
1873 NODETYPE op;
1874 {
1875         register NODE *r;
1876
1877         getnode(r);
1878         r->type = op;
1879         r->flags = MALLOC;
1880         /* if lookahead is NL, lineno is 1 too high */
1881         if (lexeme && *lexeme == '\n')
1882                 r->source_line = sourceline - 1;
1883         else
1884                 r->source_line = sourceline;
1885         r->source_file = source;
1886         return r;
1887 }
1888
1889 /* node --- allocates a node with defined lnode and rnode. */
1890
1891 NODE *
1892 node(left, op, right)
1893 NODE *left, *right;
1894 NODETYPE op;
1895 {
1896         register NODE *r;
1897
1898         r = node_common(op);
1899         r->lnode = left;
1900         r->rnode = right;
1901         return r;
1902 }
1903
1904 /* snode ---    allocate a node with defined subnode and proc for builtin
1905                 functions. Checks for arg. count and supplies defaults where
1906                 possible. */
1907
1908 static NODE *
1909 snode(subn, op, idx)
1910 NODETYPE op;
1911 int idx;
1912 NODE *subn;
1913 {
1914         register NODE *r;
1915         register NODE *n;
1916         int nexp = 0;
1917         int args_allowed;
1918
1919         r = node_common(op);
1920
1921         /* traverse expression list to see how many args. given */
1922         for (n = subn; n != NULL; n = n->rnode) {
1923                 nexp++;
1924                 if (nexp > 3)
1925                         break;
1926         }
1927
1928         /* check against how many args. are allowed for this builtin */
1929         args_allowed = tokentab[idx].flags & ARGS;
1930         if (args_allowed && (args_allowed & A(nexp)) == 0)
1931                 fatal("%s() cannot have %d argument%c",
1932                         tokentab[idx].operator, nexp, nexp == 1 ? ' ' : 's');
1933
1934         r->proc = tokentab[idx].ptr;
1935
1936         /* special case processing for a few builtins */
1937         /*
1938          * FIXME: go through these to make sure that everything done
1939          *        here is really right. Move anything that's not into
1940          *        the corresponding routine.
1941          */
1942         if (nexp == 0 && r->proc == do_length) {
1943                 subn = node(node(make_number(0.0), Node_field_spec, (NODE *) NULL),
1944                             Node_expression_list,
1945                             (NODE *) NULL);
1946         } else if (r->proc == do_match) {
1947                 if (subn->rnode->lnode->type != Node_regex)
1948                         subn->rnode->lnode = mk_rexp(subn->rnode->lnode);
1949         } else if (r->proc == do_sub || r->proc == do_gsub) {
1950                 if (subn->lnode->type != Node_regex)
1951                         subn->lnode = mk_rexp(subn->lnode);
1952                 if (nexp == 2)
1953                         append_right(subn, node(node(make_number(0.0),
1954                                                      Node_field_spec,
1955                                                      (NODE *) NULL),
1956                                                 Node_expression_list,
1957                                                 (NODE *) NULL));
1958                 else if (subn->rnode->rnode->lnode->type == Node_val) {
1959                         if (do_lint)
1960                                 warning("string literal as last arg of substitute");
1961                 } else if (! isassignable(subn->rnode->rnode->lnode))
1962                         yyerror("%s third parameter is not a changeable object",
1963                                 r->proc == do_sub ? "sub" : "gsub");
1964         } else if (r->proc == do_gensub) {
1965                 if (subn->lnode->type != Node_regex)
1966                         subn->lnode = mk_rexp(subn->lnode);
1967                 if (nexp == 3)
1968                         append_right(subn, node(node(make_number(0.0),
1969                                                      Node_field_spec,
1970                                                      (NODE *) NULL),
1971                                                 Node_expression_list,
1972                                                 (NODE *) NULL));
1973         } else if (r->proc == do_split) {
1974                 if (nexp == 2)
1975                         append_right(subn,
1976                             node(FS_node, Node_expression_list, (NODE *) NULL));
1977                 n = subn->rnode->rnode->lnode;
1978                 if (n->type != Node_regex)
1979                         subn->rnode->rnode->lnode = mk_rexp(n);
1980                 if (nexp == 2)
1981                         subn->rnode->rnode->lnode->re_flags |= FS_DFLT;
1982         }
1983
1984         r->subnode = subn;
1985         return r;
1986 }
1987
1988 /*
1989  * mkrangenode:
1990  * This allocates a Node_line_range node with defined condpair and
1991  * zeroes the trigger word to avoid the temptation of assuming that calling
1992  * 'node( foo, Node_line_range, 0)' will properly initialize 'triggered'. 
1993  * Otherwise like node().
1994  */
1995
1996 static NODE *
1997 mkrangenode(cpair)
1998 NODE *cpair;
1999 {
2000         register NODE *r;
2001
2002         getnode(r);
2003         r->type = Node_line_range;
2004         r->condpair = cpair;
2005         r->triggered = FALSE;
2006         return r;
2007 }
2008
2009 /* make_for_loop --- build a for loop */
2010
2011 static NODE *
2012 make_for_loop(init, cond, incr)
2013 NODE *init, *cond, *incr;
2014 {
2015         register FOR_LOOP_HEADER *r;
2016         NODE *n;
2017
2018         emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop");
2019         getnode(n);
2020         n->type = Node_illegal;
2021         r->init = init;
2022         r->cond = cond;
2023         r->incr = incr;
2024         n->sub.nodep.r.hd = r;
2025         return n;
2026 }
2027
2028 /* dup_parms --- return TRUE if there are duplicate parameters */
2029
2030 static int
2031 dup_parms(func)
2032 NODE *func;
2033 {
2034         register NODE *np;
2035         char *fname, **names;
2036         int count, i, j, dups;
2037         NODE *params;
2038
2039         if (func == NULL)       /* error earlier */
2040                 return TRUE;
2041
2042         fname = func->param;
2043         count = func->param_cnt;
2044         params = func->rnode;
2045
2046         if (count == 0)         /* no args, no problem */
2047                 return FALSE;
2048
2049         if (params == NULL)     /* error earlier */
2050                 return TRUE;
2051
2052         emalloc(names, char **, count * sizeof(char *), "dup_parms");
2053
2054         i = 0;
2055         for (np = params; np != NULL; np = np->rnode) {
2056                 if (np->param == NULL) { /* error earlier, give up, go home */
2057                         free(names);
2058                         return TRUE;
2059                 }
2060                 names[i++] = np->param;
2061         }
2062
2063         dups = 0;
2064         for (i = 1; i < count; i++) {
2065                 for (j = 0; j < i; j++) {
2066                         if (strcmp(names[i], names[j]) == 0) {
2067                                 dups++;
2068                                 error(
2069         "function `%s': parameter #%d, `%s', duplicates parameter #%d",
2070                                         fname, i+1, names[j], j+1);
2071                         }
2072                 }
2073         }
2074
2075         free(names);
2076         return (dups > 0 ? TRUE : FALSE);
2077 }
2078
2079 /*
2080  * install:
2081  * Install a name in the symbol table, even if it is already there.
2082  * Caller must check against redefinition if that is desired. 
2083  */
2084
2085 NODE *
2086 install(name, value)
2087 char *name;
2088 NODE *value;
2089 {
2090         register NODE *hp;
2091         register size_t len;
2092         register int bucket;
2093
2094         len = strlen(name);
2095         bucket = hash(name, len, (unsigned long) HASHSIZE);
2096         getnode(hp);
2097         hp->type = Node_hashnode;
2098         hp->hnext = variables[bucket];
2099         variables[bucket] = hp;
2100         hp->hlength = len;
2101         hp->hvalue = value;
2102         hp->hname = name;
2103         hp->hvalue->vname = name;
2104         return hp->hvalue;
2105 }
2106
2107 /* lookup --- find the most recent hash node for name installed by install */
2108
2109 NODE *
2110 lookup(name)
2111 const char *name;
2112 {
2113         register NODE *bucket;
2114         register size_t len;
2115
2116         len = strlen(name);
2117         for (bucket = variables[hash(name, len, (unsigned long) HASHSIZE)];
2118                         bucket != NULL; bucket = bucket->hnext)
2119                 if (bucket->hlength == len && STREQN(bucket->hname, name, len))
2120                         return bucket->hvalue;
2121
2122         return NULL;
2123 }
2124
2125 /*
2126  * append_right:
2127  * Add new to the rightmost branch of LIST.  This uses n^2 time, so we make
2128  * a simple attempt at optimizing it.
2129  */
2130
2131 static NODE *
2132 append_right(list, new)
2133 NODE *list, *new;
2134 {
2135         register NODE *oldlist;
2136         static NODE *savefront = NULL, *savetail = NULL;
2137
2138         if (list == NULL || new == NULL)
2139                 return list;
2140
2141         oldlist = list;
2142         if (savefront == oldlist) {
2143                 savetail = savetail->rnode = new;
2144                 return oldlist;
2145         } else
2146                 savefront = oldlist;
2147         while (list->rnode != NULL)
2148                 list = list->rnode;
2149         savetail = list->rnode = new;
2150         return oldlist;
2151 }
2152
2153 /*
2154  * func_install:
2155  * check if name is already installed;  if so, it had better have Null value,
2156  * in which case def is added as the value. Otherwise, install name with def
2157  * as value. 
2158  */
2159
2160 static void
2161 func_install(params, def)
2162 NODE *params;
2163 NODE *def;
2164 {
2165         NODE *r;
2166         NODE *n;
2167
2168         /* check for function foo(foo) { ... }.  bleh. */
2169         for (n = params->rnode; n != NULL; n = n->rnode) {
2170                 if (strcmp(n->param, params->param) == 0)
2171                         fatal("function `%s': can't use function name as parameter name",
2172                                         params->param); 
2173         }
2174
2175         pop_params(params->rnode);
2176         pop_var(params, FALSE);
2177         r = lookup(params->param);
2178         if (r != NULL) {
2179                 fatal("function name `%s' previously defined", params->param);
2180         } else
2181                 (void) install(params->param, node(params, Node_func, def));
2182
2183         func_use(params->param, FUNC_DEFINE);
2184 }
2185
2186 /* pop_var --- remove a variable from the symbol table */
2187
2188 static void
2189 pop_var(np, freeit)
2190 NODE *np;
2191 int freeit;
2192 {
2193         register NODE *bucket, **save;
2194         register size_t len;
2195         char *name;
2196
2197         name = np->param;
2198         len = strlen(name);
2199         save = &(variables[hash(name, len, (unsigned long) HASHSIZE)]);
2200         for (bucket = *save; bucket != NULL; bucket = bucket->hnext) {
2201                 if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
2202                         *save = bucket->hnext;
2203                         freenode(bucket);
2204                         if (freeit)
2205                                 free(np->param);
2206                         return;
2207                 }
2208                 save = &(bucket->hnext);
2209         }
2210 }
2211
2212 /* pop_params --- remove list of function parameters from symbol table */
2213
2214 /*
2215  * pop parameters out of the symbol table. do this in reverse order to
2216  * avoid reading freed memory if there were duplicated parameters.
2217  */
2218 static void
2219 pop_params(params)
2220 NODE *params;
2221 {
2222         if (params == NULL)
2223                 return;
2224         pop_params(params->rnode);
2225         pop_var(params, TRUE);
2226 }
2227
2228 /* make_param --- make NAME into a function parameter */
2229
2230 static NODE *
2231 make_param(name)
2232 char *name;
2233 {
2234         NODE *r;
2235
2236         getnode(r);
2237         r->type = Node_param_list;
2238         r->rnode = NULL;
2239         r->param = name;
2240         r->param_cnt = param_counter++;
2241         return (install(name, r));
2242 }
2243
2244 static struct fdesc {
2245         char *name;
2246         short used;
2247         short defined;
2248         struct fdesc *next;
2249 } *ftable[HASHSIZE];
2250
2251 /* func_use --- track uses and definitions of functions */
2252
2253 static void
2254 func_use(name, how)
2255 char *name;
2256 enum defref how;
2257 {
2258         struct fdesc *fp;
2259         int len;
2260         int ind;
2261
2262         len = strlen(name);
2263         ind = hash(name, len, HASHSIZE);
2264
2265         for (fp = ftable[ind]; fp != NULL; fp = fp->next) {
2266                 if (strcmp(fp->name, name) == 0) {
2267                         if (how == FUNC_DEFINE)
2268                                 fp->defined++;
2269                         else
2270                                 fp->used++;
2271                         return;
2272                 }
2273         }
2274
2275         /* not in the table, fall through to allocate a new one */
2276
2277         emalloc(fp, struct fdesc *, sizeof(struct fdesc), "func_use");
2278         memset(fp, '\0', sizeof(struct fdesc));
2279         emalloc(fp->name, char *, len + 1, "func_use");
2280         strcpy(fp->name, name);
2281         if (how == FUNC_DEFINE)
2282                 fp->defined++;
2283         else
2284                 fp->used++;
2285         fp->next = ftable[ind];
2286         ftable[ind] = fp;
2287 }
2288
2289 /* check_funcs --- verify functions that are called but not defined */
2290
2291 static void
2292 check_funcs()
2293 {
2294         struct fdesc *fp, *next;
2295         int i;
2296
2297         for (i = 0; i < HASHSIZE; i++) {
2298                 for (fp = ftable[i]; fp != NULL; fp = fp->next) {
2299 #ifdef REALLYMEAN
2300                         /* making this the default breaks old code. sigh. */
2301                         if (fp->defined == 0) {
2302                                 error(
2303                 "function `%s' called but never defined", fp->name);
2304                                 errcount++;
2305                         }
2306 #else
2307                         if (do_lint && fp->defined == 0)
2308                                 warning(
2309                 "function `%s' called but never defined", fp->name);
2310 #endif
2311                         if (do_lint && fp->used == 0) {
2312                                 warning("function `%s' defined but never called",
2313                                         fp->name);
2314                         }
2315                 }
2316         }
2317
2318         /* now let's free all the memory */
2319         for (i = 0; i < HASHSIZE; i++) {
2320                 for (fp = ftable[i]; fp != NULL; fp = next) {
2321                         next = fp->next;
2322                         free(fp->name);
2323                         free(fp);
2324                 }
2325         }
2326 }
2327
2328 /* param_sanity --- look for parameters that are regexp constants */
2329
2330 static void
2331 param_sanity(arglist)
2332 NODE *arglist;
2333 {
2334         NODE *argp, *arg;
2335         int i;
2336
2337         for (i = 1, argp = arglist; argp != NULL; argp = argp->rnode, i++) {
2338                 arg = argp->lnode;
2339                 if (arg->type == Node_regex)
2340                         warning("regexp constant for parameter #%d yields boolean value", i);
2341         }
2342 }
2343
2344 /* variable --- make sure NAME is in the symbol table */
2345
2346 NODE *
2347 variable(name, can_free, type)
2348 char *name;
2349 int can_free;
2350 NODETYPE type;
2351 {
2352         register NODE *r;
2353         static int env_loaded = FALSE;
2354
2355         if (! env_loaded && STREQ(name, "ENVIRON")) {
2356                 load_environ();
2357                 env_loaded = TRUE;
2358         }
2359         if ((r = lookup(name)) == NULL)
2360                 r = install(name, node(Nnull_string, type, (NODE *) NULL));
2361         else if (can_free)
2362                 free(name);
2363         return r;
2364 }
2365
2366 /* mk_rexp --- make a regular expression constant */
2367
2368 static NODE *
2369 mk_rexp(exp)
2370 NODE *exp;
2371 {
2372         NODE *n;
2373
2374         if (exp->type == Node_regex)
2375                 return exp;
2376
2377         getnode(n);
2378         n->type = Node_regex;
2379         n->re_exp = exp;
2380         n->re_text = NULL;
2381         n->re_reg = NULL;
2382         n->re_flags = 0;
2383         n->re_cnt = 1;
2384         return n;
2385 }
2386
2387 /* isnoeffect --- when used as a statement, has no side effects */
2388
2389 /*
2390  * To be completely general, we should recursively walk the parse
2391  * tree, to make sure that all the subexpressions also have no effect.
2392  * Instead, we just weaken the actual warning that's printed, up above
2393  * in the grammar.
2394  */
2395
2396 static int
2397 isnoeffect(type)
2398 NODETYPE type;
2399 {
2400         switch (type) {
2401         case Node_times:
2402         case Node_quotient:
2403         case Node_mod:
2404         case Node_plus:
2405         case Node_minus:
2406         case Node_subscript:
2407         case Node_concat:
2408         case Node_exp:
2409         case Node_unary_minus:
2410         case Node_field_spec:
2411         case Node_and:
2412         case Node_or:
2413         case Node_equal:
2414         case Node_notequal:
2415         case Node_less:
2416         case Node_greater:
2417         case Node_leq:
2418         case Node_geq:
2419         case Node_match:
2420         case Node_nomatch:
2421         case Node_not:
2422         case Node_val:
2423         case Node_in_array:
2424         case Node_NF:
2425         case Node_NR:
2426         case Node_FNR:
2427         case Node_FS:
2428         case Node_RS:
2429         case Node_FIELDWIDTHS:
2430         case Node_IGNORECASE:
2431         case Node_OFS:
2432         case Node_ORS:
2433         case Node_OFMT:
2434         case Node_CONVFMT:
2435                 return TRUE;
2436         default:
2437                 break;  /* keeps gcc -Wall happy */
2438         }
2439
2440         return FALSE;
2441 }
2442
2443 /* isassignable --- can this node be assigned to? */
2444
2445 static int
2446 isassignable(n)
2447 register NODE *n;
2448 {
2449         switch (n->type) {
2450         case Node_var:
2451         case Node_FIELDWIDTHS:
2452         case Node_RS:
2453         case Node_FS:
2454         case Node_FNR:
2455         case Node_NR:
2456         case Node_NF:
2457         case Node_IGNORECASE:
2458         case Node_OFMT:
2459         case Node_CONVFMT:
2460         case Node_ORS:
2461         case Node_OFS:
2462         case Node_field_spec:
2463         case Node_subscript:
2464                 return TRUE;
2465         case Node_param_list:
2466                 return ((n->flags & FUNC) == 0);  /* ok if not func name */
2467         default:
2468                 break;  /* keeps gcc -Wall happy */
2469         }
2470         return FALSE;
2471 }
2472
2473 /* for debugging */
2474 NODE *
2475 stopme(tree)
2476 NODE *tree;
2477 {
2478         return tmp_number((AWKNUM) 0.0);
2479 }