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