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