~vcs-imports/gawk/master

40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1
/*
277.1.134 by Arnold D. Robbins
Minor cleanups in debugger.
2
 * command.y - yacc/bison parser for debugger commands.
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
3
 */
4
5
/* 
159 by Arnold D. Robbins
Update copyrights.
6
 * Copyright (C) 2004, 2010, 2011 the Free Software Foundation, Inc.
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
7
 * 
8
 * This file is part of GAWK, the GNU implementation of the
9
 * AWK Programming Language.
10
 * 
11
 * GAWK is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 2 of the License, or
14
 * (at your option) any later version.
15
 * 
16
 * GAWK is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 * 
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, write to the Free Software
23
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
24
 */
25
26
%{
27
#include "awk.h"
28
#include "cmd.h"
29
30
#if 0
31
#define YYDEBUG 12
32
int yydebug = 2;
33
#endif
34
35
static int yylex(void);
36
static void yyerror(const char *mesg, ...);
37
38
static int find_command(const char *token, size_t toklen);
39
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
40
static bool want_nodeval = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
41
277.1.134 by Arnold D. Robbins
Minor cleanups in debugger.
42
static int cmd_idx = -1;		/* index of current command in cmd table */
43
static int repeat_idx = -1;		/* index of last repeatable command in command table */
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
44
static CMDARG *arg_list = NULL;		/* list of arguments */ 
45
static long errcount = 0;
46
static char *lexptr_begin = NULL;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
47
static bool in_commands = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
48
static int num_dim;
49
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
50
static bool in_eval = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
51
static const char start_EVAL[] = "function @eval(){";
52
static const char end_EVAL[] = "}";	
281.1.1 by john haque
Speed/memory performance improvements.
53
static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
54
static char *next_word(char *p, int len, char **endp);
55
static NODE *concat_args(CMDARG *a, int count);
56
57
#ifdef HAVE_LIBREADLINE
58
static void history_expand_line(char **line);
59
static char *command_generator(const char *text, int state);
60
static char *srcfile_generator(const char *text, int state);
61
static char *argument_generator(const char *text, int state);
62
static char *variable_generator(const char *text, int state);
63
extern char *option_generator(const char *text, int state);
64
static int this_cmd = D_illegal;
65
#else
66
#define history_expand_line(p)	/* nothing */
67
static int rl_inhibit_completion;	/* dummy variable */
68
#endif
69
70
struct argtoken {
71
	const char *name;
72
	enum argtype cmd;
73
	enum nametypeval value;
74
};
75
76
/*
77
 * These two should be static, but there are some compilers that
78
 * don't like the static keyword with an empty size. Therefore give
79
 * them names that are less likely to conflict with the rest of gawk.
80
 */
81
#define argtab zz_debug_argtab
82
#define cmdtab zz_debug_cmdtab
83
84
extern struct argtoken argtab[];
85
extern struct cmdtoken cmdtab[];
86
87
static CMDARG *mk_cmdarg(enum argtype type);
88
static void append_cmdarg(CMDARG *arg);
89
static int find_argument(CMDARG *arg);
90
#define YYSTYPE CMDARG *
91
%}
92
93
%token D_BACKTRACE D_BREAK D_CLEAR D_CONTINUE D_DELETE D_DISABLE D_DOWN
94
%token D_ENABLE D_FINISH D_FRAME D_HELP D_IGNORE D_INFO D_LIST
95
%token D_NEXT D_NEXTI D_PRINT D_PRINTF D_QUIT D_RETURN D_RUN D_SET
96
%token D_STEP D_STEPI D_TBREAK D_UP D_UNTIL
97
%token D_DISPLAY D_UNDISPLAY D_WATCH D_UNWATCH
98
%token D_DUMP D_TRACE
99
%token D_INT D_STRING D_NODE D_VARIABLE
100
%token D_OPTION D_COMMANDS D_END D_SILENT D_SOURCE
101
%token D_SAVE D_EVAL D_CONDITION
102
%token D_STATEMENT
103
104
%%
105
106
input
107
	: /* empty */
108
	| input line
109
	  {
110
		cmd_idx = -1;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
111
		want_nodeval = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
112
		if (lexptr_begin != NULL) {
113
			if (input_from_tty && lexptr_begin[0] != '\0')
114
				add_history(lexptr_begin);
115
			efree(lexptr_begin);
116
			lexptr_begin = NULL;
117
		}
118
		if (arg_list != NULL) {
119
			free_cmdarg(arg_list);
120
			arg_list = NULL;
121
		}
122
	  }
123
	;
124
125
line
126
	: nls
127
	| command nls
128
	  {
129
		if (errcount == 0 && cmd_idx >= 0) {
130
			Func_cmd cmdfunc;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
131
			bool terminate = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
132
			CMDARG *args;
133
			int ctype = 0;
134
			
135
			ctype = cmdtab[cmd_idx].type;
136
137
			/* a blank line repeats previous command
138
			 * (list, next, nexti, step, stepi and continue without arguments).
139
			 * save the index in the command table; used in yylex
140
			 */
141
			if ((ctype == D_list
142
					|| ctype == D_next
143
					|| ctype == D_step
144
					|| ctype == D_nexti
145
					|| ctype == D_stepi
146
					|| ctype == D_continue)
147
				&& arg_list == NULL
148
				&& ! in_commands
149
				&& input_from_tty
150
			)
151
				repeat_idx = cmd_idx;
152
			else
153
				repeat_idx = -1;
154
155
			/* call the command handler; reset the globals arg_list, cmd_idx,
156
			 * since this handler could invoke yyparse again.
157
			 * call do_commands for the list of commands in `commands';
158
			 * arg_list isn't freed on return.
159
			 */
160
161
			cmdfunc = cmdtab[cmd_idx].cf_ptr;
162
			if (in_commands)
163
				cmdfunc = do_commands;
164
			cmd_idx = -1;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
165
			want_nodeval = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
166
167
			args = arg_list;
168
			arg_list = NULL;
169
170
			terminate = (*cmdfunc)(args, ctype);
171
			if (! in_commands || ctype == D_commands)
172
				free_cmdarg(args);
173
			if (terminate)
174
				YYACCEPT;
175
		}
176
	  }
177
	| error nls
178
	  {
179
		yyerrok;
180
	  }
181
	;
182
183
control_cmd
184
	: D_CONTINUE
185
	| D_NEXT
186
	| D_NEXTI
187
	| D_STEP
188
	| D_STEPI
189
	;
190
191
d_cmd
192
	: D_UNDISPLAY
193
	| D_UNWATCH
194
	| D_DISABLE
195
	| D_DELETE
196
	;
197
198
frame_cmd
199
	: D_UP
200
	| D_DOWN
201
	| D_BACKTRACE
202
	| D_FRAME
203
	;
204
205
break_cmd
206
	: D_BREAK
207
	| D_TBREAK
208
	;
209
210
/* mid-rule action buried in non-terminal to avoid conflict */
211
set_want_nodeval
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
212
	: { want_nodeval = true; }
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
213
	;
214
215
eval_prologue
216
	: D_EVAL set_want_nodeval opt_param_list nls
217
	  {
218
		if (errcount == 0) {
219
			/* don't free arg_list;	passed on to statement_list
220
			 * non-terminal (empty rule action). See below.
221
			 */
222
			if (input_from_tty) {
277.1.134 by Arnold D. Robbins
Minor cleanups in debugger.
223
				dbg_prompt = eval_prompt;
224
				fprintf(out_fp,
225
		_("Type (g)awk statement(s). End with the command \"end\"\n"));
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
226
				rl_inhibit_completion = 1;
227
			}
228
			cmd_idx = -1;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
229
			in_eval = true;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
230
		}
231
	  }
232
	;
233
234
statement_list
235
	: /* empty */
236
	  {
237
		$$ = append_statement(arg_list, (char *) start_EVAL);
238
		if (read_a_line == read_commands_string)	/* unserializing 'eval' in 'commands' */
239
			$$->a_string[0] = '\0';
240
		free_cmdarg(arg_list);
241
		arg_list = NULL;
242
	  }
243
	| statement_list D_STATEMENT { $$ = append_statement($1, lexptr_begin); } nls
244
	  {
245
		$$ = $3;
246
	  }
247
	;
248
249
eval_cmd
250
	: eval_prologue statement_list D_END
251
	  {
252
		arg_list = append_statement($2, (char *) end_EVAL);
253
		if (read_a_line == read_commands_string) {	/* unserializing 'eval' in 'commands' */
254
			char *str = arg_list->a_string;
255
			size_t len = strlen(str);
256
			assert(len > 2 && str[len - 2] == '}');
257
			str[len - 2] = '\0';
258
		}
259
		if (input_from_tty) {
277.1.134 by Arnold D. Robbins
Minor cleanups in debugger.
260
			dbg_prompt = in_commands ? commands_prompt : dgawk_prompt;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
261
			rl_inhibit_completion = 0;
262
		}
263
		cmd_idx = find_command("eval", 4);
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
264
		in_eval = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
265
	  }
266
	| D_EVAL set_want_nodeval string_node
267
	  {
268
		NODE *n;
269
		CMDARG *arg;
270
		n = $3->a_node;
271
		arg = append_statement(NULL, (char *) start_EVAL);
272
		(void) append_statement(arg, n->stptr);
273
		(void) append_statement(arg, (char *) end_EVAL);
274
		free_cmdarg(arg_list);
275
		arg_list = arg;
276
	  }
277
	;
278
279
command
280
	: D_HELP help_args
281
	| D_QUIT
282
	| D_RUN
283
	| D_FINISH
284
	| control_cmd opt_plus_integer
285
	| frame_cmd opt_integer
286
	  {
287
		if (cmdtab[cmd_idx].class == D_FRAME
288
				&& $2 != NULL && $2->a_int < 0)
289
			yyerror(_("invalid frame number: %d"), $2->a_int);
290
	  }
291
	| D_INFO D_STRING
292
	  {
293
		int idx = find_argument($2);
294
		if (idx < 0)
295
			yyerror(_("info: invalid option - \"%s\""), $2->a_string);
296
		else {
297
			efree($2->a_string);
298
			$2->a_string = NULL;
299
			$2->type = D_argument;
300
			$2->a_argument = argtab[idx].value;
301
		}
302
	  }
303
	| D_IGNORE plus_integer D_INT
304
	| D_ENABLE enable_args
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
305
	| D_PRINT { want_nodeval = true; } print_args
306
	| D_PRINTF { want_nodeval = true; } printf_args
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
307
	| D_LIST list_args
308
	| D_UNTIL location
309
	| D_CLEAR location
310
	| break_cmd break_args 
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
311
	| D_SET { want_nodeval = true; } variable '=' node
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
312
	| D_OPTION option_args
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
313
	| D_RETURN { want_nodeval = true; } opt_node
314
	| D_DISPLAY { want_nodeval = true; } opt_variable
315
	| D_WATCH { want_nodeval = true; } variable condition_exp
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
316
	| d_cmd opt_integer_list
317
	| D_DUMP opt_string
318
	| D_SOURCE D_STRING
319
	  {
320
		if (in_cmd_src($2->a_string))
321
			yyerror(_("source \"%s\": already sourced."), $2->a_string);
322
	  }
323
	| D_SAVE D_STRING
324
	  {
325
		if (! input_from_tty)
326
			yyerror(_("save \"%s\": command not permitted."), $2->a_string);
327
	  }
328
	| D_COMMANDS commands_arg
329
	  {
330
		int type = 0;
331
		int num;
332
333
		if ($2 != NULL)
334
			num = $2->a_int;
335
336
		if (errcount != 0)
337
			;
338
		else if (in_commands)
339
			yyerror(_("Can't use command `commands' for breakpoint/watchpoint commands"));
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
340
		else if ($2 == NULL &&  ! (type = has_break_or_watch_point(&num, true)))
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
341
			yyerror(_("no breakpoint/watchpoint has been set yet"));
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
342
		else if ($2 != NULL && ! (type = has_break_or_watch_point(&num, false)))
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
343
			yyerror(_("invalid breakpoint/watchpoint number"));
344
		if (type) {
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
345
			in_commands = true;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
346
			if (input_from_tty) {
277.1.134 by Arnold D. Robbins
Minor cleanups in debugger.
347
				dbg_prompt = commands_prompt; 
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
348
				fprintf(out_fp, _("Type commands for when %s %d is hit, one per line.\n"),
349
								(type == D_break) ? "breakpoint" : "watchpoint", num);
350
				fprintf(out_fp, _("End with the command \"end\"\n"));
351
			}
352
		}
353
	  }
354
	| D_END
355
	  {
356
		if (! in_commands)
357
			yyerror(_("`end' valid only in command `commands' or `eval'"));
358
		else {
359
			if (input_from_tty)
277.1.134 by Arnold D. Robbins
Minor cleanups in debugger.
360
				dbg_prompt = dgawk_prompt;	
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
361
			in_commands = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
362
		}
363
	  }
364
	| D_SILENT
365
	  {
366
		if (! in_commands)
367
			yyerror(_("`silent' valid only in command `commands'"));
368
	  }
369
	| D_TRACE D_STRING
370
	  {
371
		int idx = find_argument($2);
372
		if (idx < 0)
373
			yyerror(_("trace: invalid option - \"%s\""), $2->a_string);
374
		else {
375
			efree($2->a_string);
376
			$2->a_string = NULL;
377
			$2->type = D_argument;
378
			$2->a_argument = argtab[idx].value;
379
		}
380
	  }
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
381
	| D_CONDITION plus_integer { want_nodeval = true; } condition_exp
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
382
	  {
383
		int type;
384
		int num = $2->a_int;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
385
		type = has_break_or_watch_point(&num, false);
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
386
		if (! type)
387
			yyerror(_("condition: invalid breakpoint/watchpoint number"));
388
	  }
389
	| eval_cmd
390
	  {
391
		if (in_commands) {
392
			/* Prepend command 'eval' to argument list */
393
			CMDARG *arg;
394
			arg = mk_cmdarg(D_string);
395
			arg->a_string = estrdup("eval", 4);
396
			arg->next = arg_list;
397
			arg_list = arg;
398
		}
399
	  }
400
	;
401
402
condition_exp
403
	: opt_string_node
404
	  {
405
		if ($1 != NULL) {
406
			NODE *n = $1->a_node;
407
			$1->type = D_string;
408
			$1->a_string = n->stptr;
409
			freenode(n);
410
		}
411
		$$ = $1;
412
	  }
413
	;
414
415
commands_arg
416
	: opt_plus_integer
417
	| error
418
	  {	$$ = NULL; }
419
	;
420
421
opt_param_list
422
	: /* empty */
423
	  { $$ = NULL; }
424
	| param_list
425
	;
426
427
param_list
428
	: D_VARIABLE
429
	| param_list D_VARIABLE
430
	| param_list ',' D_VARIABLE
431
	| error
432
	  { $$ = NULL; }
433
	;
434
435
opt_string_node
436
	: /* empty */
437
	  { $$ = NULL; }
438
	| string_node
439
	| error
440
	  { $$ = NULL; }
441
	;
442
443
string_node
444
	: D_NODE
445
	  {
446
		NODE *n;
447
		n = $1->a_node;
448
		if ((n->flags & STRING) == 0)
449
			yyerror(_("argument not a string"));
450
	  }
451
	;
452
453
option_args
454
	: /* empty */
455
	  { $$ = NULL; }
456
	| D_STRING
457
	  {
458
		if (find_option($1->a_string) < 0)
459
			yyerror(_("option: invalid parameter - \"%s\""), $1->a_string);
460
 	  }
461
	| D_STRING '=' D_STRING
462
	  {
463
		if (find_option($1->a_string) < 0)
464
			yyerror(_("option: invalid parameter - \"%s\""), $1->a_string);
465
 	  }
466
	;
467
468
func_name
469
	: D_STRING
470
	  {
471
		NODE *n;
472
		n = lookup($1->a_string);
473
		if (n == NULL || n->type != Node_func)
474
			yyerror(_("no such function - \"%s\""), $1->a_string);
475
		else {
476
			$1->type = D_func;
477
			efree($1->a_string);
478
			$1->a_string = NULL;
479
			$1->a_node = n;
480
		}
481
	  }
482
	;
483
484
location
485
	: /* empty */
486
	  { $$ = NULL; }
487
	| plus_integer
488
	| func_name
489
	| D_STRING ':' plus_integer
490
	| D_STRING ':' func_name
491
	;
492
493
break_args
494
	: /* empty */
495
	  { $$ = NULL; }	
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
496
	| plus_integer { want_nodeval = true; } condition_exp
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
497
	| func_name 
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
498
	| D_STRING ':' plus_integer { want_nodeval = true; } condition_exp
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
499
	| D_STRING ':' func_name
500
	;
501
502
opt_variable
503
	: /* empty */
504
	  { $$ = NULL; }
505
	| variable
506
	;
507
508
opt_string
509
	: /* empty */
510
	  { $$ = NULL; }
511
	| D_STRING
512
	;
513
514
opt_node
515
	: /* empty */
516
	  { $$ = NULL; }
517
	| node
518
	;
519
520
help_args
521
	: /* empty */
522
	| D_STRING
523
	;
524
525
enable_args
526
	: opt_integer_list
527
	| D_STRING opt_integer_list
528
	  {
529
		int idx = find_argument($1);
530
		if (idx < 0)
531
			yyerror(_("enable: invalid option - \"%s\""), $1->a_string);
532
		else {
533
			efree($1->a_string);
534
			$1->a_string = NULL;
535
			$1->type = D_argument;
536
			$1->a_argument = argtab[idx].value;
537
		}
538
	  }
539
	;
540
541
print_exp
542
	: variable
543
	| '@' D_VARIABLE
544
	  {
545
		$2->type = D_array;	/* dump all items */
546
		$2->a_count = 0;
547
	  }
548
	| '@' D_VARIABLE subscript_list /* dump sub-array items*/
549
	  {
550
		$2->type = D_array;
551
		$2->a_count = num_dim;
552
	  }
553
	;
554
555
print_args
556
	: print_exp
557
	| print_args print_exp
558
	| print_args ',' print_exp
559
	| error
560
	;
561
562
printf_exp
563
	: D_NODE
564
	| variable
565
	;
566
567
printf_args
568
	: printf_exp
569
	| printf_args ',' printf_exp
570
	| error
571
	;
572
573
list_args
574
	: /* empty */
575
	  { $$ = NULL; }
576
	| '+'
577
	  { $$ = NULL; }
578
	| '-'
579
	  {
580
		CMDARG *a;
581
		a = mk_cmdarg(D_int);
582
		a->a_int = -1;
583
		append_cmdarg(a);
584
	  }
585
	| plus_integer
586
	| func_name
587
	| integer_range
588
	| D_STRING ':' plus_integer
589
	| D_STRING ':' func_name
590
	| D_STRING ':' integer_range
591
	;
592
593
integer_range
594
	: plus_integer '-' plus_integer
595
	  {
596
		if ($1->a_int > $3->a_int)
597
			yyerror(_("invalid range specification: %d - %d"),
598
				$1->a_int, $3->a_int);
599
		else
600
			$1->type = D_range;
601
		$$ = $1;
602
	  }
603
	;
604
605
opt_integer_list
606
	: /* empty */
607
	  { $$ = NULL; }
608
	| integer_list
609
	| error
610
	;
611
612
integer_list
613
	: plus_integer
614
	| integer_range
615
	| integer_list plus_integer
616
	| integer_list integer_range
617
	;
618
619
exp_list
620
	: node
621
	  { $$ = $1; }
622
	| exp_list ',' node
623
	  { $$ = $1; }
624
	| error
625
	;
626
627
subscript
628
	: '[' exp_list ']'
629
	  {
630
		CMDARG *a;
631
		NODE *subs;
632
		int count = 0;
633
		
634
		for (a = $2; a != NULL; a = a->next)
635
			count++;
45 by Arnold D. Robbins
Fixes from John Haque.
636
		subs = concat_args($2, count);
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
637
		free_cmdarg($2->next);
638
		$2->next = NULL;
639
		$2->type = D_node;
640
		$2->a_node = subs;
641
		$$ = $2;
642
	  }
643
	| '[' exp_list error 
644
	;
645
646
subscript_list
647
	: subscript
648
	  { $$ = $1; num_dim = 1; }
649
	| subscript_list subscript
650
	  {	$$ = $1; num_dim++; }
651
	;
652
653
variable
654
	: D_VARIABLE
655
	| '$' D_NODE
656
	  {
657
		NODE *n = $2->a_node;
658
		if ((n->flags & NUMBER) == 0)
659
			yyerror(_("non-numeric value for field number"));
660
		else
661
			$2->type = D_field;
662
		$$ = $2;
663
	  }
664
	| D_VARIABLE subscript_list
665
	  {
666
		/* a_string is array name, a_count is dimension count */
667
		$1->type = D_subscript;
668
		$1->a_count = num_dim;
669
		$$ = $1;
670
	  }
671
	;
672
673
node
674
	: D_NODE
675
	  { $$ = $1; }
676
	| '+' D_NODE
677
	  { 
678
		NODE *n = $2->a_node;
679
		if ((n->flags & NUMBER) == 0)
680
			yyerror(_("non-numeric value found, numeric expected"));
681
		$$ = $2;
682
	  }
683
	| '-' D_NODE
684
	  { 
685
		NODE *n = $2->a_node;
686
		if ((n->flags & NUMBER) == 0)
687
			yyerror(_("non-numeric value found, numeric expected"));
688
		else
302.1.1 by john haque
Finish MPFR changes and clean up code.
689
			negate_num(n);
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
690
		$$ = $2;
691
	  }
692
	;
693
694
opt_plus_integer
695
	: /* empty */
696
	  { $$ = NULL; }
697
	| plus_integer
698
	  { $$ = $1; }
699
	;
700
701
opt_integer
702
	: /* empty */
703
	  { $$ = NULL; }
704
	| integer
705
	  { $$ = $1; }
706
	;
707
			
708
plus_integer
709
	: D_INT
710
	  {
711
		if ($1->a_int == 0)
712
			yyerror(_("non-zero integer value"));
713
		$$ = $1;
714
	  }
715
	| '+' D_INT
716
	  {
717
		if ($2->a_int == 0)
718
			yyerror(_("non-zero integer value"));
719
		$$ = $2;
720
	  }
721
	;
722
	
723
integer
724
	: D_INT
725
	  { $$ = $1; }
726
	| '+' D_INT
727
	  { $$ = $2; }
728
	| '-' D_INT
729
	  {
730
		$2->a_int = - $2->a_int;
731
		$$ = $2;
732
	  }
733
	;
734
735
nls
736
	: '\n'
737
	  {
738
		if (lexptr_begin != NULL) {
739
			if (input_from_tty && lexptr_begin[0] != '\0')
740
				add_history(lexptr_begin);
741
			efree(lexptr_begin);
742
			lexptr_begin = NULL;
743
		}
744
	  }
745
	;
746
747
%%
748
749
750
/* append_statement --- append 'stmt' to the list of eval awk statements */ 
751
752
static CMDARG *
281.1.1 by john haque
Speed/memory performance improvements.
753
append_statement(CMDARG *stmt_list, char *stmt) 
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
754
{
755
	CMDARG *a, *arg; 
756
	char *s;
757
	int len, slen, ssize;
758
759
#define EVALSIZE	512
760
761
	if (stmt == start_EVAL) {
762
		len = sizeof(start_EVAL);
281.1.1 by john haque
Speed/memory performance improvements.
763
		for (a = stmt_list; a != NULL; a = a->next)
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
764
			len += strlen(a->a_string) + 1;	/* 1 for ',' */
765
		len += EVALSIZE;
766
767
		emalloc(s, char *, (len + 2) * sizeof(char), "append_statement");
768
		arg = mk_cmdarg(D_string);
769
		arg->a_string = s;
770
		arg->a_count = len;	/* kludge */
771
772
		slen = sizeof("function @eval(") - 1;
773
		memcpy(s, start_EVAL, slen);
774
281.1.1 by john haque
Speed/memory performance improvements.
775
		for (a = stmt_list; a != NULL; a = a->next) {
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
776
			len = strlen(a->a_string);
777
			memcpy(s + slen, a->a_string, len);
778
			slen += len;
779
			if (a->next != NULL)
780
				s[slen++] = ',';
781
		}
782
		s[slen++] = ')';
783
		s[slen++] = '{';
784
		s[slen] = '\0';
785
		return arg;
786
	}
787
		 
788
	len = strlen(stmt) + 1;	/* 1 for newline */
281.1.1 by john haque
Speed/memory performance improvements.
789
	s = stmt_list->a_string;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
790
	slen = strlen(s);
281.1.1 by john haque
Speed/memory performance improvements.
791
	ssize = stmt_list->a_count;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
792
	if (len > ssize - slen) {
793
		ssize = slen + len + EVALSIZE;
794
		erealloc(s, char *, (ssize + 2) * sizeof(char), "append_statement");
281.1.1 by john haque
Speed/memory performance improvements.
795
		stmt_list->a_string = s;
796
		stmt_list->a_count = ssize;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
797
	}
798
	memcpy(s + slen, stmt, len);
799
	slen += len;
800
	if (slen >= 2 && s[slen - 2] != '\n') {
801
		s[slen - 1] = '\n';
802
		s[slen] = '\0';
803
	}
804
805
	if (stmt == end_EVAL)
281.1.1 by john haque
Speed/memory performance improvements.
806
		erealloc(stmt_list->a_string, char *, slen + 2, "append_statement");
807
	return stmt_list;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
808
809
#undef EVALSIZE
810
}
811
812
813
/* command names sorted in ascending order */
814
815
struct cmdtoken cmdtab[] = {
816
{ "backtrace", "bt", D_backtrace, D_BACKTRACE, do_backtrace,
817
	gettext_noop("backtrace [N] - print trace of all or N innermost (outermost if N < 0) frames.") },
818
{ "break", "b", D_break, D_BREAK, do_breakpoint,
819
	gettext_noop("break [[filename:]N|function] - set breakpoint at the specified location.") },
820
{ "clear", "", D_clear, D_CLEAR, do_clear,
821
	gettext_noop("clear [[filename:]N|function] - delete breakpoints previously set.") },
822
{ "commands", "", D_commands, D_COMMANDS, do_commands,
823
	gettext_noop("commands [num] - starts a list of commands to be executed at a breakpoint(watchpoint) hit.") },
824
{ "condition", "", D_condition, D_CONDITION, do_condition,
825
	gettext_noop("condition num [expr] - set or clear breakpoint or watchpoint condition.") },
826
{ "continue", "c", D_continue, D_CONTINUE, do_continue,
827
	gettext_noop("continue [COUNT] - continue program being debugged.") },
828
{ "delete", "d", D_delete, D_DELETE, do_delete_breakpoint,
829
	gettext_noop("delete [breakpoints] [range] - delete specified breakpoints.") },
830
{ "disable", "", D_disable, D_DISABLE, do_disable_breakpoint,
831
	gettext_noop("disable [breakpoints] [range] - disable specified breakpoints.") },
832
{ "display", "", D_display, D_DISPLAY, do_display,
833
	gettext_noop("display [var] - print value of variable each time the program stops.") },
834
{ "down", "", D_down, D_DOWN, do_down,
835
	gettext_noop("down [N] - move N frames down the stack.") },
836
{ "dump", "", D_dump, D_DUMP, do_dump_instructions,
837
	gettext_noop("dump [filename] - dump instructions to file or stdout.") },
838
{ "enable", "e", D_enable, D_ENABLE, do_enable_breakpoint,
839
	gettext_noop("enable [once|del] [breakpoints] [range] - enable specified breakpoints.") },
840
{ "end", "", D_end, D_END, do_commands,
841
	gettext_noop("end - end a list of commands or awk statements.") },
842
{ "eval", "", D_eval, D_EVAL, do_eval,
843
	gettext_noop("eval stmt|[p1, p2, ...] - evaluate awk statement(s).") },
844
{ "finish", "", D_finish, D_FINISH, do_finish,
845
	gettext_noop("finish - execute until selected stack frame returns.") },
846
{ "frame", "f", D_frame, D_FRAME, do_frame,
847
	gettext_noop("frame [N] - select and print stack frame number N.") },
848
{ "help", "h", D_help, D_HELP, do_help,
849
	gettext_noop("help [command] - print list of commands or explanation of command.") },
850
{ "ignore", "", D_ignore, D_IGNORE, do_ignore_breakpoint,
851
	gettext_noop("ignore N COUNT - set ignore-count of breakpoint number N to COUNT.") },
852
{ "info", "i", D_info, D_INFO, do_info,
853
	gettext_noop("info topic - source|sources|variables|functions|break|frame|args|locals|display|watch.") },
854
{ "list", "l", D_list, D_LIST, do_list,
855
	gettext_noop("list [-|+|[filename:]lineno|function|range] - list specified line(s).") },
856
{ "next", "n", D_next, D_NEXT, do_next,
857
	gettext_noop("next [COUNT] - step program, proceeding through subroutine calls.") },
858
{ "nexti", "ni", D_nexti, D_NEXTI, do_nexti,
859
	gettext_noop("nexti [COUNT] - step one instruction, but proceed through subroutine calls.") },
860
{ "option", "o", D_option, D_OPTION, do_option,
861
	gettext_noop("option [name[=value]] - set or display debugger option(s).") },
862
{ "print", "p", D_print, D_PRINT, do_print_var,
863
	gettext_noop("print var [var] - print value of a variable or array.") },
864
{ "printf", "", D_printf, D_PRINTF, do_print_f,
865
	gettext_noop("printf format, [arg], ... - formatted output.") },
866
{ "quit", "q", D_quit, D_QUIT, do_quit,
867
	gettext_noop("quit - exit debugger.") },
868
{ "return", "", D_return, D_RETURN, do_return,
869
	gettext_noop("return [value] - make selected stack frame return to its caller.") },
870
{ "run", "r", D_run, D_RUN, do_run,
871
	gettext_noop("run - start or restart executing program.") },
872
#ifdef HAVE_LIBREADLINE
873
{ "save", "", D_save, D_SAVE, do_save,
874
	gettext_noop("save filename - save commands from the session to file.") },
875
#endif
876
{ "set", "", D_set, D_SET, do_set_var,
877
	gettext_noop("set var = value - assign value to a scalar variable.") },
878
{ "silent", "", D_silent, D_SILENT, do_commands,
879
	gettext_noop("silent - suspends usual message when stopped at a breakpoint/watchpoint.") },
880
{ "source", "", D_source, D_SOURCE, do_source,
881
	gettext_noop("source file - execute commands from file.") },
882
{ "step", "s", D_step, D_STEP, do_step,
883
	gettext_noop("step [COUNT] - step program until it reaches a different source line.") },
884
{ "stepi", "si", D_stepi, D_STEPI, do_stepi,
885
	gettext_noop("stepi [COUNT] - step one instruction exactly.") },
886
{ "tbreak", "t", D_tbreak, D_TBREAK, do_tmp_breakpoint,
887
	gettext_noop("tbreak [[filename:]N|function] - set a temporary breakpoint.") },
888
{ "trace", "", D_trace, D_TRACE, do_trace_instruction,
889
	gettext_noop("trace on|off - print instruction before executing.") },
890
{ "undisplay",	"", D_undisplay, D_UNDISPLAY, do_undisplay,
891
	gettext_noop("undisplay [N] - remove variable(s) from automatic display list.") },
892
{ "until", "u", D_until, D_UNTIL, do_until,
893
	gettext_noop("until [[filename:]N|function] - execute until program reaches a different line or line N within current frame.") },
894
{ "unwatch", "", D_unwatch, D_UNWATCH, do_unwatch,
895
	gettext_noop("unwatch [N] - remove variable(s) from watch list.") },
896
{ "up",	"", D_up, D_UP, do_up,
897
	gettext_noop("up [N] - move N frames up the stack.") },
898
{ "watch", "w", D_watch, D_WATCH, do_watch,
899
	gettext_noop("watch var - set a watchpoint for a variable.") },
900
{ NULL, NULL, D_illegal, 0, (Func_cmd) 0,
901
	 NULL },
902
};
903
904
struct argtoken argtab[] = {
905
	{ "args", D_info, A_ARGS },
906
	{ "break", D_info, A_BREAK },
907
	{ "del", D_enable, A_DEL },
908
	{ "display", D_info, A_DISPLAY },
909
	{ "frame", D_info, A_FRAME },
910
	{ "functions", D_info, A_FUNCTIONS },
911
	{ "locals", D_info, A_LOCALS },
912
	{ "off", D_trace, A_TRACE_OFF },
913
	{ "on", D_trace, A_TRACE_ON },
914
	{ "once", D_enable, A_ONCE },
915
	{ "source", D_info, A_SOURCE },
916
	{ "sources", D_info, A_SOURCES },
917
	{ "variables", D_info, A_VARIABLES },
918
	{ "watch", D_info, A_WATCH },
919
	{ NULL, D_illegal, 0 },
920
};
921
922
923
/* get_command --- return command handler function */
924
925
Func_cmd
926
get_command(int ctype)
927
{
928
	int i;
929
	for (i = 0; cmdtab[i].name != NULL; i++) {
930
		if (cmdtab[i].type == ctype)
931
			return cmdtab[i].cf_ptr;
932
	}
933
	return (Func_cmd) 0;
934
}
935
936
/* get_command_name --- return command name given it's type */
937
938
const char *
939
get_command_name(int ctype)
940
{
941
	int i;
942
	for (i = 0; cmdtab[i].name != NULL; i++) {
943
		if (cmdtab[i].type == ctype)
944
			return cmdtab[i].name;
945
	}
946
	return NULL;
947
} 
948
949
/* mk_cmdarg --- make an argument for command */
950
951
static CMDARG *
952
mk_cmdarg(enum argtype type)
953
{
954
	CMDARG *arg;
955
	emalloc(arg, CMDARG *, sizeof(CMDARG), "mk_cmdarg");
956
	memset(arg, 0, sizeof(CMDARG));
957
	arg->type = type;
958
	return arg;
959
}
960
961
/* append_cmdarg --- append ARG to the list of arguments for the current command */
962
 
963
static void
964
append_cmdarg(CMDARG *arg)
965
{
966
	static CMDARG *savetail;
967
968
	if (arg_list == NULL)
969
		arg_list = arg;
970
	else
971
		savetail->next = arg;
972
	savetail = arg;
973
}
974
975
/* free_cmdarg --- free all arguments in LIST */
976
977
void
978
free_cmdarg(CMDARG *list)
979
{
980
	CMDARG *arg, *nexta;
981
982
	for (arg = list; arg != NULL; arg = nexta) {
983
		nexta = arg->next;
984
985
		switch (arg->type) {
986
		case D_variable:
987
		case D_subscript:
988
		case D_array:
989
		case D_string:
990
			if (arg->a_string != NULL)
991
				efree(arg->a_string);
992
			break;
993
		case D_node:
994
		case D_field:
995
			unref(arg->a_node);
996
			break;
997
		default:
998
			break;
999
		}
1000
		efree(arg);
1001
	}
1002
}
1003
1004
/* yyerror --- print a syntax error message */
1005
1006
static void
1007
yyerror(const char *mesg, ...)
1008
{
1009
	va_list args;
1010
	va_start(args, mesg);
1011
	fprintf(out_fp, _("error: "));
1012
	vfprintf(out_fp, mesg, args);
1013
	fprintf(out_fp, "\n");
1014
	va_end(args);
1015
	errcount++;
1016
	repeat_idx = -1;
1017
}
1018
1019
1020
/* yylex --- read a command and turn it into tokens */
1021
1022
static int
1023
yylex(void)
1024
{
1025
	static char *lexptr = NULL;
1026
	static char *lexend;
1027
	int c;
1028
	char *tokstart;
1029
	size_t toklen; 
1030
1031
	yylval = (CMDARG *) NULL;
1032
1033
	if (errcount > 0 && lexptr_begin == NULL) {
1034
		/* fake a new line */
1035
		errcount = 0;
1036
		return '\n';
1037
	}
1038
1039
	if (lexptr_begin == NULL) {
1040
again:
277.1.134 by Arnold D. Robbins
Minor cleanups in debugger.
1041
		lexptr_begin = read_a_line(dbg_prompt);
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1042
		if (lexptr_begin == NULL) {	/* EOF or error */
1043
			if (get_eof_status() == EXIT_FATAL) 
1044
				exit(EXIT_FATAL);
1045
			if (get_eof_status() == EXIT_FAILURE) {
1046
				static int seen_eof = 0;
1047
1048
				/* force a quit, and let do_quit (in debug.c) exit */
1049
				if (! seen_eof) {
1050
					if (errno != 0)	{
203 by Arnold D. Robbins
Fix problem with subarray of deleted array.
1051
						fprintf(stderr, _("can't read command (%s)\n"), strerror(errno));
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1052
						exit_val = EXIT_FAILURE;
1053
					} /* else
1054
						exit_val = EXIT_SUCCESS; */
1055
1056
					seen_eof = 1;
1057
					return '\n';	/* end current command if any */
1058
				} else if (seen_eof++ == 1) {
1059
					cmd_idx = find_command("quit", 4);
1060
					return D_QUIT;	/* 'quit' token */
1061
				} else
1062
					return '\n';	/* end command 'quit' */
1063
			}
1064
			if (errno != 0)
1065
				d_error(_("can't read command (%s)"), strerror(errno));
1066
			if (pop_cmd_src() == 0)
1067
				goto again;
1068
			exit(EXIT_FATAL);	/* shouldn't happen */
1069
		}
1070
1071
		if (! in_commands && ! in_eval	/* history expansion off in 'commands' and 'eval' */
1072
				&& input_from_tty
1073
		)
1074
			history_expand_line(&lexptr_begin);
1075
	
1076
		lexptr = lexptr_begin;
1077
		lexend = lexptr + strlen(lexptr);
1078
		if (*lexptr == '\0'		/* blank line */
1079
				&& repeat_idx >= 0
1080
				&& input_from_tty
1081
				&& ! in_eval
1082
		) {
1083
#ifdef HAVE_LIBREADLINE
1084
			HIST_ENTRY *h;
1085
			h = previous_history();
1086
			if (h != NULL)
1087
				add_history(h->line);
1088
#endif
1089
			cmd_idx = repeat_idx;
1090
			return cmdtab[cmd_idx].class;	/* repeat last command */
1091
		}
1092
		repeat_idx = -1;
1093
	}
1094
	
1095
	c = *lexptr;
1096
1097
	while (c == ' ' || c == '\t')
1098
		c = *++lexptr;
1099
1100
	if (! input_from_tty && c == '#')
1101
		return '\n'; 
1102
1103
	tokstart = lexptr;
1104
	if (lexptr >= lexend)
1105
		return '\n';
1106
1107
	if (cmd_idx < 0) {	/* need a command */
1108
		if (c == '?' && tokstart[1] == '\0'	&& ! in_eval) {
1109
			lexptr++;
1110
			cmd_idx = find_command("help", 4);
1111
			return D_HELP;
1112
		}
1113
1114
		while (c != '\0' && c != ' ' && c != '\t') {
1115
			if (! isalpha(c) && ! in_eval) {
1116
				yyerror(_("invalid character in command"));
1117
				return '\n';
1118
			}
1119
			c = *++lexptr;
1120
		}
1121
1122
		toklen = lexptr - tokstart;
1123
1124
		if (in_eval) {
1125
			if (toklen == 3
1126
					&& tokstart[3] == '\0'
1127
					&& tokstart[0] == 'e'
1128
					&& tokstart[1] == 'n'
1129
					&& tokstart[2] == 'd'
1130
			) {
1131
				cmd_idx = find_command(tokstart, toklen);
1132
				return D_END;
1133
			}
1134
			lexptr = lexend;
1135
			return D_STATEMENT;
1136
		}
1137
1138
		cmd_idx = find_command(tokstart, toklen);
1139
		if (cmd_idx >= 0) {
1140
			if (in_commands && cmdtab[cmd_idx].type != D_eval) {
1141
				/* add the actual command string (lexptr_begin) to
1142
				 * arg_list; command string for 'eval' prepended to the arg_list
1143
				 * in the grammer above (see eval_cmd non-terminal).
1144
				 */
1145
				CMDARG *arg;
1146
				arg = mk_cmdarg(D_string);
1147
				arg->a_string = estrdup(lexptr_begin, lexend - lexptr_begin);
1148
				append_cmdarg(arg);
1149
			}
1150
			return cmdtab[cmd_idx].class;
1151
		} else {
1152
			yyerror(_("unknown command - \"%.*s\", try help"), toklen, tokstart);
1153
			return '\n';
1154
		}
1155
	}
1156
1157
	c = *lexptr;
1158
	
1159
	if (cmdtab[cmd_idx].type == D_option) {
1160
		if (c == '=')
1161
			return *lexptr++;
1162
	} else if (c == '-' || c == '+' || c == ':' || c == '|')
1163
		return *lexptr++;
1164
1165
	if (c == '"') {
1166
		char *str, *p;
281.1.2 by john haque
Add a test file, cleanup code and update doc.
1167
		int flags = ALREADY_MALLOCED;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
1168
		bool esc_seen = false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1169
1170
		toklen = lexend - lexptr;
1171
		emalloc(str, char *, toklen + 2, "yylex");
1172
		p = str;
1173
1174
		while ((c = *++lexptr) != '"') {
1175
			if (lexptr == lexend) {
1176
err:
1177
				efree(str);
1178
				yyerror(_("unterminated string"));
1179
				return '\n';
1180
			}
1181
			if (c == '\\') {
1182
				c = *++lexptr;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
1183
				esc_seen = true;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1184
				if (want_nodeval || c != '"')
1185
					*p++ = '\\';
1186
			}
1187
			if (lexptr == lexend)
1188
				goto err;
1189
			*p++ = c;
1190
		}
1191
		lexptr++;
1192
		*p = '\0';
1193
1194
		if (! want_nodeval) {
1195
			yylval = mk_cmdarg(D_string);
281.1.1 by john haque
Speed/memory performance improvements.
1196
			yylval->a_string = str;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1197
			append_cmdarg(yylval);
1198
			return D_STRING;
1199
		} else {	/* awk string */
1200
			if (esc_seen)
281.1.2 by john haque
Add a test file, cleanup code and update doc.
1201
				flags |= SCAN;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1202
			yylval = mk_cmdarg(D_node);
281.1.2 by john haque
Add a test file, cleanup code and update doc.
1203
			yylval->a_node = make_str_node(str, p - str, flags);
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1204
			append_cmdarg(yylval);
1205
			return D_NODE;
1206
		}
1207
	}
1208
1209
	if (! want_nodeval) {
1210
		while ((c = *++lexptr) != '\0' && c != ':' && c != '-'
1211
					&& c != ' ' && c != '\t' && c != '=')
1212
			;
1213
1214
		/* Is it an integer? */
117 by Arnold D. Robbins
Fix ctype calls on Cygwin.
1215
		if (isdigit((unsigned char) tokstart[0]) && cmdtab[cmd_idx].type != D_option) {
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1216
			char *end;
1217
			long l;
1218
1219
			errno = 0;
1220
			l = strtol(tokstart, &end, 0);
1221
			if (errno != 0) {
1222
				yyerror(_("%s"), strerror(errno));
1223
				errno = 0;
1224
				return '\n';
1225
			}
1226
1227
			if (lexptr == end) {
1228
				yylval = mk_cmdarg(D_int);
1229
				yylval->a_int = l;
1230
				append_cmdarg(yylval);
1231
				return D_INT;
1232
			}
1233
		}
1234
1235
		/* Must be string */
1236
		yylval = mk_cmdarg(D_string);
1237
		yylval->a_string = estrdup(tokstart, lexptr - tokstart);
1238
		append_cmdarg(yylval);
1239
		return D_STRING;
1240
	}
1241
1242
	/* look for awk number */
1243
117 by Arnold D. Robbins
Fix ctype calls on Cygwin.
1244
	if (isdigit((unsigned char) tokstart[0])) {
302.1.1 by john haque
Finish MPFR changes and clean up code.
1245
		NODE *r = NULL;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1246
1247
		errno = 0;
302.1.1 by john haque
Finish MPFR changes and clean up code.
1248
#ifdef HAVE_MPFR
1249
		if (do_mpfr) {
306 by john haque
Add arbitrary-precision arithmetic on integers.
1250
			int tval;
1251
			r = mpg_float();
316 by john haque
Change MPFR variable RND_MODE to ROUND_MODE.
1252
			tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 0, ROUND_MODE);
306 by john haque
Add arbitrary-precision arithmetic on integers.
1253
			IEEE_FMT(r->mpg_numbr, tval);
1254
			if (mpfr_integer_p(r->mpg_numbr)) {
1255
				/* integral value, convert to a GMP type. */
1256
				NODE *tmp = r;
1257
				r = mpg_integer();
1258
				mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
1259
				unref(tmp);
1260
			}			
302.1.1 by john haque
Finish MPFR changes and clean up code.
1261
		} else 
1262
#endif
1263
			r = make_number(strtod(tokstart, & lexptr));
1264
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1265
		if (errno != 0) {
1266
			yyerror(strerror(errno));
302.1.1 by john haque
Finish MPFR changes and clean up code.
1267
			unref(r);
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1268
			errno = 0;
1269
			return '\n';
1270
		}
1271
		yylval = mk_cmdarg(D_node);
302.1.1 by john haque
Finish MPFR changes and clean up code.
1272
		yylval->a_node = r;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1273
		append_cmdarg(yylval);
1274
		return D_NODE;
1275
	}
1276
1277
	c = *lexptr;
1278
	if (c == '$' || c == '@'
1279
			|| c == '[' || c == ']'
1280
			|| c == ',' || c == '=')
1281
		return *lexptr++;
1282
1283
	if (c != '_' && ! isalpha(c)) {
1284
		yyerror(_("invalid character"));
1285
		return '\n';
1286
	}
1287
1288
	while (isalnum(c) || c == '_')
1289
		c = *++lexptr;
1290
	toklen = lexptr - tokstart;
1291
1292
	/* awk variable */
1293
	yylval = mk_cmdarg(D_variable);
1294
	yylval->a_string = estrdup(tokstart, toklen);
1295
	append_cmdarg(yylval);
1296
	return D_VARIABLE;
1297
}
1298
1299
/* find_argument --- find index in 'argtab' for a command option */
1300
1301
static int
1302
find_argument(CMDARG *arg)
1303
{
1304
	/* non-number argument */
1305
	int idx;
1306
	char *name, *p;
1307
	size_t len;
1308
	assert(cmd_idx >= 0);
1309
	name = arg->a_string;
1310
	len = strlen(name);
1311
	for (idx = 0; (p = (char *) argtab[idx].name) != NULL; idx++) {
1312
		if (cmdtab[cmd_idx].type == argtab[idx].cmd
1313
				&& *p == *name
1314
				&& strlen(p) == len
1315
				&& strncmp(p, name, len) == 0
1316
		)
1317
			return idx;
1318
	}
1319
	return -1;	/* invalid option */
1320
}
1321
1322
/* concat_args --- concatenate argument strings into a single string NODE */
1323
1324
static NODE *
1325
concat_args(CMDARG *arg, int count)
1326
{
1327
	NODE *n;
1328
	NODE **tmp;
1329
	char *str, *subsep, *p;
1330
	long len, subseplen;
1331
	int i;
1332
1333
	if (count == 1) {
1334
		n = force_string(arg->a_node);
1335
		return dupnode(n);
1336
	}
1337
	
1338
	emalloc(tmp, NODE **, count * sizeof(NODE *), "concat_args");
1339
	subseplen = SUBSEP_node->var_value->stlen;
1340
	subsep = SUBSEP_node->var_value->stptr;
1341
	len = -subseplen;
1342
1343
	for (i = 0; i < count; i++) {
1344
		n = force_string(arg->a_node);
1345
		len += n->stlen + subseplen;
1346
		tmp[i] = n;
1347
		arg = arg->next;
1348
	}
1349
1350
	emalloc(str, char *, len + 2, "concat_args");
1351
	n = tmp[0];
1352
	memcpy(str, n->stptr, n->stlen);
1353
	p = str + n->stlen;
1354
	for (i = 1; i < count; i++) {
1355
		if (subseplen == 1)
1356
			*p++ = *subsep;
1357
		else if (subseplen > 0) {
1358
			memcpy(p, subsep, subseplen);
1359
			p += subseplen;
1360
		}
1361
1362
		n = tmp[i];
1363
		memcpy(p, n->stptr, n->stlen);
1364
		p += n->stlen;
1365
	}
1366
	str[len] = '\0';
1367
	efree(tmp);
281.1.2 by john haque
Add a test file, cleanup code and update doc.
1368
	return make_str_node(str, len, ALREADY_MALLOCED);
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1369
}
1370
1371
/* find_command --- find the index in 'cmdtab' using exact,
1372
 *                  abbreviation or unique partial match 
1373
 */
1374
1375
static int
1376
find_command(const char *token, size_t toklen)
1377
{
1378
	char *name, *abrv;
1379
	int i, k;
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
1380
	bool try_exact = true;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1381
	int abrv_match = -1;
1382
	int partial_match = -1;
1383
1384
#if 'a' == 0x81 /* it's EBCDIC */
1385
	/* make sure all lower case characters in token (sorting
1386
	 * isn't the solution in this case)
1387
	 */
1388
	for (i = 0; i < toklen; i++) {
1389
		if (token[i] != tolower(token[i]))
1390
			return -1;
1391
	}
1392
#endif
1393
1394
	k = sizeof(cmdtab)/sizeof(cmdtab[0]) - 1;
1395
	for (i = 0; i < k; i++) {
1396
		name = (char *) cmdtab[i].name;
1397
		if (try_exact && *token == *name
1398
				&& toklen == strlen(name)
1399
				&& strncmp(name, token, toklen) == 0
1400
		)
1401
			return i;
281.1.1 by john haque
Speed/memory performance improvements.
1402
1403
		if (*name > *token || i == (k - 1))
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
1404
			try_exact = false;
281.1.1 by john haque
Speed/memory performance improvements.
1405
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1406
		if (abrv_match < 0) {
1407
			abrv = cmdtab[i].abbrvn;
1408
			if (abrv[0] == token[0]) {
1409
				if (toklen == 1 && ! abrv[1])
1410
					abrv_match = i;
1411
				else if (toklen == 2 && abrv[1] == token[1])
1412
					abrv_match = i;
1413
			}
1414
		}
1415
		if (! try_exact && abrv_match >= 0)
1416
			return abrv_match;
1417
		if (partial_match < 0) {
1418
			if (*token == *name
1419
					&& toklen < strlen(name)
1420
					&& strncmp(name, token, toklen) == 0
1421
			) {
1422
				if ((i == k - 1 || strncmp(cmdtab[i + 1].name, token, toklen) != 0)
1423
					&& (i == 0 || strncmp(cmdtab[i - 1].name, token, toklen) != 0)
1424
				)
1425
					partial_match = i;
1426
			}
1427
		}
1428
	}
1429
	return partial_match;
1430
}
1431
1432
/* do_help -- help command */
1433
1434
int
1435
do_help(CMDARG *arg, int cmd)
1436
{
1437
	int i;
1438
	if (arg == NULL) {
1439
		initialize_pager(out_fp);
1440
		if (setjmp(pager_quit_tag) == 0) {
1441
			for (i = 0; cmdtab[i].name != NULL; i++) {
1442
				gprintf(out_fp, "%s:\n", cmdtab[i].name);
1443
				gprintf(out_fp, "\t%s\n", _(cmdtab[i].help_txt));
1444
			}
1445
		}
1446
	} else if (arg->type == D_string) {
1447
		char *name;
1448
		name = arg->a_string;
1449
		i = find_command(name, strlen(name));
1450
		if (i >= 0) {
1451
			fprintf(out_fp, "%s\n", cmdtab[i].help_txt);
277.1.87 by Arnold D. Robbins
Remove ancient STREQ, STREQN macros.
1452
			if (strcmp(cmdtab[i].name, "option") == 0)
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1453
				option_help();
1454
		} else
1455
			fprintf(out_fp, _("undefined command: %s\n"), name);
1456
	}
1457
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
1458
	return false;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1459
}
1460
1461
1462
/* next_word --- find the next word in a line to complete 
1463
 *               (word seperation characters are space and tab).
1464
 */
1465
   
1466
static char *
1467
next_word(char *p, int len, char **endp)
1468
{
1469
	char *q;
1470
	int i;
1471
1472
	if (p == NULL || len <= 0)
1473
		return NULL;
1474
	for (i = 0; i < len; i++, p++)
1475
		if (*p != ' ' && *p != '\t')
1476
			break;
1477
	if (i == len)
1478
		return NULL;
1479
	if (endp != NULL) {
1480
		for (i++, q = p + 1; i < len; i++, q++)
1481
			if (*q == ' ' || *q == '\t')
1482
				break;
1483
		*endp = q;
1484
	}
1485
	return p;
1486
}
1487
1488
#ifdef HAVE_LIBREADLINE
1489
1490
/* command_completion --- attempt to complete based on the word number in line;
1491
 *    try to complete on command names if this is the first word; for the next
1492
 *    word(s), the type of completion depends on the command name (first word).
1493
 */
1494
1495
#ifndef RL_READLINE_VERSION		/* < 4.2a */
1496
#define rl_completion_matches(x, y) completion_matches((char *) (x), (y))
1497
#endif
1498
1499
1500
char **
1501
command_completion(const char *text, int start, int end)
1502
{
1503
	char *cmdtok, *e;
1504
	int idx;
1505
	int len;
1506
319.1.9 by Arnold D. Robbins
Move to use of bool type, true, false, everywhere.
1507
	rl_attempted_completion_over = true;	/* no default filename completion please */
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1508
1509
	this_cmd = D_illegal;
1510
	len = start;
1511
	if ((cmdtok = next_word(rl_line_buffer, len, &e)) == NULL)	/* no first word yet */
1512
		return  rl_completion_matches(text, command_generator);
1513
	len -= (e - rl_line_buffer);
1514
1515
	idx = find_command(cmdtok, e - cmdtok);
1516
	if (idx < 0)
1517
		return NULL;
1518
	this_cmd = cmdtab[idx].type;
1519
1520
	if (! next_word(e, len, NULL)) {
1521
		switch (this_cmd) {
1522
		case D_break:
1523
		case D_list:
1524
		case D_until:
1525
		case D_tbreak:
1526
		case D_clear:
1527
			return rl_completion_matches(text, srcfile_generator);
1528
		case D_info:
1529
		case D_enable:
1530
		case D_trace:
1531
		case D_help:
1532
			return rl_completion_matches(text, argument_generator);
1533
		case D_option:
1534
			return rl_completion_matches(text, option_generator);
1535
		case D_print:
1536
		case D_printf:
1537
		case D_set:
1538
		case D_display:
1539
		case D_watch:
1540
			return rl_completion_matches(text, variable_generator);
1541
		default:
1542
			return NULL;
1543
		}
1544
	}
281.1.1 by john haque
Speed/memory performance improvements.
1545
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1546
	if (this_cmd == D_print || this_cmd == D_printf)
1547
		return rl_completion_matches(text, variable_generator);
1548
	return NULL;
1549
}	
1550
1551
/* command_generator --- generator function for command completion */
1552
 
1553
static char *
1554
command_generator(const char *text, int state)
1555
{
1556
	static size_t textlen;
1557
	static int idx = 0;
1558
	char *name;
1559
1560
	if (! state) {	/* first time */
1561
		textlen = strlen(text);
1562
		idx = 0;
1563
	}
1564
	while ((name = (char *) cmdtab[idx].name) != NULL) {
1565
		idx++;
1566
		if (strncmp(name, text, textlen) == 0)
1567
			return estrdup(name, strlen(name));
1568
	}
1569
	return NULL;
1570
}
1571
1572
/* srcfile_generator --- generator function for source file completion */
1573
1574
static char *
1575
srcfile_generator(const char *text, int state)
1576
{
1577
	static size_t textlen;
1578
	static SRCFILE *s;
1579
	char *name;
1580
	extern SRCFILE *srcfiles;
1581
1582
	if (! state) {	/* first time */
1583
		textlen = strlen(text);
1584
		s = srcfiles->next;
1585
	}
1586
	while (s != srcfiles) {
1587
		if (s->stype != SRC_FILE && s->stype != SRC_INC) {
1588
			s = s->next;
1589
			continue;
1590
		}
1591
		name = s->src;
1592
		s = s->next;
1593
		if (strncmp(name, text, textlen) == 0)
1594
			return estrdup(name, strlen(name));
1595
	}
1596
	return NULL;
1597
}
1598
1599
/* argument_generator --- generator function for non-number argument completion */
1600
1601
static char *
1602
argument_generator(const char *text, int state)
1603
{
1604
	static size_t textlen;
1605
	static int idx;
281.1.1 by john haque
Speed/memory performance improvements.
1606
	const char *name;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1607
1608
	if (! state) {	/* first time */
1609
		textlen = strlen(text);
1610
		idx = 0;
1611
	}
1612
1613
	if (this_cmd == D_help) {
281.1.1 by john haque
Speed/memory performance improvements.
1614
		while ((name = cmdtab[idx++].name) != NULL) {
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1615
			if (strncmp(name, text, textlen) == 0)
1616
				return estrdup(name, strlen(name));
1617
		}
1618
	} else {
281.1.1 by john haque
Speed/memory performance improvements.
1619
		while ((name = argtab[idx].name) != NULL) {
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1620
			if (this_cmd != argtab[idx++].cmd)
1621
				continue;
1622
			if (strncmp(name, text, textlen) == 0)
1623
				return estrdup(name, strlen(name));
1624
		}
1625
	}		
1626
	return NULL;
1627
}
1628
1629
/* variable_generator --- generator function for variable name completion */
1630
1631
static char *
1632
variable_generator(const char *text, int state)
1633
{
1634
	static size_t textlen;
1635
	static int idx = 0;
281.1.1 by john haque
Speed/memory performance improvements.
1636
	static NODE *func = NULL;
1637
	static NODE **vars = NULL;
1638
	const char *name;
1639
	NODE *r;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1640
1641
	if (! state) {	/* first time */
1642
		textlen = strlen(text);
281.1.1 by john haque
Speed/memory performance improvements.
1643
		if (vars != NULL)
1644
			efree(vars);
1645
		vars = variable_list();
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1646
		idx = 0;
281.1.1 by john haque
Speed/memory performance improvements.
1647
		func = get_function();  /* function in current context */
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1648
	}
1649
1650
	/* function params */
281.1.1 by john haque
Speed/memory performance improvements.
1651
	while (func != NULL) {
1652
		if (idx >= func->param_cnt) {
1653
			func = NULL;	/* don't try to match params again */
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1654
			idx = 0;
1655
			break;
1656
		}
281.1.1 by john haque
Speed/memory performance improvements.
1657
		name = func->fparms[idx++].param;
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1658
		if (strncmp(name, text, textlen) == 0)
1659
			return estrdup(name, strlen(name));
1660
	}
1661
1662
	/* globals */
281.1.1 by john haque
Speed/memory performance improvements.
1663
	while ((r = vars[idx++]) != NULL) {
1664
		name = r->vname;
1665
		if (strncmp(name, text, textlen) == 0)
1666
			return estrdup(name, strlen(name));
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1667
	}
281.1.1 by john haque
Speed/memory performance improvements.
1668
40 by Arnold D. Robbins
Bring latest byte code gawk into git. Hurray!
1669
	return NULL;
1670
}
1671
1672
/* history_expand_line ---  history expand the LINE */
1673
1674
static void
1675
history_expand_line(char **line)
1676
{
1677
	int ret;
1678
	char *expansion;
1679
1680
	if (! *line || input_fd != 0 || ! input_from_tty)
1681
		return;
1682
	using_history();
1683
	ret = history_expand(*line, &expansion);
1684
	if (ret < 0 || ret == 2)
1685
		efree(expansion);
1686
	else {
1687
		efree(*line);
1688
		*line = expansion;
1689
	}
1690
}
1691
1692
#endif