2 * awk.y --- yacc/bison parser
6 * Copyright (C) 1986, 1988, 1989, 1991-2000 the Free Software Foundation, Inc.
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Programming Language.
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.
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.
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
34 #define DONT_FREE FALSE
36 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
37 static void yyerror(const char *m, ...) ;
39 static void yyerror(); /* va_alist */
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));
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));
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 */
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;
77 #define HASHSIZE 1021 /* this constant only used here */
78 NODE *variables[HASHSIZE];
81 extern int sourceline;
82 extern struct src *srcfiles;
85 extern NODE *begin_block;
86 extern NODE *end_block;
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
112 %token <sval> FUNC_CALL NAME REGEXP
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
125 /* these are just yylval numbers */
127 /* Lowest to highest */
134 %left FUNC_CALL LEX_BUILTIN LEX_LENGTH
137 %nonassoc RELOP '<' '>' '|' APPEND_OP
139 %left YSTRING YNUMBER
144 %left INCREMENT DECREMENT
150 : opt_nls program opt_nls
152 expression_value = $2;
167 /* add the rule to the tail of list */
174 if ($1->type != Node_rule_list)
175 $1 = node($1, Node_rule_list,
177 $$ = append_right($1,
178 node($2, Node_rule_list, (NODE *) NULL));
182 | error { $$ = NULL; }
183 | program error { $$ = NULL; }
184 | /* empty */ { $$ = NULL; }
188 : LEX_BEGIN { io_allowed = FALSE; }
191 if (begin_block != NULL) {
192 if (begin_block->type != Node_rule_list)
193 begin_block = node(begin_block, Node_rule_list,
195 (void) append_right(begin_block, node(
196 node((NODE *) NULL, Node_rule_node, $3),
197 Node_rule_list, (NODE *) NULL) );
199 begin_block = node((NODE *) NULL, Node_rule_node, $3);
204 | LEX_END { io_allowed = FALSE; }
207 if (end_block != NULL) {
208 if (end_block->type != Node_rule_list)
209 end_block = node(end_block, Node_rule_list,
211 (void) append_right (end_block, node(
212 node((NODE *) NULL, Node_rule_node, $3),
213 Node_rule_list, (NODE *) NULL));
215 end_block = node((NODE *) NULL, Node_rule_node, $3);
220 | LEX_BEGIN statement_term
222 warning("BEGIN blocks must have an action part");
226 | LEX_END statement_term
228 warning("END blocks must have an action part");
233 { $$ = node($1, Node_rule_node, $2); yyerrok; }
235 { $$ = node((NODE *) NULL, Node_rule_node, $1); yyerrok; }
236 | pattern statement_term
240 node(node(node(make_number(0.0),
243 Node_expression_list,
249 | function_prologue function_body
251 func_install($1, $2);
264 yyerror("%s() is a built-in function, it cannot be redefined",
281 func_name '(' opt_param_list r_paren opt_nls
287 $$ = append_right(t, $5);
289 /* check for duplicate parameter names */
296 : l_brace statements r_brace opt_semi
301 | l_brace r_brace opt_semi opt_nls
303 $$ = node((NODE *) NULL, Node_K_return, (NODE *) NULL);
313 { $$ = mkrangenode(node($1, Node_cond_pair, $3)); }
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.
329 n->type = Node_regex;
331 n->re_exp = make_string($3, len);
332 n->re_reg = make_regexp($3, len, FALSE, TRUE);
341 : l_brace statements r_brace opt_semi opt_nls
343 | l_brace r_brace opt_semi opt_nls
351 if (do_lint && isnoeffect($$->type))
352 warning("statement may have no effect");
354 | statements statement
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));
378 | l_brace statements r_brace
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
389 * Efficiency hack. Recognize the special case of
394 * and treat it as if it were
398 * Check that the body is a `delete a[i]' statement,
399 * and that both the loop var and array names match.
401 if ($8->type == Node_K_delete
403 && strcmp($3, $8->rnode->var_value->vname) == 0
404 && strcmp($5, $8->lnode->vname) == 0) {
405 $8->type = Node_K_delete_loop;
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)));
413 | LEX_FOR '(' opt_exp semi exp semi opt_exp r_paren opt_nls statement
415 $$ = node($10, Node_K_for, (NODE *) make_for_loop($3, $5, $7));
417 | LEX_FOR '(' opt_exp semi semi opt_exp r_paren opt_nls statement
419 $$ = node($9, Node_K_for,
420 (NODE *) make_for_loop($3, (NODE *) NULL, $6));
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
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
432 if ($1 == Node_K_print && $2 == NULL) {
433 static int warned = FALSE;
435 $2 = node(node(make_number(0.0),
438 Node_expression_list,
441 if (do_lint && ! io_allowed && ! warned) {
444 "plain `print' in BEGIN or END rule should probably be `print \"\"'");
448 $$ = node($2, $1, $3);
450 | LEX_NEXT opt_exp statement_term
454 if ($2 == lookup("file")) {
455 static int warned = FALSE;
459 warning("`next file' is obsolete; use `nextfile'");
462 warning("`next file' is a gawk extension");
463 if (do_traditional) {
465 * can't use yyerror, since may have overshot
469 error("`next file' is a gawk extension");
474 error("`next file' used in BEGIN or END action");
476 type = Node_K_nextfile;
479 error("illegal expression after `next'");
480 type = Node_K_next; /* sanity */
484 yyerror("`next' used in BEGIN or END action");
487 $$ = node((NODE *) NULL, type, (NODE *) NULL);
489 | LEX_NEXTFILE statement_term
492 warning("`nextfile' is a gawk extension");
493 if (do_traditional) {
495 * can't use yyerror, since may have overshot
499 error("`nextfile' is a gawk extension");
504 error("`nextfile' used in BEGIN or END action");
506 $$ = node((NODE *) NULL, Node_K_nextfile, (NODE *) NULL);
508 | LEX_EXIT opt_exp statement_term
509 { $$ = node($2, Node_K_exit, (NODE *) NULL); }
513 yyerror("`return' used outside function context");
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
522 warning("`delete array' is a gawk extension");
523 if (do_traditional) {
525 * can't use yyerror, since may have overshot
529 error("`delete array' is a gawk extension");
531 $$ = node(variable($2, CAN_FREE, Node_var_array), Node_K_delete, (NODE *) NULL);
545 : LEX_IF '(' exp r_paren opt_nls statement
547 $$ = node($3, Node_K_if,
548 node($6, Node_if_branches, (NODE *) NULL));
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)); }
558 { want_assign = FALSE; }
571 { $$ = node($2, Node_redirect_input, (NODE *) NULL); }
578 { $$ = node($2, Node_redirect_output, (NODE *) NULL); }
580 { $$ = node($2, Node_redirect_append, (NODE *) NULL); }
582 { $$ = node($2, Node_redirect_pipe, (NODE *) NULL); }
594 { $$ = make_param($1); }
595 | param_list comma NAME
596 { $$ = append_right($1, make_param($3)); yyerrok; }
601 | param_list comma error
605 /* optional expression, as in for loop */
622 { $$ = node($1, Node_expression_list, (NODE *) NULL); }
623 | rexpression_list comma rexp
625 $$ = append_right($1,
626 node($3, Node_expression_list, (NODE *) NULL));
631 | rexpression_list error
633 | rexpression_list error rexp
635 | rexpression_list comma error
648 { $$ = node($1, Node_expression_list, (NODE *) NULL); }
649 | expression_list comma exp
651 $$ = append_right($1,
652 node($3, Node_expression_list, (NODE *) NULL));
657 | expression_list error
659 | expression_list error exp
661 | expression_list comma error
665 /* Expressions, not including the comma operator. */
666 exp : variable ASSIGNOP
667 { want_assign = FALSE; }
670 if (do_lint && $4->type == Node_regex)
671 warning("Regular expression on left of assignment.");
672 $$ = node($1, $2, $4);
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
678 $$ = node($4, Node_K_getline,
679 node($1, Node_redirect_pipein, (NODE *) NULL));
681 | LEX_GETLINE opt_variable input_redir
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);
688 { $$ = node($1, Node_and, $3); }
690 { $$ = node($1, Node_or, $3); }
693 if ($1->type == Node_regex)
694 warning("Regular expression on left of MATCH operator.");
695 $$ = node($1, $2, mk_rexp($3));
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");
707 | '!' regexp %prec UNARY
709 $$ = node(node(make_number(0.0),
716 { $$ = node(variable($3, CAN_FREE, Node_var_array), Node_in_array, $1); }
719 if (do_lint && $3->type == Node_regex)
720 warning("Regular expression on left of comparison.");
721 $$ = node($1, $2, $3);
724 { $$ = node($1, Node_less, $3); }
726 { $$ = node($1, Node_greater, $3); }
727 | exp '?' exp ':' exp
728 { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
731 | exp simp_exp %prec CONCAT_OP
732 { $$ = node($1, Node_concat, $2); }
737 { want_assign = FALSE; }
739 { $$ = node($1, $2, $4); }
741 { $$ = node($1, Node_and, $3); }
743 { $$ = node($1, Node_or, $3); }
744 | LEX_GETLINE opt_variable input_redir
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);
752 | '!' regexp %prec UNARY
753 { $$ = node((NODE *) NULL, Node_nomatch, $2); }
755 { $$ = node($1, $2, mk_rexp($3)); }
757 { $$ = node(variable($3, CAN_FREE, Node_var_array), Node_in_array, $1); }
759 { $$ = node($1, $2, $3); }
760 | rexp '?' rexp ':' rexp
761 { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
764 | rexp simp_exp %prec CONCAT_OP
765 { $$ = node($1, Node_concat, $2); }
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); }
784 { $$ = node($1, Node_postincrement, (NODE *) NULL); }
786 { $$ = node($1, Node_postdecrement, (NODE *) NULL); }
790 : '!' simp_exp %prec UNARY
791 { $$ = node($2, Node_not, (NODE *) NULL); }
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); }
802 warning("call of `length' without parentheses is not portable");
803 $$ = snode((NODE *) NULL, Node_builtin, (int) $1);
805 warning("call of `length' without parentheses is deprecated by POSIX");
807 | FUNC_CALL '(' opt_expression_list r_paren
809 $$ = node($3, Node_func_call, make_string($1, strlen($1)));
810 func_use($1, FUNC_USE);
816 { $$ = node($2, Node_preincrement, (NODE *) NULL); }
818 { $$ = node($2, Node_predecrement, (NODE *) NULL); }
824 | '-' simp_exp %prec UNARY
826 if ($2->type == Node_val) {
827 $2->numbr = -(force_number($2));
830 $$ = node($2, Node_unary_minus, (NODE *) NULL);
832 | '+' simp_exp %prec UNARY
836 * POSIX semantics: force a conversion to numeric type
838 $$ = node (make_number(0.0), Node_plus, $2);
851 { $$ = variable($1, CAN_FREE, Node_var); }
852 | NAME '[' expression_list ']'
855 fatal("invalid subscript expression");
856 } else if ($3->rnode == NULL) {
857 $$ = node(variable($1, CAN_FREE, Node_var_array), Node_subscript, $3->lnode);
860 $$ = node(variable($1, CAN_FREE, Node_var_array), Node_subscript, $3);
862 | '$' non_post_simp_exp
863 { $$ = node($2, Node_field_spec, (NODE *) NULL); }
871 : '}' opt_nls { yyerrok; }
884 : ';' { yyerrok; want_assign = FALSE; }
887 comma : ',' opt_nls { yyerrok; }
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 */
908 /* Tokentab is sorted ascii ascending order, so it can be binary searched. */
909 /* Function pointers come from declarations in awk.h. */
911 static struct token tokentab[] = {
912 {"BEGIN", Node_illegal, LEX_BEGIN, 0, 0},
913 {"END", Node_illegal, LEX_END, 0, 0},
915 {"adump", Node_builtin, LEX_BUILTIN, GAWKX|A(1), do_adump},
918 {"and", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_and},
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},
924 {"compl", Node_builtin, LEX_BUILTIN, GAWKX|A(1), do_compl},
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},
947 {"lshift", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift},
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},
953 {"or", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_or},
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},
960 {"rshift", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift},
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},
968 {"stopme", Node_builtin, LEX_BUILTIN, GAWKX|A(0), stopme},
970 {"strftime", Node_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2), do_strftime},
972 {"strtonum", Node_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum},
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},
982 {"xor", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_xor},
986 /* yyerror --- print a syntax error message, show where */
988 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
990 yyerror(const char *m, ...)
999 const char *mesg = NULL;
1000 register char *bp, *cp;
1003 static char end_of_file_line[] = "(END OF FILE)";
1006 /* Find the current line in the input file */
1007 if (lexptr && lexeme) {
1008 if (thisline == NULL) {
1012 mesg = "unexpected newline";
1014 for (; cp != lexptr_begin && *cp != '\n'; --cp)
1020 /* NL isn't guaranteed */
1022 while (bp < lexend && *bp && *bp != '\n')
1025 thisline = end_of_file_line;
1026 bp = thisline + strlen(thisline);
1028 msg("%.*s", (int) (bp - thisline), thisline);
1030 cp = buf + sizeof(buf) - 24; /* 24 more than longest msg. input */
1031 if (lexptr != NULL) {
1033 while (bp < cp && scan < lexeme)
1034 if (*scan++ == '\t')
1041 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
1048 mesg = va_arg(args, char *);
1055 /* get_src_buf --- read the next buffer of source program */
1060 static int samefile = FALSE;
1061 static int nextfile = 0;
1062 static char *buf = NULL;
1065 register char *scan;
1067 static int did_newline = FALSE;
1071 # define SLOP 128 /* enough space to hold most source lines */
1075 if (nextfile > numfiles)
1078 if (srcfiles[nextfile].stype == CMDLINE) {
1080 len = strlen(srcfiles[nextfile].val);
1083 * Yet Another Special case:
1084 * gawk '' /path/name
1087 static int warned = FALSE;
1089 if (do_lint && ! warned) {
1091 warning("empty program text on command line");
1097 lexptr = lexptr_begin = srcfiles[nextfile].val;
1098 lexend = lexptr + len;
1099 } else if (! did_newline && *(lexptr-1) != '\n') {
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.
1108 offset = lexptr - lexeme;
1109 for (scan = lexeme; scan > lexptr_begin; scan--)
1110 if (*scan == '\n') {
1114 len = lexptr - scan;
1115 emalloc(buf, char *, len+1, "get_src_buf");
1116 memcpy(buf, scan, len);
1120 lexeme = lexptr - offset;
1122 lexend = lexptr + 1;
1125 lexeme = lexptr = lexptr_begin = NULL;
1127 if (lexptr == NULL && ++nextfile <= numfiles)
1132 source = srcfiles[nextfile].val;
1133 if (source == NULL) {
1139 return lexeme = lexptr = lexptr_begin = NULL;
1141 fd = pathopen(source);
1142 if (fd <= INVALID_HANDLE) {
1145 /* suppress file name and line no. in error mesg */
1148 fatal("can't open source file \"%s\" for reading (%s)",
1149 in, strerror(errno));
1151 len = optimal_bufsize(fd, & sbuf);
1155 emalloc(buf, char *, len + SLOP, "get_src_buf");
1156 lexptr_begin = buf + SLOP;
1161 * Here, we retain the current source line (up to length SLOP)
1162 * in the beginning of the buffer that was overallocated above
1167 offset = lexptr - lexeme;
1168 for (scan = lexeme; scan > lexptr_begin; scan--)
1169 if (*scan == '\n') {
1173 linelen = lexptr - scan;
1176 thisline = buf + SLOP - linelen;
1177 memcpy(thisline, scan, linelen);
1178 lexeme = buf + SLOP - offset;
1179 lexptr_begin = thisline;
1181 n = read(fd, buf + SLOP, len);
1183 fatal("can't read sourcefile \"%s\" (%s)",
1184 source, strerror(errno));
1187 static int warned = FALSE;
1189 if (do_lint && ! warned) {
1191 warning("source file `%s' is empty", source);
1194 if (fileno(stdin) != fd) /* safety */
1203 lexptr = buf + SLOP;
1204 lexend = lexptr + n;
1208 /* tokadd --- add a character to the token buffer */
1210 #define tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok)
1212 /* tokexpand --- grow the token buffer */
1217 static int toksize = 60;
1220 tokoffset = tok - tokstart;
1222 if (tokstart != NULL)
1223 erealloc(tokstart, char *, toksize, "tokexpand");
1225 emalloc(tokstart, char *, toksize, "tokexpand");
1226 tokend = tokstart + toksize;
1227 tok = tokstart + tokoffset;
1231 /* nextc --- get the next input character */
1239 if (lexptr && lexptr < lexend)
1240 c = (int) (unsigned char) *lexptr++;
1241 else if (get_src_buf())
1242 c = (int) (unsigned char) *lexptr++;
1249 #define nextc() ((lexptr && lexptr < lexend) ? \
1250 ((int) (unsigned char) *lexptr++) : \
1251 (get_src_buf() ? ((int) (unsigned char) *lexptr++) : EOF) \
1255 /* pushback --- push a character back on the input */
1257 #define pushback() (lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr)
1259 /* allow_newline --- allow newline after &&, ||, ? and : */
1271 while ((c = nextc()) != '\n' && c != EOF)
1285 /* yylex --- Read the input and turn it into tokens. */
1291 int seen_e = FALSE; /* These are for numbers */
1292 int seen_point = FALSE;
1293 int esc_seen; /* for literal strings */
1295 static int did_newline = FALSE;
1297 static int lasttok = 0, eof_warned = FALSE;
1300 if (nextc() == EOF) {
1301 if (lasttok != NEWLINE) {
1303 if (do_lint && ! eof_warned) {
1304 warning("source file does not end in newline");
1307 return NEWLINE; /* fake it */
1314 * added for OS/2's extproc feature of cmd.exe
1315 * (like #! in BSD sh)
1317 if (strncasecmp(lexptr, "extproc ", 8) == 0) {
1318 while (*lexptr && *lexptr != '\n')
1325 int in_brack = 0; /* count brackets, [[:alnum:]] allowed */
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.
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.
1340 * The code for \ handles \[ and \].
1343 want_regexp = FALSE;
1349 /* one day check for `.' and `=' too */
1350 if ((c1 = nextc()) == ':' || in_brack == 0)
1355 if (tokstart[0] == '['
1356 && (tok == tokstart + 1
1357 || (tok == tokstart + 2
1358 && tokstart[1] == '^')))
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') {
1376 case '/': /* end of the regexp */
1382 yylval.sval = tokstart;
1383 return lasttok = REGEXP;
1386 yyerror("unterminated regexp");
1387 return lasttok = REGEXP; /* kludge */
1389 yyerror("unterminated regexp at end of file");
1390 return lasttok = REGEXP; /* kludge */
1396 while ((c = nextc()) == ' ' || c == '\t')
1399 lexeme = lexptr ? lexptr - 1 : lexptr;
1402 yylval.nodetypeval = Node_illegal;
1406 if (lasttok != NEWLINE) {
1408 if (do_lint && ! eof_warned) {
1409 warning("source file does not end in newline");
1412 return NEWLINE; /* fake it */
1418 return lasttok = NEWLINE;
1420 case '#': /* it's a comment */
1421 while ((c = nextc()) != '\n') {
1423 if (lasttok != NEWLINE) {
1425 if (do_lint && ! eof_warned) {
1427 "source file does not end in newline");
1430 return NEWLINE; /* fake it */
1436 return lasttok = NEWLINE;
1439 #ifdef RELAXED_CONTINUATION
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.
1446 if (! do_traditional) {
1447 /* strip trailing white-space and/or comment */
1448 while ((c = nextc()) == ' ' || c == '\t')
1453 "use of `\\ #...' line continuation is not portable");
1454 while ((c = nextc()) != '\n')
1460 #endif /* RELAXED_CONTINUATION */
1461 if (nextc() == '\n') {
1465 yyerror("backslash not last character on line");
1472 return lasttok = '$';
1484 want_assign = FALSE;
1491 if ((c = nextc()) == '=') {
1492 yylval.nodetypeval = Node_assign_times;
1493 return lasttok = ASSIGNOP;
1494 } else if (do_posix) {
1496 return lasttok = '*';
1497 } else if (c == '*') {
1498 /* make ** and **= aliases for ^ and ^= */
1499 static int did_warn_op = FALSE, did_warn_assgn = FALSE;
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");
1507 yylval.nodetypeval = Node_assign_exp;
1511 if (do_lint && ! did_warn_op) {
1513 warning("** is not allowed by POSIX");
1514 warning("operator `**' is not supported in old awk");
1516 return lasttok = '^';
1520 return lasttok = '*';
1524 if (nextc() == '=') {
1525 yylval.nodetypeval = Node_assign_quotient;
1526 return lasttok = ASSIGNOP;
1530 return lasttok = '/';
1533 if (nextc() == '=') {
1534 yylval.nodetypeval = Node_assign_mod;
1535 return lasttok = ASSIGNOP;
1538 return lasttok = '%';
1542 static int did_warn_op = FALSE, did_warn_assgn = FALSE;
1544 if (nextc() == '=') {
1545 if (do_lint && ! did_warn_assgn) {
1546 did_warn_assgn = TRUE;
1547 warning("operator `^=' is not supported in old awk");
1549 yylval.nodetypeval = Node_assign_exp;
1550 return lasttok = ASSIGNOP;
1553 if (do_lint && ! did_warn_op) {
1555 warning("operator `^' is not supported in old awk");
1557 return lasttok = '^';
1561 if ((c = nextc()) == '=') {
1562 yylval.nodetypeval = Node_assign_plus;
1563 return lasttok = ASSIGNOP;
1566 return lasttok = INCREMENT;
1568 return lasttok = '+';
1571 if ((c = nextc()) == '=') {
1572 yylval.nodetypeval = Node_notequal;
1573 return lasttok = RELOP;
1576 yylval.nodetypeval = Node_nomatch;
1577 want_assign = FALSE;
1578 return lasttok = MATCHOP;
1581 return lasttok = '!';
1584 if (nextc() == '=') {
1585 yylval.nodetypeval = Node_leq;
1586 return lasttok = RELOP;
1588 yylval.nodetypeval = Node_less;
1590 return lasttok = '<';
1593 if (nextc() == '=') {
1594 yylval.nodetypeval = Node_equal;
1595 return lasttok = RELOP;
1597 yylval.nodetypeval = Node_assign;
1599 return lasttok = ASSIGNOP;
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;
1609 yylval.nodetypeval = Node_greater;
1611 return lasttok = '>';
1614 yylval.nodetypeval = Node_match;
1615 want_assign = FALSE;
1616 return lasttok = MATCHOP;
1620 * Added did newline stuff. Easier than
1621 * hacking the grammar.
1624 did_newline = FALSE;
1628 --lexptr; /* pick up } next time */
1629 return lasttok = NEWLINE;
1633 while ((c = nextc()) != '"') {
1636 yyerror("unterminated string");
1650 yyerror("unterminated string");
1655 yylval.nodeval = make_str_node(tokstart,
1656 tok - tokstart, esc_seen ? SCAN : 0);
1657 yylval.nodeval->flags |= PERM;
1658 return lasttok = YSTRING;
1661 if ((c = nextc()) == '=') {
1662 yylval.nodetypeval = Node_assign_minus;
1663 return lasttok = ASSIGNOP;
1666 return lasttok = DECREMENT;
1668 return lasttok = '-';
1674 return lasttok = '.';
1690 int gotnumber = FALSE;
1699 if (tok == tokstart + 2)
1719 if ((c = nextc()) == '-' || c == '+')
1735 if (do_traditional || ! inhex)
1760 else if (do_lint && ! eof_warned) {
1761 warning("source file does not end in newline");
1766 if (! do_traditional && isnondecimal(tokstart))
1767 yylval.nodeval = make_number(nondec2awknum(tokstart, strlen(tokstart)));
1770 yylval.nodeval = make_number(atof(tokstart));
1771 yylval.nodeval->flags |= PERM;
1772 return lasttok = YNUMBER;
1775 if ((c = nextc()) == '&') {
1776 yylval.nodetypeval = Node_and;
1778 want_assign = FALSE;
1779 return lasttok = LEX_AND;
1782 return lasttok = '&';
1785 if ((c = nextc()) == '|') {
1786 yylval.nodetypeval = Node_or;
1788 want_assign = FALSE;
1789 return lasttok = LEX_OR;
1792 return lasttok = '|';
1795 if (c != '_' && ! isalpha(c)) {
1796 yyerror("Invalid char '%c' in expression\n", c);
1800 /* it's some type of name-type-thing. Find its length. */
1802 while (is_identchar(c)) {
1807 emalloc(tokkey, char *, tok - tokstart, "yylex");
1808 memcpy(tokkey, tokstart, tok - tokstart);
1811 else if (do_lint && ! eof_warned) {
1812 warning("source file does not end in newline");
1816 /* See if it is a special token. */
1818 high = (sizeof(tokentab) / sizeof(tokentab[0])) - 1;
1819 while (low <= high) {
1822 mid = (low + high) / 2;
1823 c = *tokstart - tokentab[mid].operator[0];
1824 i = c ? c : strcmp(tokstart, tokentab[mid].operator);
1826 if (i < 0) /* token < mid */
1828 else if (i > 0) /* token > mid */
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);
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)))
1848 if (tokentab[mid].class == LEX_BUILTIN
1849 || tokentab[mid].class == LEX_LENGTH
1853 yylval.nodetypeval = tokentab[mid].value;
1856 return lasttok = tokentab[mid].class;
1860 yylval.sval = tokkey;
1862 return lasttok = FUNC_CALL;
1865 return lasttok = NAME;
1869 /* node_common --- common code for allocating a new node */
1880 /* if lookahead is NL, lineno is 1 too high */
1881 if (lexeme && *lexeme == '\n')
1882 r->source_line = sourceline - 1;
1884 r->source_line = sourceline;
1885 r->source_file = source;
1889 /* node --- allocates a node with defined lnode and rnode. */
1892 node(left, op, right)
1898 r = node_common(op);
1904 /* snode --- allocate a node with defined subnode and proc for builtin
1905 functions. Checks for arg. count and supplies defaults where
1909 snode(subn, op, idx)
1919 r = node_common(op);
1921 /* traverse expression list to see how many args. given */
1922 for (n = subn; n != NULL; n = n->rnode) {
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');
1934 r->proc = tokentab[idx].ptr;
1936 /* special case processing for a few builtins */
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.
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,
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);
1953 append_right(subn, node(node(make_number(0.0),
1956 Node_expression_list,
1958 else if (subn->rnode->rnode->lnode->type == Node_val) {
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);
1968 append_right(subn, node(node(make_number(0.0),
1971 Node_expression_list,
1973 } else if (r->proc == do_split) {
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);
1981 subn->rnode->rnode->lnode->re_flags |= FS_DFLT;
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().
2003 r->type = Node_line_range;
2004 r->condpair = cpair;
2005 r->triggered = FALSE;
2009 /* make_for_loop --- build a for loop */
2012 make_for_loop(init, cond, incr)
2013 NODE *init, *cond, *incr;
2015 register FOR_LOOP_HEADER *r;
2018 emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop");
2020 n->type = Node_illegal;
2024 n->sub.nodep.r.hd = r;
2028 /* dup_parms --- return TRUE if there are duplicate parameters */
2035 char *fname, **names;
2036 int count, i, j, dups;
2039 if (func == NULL) /* error earlier */
2042 fname = func->param;
2043 count = func->param_cnt;
2044 params = func->rnode;
2046 if (count == 0) /* no args, no problem */
2049 if (params == NULL) /* error earlier */
2052 emalloc(names, char **, count * sizeof(char *), "dup_parms");
2055 for (np = params; np != NULL; np = np->rnode) {
2056 if (np->param == NULL) { /* error earlier, give up, go home */
2060 names[i++] = np->param;
2064 for (i = 1; i < count; i++) {
2065 for (j = 0; j < i; j++) {
2066 if (strcmp(names[i], names[j]) == 0) {
2069 "function `%s': parameter #%d, `%s', duplicates parameter #%d",
2070 fname, i+1, names[j], j+1);
2076 return (dups > 0 ? TRUE : FALSE);
2081 * Install a name in the symbol table, even if it is already there.
2082 * Caller must check against redefinition if that is desired.
2086 install(name, value)
2091 register size_t len;
2092 register int bucket;
2095 bucket = hash(name, len, (unsigned long) HASHSIZE);
2097 hp->type = Node_hashnode;
2098 hp->hnext = variables[bucket];
2099 variables[bucket] = hp;
2103 hp->hvalue->vname = name;
2107 /* lookup --- find the most recent hash node for name installed by install */
2113 register NODE *bucket;
2114 register size_t len;
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;
2127 * Add new to the rightmost branch of LIST. This uses n^2 time, so we make
2128 * a simple attempt at optimizing it.
2132 append_right(list, new)
2135 register NODE *oldlist;
2136 static NODE *savefront = NULL, *savetail = NULL;
2138 if (list == NULL || new == NULL)
2142 if (savefront == oldlist) {
2143 savetail = savetail->rnode = new;
2146 savefront = oldlist;
2147 while (list->rnode != NULL)
2149 savetail = list->rnode = new;
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
2161 func_install(params, def)
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",
2175 pop_params(params->rnode);
2176 pop_var(params, FALSE);
2177 r = lookup(params->param);
2179 fatal("function name `%s' previously defined", params->param);
2181 (void) install(params->param, node(params, Node_func, def));
2183 func_use(params->param, FUNC_DEFINE);
2186 /* pop_var --- remove a variable from the symbol table */
2193 register NODE *bucket, **save;
2194 register size_t len;
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;
2208 save = &(bucket->hnext);
2212 /* pop_params --- remove list of function parameters from symbol table */
2215 * pop parameters out of the symbol table. do this in reverse order to
2216 * avoid reading freed memory if there were duplicated parameters.
2224 pop_params(params->rnode);
2225 pop_var(params, TRUE);
2228 /* make_param --- make NAME into a function parameter */
2237 r->type = Node_param_list;
2240 r->param_cnt = param_counter++;
2241 return (install(name, r));
2244 static struct fdesc {
2249 } *ftable[HASHSIZE];
2251 /* func_use --- track uses and definitions of functions */
2263 ind = hash(name, len, HASHSIZE);
2265 for (fp = ftable[ind]; fp != NULL; fp = fp->next) {
2266 if (strcmp(fp->name, name) == 0) {
2267 if (how == FUNC_DEFINE)
2275 /* not in the table, fall through to allocate a new one */
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)
2285 fp->next = ftable[ind];
2289 /* check_funcs --- verify functions that are called but not defined */
2294 struct fdesc *fp, *next;
2297 for (i = 0; i < HASHSIZE; i++) {
2298 for (fp = ftable[i]; fp != NULL; fp = fp->next) {
2300 /* making this the default breaks old code. sigh. */
2301 if (fp->defined == 0) {
2303 "function `%s' called but never defined", fp->name);
2307 if (do_lint && fp->defined == 0)
2309 "function `%s' called but never defined", fp->name);
2311 if (do_lint && fp->used == 0) {
2312 warning("function `%s' defined but never called",
2318 /* now let's free all the memory */
2319 for (i = 0; i < HASHSIZE; i++) {
2320 for (fp = ftable[i]; fp != NULL; fp = next) {
2328 /* param_sanity --- look for parameters that are regexp constants */
2331 param_sanity(arglist)
2337 for (i = 1, argp = arglist; argp != NULL; argp = argp->rnode, i++) {
2339 if (arg->type == Node_regex)
2340 warning("regexp constant for parameter #%d yields boolean value", i);
2344 /* variable --- make sure NAME is in the symbol table */
2347 variable(name, can_free, type)
2353 static int env_loaded = FALSE;
2355 if (! env_loaded && STREQ(name, "ENVIRON")) {
2359 if ((r = lookup(name)) == NULL)
2360 r = install(name, node(Nnull_string, type, (NODE *) NULL));
2366 /* mk_rexp --- make a regular expression constant */
2374 if (exp->type == Node_regex)
2378 n->type = Node_regex;
2387 /* isnoeffect --- when used as a statement, has no side effects */
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
2406 case Node_subscript:
2409 case Node_unary_minus:
2410 case Node_field_spec:
2429 case Node_FIELDWIDTHS:
2430 case Node_IGNORECASE:
2437 break; /* keeps gcc -Wall happy */
2443 /* isassignable --- can this node be assigned to? */
2451 case Node_FIELDWIDTHS:
2457 case Node_IGNORECASE:
2462 case Node_field_spec:
2463 case Node_subscript:
2465 case Node_param_list:
2466 return ((n->flags & FUNC) == 0); /* ok if not func name */
2468 break; /* keeps gcc -Wall happy */
2478 return tmp_number((AWKNUM) 0.0);