~vcs-imports/gawk/master

« back to all changes in this revision

Viewing changes to awk.y

  • Committer: Arnold D. Robbins
  • Date: 2010-07-16 08:58:26 UTC
  • Revision ID: git-v1:765c7494b3dac62207e6cd57fb839997e237f292
Moving to 2.13.2.

Show diffs side-by-side

added added

removed removed

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