GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/awk/awkgram.y Lines: 14 19 73.7 %
Date: 2017-11-07 Branches: 8 20 40.0 %

Line Branch Exec Source
1
/*	$OpenBSD: awkgram.y,v 1.9 2011/09/28 19:27:18 millert Exp $	*/
2
/****************************************************************
3
Copyright (C) Lucent Technologies 1997
4
All Rights Reserved
5
6
Permission to use, copy, modify, and distribute this software and
7
its documentation for any purpose and without fee is hereby
8
granted, provided that the above copyright notice appear in all
9
copies and that both that the copyright notice and this
10
permission notice and warranty disclaimer appear in supporting
11
documentation, and that the name Lucent Technologies or any of
12
its entities not be used in advertising or publicity pertaining
13
to distribution of the software without specific, written prior
14
permission.
15
16
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
19
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23
THIS SOFTWARE.
24
****************************************************************/
25
26
%{
27
#include <stdio.h>
28
#include <string.h>
29
#include "awk.h"
30
31
void checkdup(Node *list, Cell *item);
32
int yywrap(void) { return(1); }
33
34
Node	*beginloc = 0;
35
Node	*endloc = 0;
36
int	infunc	= 0;	/* = 1 if in arglist or body of func */
37
int	inloop	= 0;	/* = 1 if in while, for, do */
38
char	*curfname = 0;	/* current function name */
39
Node	*arglist = 0;	/* list of args for current function */
40
%}
41
42
%union {
43
	Node	*p;
44
	Cell	*cp;
45
	int	i;
46
	char	*s;
47
}
48
49
%token	<i>	FIRSTTOKEN	/* must be first */
50
%token	<p>	PROGRAM PASTAT PASTAT2 XBEGIN XEND
51
%token	<i>	NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']'
52
%token	<i>	ARRAY
53
%token	<i>	MATCH NOTMATCH MATCHOP
54
%token	<i>	FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS EMPTYRE
55
%token	<i>	AND BOR APPEND EQ GE GT LE LT NE IN
56
%token	<i>	ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC
57
%token	<i>	SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE
58
%token	<i>	ADD MINUS MULT DIVIDE MOD
59
%token	<i>	ASSIGN ASGNOP ADDEQ SUBEQ MULTEQ DIVEQ MODEQ POWEQ
60
%token	<i>	PRINT PRINTF SPRINTF
61
%token	<p>	ELSE INTEST CONDEXPR
62
%token	<i>	POSTINCR PREINCR POSTDECR PREDECR
63
%token	<cp>	VAR IVAR VARNF CALL NUMBER STRING
64
%token	<s>	REGEXPR
65
66
%type	<p>	pas pattern ppattern plist pplist patlist prarg term re
67
%type	<p>	pa_pat pa_stat pa_stats
68
%type	<s>	reg_expr
69
%type	<p>	simple_stmt opt_simple_stmt stmt stmtlist
70
%type	<p>	var varname funcname varlist
71
%type	<p>	for if else while
72
%type	<i>	do st
73
%type	<i>	pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
74
%type	<i>	subop print
75
76
%right	ASGNOP
77
%right	'?'
78
%right	':'
79
%left	BOR
80
%left	AND
81
%left	GETLINE
82
%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
83
%left	ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC
84
%left	GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
85
%left	PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR
86
%left	REGEXPR VAR VARNF IVAR WHILE '('
87
%left	CAT
88
%left	'+' '-'
89
%left	'*' '/' '%'
90
%left	NOT UMINUS
91
%right	POWER
92
%right	DECR INCR
93
%left	INDIRECT
94
%token	LASTTOKEN	/* must be last */
95
96
%%
97
98
program:
99
	  pas	{ if (errorflag==0)
100
			winner = (Node *)stat3(PROGRAM, beginloc, $1, endloc); }
101
	| error	{ yyclearin; bracecheck(); SYNTAX("bailing out"); }
102
	;
103
104
and:
105
	  AND | and NL
106
	;
107
108
bor:
109
	  BOR | bor NL
110
	;
111
112
comma:
113
	  ',' | comma NL
114
	;
115
116
do:
117
	  DO | do NL
118
	;
119
120
else:
121
	  ELSE | else NL
122
	;
123
124
for:
125
	  FOR '(' opt_simple_stmt ';' opt_nl pattern ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
126
		{ --inloop; $$ = stat4(FOR, $3, notnull($6), $9, $12); }
127
	| FOR '(' opt_simple_stmt ';'  ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
128
		{ --inloop; $$ = stat4(FOR, $3, NIL, $7, $10); }
129
	| FOR '(' varname IN varname rparen {inloop++;} stmt
130
		{ --inloop; $$ = stat3(IN, $3, makearr($5), $8); }
131
	;
132
133
funcname:
134
	  VAR	{ setfname($1); }
135
	| CALL	{ setfname($1); }
136
	;
137
138
if:
139
	  IF '(' pattern rparen		{ $$ = notnull($3); }
140
	;
141
142
lbrace:
143
	  '{' | lbrace NL
144
	;
145
146
nl:
147
	  NL | nl NL
148
	;
149
150
opt_nl:
151
	  /* empty */	{ $$ = 0; }
152
	| nl
153
	;
154
155
opt_pst:
156
	  /* empty */	{ $$ = 0; }
157
	| pst
158
	;
159
160
161
opt_simple_stmt:
162
	  /* empty */			{ $$ = 0; }
163
	| simple_stmt
164
	;
165
166
pas:
167
	  opt_pst			{ $$ = 0; }
168
	| opt_pst pa_stats opt_pst	{ $$ = $2; }
169
	;
170
171
pa_pat:
172
	  pattern	{ $$ = notnull($1); }
173
	;
174
175
pa_stat:
176
	  pa_pat			{ $$ = stat2(PASTAT, $1, stat2(PRINT, rectonode(), NIL)); }
177
	| pa_pat lbrace stmtlist '}'	{ $$ = stat2(PASTAT, $1, $3); }
178
	| pa_pat ',' opt_nl pa_pat		{ $$ = pa2stat($1, $4, stat2(PRINT, rectonode(), NIL)); }
179
	| pa_pat ',' opt_nl pa_pat lbrace stmtlist '}'	{ $$ = pa2stat($1, $4, $6); }
180
	| lbrace stmtlist '}'		{ $$ = stat2(PASTAT, NIL, $2); }
181
	| XBEGIN lbrace stmtlist '}'
182
		{ beginloc = linkum(beginloc, $3); $$ = 0; }
183
	| XEND lbrace stmtlist '}'
184
		{ endloc = linkum(endloc, $3); $$ = 0; }
185
	| FUNC funcname '(' varlist rparen {infunc++;} lbrace stmtlist '}'
186
		{ infunc--; curfname=0; defn((Cell *)$2, $4, $8); $$ = 0; }
187
	;
188
189
pa_stats:
190
	  pa_stat
191
	| pa_stats opt_pst pa_stat	{ $$ = linkum($1, $3); }
192
	;
193
194
patlist:
195
	  pattern
196
	| patlist comma pattern		{ $$ = linkum($1, $3); }
197
	;
198
199
ppattern:
200
	  var ASGNOP ppattern		{ $$ = op2($2, $1, $3); }
201
	| ppattern '?' ppattern ':' ppattern %prec '?'
202
	 	{ $$ = op3(CONDEXPR, notnull($1), $3, $5); }
203
	| ppattern bor ppattern %prec BOR
204
		{ $$ = op2(BOR, notnull($1), notnull($3)); }
205
	| ppattern and ppattern %prec AND
206
		{ $$ = op2(AND, notnull($1), notnull($3)); }
207
	| ppattern MATCHOP reg_expr	{ $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
208
	| ppattern MATCHOP ppattern
209
		{ if (constnode($3))
210
			$$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
211
		  else
212
			$$ = op3($2, (Node *)1, $1, $3); }
213
	| ppattern IN varname		{ $$ = op2(INTEST, $1, makearr($3)); }
214
	| '(' plist ')' IN varname	{ $$ = op2(INTEST, $2, makearr($5)); }
215
	| ppattern term %prec CAT	{ $$ = op2(CAT, $1, $2); }
216
	| re
217
	| term
218
	;
219
220
pattern:
221
	  var ASGNOP pattern		{ $$ = op2($2, $1, $3); }
222
	| pattern '?' pattern ':' pattern %prec '?'
223
	 	{ $$ = op3(CONDEXPR, notnull($1), $3, $5); }
224
	| pattern bor pattern %prec BOR
225
		{ $$ = op2(BOR, notnull($1), notnull($3)); }
226
	| pattern and pattern %prec AND
227
		{ $$ = op2(AND, notnull($1), notnull($3)); }
228
	| pattern EQ pattern		{ $$ = op2($2, $1, $3); }
229
	| pattern GE pattern		{ $$ = op2($2, $1, $3); }
230
	| pattern GT pattern		{ $$ = op2($2, $1, $3); }
231
	| pattern LE pattern		{ $$ = op2($2, $1, $3); }
232
	| pattern LT pattern		{ $$ = op2($2, $1, $3); }
233
	| pattern NE pattern		{ $$ = op2($2, $1, $3); }
234
	| pattern MATCHOP reg_expr	{ $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
235
	| pattern MATCHOP pattern
236
		{ if (constnode($3))
237
			$$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
238
		  else
239
			$$ = op3($2, (Node *)1, $1, $3); }
240
	| pattern IN varname		{ $$ = op2(INTEST, $1, makearr($3)); }
241
	| '(' plist ')' IN varname	{ $$ = op2(INTEST, $2, makearr($5)); }
242
	| pattern '|' GETLINE var	{
243
			if (safe) SYNTAX("cmd | getline is unsafe");
244
			else $$ = op3(GETLINE, $4, itonp($2), $1); }
245
	| pattern '|' GETLINE		{
246
			if (safe) SYNTAX("cmd | getline is unsafe");
247
			else $$ = op3(GETLINE, (Node*)0, itonp($2), $1); }
248
	| pattern term %prec CAT	{ $$ = op2(CAT, $1, $2); }
249
	| re
250
	| term
251
	;
252
253
plist:
254
	  pattern comma pattern		{ $$ = linkum($1, $3); }
255
	| plist comma pattern		{ $$ = linkum($1, $3); }
256
	;
257
258
pplist:
259
	  ppattern
260
	| pplist comma ppattern		{ $$ = linkum($1, $3); }
261
	;
262
263
prarg:
264
	  /* empty */			{ $$ = rectonode(); }
265
	| pplist
266
	| '(' plist ')'			{ $$ = $2; }
267
	;
268
269
print:
270
	  PRINT | PRINTF
271
	;
272
273
pst:
274
	  NL | ';' | pst NL | pst ';'
275
	;
276
277
rbrace:
278
	  '}' | rbrace NL
279
	;
280
281
re:
282
	   reg_expr
283
		{ $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); }
284
	| NOT re	{ $$ = op1(NOT, notnull($2)); }
285
	;
286
287
reg_expr:
288
	  '/' {startreg();} REGEXPR '/'		{ $$ = $3; }
289
	;
290
291
rparen:
292
	  ')' | rparen NL
293
	;
294
295
simple_stmt:
296
	  print prarg '|' term		{
297
			if (safe) SYNTAX("print | is unsafe");
298
			else $$ = stat3($1, $2, itonp($3), $4); }
299
	| print prarg APPEND term	{
300
			if (safe) SYNTAX("print >> is unsafe");
301
			else $$ = stat3($1, $2, itonp($3), $4); }
302
	| print prarg GT term		{
303
			if (safe) SYNTAX("print > is unsafe");
304
			else $$ = stat3($1, $2, itonp($3), $4); }
305
	| print prarg			{ $$ = stat3($1, $2, NIL, NIL); }
306
	| DELETE varname '[' patlist ']' { $$ = stat2(DELETE, makearr($2), $4); }
307
	| DELETE varname		 { $$ = stat2(DELETE, makearr($2), 0); }
308
	| pattern			{ $$ = exptostat($1); }
309
	| error				{ yyclearin; SYNTAX("illegal statement"); }
310
	;
311
312
st:
313
	  nl
314
	| ';' opt_nl
315
	;
316
317
stmt:
318
	  BREAK st		{ if (!inloop) SYNTAX("break illegal outside of loops");
319
				  $$ = stat1(BREAK, NIL); }
320
	| CONTINUE st		{  if (!inloop) SYNTAX("continue illegal outside of loops");
321
				  $$ = stat1(CONTINUE, NIL); }
322
	| do {inloop++;} stmt {--inloop;} WHILE '(' pattern ')' st
323
		{ $$ = stat2(DO, $3, notnull($7)); }
324
	| EXIT pattern st	{ $$ = stat1(EXIT, $2); }
325
	| EXIT st		{ $$ = stat1(EXIT, NIL); }
326
	| for
327
	| if stmt else stmt	{ $$ = stat3(IF, $1, $2, $4); }
328
	| if stmt		{ $$ = stat3(IF, $1, $2, NIL); }
329
	| lbrace stmtlist rbrace { $$ = $2; }
330
	| NEXT st	{ if (infunc)
331
				SYNTAX("next is illegal inside a function");
332
			  $$ = stat1(NEXT, NIL); }
333
	| NEXTFILE st	{ if (infunc)
334
				SYNTAX("nextfile is illegal inside a function");
335
			  $$ = stat1(NEXTFILE, NIL); }
336
	| RETURN pattern st	{ $$ = stat1(RETURN, $2); }
337
	| RETURN st		{ $$ = stat1(RETURN, NIL); }
338
	| simple_stmt st
339
	| while {inloop++;} stmt	{ --inloop; $$ = stat2(WHILE, $1, $3); }
340
	| ';' opt_nl		{ $$ = 0; }
341
	;
342
343
stmtlist:
344
	  stmt
345
	| stmtlist stmt		{ $$ = linkum($1, $2); }
346
	;
347
348
subop:
349
	  SUB | GSUB
350
	;
351
352
term:
353
 	  term '/' ASGNOP term		{ $$ = op2(DIVEQ, $1, $4); }
354
 	| term '+' term			{ $$ = op2(ADD, $1, $3); }
355
	| term '-' term			{ $$ = op2(MINUS, $1, $3); }
356
	| term '*' term			{ $$ = op2(MULT, $1, $3); }
357
	| term '/' term			{ $$ = op2(DIVIDE, $1, $3); }
358
	| term '%' term			{ $$ = op2(MOD, $1, $3); }
359
	| term POWER term		{ $$ = op2(POWER, $1, $3); }
360
	| '-' term %prec UMINUS		{ $$ = op1(UMINUS, $2); }
361
	| '+' term %prec UMINUS		{ $$ = $2; }
362
	| NOT term %prec UMINUS		{ $$ = op1(NOT, notnull($2)); }
363
	| BLTIN '(' ')'			{ $$ = op2(BLTIN, itonp($1), rectonode()); }
364
	| BLTIN '(' patlist ')'		{ $$ = op2(BLTIN, itonp($1), $3); }
365
	| BLTIN				{ $$ = op2(BLTIN, itonp($1), rectonode()); }
366
	| CALL '(' ')'			{ $$ = op2(CALL, celltonode($1,CVAR), NIL); }
367
	| CALL '(' patlist ')'		{ $$ = op2(CALL, celltonode($1,CVAR), $3); }
368
	| CLOSE term			{ $$ = op1(CLOSE, $2); }
369
	| DECR var			{ $$ = op1(PREDECR, $2); }
370
	| INCR var			{ $$ = op1(PREINCR, $2); }
371
	| var DECR			{ $$ = op1(POSTDECR, $1); }
372
	| var INCR			{ $$ = op1(POSTINCR, $1); }
373
	| GETLINE var LT term		{ $$ = op3(GETLINE, $2, itonp($3), $4); }
374
	| GETLINE LT term		{ $$ = op3(GETLINE, NIL, itonp($2), $3); }
375
	| GETLINE var			{ $$ = op3(GETLINE, $2, NIL, NIL); }
376
	| GETLINE			{ $$ = op3(GETLINE, NIL, NIL, NIL); }
377
	| INDEX '(' pattern comma pattern ')'
378
		{ $$ = op2(INDEX, $3, $5); }
379
	| INDEX '(' pattern comma reg_expr ')'
380
		{ SYNTAX("index() doesn't permit regular expressions");
381
		  $$ = op2(INDEX, $3, (Node*)$5); }
382
	| '(' pattern ')'		{ $$ = $2; }
383
	| MATCHFCN '(' pattern comma reg_expr ')'
384
		{ $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa($5, 1)); }
385
	| MATCHFCN '(' pattern comma pattern ')'
386
		{ if (constnode($5))
387
			$$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa(strnode($5), 1));
388
		  else
389
			$$ = op3(MATCHFCN, (Node *)1, $3, $5); }
390
	| NUMBER			{ $$ = celltonode($1, CCON); }
391
	| SPLIT '(' pattern comma varname comma pattern ')'     /* string */
392
		{ $$ = op4(SPLIT, $3, makearr($5), $7, (Node*)STRING); }
393
	| SPLIT '(' pattern comma varname comma reg_expr ')'    /* const /regexp/ */
394
		{ $$ = op4(SPLIT, $3, makearr($5), (Node*)makedfa($7, 1), (Node *)REGEXPR); }
395
	| SPLIT '(' pattern comma varname ')'
396
		{ $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); }  /* default */
397
	| SPRINTF '(' patlist ')'	{ $$ = op1($1, $3); }
398
	| STRING	 		{ $$ = celltonode($1, CCON); }
399
	| subop '(' reg_expr comma pattern ')'
400
		{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
401
	| subop '(' pattern comma pattern ')'
402
		{ if (constnode($3))
403
			$$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, rectonode());
404
		  else
405
			$$ = op4($1, (Node *)1, $3, $5, rectonode()); }
406
	| subop '(' reg_expr comma pattern comma var ')'
407
		{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, $7); }
408
	| subop '(' pattern comma pattern comma var ')'
409
		{ if (constnode($3))
410
			$$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, $7);
411
		  else
412
			$$ = op4($1, (Node *)1, $3, $5, $7); }
413
	| SUBSTR '(' pattern comma pattern comma pattern ')'
414
		{ $$ = op3(SUBSTR, $3, $5, $7); }
415
	| SUBSTR '(' pattern comma pattern ')'
416
		{ $$ = op3(SUBSTR, $3, $5, NIL); }
417
	| var
418
	;
419
420
var:
421
	  varname
422
	| varname '[' patlist ']'	{ $$ = op2(ARRAY, makearr($1), $3); }
423
	| IVAR				{ $$ = op1(INDIRECT, celltonode($1, CVAR)); }
424
	| INDIRECT term	 		{ $$ = op1(INDIRECT, $2); }
425
	;
426
427
varlist:
428
	  /* nothing */		{ arglist = $$ = 0; }
429
	| VAR			{ arglist = $$ = celltonode($1,CVAR); }
430
	| varlist comma VAR	{
431
			checkdup($1, $3);
432
			arglist = $$ = linkum($1,celltonode($3,CVAR)); }
433
	;
434
435
varname:
436
	  VAR			{ $$ = celltonode($1, CVAR); }
437
	| ARG 			{ $$ = op1(ARG, itonp($1)); }
438
	| VARNF			{ $$ = op1(VARNF, (Node *) $1); }
439
	;
440
441
442
while:
443
	  WHILE '(' pattern rparen	{ $$ = notnull($3); }
444
	;
445
446
%%
447
448
void setfname(Cell *p)
449
{
450
62
	if (isarr(p))
451
		SYNTAX("%s is an array, not a function", p->nval);
452
31
	else if (isfcn(p))
453
		SYNTAX("you can't define function %s more than once", p->nval);
454
31
	curfname = p->nval;
455
31
}
456
457
int constnode(Node *p)
458
{
459
24
	return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON;
460
}
461
462
char *strnode(Node *p)
463
{
464
12
	return ((Cell *)(p->narg[0]))->sval;
465
}
466
467
Node *notnull(Node *n)
468
{
469


2778
	switch (n->nobj) {
470
	case LE: case LT: case EQ: case NE: case GT: case GE:
471
	case BOR: case AND: case NOT:
472
1088
		return n;
473
	default:
474
301
		return op2(NE, n, nullnode);
475
	}
476
1389
}
477
478
void checkdup(Node *vl, Cell *cp)	/* check if name already in list */
479
{
480
16
	char *s = cp->nval;
481
32
	for ( ; vl; vl = vl->nnext) {
482
8
		if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) {
483
			SYNTAX("duplicate argument %s", s);
484
			break;
485
		}
486
	}
487
8
}