185587Sobrien/****************************************************************
285587SobrienCopyright (C) Lucent Technologies 1997
385587SobrienAll Rights Reserved
485587Sobrien
585587SobrienPermission to use, copy, modify, and distribute this software and
685587Sobrienits documentation for any purpose and without fee is hereby
785587Sobriengranted, provided that the above copyright notice appear in all
885587Sobriencopies and that both that the copyright notice and this
985587Sobrienpermission notice and warranty disclaimer appear in supporting
1085587Sobriendocumentation, and that the name Lucent Technologies or any of
1185587Sobrienits entities not be used in advertising or publicity pertaining
1285587Sobriento distribution of the software without specific, written prior
1385587Sobrienpermission.
1485587Sobrien
1585587SobrienLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1685587SobrienINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1785587SobrienIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1885587SobrienSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1985587SobrienWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2085587SobrienIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2185587SobrienARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2285587SobrienTHIS SOFTWARE.
2385587Sobrien****************************************************************/
2485587Sobrien
2585587Sobrien%{
2685587Sobrien#include <stdio.h>
2785587Sobrien#include <string.h>
2885587Sobrien#include "awk.h"
2985587Sobrien
3085587Sobrienvoid checkdup(Node *list, Cell *item);
3185587Sobrienint yywrap(void) { return(1); }
3285587Sobrien
3385587SobrienNode	*beginloc = 0;
3485587SobrienNode	*endloc = 0;
3585587Sobrienint	infunc	= 0;	/* = 1 if in arglist or body of func */
3685587Sobrienint	inloop	= 0;	/* = 1 if in while, for, do */
3785587Sobrienchar	*curfname = 0;	/* current function name */
3885587SobrienNode	*arglist = 0;	/* list of args for current function */
3985587Sobrien%}
4085587Sobrien
4185587Sobrien%union {
4285587Sobrien	Node	*p;
4385587Sobrien	Cell	*cp;
4485587Sobrien	int	i;
4585587Sobrien	char	*s;
4685587Sobrien}
4785587Sobrien
4885587Sobrien%token	<i>	FIRSTTOKEN	/* must be first */
4985587Sobrien%token	<p>	PROGRAM PASTAT PASTAT2 XBEGIN XEND
5085587Sobrien%token	<i>	NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']'
5185587Sobrien%token	<i>	ARRAY
5285587Sobrien%token	<i>	MATCH NOTMATCH MATCHOP
53170331Srafan%token	<i>	FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS EMPTYRE
5485587Sobrien%token	<i>	AND BOR APPEND EQ GE GT LE LT NE IN
5585587Sobrien%token	<i>	ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC
5685587Sobrien%token	<i>	SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE
5785587Sobrien%token	<i>	ADD MINUS MULT DIVIDE MOD
5885587Sobrien%token	<i>	ASSIGN ASGNOP ADDEQ SUBEQ MULTEQ DIVEQ MODEQ POWEQ
5985587Sobrien%token	<i>	PRINT PRINTF SPRINTF
6085587Sobrien%token	<p>	ELSE INTEST CONDEXPR
6185587Sobrien%token	<i>	POSTINCR PREINCR POSTDECR PREDECR
6285587Sobrien%token	<cp>	VAR IVAR VARNF CALL NUMBER STRING
6385587Sobrien%token	<s>	REGEXPR
6485587Sobrien
6585587Sobrien%type	<p>	pas pattern ppattern plist pplist patlist prarg term re
6685587Sobrien%type	<p>	pa_pat pa_stat pa_stats
6785587Sobrien%type	<s>	reg_expr
6885587Sobrien%type	<p>	simple_stmt opt_simple_stmt stmt stmtlist
6985587Sobrien%type	<p>	var varname funcname varlist
7085587Sobrien%type	<p>	for if else while
7185587Sobrien%type	<i>	do st
7285587Sobrien%type	<i>	pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
7385587Sobrien%type	<i>	subop print
7485587Sobrien
7585587Sobrien%right	ASGNOP
7685587Sobrien%right	'?'
7785587Sobrien%right	':'
7885587Sobrien%left	BOR
7985587Sobrien%left	AND
8085587Sobrien%left	GETLINE
8185587Sobrien%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|'
8285587Sobrien%left	ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC
8385587Sobrien%left	GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER
8485587Sobrien%left	PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR
8585587Sobrien%left	REGEXPR VAR VARNF IVAR WHILE '('
8685587Sobrien%left	CAT
8785587Sobrien%left	'+' '-'
8885587Sobrien%left	'*' '/' '%'
8985587Sobrien%left	NOT UMINUS
9085587Sobrien%right	POWER
9185587Sobrien%right	DECR INCR
9285587Sobrien%left	INDIRECT
9385587Sobrien%token	LASTTOKEN	/* must be last */
9485587Sobrien
9585587Sobrien%%
9685587Sobrien
9785587Sobrienprogram:
9885587Sobrien	  pas	{ if (errorflag==0)
9985587Sobrien			winner = (Node *)stat3(PROGRAM, beginloc, $1, endloc); }
10085587Sobrien	| error	{ yyclearin; bracecheck(); SYNTAX("bailing out"); }
10185587Sobrien	;
10285587Sobrien
10385587Sobrienand:
10485587Sobrien	  AND | and NL
10585587Sobrien	;
10685587Sobrien
10785587Sobrienbor:
10885587Sobrien	  BOR | bor NL
10985587Sobrien	;
11085587Sobrien
11185587Sobriencomma:
11285587Sobrien	  ',' | comma NL
11385587Sobrien	;
11485587Sobrien
11585587Sobriendo:
11685587Sobrien	  DO | do NL
11785587Sobrien	;
11885587Sobrien
11985587Sobrienelse:
12085587Sobrien	  ELSE | else NL
12185587Sobrien	;
12285587Sobrien
12385587Sobrienfor:
12485587Sobrien	  FOR '(' opt_simple_stmt ';' opt_nl pattern ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
12585587Sobrien		{ --inloop; $$ = stat4(FOR, $3, notnull($6), $9, $12); }
12685587Sobrien	| FOR '(' opt_simple_stmt ';'  ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt
12785587Sobrien		{ --inloop; $$ = stat4(FOR, $3, NIL, $7, $10); }
12885587Sobrien	| FOR '(' varname IN varname rparen {inloop++;} stmt
12985587Sobrien		{ --inloop; $$ = stat3(IN, $3, makearr($5), $8); }
13085587Sobrien	;
13185587Sobrien
13285587Sobrienfuncname:
13385587Sobrien	  VAR	{ setfname($1); }
13485587Sobrien	| CALL	{ setfname($1); }
13585587Sobrien	;
13685587Sobrien
13785587Sobrienif:
13885587Sobrien	  IF '(' pattern rparen		{ $$ = notnull($3); }
13985587Sobrien	;
14085587Sobrien
14185587Sobrienlbrace:
14285587Sobrien	  '{' | lbrace NL
14385587Sobrien	;
14485587Sobrien
14585587Sobriennl:
14685587Sobrien	  NL | nl NL
14785587Sobrien	;
14885587Sobrien
14985587Sobrienopt_nl:
15085587Sobrien	  /* empty */	{ $$ = 0; }
15185587Sobrien	| nl
15285587Sobrien	;
15385587Sobrien
15485587Sobrienopt_pst:
15585587Sobrien	  /* empty */	{ $$ = 0; }
15685587Sobrien	| pst
15785587Sobrien	;
15885587Sobrien
15985587Sobrien
16085587Sobrienopt_simple_stmt:
16185587Sobrien	  /* empty */			{ $$ = 0; }
16285587Sobrien	| simple_stmt
16385587Sobrien	;
16485587Sobrien
16585587Sobrienpas:
16685587Sobrien	  opt_pst			{ $$ = 0; }
16785587Sobrien	| opt_pst pa_stats opt_pst	{ $$ = $2; }
16885587Sobrien	;
16985587Sobrien
17085587Sobrienpa_pat:
17185587Sobrien	  pattern	{ $$ = notnull($1); }
17285587Sobrien	;
17385587Sobrien
17485587Sobrienpa_stat:
17585587Sobrien	  pa_pat			{ $$ = stat2(PASTAT, $1, stat2(PRINT, rectonode(), NIL)); }
17685587Sobrien	| pa_pat lbrace stmtlist '}'	{ $$ = stat2(PASTAT, $1, $3); }
177224731Sru	| pa_pat ',' opt_nl pa_pat		{ $$ = pa2stat($1, $4, stat2(PRINT, rectonode(), NIL)); }
178224731Sru	| pa_pat ',' opt_nl pa_pat lbrace stmtlist '}'	{ $$ = pa2stat($1, $4, $6); }
17985587Sobrien	| lbrace stmtlist '}'		{ $$ = stat2(PASTAT, NIL, $2); }
18085587Sobrien	| XBEGIN lbrace stmtlist '}'
18185587Sobrien		{ beginloc = linkum(beginloc, $3); $$ = 0; }
18285587Sobrien	| XEND lbrace stmtlist '}'
18385587Sobrien		{ endloc = linkum(endloc, $3); $$ = 0; }
18485587Sobrien	| FUNC funcname '(' varlist rparen {infunc++;} lbrace stmtlist '}'
18585587Sobrien		{ infunc--; curfname=0; defn((Cell *)$2, $4, $8); $$ = 0; }
18685587Sobrien	;
18785587Sobrien
18885587Sobrienpa_stats:
18985587Sobrien	  pa_stat
19085587Sobrien	| pa_stats opt_pst pa_stat	{ $$ = linkum($1, $3); }
19185587Sobrien	;
19285587Sobrien
19385587Sobrienpatlist:
19485587Sobrien	  pattern
19585587Sobrien	| patlist comma pattern		{ $$ = linkum($1, $3); }
19685587Sobrien	;
19785587Sobrien
19885587Sobrienppattern:
19985587Sobrien	  var ASGNOP ppattern		{ $$ = op2($2, $1, $3); }
20085587Sobrien	| ppattern '?' ppattern ':' ppattern %prec '?'
20185587Sobrien	 	{ $$ = op3(CONDEXPR, notnull($1), $3, $5); }
20285587Sobrien	| ppattern bor ppattern %prec BOR
20385587Sobrien		{ $$ = op2(BOR, notnull($1), notnull($3)); }
20485587Sobrien	| ppattern and ppattern %prec AND
20585587Sobrien		{ $$ = op2(AND, notnull($1), notnull($3)); }
20685587Sobrien	| ppattern MATCHOP reg_expr	{ $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
20785587Sobrien	| ppattern MATCHOP ppattern
20885587Sobrien		{ if (constnode($3))
20985587Sobrien			$$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
21085587Sobrien		  else
21185587Sobrien			$$ = op3($2, (Node *)1, $1, $3); }
21285587Sobrien	| ppattern IN varname		{ $$ = op2(INTEST, $1, makearr($3)); }
21385587Sobrien	| '(' plist ')' IN varname	{ $$ = op2(INTEST, $2, makearr($5)); }
21485587Sobrien	| ppattern term %prec CAT	{ $$ = op2(CAT, $1, $2); }
21585587Sobrien	| re
21685587Sobrien	| term
21785587Sobrien	;
21885587Sobrien
21985587Sobrienpattern:
22085587Sobrien	  var ASGNOP pattern		{ $$ = op2($2, $1, $3); }
22185587Sobrien	| pattern '?' pattern ':' pattern %prec '?'
22285587Sobrien	 	{ $$ = op3(CONDEXPR, notnull($1), $3, $5); }
22385587Sobrien	| pattern bor pattern %prec BOR
22485587Sobrien		{ $$ = op2(BOR, notnull($1), notnull($3)); }
22585587Sobrien	| pattern and pattern %prec AND
22685587Sobrien		{ $$ = op2(AND, notnull($1), notnull($3)); }
22785587Sobrien	| pattern EQ pattern		{ $$ = op2($2, $1, $3); }
22885587Sobrien	| pattern GE pattern		{ $$ = op2($2, $1, $3); }
22985587Sobrien	| pattern GT pattern		{ $$ = op2($2, $1, $3); }
23085587Sobrien	| pattern LE pattern		{ $$ = op2($2, $1, $3); }
23185587Sobrien	| pattern LT pattern		{ $$ = op2($2, $1, $3); }
23285587Sobrien	| pattern NE pattern		{ $$ = op2($2, $1, $3); }
23385587Sobrien	| pattern MATCHOP reg_expr	{ $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); }
23485587Sobrien	| pattern MATCHOP pattern
23585587Sobrien		{ if (constnode($3))
23685587Sobrien			$$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0));
23785587Sobrien		  else
23885587Sobrien			$$ = op3($2, (Node *)1, $1, $3); }
23985587Sobrien	| pattern IN varname		{ $$ = op2(INTEST, $1, makearr($3)); }
24085587Sobrien	| '(' plist ')' IN varname	{ $$ = op2(INTEST, $2, makearr($5)); }
24185587Sobrien	| pattern '|' GETLINE var	{
24285587Sobrien			if (safe) SYNTAX("cmd | getline is unsafe");
24385587Sobrien			else $$ = op3(GETLINE, $4, itonp($2), $1); }
24485587Sobrien	| pattern '|' GETLINE		{
24585587Sobrien			if (safe) SYNTAX("cmd | getline is unsafe");
24685587Sobrien			else $$ = op3(GETLINE, (Node*)0, itonp($2), $1); }
24785587Sobrien	| pattern term %prec CAT	{ $$ = op2(CAT, $1, $2); }
24885587Sobrien	| re
24985587Sobrien	| term
25085587Sobrien	;
25185587Sobrien
25285587Sobrienplist:
25385587Sobrien	  pattern comma pattern		{ $$ = linkum($1, $3); }
25485587Sobrien	| plist comma pattern		{ $$ = linkum($1, $3); }
25585587Sobrien	;
25685587Sobrien
25785587Sobrienpplist:
25885587Sobrien	  ppattern
25985587Sobrien	| pplist comma ppattern		{ $$ = linkum($1, $3); }
26085587Sobrien	;
26185587Sobrien
26285587Sobrienprarg:
26385587Sobrien	  /* empty */			{ $$ = rectonode(); }
26485587Sobrien	| pplist
26585587Sobrien	| '(' plist ')'			{ $$ = $2; }
26685587Sobrien	;
26785587Sobrien
26885587Sobrienprint:
26985587Sobrien	  PRINT | PRINTF
27085587Sobrien	;
27185587Sobrien
27285587Sobrienpst:
27385587Sobrien	  NL | ';' | pst NL | pst ';'
27485587Sobrien	;
27585587Sobrien
27685587Sobrienrbrace:
27785587Sobrien	  '}' | rbrace NL
27885587Sobrien	;
27985587Sobrien
28085587Sobrienre:
28185587Sobrien	   reg_expr
28285587Sobrien		{ $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); }
28385587Sobrien	| NOT re	{ $$ = op1(NOT, notnull($2)); }
28485587Sobrien	;
28585587Sobrien
28685587Sobrienreg_expr:
28785587Sobrien	  '/' {startreg();} REGEXPR '/'		{ $$ = $3; }
28885587Sobrien	;
28985587Sobrien
29085587Sobrienrparen:
29185587Sobrien	  ')' | rparen NL
29285587Sobrien	;
29385587Sobrien
29485587Sobriensimple_stmt:
29585587Sobrien	  print prarg '|' term		{
29685587Sobrien			if (safe) SYNTAX("print | is unsafe");
29785587Sobrien			else $$ = stat3($1, $2, itonp($3), $4); }
29885587Sobrien	| print prarg APPEND term	{
29985587Sobrien			if (safe) SYNTAX("print >> is unsafe");
30085587Sobrien			else $$ = stat3($1, $2, itonp($3), $4); }
30185587Sobrien	| print prarg GT term		{
30285587Sobrien			if (safe) SYNTAX("print > is unsafe");
30385587Sobrien			else $$ = stat3($1, $2, itonp($3), $4); }
30485587Sobrien	| print prarg			{ $$ = stat3($1, $2, NIL, NIL); }
30585587Sobrien	| DELETE varname '[' patlist ']' { $$ = stat2(DELETE, makearr($2), $4); }
30685587Sobrien	| DELETE varname		 { $$ = stat2(DELETE, makearr($2), 0); }
30785587Sobrien	| pattern			{ $$ = exptostat($1); }
30885587Sobrien	| error				{ yyclearin; SYNTAX("illegal statement"); }
30985587Sobrien	;
31085587Sobrien
31185587Sobrienst:
31285587Sobrien	  nl
31385587Sobrien	| ';' opt_nl
31485587Sobrien	;
31585587Sobrien
31685587Sobrienstmt:
31785587Sobrien	  BREAK st		{ if (!inloop) SYNTAX("break illegal outside of loops");
31885587Sobrien				  $$ = stat1(BREAK, NIL); }
31985587Sobrien	| CONTINUE st		{  if (!inloop) SYNTAX("continue illegal outside of loops");
32085587Sobrien				  $$ = stat1(CONTINUE, NIL); }
32185587Sobrien	| do {inloop++;} stmt {--inloop;} WHILE '(' pattern ')' st
32285587Sobrien		{ $$ = stat2(DO, $3, notnull($7)); }
32385587Sobrien	| EXIT pattern st	{ $$ = stat1(EXIT, $2); }
32485587Sobrien	| EXIT st		{ $$ = stat1(EXIT, NIL); }
32585587Sobrien	| for
32685587Sobrien	| if stmt else stmt	{ $$ = stat3(IF, $1, $2, $4); }
32785587Sobrien	| if stmt		{ $$ = stat3(IF, $1, $2, NIL); }
32885587Sobrien	| lbrace stmtlist rbrace { $$ = $2; }
32985587Sobrien	| NEXT st	{ if (infunc)
33085587Sobrien				SYNTAX("next is illegal inside a function");
33185587Sobrien			  $$ = stat1(NEXT, NIL); }
33285587Sobrien	| NEXTFILE st	{ if (infunc)
33385587Sobrien				SYNTAX("nextfile is illegal inside a function");
33485587Sobrien			  $$ = stat1(NEXTFILE, NIL); }
33585587Sobrien	| RETURN pattern st	{ $$ = stat1(RETURN, $2); }
33685587Sobrien	| RETURN st		{ $$ = stat1(RETURN, NIL); }
33785587Sobrien	| simple_stmt st
33885587Sobrien	| while {inloop++;} stmt	{ --inloop; $$ = stat2(WHILE, $1, $3); }
33985587Sobrien	| ';' opt_nl		{ $$ = 0; }
34085587Sobrien	;
34185587Sobrien
34285587Sobrienstmtlist:
34385587Sobrien	  stmt
34485587Sobrien	| stmtlist stmt		{ $$ = linkum($1, $2); }
34585587Sobrien	;
34685587Sobrien
34785587Sobriensubop:
34885587Sobrien	  SUB | GSUB
34985587Sobrien	;
35085587Sobrien
35185587Sobrienterm:
35285587Sobrien 	  term '/' ASGNOP term		{ $$ = op2(DIVEQ, $1, $4); }
35385587Sobrien 	| term '+' term			{ $$ = op2(ADD, $1, $3); }
35485587Sobrien	| term '-' term			{ $$ = op2(MINUS, $1, $3); }
35585587Sobrien	| term '*' term			{ $$ = op2(MULT, $1, $3); }
35685587Sobrien	| term '/' term			{ $$ = op2(DIVIDE, $1, $3); }
35785587Sobrien	| term '%' term			{ $$ = op2(MOD, $1, $3); }
35885587Sobrien	| term POWER term		{ $$ = op2(POWER, $1, $3); }
35985587Sobrien	| '-' term %prec UMINUS		{ $$ = op1(UMINUS, $2); }
36085587Sobrien	| '+' term %prec UMINUS		{ $$ = $2; }
36185587Sobrien	| NOT term %prec UMINUS		{ $$ = op1(NOT, notnull($2)); }
36285587Sobrien	| BLTIN '(' ')'			{ $$ = op2(BLTIN, itonp($1), rectonode()); }
36385587Sobrien	| BLTIN '(' patlist ')'		{ $$ = op2(BLTIN, itonp($1), $3); }
36485587Sobrien	| BLTIN				{ $$ = op2(BLTIN, itonp($1), rectonode()); }
36585587Sobrien	| CALL '(' ')'			{ $$ = op2(CALL, celltonode($1,CVAR), NIL); }
36685587Sobrien	| CALL '(' patlist ')'		{ $$ = op2(CALL, celltonode($1,CVAR), $3); }
36785587Sobrien	| CLOSE term			{ $$ = op1(CLOSE, $2); }
36885587Sobrien	| DECR var			{ $$ = op1(PREDECR, $2); }
36985587Sobrien	| INCR var			{ $$ = op1(PREINCR, $2); }
37085587Sobrien	| var DECR			{ $$ = op1(POSTDECR, $1); }
37185587Sobrien	| var INCR			{ $$ = op1(POSTINCR, $1); }
37285587Sobrien	| GETLINE var LT term		{ $$ = op3(GETLINE, $2, itonp($3), $4); }
37385587Sobrien	| GETLINE LT term		{ $$ = op3(GETLINE, NIL, itonp($2), $3); }
37485587Sobrien	| GETLINE var			{ $$ = op3(GETLINE, $2, NIL, NIL); }
37585587Sobrien	| GETLINE			{ $$ = op3(GETLINE, NIL, NIL, NIL); }
37685587Sobrien	| INDEX '(' pattern comma pattern ')'
37785587Sobrien		{ $$ = op2(INDEX, $3, $5); }
37885587Sobrien	| INDEX '(' pattern comma reg_expr ')'
37985587Sobrien		{ SYNTAX("index() doesn't permit regular expressions");
38085587Sobrien		  $$ = op2(INDEX, $3, (Node*)$5); }
38185587Sobrien	| '(' pattern ')'		{ $$ = $2; }
38285587Sobrien	| MATCHFCN '(' pattern comma reg_expr ')'
38385587Sobrien		{ $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa($5, 1)); }
38485587Sobrien	| MATCHFCN '(' pattern comma pattern ')'
38585587Sobrien		{ if (constnode($5))
38685587Sobrien			$$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa(strnode($5), 1));
38785587Sobrien		  else
38885587Sobrien			$$ = op3(MATCHFCN, (Node *)1, $3, $5); }
38985587Sobrien	| NUMBER			{ $$ = celltonode($1, CCON); }
39085587Sobrien	| SPLIT '(' pattern comma varname comma pattern ')'     /* string */
39185587Sobrien		{ $$ = op4(SPLIT, $3, makearr($5), $7, (Node*)STRING); }
39285587Sobrien	| SPLIT '(' pattern comma varname comma reg_expr ')'    /* const /regexp/ */
39385587Sobrien		{ $$ = op4(SPLIT, $3, makearr($5), (Node*)makedfa($7, 1), (Node *)REGEXPR); }
39485587Sobrien	| SPLIT '(' pattern comma varname ')'
39585587Sobrien		{ $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); }  /* default */
39685587Sobrien	| SPRINTF '(' patlist ')'	{ $$ = op1($1, $3); }
39785587Sobrien	| STRING	 		{ $$ = celltonode($1, CCON); }
39885587Sobrien	| subop '(' reg_expr comma pattern ')'
39985587Sobrien		{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); }
40085587Sobrien	| subop '(' pattern comma pattern ')'
40185587Sobrien		{ if (constnode($3))
40285587Sobrien			$$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, rectonode());
40385587Sobrien		  else
40485587Sobrien			$$ = op4($1, (Node *)1, $3, $5, rectonode()); }
40585587Sobrien	| subop '(' reg_expr comma pattern comma var ')'
40685587Sobrien		{ $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, $7); }
40785587Sobrien	| subop '(' pattern comma pattern comma var ')'
40885587Sobrien		{ if (constnode($3))
40985587Sobrien			$$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, $7);
41085587Sobrien		  else
41185587Sobrien			$$ = op4($1, (Node *)1, $3, $5, $7); }
41285587Sobrien	| SUBSTR '(' pattern comma pattern comma pattern ')'
41385587Sobrien		{ $$ = op3(SUBSTR, $3, $5, $7); }
41485587Sobrien	| SUBSTR '(' pattern comma pattern ')'
41585587Sobrien		{ $$ = op3(SUBSTR, $3, $5, NIL); }
41685587Sobrien	| var
41785587Sobrien	;
41885587Sobrien
41985587Sobrienvar:
42085587Sobrien	  varname
42185587Sobrien	| varname '[' patlist ']'	{ $$ = op2(ARRAY, makearr($1), $3); }
42285587Sobrien	| IVAR				{ $$ = op1(INDIRECT, celltonode($1, CVAR)); }
42385587Sobrien	| INDIRECT term	 		{ $$ = op1(INDIRECT, $2); }
42485587Sobrien	;
42585587Sobrien
42685587Sobrienvarlist:
42785587Sobrien	  /* nothing */		{ arglist = $$ = 0; }
42885587Sobrien	| VAR			{ arglist = $$ = celltonode($1,CVAR); }
42985587Sobrien	| varlist comma VAR	{
43085587Sobrien			checkdup($1, $3);
43185587Sobrien			arglist = $$ = linkum($1,celltonode($3,CVAR)); }
43285587Sobrien	;
43385587Sobrien
43485587Sobrienvarname:
43585587Sobrien	  VAR			{ $$ = celltonode($1, CVAR); }
43685587Sobrien	| ARG 			{ $$ = op1(ARG, itonp($1)); }
43785587Sobrien	| VARNF			{ $$ = op1(VARNF, (Node *) $1); }
43885587Sobrien	;
43985587Sobrien
44085587Sobrien
44185587Sobrienwhile:
44285587Sobrien	  WHILE '(' pattern rparen	{ $$ = notnull($3); }
44385587Sobrien	;
44485587Sobrien
44585587Sobrien%%
44685587Sobrien
44785587Sobrienvoid setfname(Cell *p)
44885587Sobrien{
44985587Sobrien	if (isarr(p))
45085587Sobrien		SYNTAX("%s is an array, not a function", p->nval);
45185587Sobrien	else if (isfcn(p))
45285587Sobrien		SYNTAX("you can't define function %s more than once", p->nval);
45385587Sobrien	curfname = p->nval;
45485587Sobrien}
45585587Sobrien
45685587Sobrienint constnode(Node *p)
45785587Sobrien{
45885587Sobrien	return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON;
45985587Sobrien}
46085587Sobrien
46185587Sobrienchar *strnode(Node *p)
46285587Sobrien{
46385587Sobrien	return ((Cell *)(p->narg[0]))->sval;
46485587Sobrien}
46585587Sobrien
46685587SobrienNode *notnull(Node *n)
46785587Sobrien{
46885587Sobrien	switch (n->nobj) {
46985587Sobrien	case LE: case LT: case EQ: case NE: case GT: case GE:
47085587Sobrien	case BOR: case AND: case NOT:
47185587Sobrien		return n;
47285587Sobrien	default:
47385587Sobrien		return op2(NE, n, nullnode);
47485587Sobrien	}
47585587Sobrien}
47685587Sobrien
47785587Sobrienvoid checkdup(Node *vl, Cell *cp)	/* check if name already in list */
47885587Sobrien{
47985587Sobrien	char *s = cp->nval;
48085587Sobrien	for ( ; vl; vl = vl->nnext) {
48185587Sobrien		if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) {
48285587Sobrien			SYNTAX("duplicate argument %s", s);
48385587Sobrien			break;
48485587Sobrien		}
48585587Sobrien	}
48685587Sobrien}
487