1%{
2/*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License, Version 1.0 only
7 * (the "License").  You may not use this file except in compliance
8 * with the License.
9 *
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23/*
24 * awk -- YACC grammar
25 *
26 * Copyright (c) 1995 by Sun Microsystems, Inc.
27 *
28 * Copyright 1986, 1992 by Mortice Kern Systems Inc.  All rights reserved.
29 *
30 * This Software is unpublished, valuable, confidential property of
31 * Mortice Kern Systems Inc.  Use is authorized only in accordance
32 * with the terms and conditions of the source licence agreement
33 * protecting this Software.  Any unauthorized use or disclosure of
34 * this Software is strictly prohibited and will result in the
35 * termination of the licence agreement.
36 *
37 * NOTE: this grammar correctly produces NO shift/reduce conflicts from YACC.
38 *
39 */
40
41/*
42 * Do not use any character constants as tokens, so the resulting C file
43 * is codeset independent.
44 */
45
46#ident	"%Z%%M%	%I%	%E% SMI"
47#include "awk.h"
48static NODE * fliplist ANSI((NODE *np));
49%}
50
51%union	{
52	NODE	*node;
53};
54
55/*
56 * Do not use any character constants as tokens, so the resulting C file
57 * is codeset independent.
58 *
59 * Declare terminal symbols before their operator
60 * precedences to get them in a contiguous block
61 * for giant switches in action() and exprreduce().
62 */
63/* Tokens from exprreduce() */
64%token	<node>	PARM ARRAY UFUNC FIELD IN INDEX CONCAT
65%token	<node>	NOT AND OR EXP QUEST
66%token	<node>	EQ NE GE LE GT LT
67%token	<node>	ADD SUB MUL DIV REM INC DEC PRE_INC PRE_DEC
68%token	<node>	GETLINE CALLFUNC RE TILDE NRE
69
70/* Tokens shared by exprreduce() and action() */
71%token		ASG
72
73/* Tokens from action() */
74%token	<node>	PRINT PRINTF
75%token	<node>	EXIT RETURN BREAK CONTINUE NEXT
76%token	<node>	DELETE WHILE DO FOR FORIN IF
77
78/*
79 * Terminal symbols not used in action() and exprrreduce()
80 * switch statements.
81 */
82%token	<node>	CONSTANT VAR FUNC
83%token	<node>	DEFFUNC BEGIN END CLOSE ELSE PACT
84%right		ELSE
85%token		DOT CALLUFUNC
86
87/*
88 * Tokens not used in grammar
89 */
90%token		KEYWORD SVAR
91%token		PIPESYM
92
93/*
94 * Tokens representing character constants
95 * TILDE, '~', taken care of above
96 */
97%token BAR		/* '|' */
98       CARAT		/* '^' */
99       LANGLE		/* '<' */
100       RANGLE		/* '>' */
101       PLUSC		/* '+' */
102       HYPHEN		/* '-' */
103       STAR		/* '*' */
104       SLASH		/* '/' */
105       PERCENT		/* '%' */
106       EXCLAMATION	/* '!' */
107       DOLLAR		/* '$' */
108       LSQUARE		/* '[' */
109       RSQUARE		/* ']' */
110       LPAREN		/* '(' */
111       RPAREN		/* ')' */
112       SEMI		/* ';' */
113       LBRACE		/* '{' */
114       RBRACE		/* '}' */
115
116/*
117 * Priorities of operators
118 * Lowest to highest
119 */
120%left	COMMA
121%right	BAR PIPE WRITE APPEND
122%right	ASG AADD ASUB AMUL ADIV AREM AEXP
123%right	QUEST COLON
124%left	OR
125%left	AND
126%left	IN
127%left	CARAT
128%left	TILDE NRE
129%left	EQ NE LANGLE RANGLE GE LE
130%left	CONCAT
131%left	PLUSC HYPHEN
132%left	STAR SLASH PERCENT
133%right	UPLUS UMINUS
134%right	EXCLAMATION
135%right	EXP
136%right	INC DEC URE
137%left	DOLLAR LSQUARE RSQUARE
138%left	LPAREN RPAREN
139
140%type	<node>	prog rule pattern expr rvalue lvalue fexpr varlist varlist2
141%type	<node>	statement statlist fileout exprlist eexprlist simplepattern
142%type	<node>	getline optvar var
143%type	<node>	dummy
144
145%start	dummy
146%%
147
148dummy:
149		prog			= {
150			yytree = fliplist(yytree);
151		}
152		;
153prog:
154	  rule				= {
155		yytree = $1;
156	}
157	| rule SEMI prog		= {
158		if ($1 != NNULL) {
159			if (yytree != NNULL)
160				yytree = node(COMMA, $1, yytree); else
161				yytree = $1;
162		}
163	}
164	;
165
166rule:	  pattern LBRACE statlist RBRACE	= {
167		$$ = node(PACT, $1, $3);
168		doing_begin = 0;
169	}
170	| LBRACE statlist RBRACE		= {
171		npattern++;
172		$$ = node(PACT, NNULL, $2);
173	}
174	| pattern				= {
175		$$ = node(PACT, $1, node(PRINT, NNULL, NNULL));
176		doing_begin = 0;
177	}
178	| DEFFUNC VAR
179		{ $2->n_type = UFUNC; funparm = 1; }
180	    LPAREN varlist RPAREN
181		{ funparm = 0; }
182	    LBRACE statlist { uexit($5); } RBRACE = {
183		$2->n_ufunc = node(DEFFUNC, $5, fliplist($9));
184		$$ = NNULL;
185	}
186	| DEFFUNC UFUNC				= {
187		awkerr((char *) gettext("function \"%S\" redefined"), $2->n_name);
188		/* NOTREACHED */
189	}
190	|					= {
191		$$ = NNULL;
192	}
193	;
194
195pattern:
196	  simplepattern
197	| expr COMMA expr			= {
198		++npattern;
199		$$ = node(COMMA, $1, $3);
200	}
201	;
202
203simplepattern:
204	  BEGIN					= {
205		$$ = node(BEGIN, NNULL, NNULL);
206		doing_begin++;
207	}
208	| END					= {
209		++npattern;
210		$$ = node(END, NNULL, NNULL);
211	}
212	| expr					 = {
213		++npattern;
214		$$ = $1;
215	}
216	;
217
218eexprlist:
219	  exprlist
220	|					= {
221		$$ = NNULL;
222	}
223	;
224
225exprlist:
226	  expr %prec COMMA
227	| exprlist COMMA expr			= {
228		$$ = node(COMMA, $1, $3);
229	}
230	;
231
232varlist:
233	  					= {
234		$$ = NNULL;
235	}
236	| varlist2
237	;
238
239varlist2:
240	  var
241	| var COMMA varlist2			= {
242		$$ = node(COMMA, $1, $3);
243	}
244	;
245
246fexpr:
247	  expr
248	|					= {
249		$$ = NNULL;
250	}
251	;
252
253/*
254 * Normal expression (includes regular expression)
255 */
256expr:
257	  expr PLUSC expr			= {
258		$$ = node(ADD, $1, $3);
259	}
260	| expr HYPHEN expr			= {
261		$$ = node(SUB, $1, $3);
262	}
263	| expr STAR expr			= {
264		$$ = node(MUL, $1, $3);
265	}
266	| expr SLASH expr			= {
267		$$ = node(DIV, $1, $3);
268	}
269	| expr PERCENT expr			= {
270		$$ = node(REM, $1, $3);
271	}
272	| expr EXP expr				= {
273		$$ = node(EXP, $1, $3);
274	}
275	| expr AND expr				= {
276		$$ = node(AND, $1, $3);
277	}
278	| expr OR expr				= {
279		$$ = node(OR, $1, $3);
280	}
281	| expr QUEST expr COLON expr		= {
282		$$ = node(QUEST, $1, node(COLON, $3, $5));
283	}
284	| lvalue ASG expr			= {
285		$$ = node(ASG, $1, $3);
286	}
287	| lvalue AADD expr			= {
288		$$ = node(AADD, $1, $3);
289	}
290	| lvalue ASUB expr			= {
291		$$ = node(ASUB, $1, $3);
292	}
293	| lvalue AMUL expr			= {
294		$$ = node(AMUL, $1, $3);
295	}
296	| lvalue ADIV expr			= {
297		$$ = node(ADIV, $1, $3);
298	}
299	| lvalue AREM expr			= {
300		$$ = node(AREM, $1, $3);
301	}
302	| lvalue AEXP expr			= {
303		$$ = node(AEXP, $1, $3);
304	}
305	| lvalue INC				= {
306		$$ = node(INC, $1, NNULL);
307	}
308	| lvalue DEC				= {
309		$$ = node(DEC, $1, NNULL);
310	}
311	| expr EQ expr				= {
312		$$ = node(EQ, $1, $3);
313	}
314	| expr NE expr				= {
315		$$ = node(NE, $1, $3);
316	}
317	| expr RANGLE expr			= {
318		$$ = node(GT, $1, $3);
319	}
320	| expr LANGLE expr			= {
321		$$ = node(LT, $1, $3);
322	}
323	| expr GE expr				= {
324		$$ = node(GE, $1, $3);
325	}
326	| expr LE expr				= {
327		$$ = node(LE, $1, $3);
328	}
329	| expr TILDE expr			= {
330		$$ = node(TILDE, $1, $3);
331	}
332	| expr NRE expr				= {
333		$$ = node(NRE, $1, $3);
334	}
335	| expr IN var				= {
336		$$ = node(IN, $3, $1);
337	}
338	| LPAREN exprlist RPAREN IN var		= {
339		$$ = node(IN, $5, $2);
340	}
341	| getline
342	| rvalue
343	| expr CONCAT expr			= {
344		$$ = node(CONCAT, $1, $3);
345	}
346	;
347
348lvalue:
349	  DOLLAR rvalue				= {
350		$$ = node(FIELD, $2, NNULL);
351	}
352	/*
353	 * Prevents conflict with FOR LPAREN var IN var RPAREN production
354	 */
355	| var %prec COMMA
356	| var LSQUARE exprlist RSQUARE		= {
357		$$ = node(INDEX, $1, $3);
358	}
359	;
360
361var:
362	  VAR
363	| PARM
364	;
365
366rvalue:
367	  lvalue %prec COMMA
368	| CONSTANT
369	| LPAREN expr RPAREN term		= {
370		$$ = $2;
371	}
372	| EXCLAMATION expr			= {
373		$$ = node(NOT, $2, NNULL);
374	}
375	| HYPHEN expr %prec UMINUS		= {
376		$$ = node(SUB, const0, $2);
377	}
378	| PLUSC expr %prec UPLUS		= {
379		$$ = $2;
380	}
381	| DEC lvalue				= {
382		$$ = node(PRE_DEC, $2, NNULL);
383	}
384	| INC lvalue				= {
385		$$ = node(PRE_INC, $2, NNULL);
386	}
387	| FUNC					= {
388		$$ = node(CALLFUNC, $1, NNULL);
389	}
390	| FUNC LPAREN eexprlist RPAREN term	= {
391		$$ = node(CALLFUNC, $1, $3);
392	}
393	| UFUNC LPAREN eexprlist RPAREN term	= {
394		$$ = node(CALLUFUNC, $1, $3);
395	}
396	| VAR LPAREN eexprlist RPAREN term	= {
397		$$ = node(CALLUFUNC, $1, $3);
398	}
399	| SLASH {redelim='/';} URE SLASH %prec URE	= {
400		$$ = $<node>3;
401	}
402	;
403
404statement:
405	  FOR LPAREN fexpr SEMI fexpr SEMI fexpr RPAREN statement = {
406		$$ = node(FOR, node(COMMA, $3, node(COMMA, $5, $7)), $9);
407	}
408	| FOR LPAREN var IN var RPAREN statement = {
409		register NODE *np;
410
411		/*
412		 * attempt to optimize statements for the form
413		 *    for (i in x) delete x[i]
414		 * to
415		 *    delete x
416		 */
417		np = $7;
418		if (np != NNULL
419		 && np->n_type == DELETE
420		 && (np = np->n_left)->n_type == INDEX
421		 && np->n_left == $5
422		 && np->n_right == $3)
423			$$ = node(DELETE, $5, NNULL);
424		else
425			$$ = node(FORIN, node(IN, $3, $5), $7);
426	}
427	| WHILE LPAREN expr RPAREN statement	= {
428		$$ = node(WHILE, $3, $5);
429	}
430	| DO statement WHILE LPAREN expr RPAREN	= {
431		$$ = node(DO, $5, $2);
432	}
433	| IF LPAREN expr RPAREN statement ELSE statement = {
434		$$ = node(IF, $3, node(ELSE, $5, $7));
435	}
436	| IF LPAREN expr RPAREN statement %prec ELSE	= {
437		$$ = node(IF, $3, node(ELSE, $5, NNULL));
438	}
439	| CONTINUE SEMI				= {
440		$$ = node(CONTINUE, NNULL, NNULL);
441	}
442	| BREAK SEMI				= {
443		$$ = node(BREAK, NNULL, NNULL);
444	}
445	| NEXT SEMI				= {
446		$$ = node(NEXT, NNULL, NNULL);
447	}
448	| DELETE lvalue SEMI			= {
449		$$ = node(DELETE, $2, NNULL);
450	}
451	| RETURN fexpr SEMI			= {
452		$$ = node(RETURN, $2, NNULL);
453	}
454	| EXIT fexpr SEMI			= {
455		$$ = node(EXIT, $2, NNULL);
456	}
457	| PRINT eexprlist fileout SEMI		= {
458		$$ = node(PRINT, $2, $3);
459	}
460	| PRINT LPAREN exprlist RPAREN fileout SEMI	= {
461		$$ = node(PRINT, $3, $5);
462	}
463	| PRINTF exprlist fileout SEMI		= {
464		$$ = node(PRINTF, $2, $3);
465	}
466	| PRINTF LPAREN exprlist RPAREN fileout SEMI	= {
467		$$ = node(PRINTF, $3, $5);
468	}
469	| expr SEMI 				= {
470		$$ = $1;
471	}
472	| SEMI					= {
473		$$ = NNULL;
474	}
475	| LBRACE statlist RBRACE		= {
476		$$ = $2;
477	}
478	;
479
480
481statlist:
482	  statement
483	| statlist statement			= {
484		if ($1 == NNULL)
485			$$ = $2;
486		else if ($2 == NNULL)
487			$$ = $1;
488		else
489			$$ = node(COMMA, $1, $2);
490	}
491	;
492
493fileout:
494	  WRITE expr				= {
495		$$ = node(WRITE, $2, NNULL);
496	}
497	| APPEND expr				= {
498		$$ = node(APPEND, $2, NNULL);
499	}
500	| PIPE expr				= {
501		$$ = node(PIPE, $2, NNULL);
502	}
503	|					= {
504		$$ = NNULL;
505	}
506	;
507
508getline:
509	  GETLINE optvar %prec WRITE		= {
510		$$ = node(GETLINE, $2, NNULL);
511	}
512	| expr BAR GETLINE optvar		= {
513		$$ = node(GETLINE, $4, node(PIPESYM, $1, NNULL));
514	}
515	| GETLINE optvar LANGLE expr		= {
516		$$ = node(GETLINE, $2, node(LT, $4, NNULL));
517	}
518	;
519
520optvar:
521	  lvalue
522	|					= {
523		$$ = NNULL;
524	}
525	;
526
527term:
528	  {catterm = 1;}
529	;
530%%
531/*
532 * Flip a left-recursively generated list
533 * so that it can easily be traversed from left
534 * to right without recursion.
535 */
536static NODE *
537fliplist(np)
538register NODE *np;
539{
540	int type;
541
542	if (np!=NNULL && !isleaf(np->n_flags)
543#if 0
544		 && (type = np->n_type)!=FUNC && type!=UFUNC
545#endif
546	) {
547		np->n_right = fliplist(np->n_right);
548		if ((type=np->n_type)==COMMA) {
549			register NODE *lp;
550
551			while ((lp = np->n_left)!=NNULL && lp->n_type==COMMA) {
552				register NODE* *spp;
553
554				lp->n_right = fliplist(lp->n_right);
555				for (spp = &lp->n_right;
556				    *spp != NNULL && (*spp)->n_type==COMMA;
557				     spp = &(*spp)->n_right)
558					;
559				np->n_left = *spp;
560				*spp = np;
561				np = lp;
562			}
563		}
564		if (np->n_left != NULL &&
565		    (type = np->n_left->n_type)!= FUNC && type!=UFUNC)
566			np->n_left = fliplist(np->n_left);
567	}
568	return (np);
569}
570