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 (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 *
25 * escparse.y -- parser for esc
26 *
27 * this is the yacc-based parser for Eversholt.  the syntax is simple
28 * and is defined by the LALR(1) grammar described by this file.  there
29 * should be no shift/reduce or reduce/reduce messages when building this
30 * file.
31 *
32 * as the input is parsed, a parse tree is built by calling the
33 * tree_X() functions defined in tree.c.  any syntax errors cause
34 * us to skip to the next semicolon, achieved via the "error" clause
35 * in the stmt rule below.  the yacc state machine code will call
36 * yyerror() in esclex.c and that will keep count of the errors and
37 * display the filename, line number, and current input stream of tokens
38 * to help the user figure out the problem.  the -Y flag to this program
39 * turns on the yacc debugging output which is quite large.  you probably
40 * only need to do that if you're debugging the grammar below.
41 *
42 */
43
44#include <stdio.h>
45#include <ctype.h>
46#include <string.h>
47#include <stdlib.h>
48#include <unistd.h>
49#include <time.h>
50#include <sys/time.h>
51#include "out.h"
52#include "stable.h"
53#include "literals.h"
54#include "lut.h"
55#include "esclex.h"
56#include "tree.h"
57
58%}
59%union {
60	struct tokstr tok;
61	struct node *np;
62}
63
64%right '='
65
66/*
67 * make sure ':' comes immediately after '?' in precedence declarations
68 */
69%right '?'
70%nonassoc ':'
71
72%left OR
73%left AND
74%left '|'
75%left '^'
76%left '&'
77%left EQ NE
78%left LE GE '<' '>'
79%left LSHIFT RSHIFT
80%left '-' '+'
81%left '*' '%' DIV '/'
82%right '!' '~'
83%left '.'
84
85%token <tok> PROP MASK ARROW EVENT ENGINE ASRU FRU COUNT CONFIG
86%token <tok> ID QUOTE NUMBER IF PATHFUNC
87%type <tok> enameid
88%type <np> root stmtlist stmt nvpairlist nvpair nvname nvexpr
89%type <np> exprlist expr iterid ename pname epname eexprlist ipname iname
90%type <np> numexpr cexpr func pfunc parglist parg
91%type <np> eventlist event nork norkexpr globid propbody
92
93%%
94
95root	: stmtlist
96		{ (void)tree_root($1); }
97	;
98
99stmtlist   : /*empty*/
100		{ $$ = NULL; }
101        | stmtlist stmt
102		{ $$ = tree_expr(T_LIST, $1, $2); }
103	;
104
105stmt	: error ';'
106     		{ $$ = tree_nothing(); }
107	| IF '(' expr ')' stmt
108		{ $$ = $5; }
109	| IF '(' expr ')' '{' stmtlist '}'
110		{ $$ = $6; }
111	| EVENT event nvpairlist ';'
112		{ $$ = tree_decl(T_EVENT, $2, $3, $1.file, $1.line); }
113	| ENGINE event nvpairlist ';'
114		{ $$ = tree_decl(T_ENGINE, $2, $3, $1.file, $1.line); }
115	| PROP propbody ';'
116		{
117			$$ = tree_stmt(T_PROP, $2, $1.file, $1.line);
118		}
119	| MASK propbody ';'
120		{
121			$$ = tree_stmt(T_MASK, $2, $1.file, $1.line);
122		}
123	| ASRU pname nvpairlist ';'
124		{
125			$$ = tree_decl(T_ASRU, $2, $3, $1.file, $1.line);
126		}
127	| FRU pname nvpairlist ';'
128		{
129			$$ = tree_decl(T_FRU, $2, $3, $1.file, $1.line);
130		}
131	| CONFIG ipname nvpairlist ';'
132		{
133			$$ = tree_decl(T_CONFIG, $2, $3, $1.file, $1.line);
134		}
135	| /*superfluous semicolons are ignored*/ ';'
136     		{ $$ = tree_nothing(); }
137	;
138
139propbody: eventlist nork ARROW nork eventlist
140		{
141			$$ = tree_arrow($1, $2, $4, $5);
142		}
143	| propbody nork ARROW nork eventlist
144		{
145			$$ = tree_arrow($1, $2, $4, $5);
146		}
147	;
148
149nork	: /* empty */
150		{ $$ = NULL; }
151	| '(' norkexpr ')'
152		{ $$ = $2; }
153	;
154
155norkexpr: NUMBER
156		{ $$ = tree_num($1.s, $1.file, $1.line); }
157	| ID
158		/* really can only be 'A', enforced by check_arrow() later */
159       		{ $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); }
160	| '(' norkexpr ')'
161		{ $$ = $2; }
162	| norkexpr '-' norkexpr
163		{ $$ = tree_expr(T_SUB, $1, $3); }
164	| norkexpr '+' norkexpr
165		{ $$ = tree_expr(T_ADD, $1, $3); }
166	| norkexpr '*' norkexpr
167		{ $$ = tree_expr(T_MUL, $1, $3); }
168	| norkexpr DIV norkexpr
169		{ $$ = tree_expr(T_DIV, $1, $3); }
170	| norkexpr '%' norkexpr
171		{ $$ = tree_expr(T_MOD, $1, $3); }
172	;
173
174nvpairlist: /* empty */
175		{ $$ = NULL; }
176	| nvpair
177	| nvpairlist ',' nvpair
178		{ $$ = tree_expr(T_LIST, $1, $3); }
179	;
180
181nvpair	: nvname '=' nvexpr
182		{ $$ = tree_expr(T_NVPAIR, $1, $3); }
183	| ENGINE '=' nvexpr
184		/* "engine" is a reserved word, but a valid property name */
185		{
186			$$ = tree_expr(T_NVPAIR,
187				tree_name($1.s, IT_NONE, $1.file, $1.line), $3);
188		}
189	| COUNT '=' nvexpr
190		/* "count" is a reserved word, but a valid property name */
191		{
192			$$ = tree_expr(T_NVPAIR,
193				tree_name($1.s, IT_NONE, $1.file, $1.line), $3);
194		}
195	;
196
197nvname	: ID
198		{ $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); }
199	| nvname '-' ID
200		{
201			/* hack to allow dashes in property names */
202			$$ = tree_name_repairdash($1, $3.s);
203		}
204	;
205
206/* the RHS of an nvpair can be a value, or an ename, or an ename@pname */
207nvexpr	: numexpr
208	| ename epname
209		{ $$ = tree_event($1, $2, NULL); }
210	| pname
211	| globid
212	| func
213	| NUMBER ID
214		/*
215		 * ID must be timevals only ("ms", "us", etc.).
216		 * enforced by tree_timeval().
217		 */
218		{ $$ = tree_timeval($1.s, $2.s, $1.file, $1.line); }
219	| QUOTE
220		{ $$ = tree_quote($1.s, $1.file, $1.line); }
221	;
222
223/* arithmetic operations, no variables or symbols */
224numexpr	: numexpr '-' numexpr
225		{ $$ = tree_expr(T_SUB, $1, $3); }
226	| numexpr '+' numexpr
227		{ $$ = tree_expr(T_ADD, $1, $3); }
228	| numexpr '*' numexpr
229		{ $$ = tree_expr(T_MUL, $1, $3); }
230	| numexpr DIV numexpr
231		{ $$ = tree_expr(T_DIV, $1, $3); }
232	| numexpr '/' numexpr
233		{ $$ = tree_expr(T_DIV, $1, $3); }
234	| numexpr '%' numexpr
235		{ $$ = tree_expr(T_MOD, $1, $3); }
236 	| '(' numexpr ')'
237		{ $$ = $2; }
238	| NUMBER
239		{ $$ = tree_num($1.s, $1.file, $1.line); }
240	;
241
242eventlist: event
243	| eventlist ',' event
244		{ $$ = tree_expr(T_LIST, $1, $3); }
245	;
246
247event	: ename epname eexprlist
248		{ $$ = tree_event($1, $2, $3); }
249	;
250
251epname	: /* empty */
252		{ $$ = NULL; }
253	| '@' pname
254		{ $$ = $2; }
255	;
256
257eexprlist: /* empty */
258		{ $$ = NULL; }
259	| '{' exprlist '}'
260		{ $$ = $2; }
261	;
262
263exprlist: expr
264	| exprlist ',' expr
265		{ $$ = tree_expr(T_LIST, $1, $3); }
266	;
267
268/*
269 * note that expr does not include pname, to avoid reduce/reduce
270 * conflicts between cexpr and iterid involving the use of ID
271 */
272expr	: cexpr
273	| NUMBER ID
274		/*
275		 * ID must be timevals only ("ms", "us", etc.).
276		 * enforced by tree_timeval().
277		 */
278		{ $$ = tree_timeval($1.s, $2.s, $1.file, $1.line); }
279	;
280
281cexpr	: cexpr '=' cexpr
282		{ $$ = tree_expr(T_ASSIGN, $1, $3); }
283	| cexpr '?' cexpr
284		{ $$ = tree_expr(T_CONDIF, $1, $3); }
285	| cexpr ':' cexpr
286		{ $$ = tree_expr(T_CONDELSE, $1, $3); }
287	| cexpr OR cexpr
288		{ $$ = tree_expr(T_OR, $1, $3); }
289 	| cexpr AND cexpr
290		{ $$ = tree_expr(T_AND, $1, $3); }
291	| cexpr '|' cexpr
292		{ $$ = tree_expr(T_BITOR, $1, $3); }
293	| cexpr '^' cexpr
294		{ $$ = tree_expr(T_BITXOR, $1, $3); }
295	| cexpr '&' cexpr
296		{ $$ = tree_expr(T_BITAND, $1, $3); }
297	| cexpr EQ cexpr
298		{ $$ = tree_expr(T_EQ, $1, $3); }
299	| cexpr NE cexpr
300		{ $$ = tree_expr(T_NE, $1, $3); }
301	| cexpr '<' cexpr
302		{ $$ = tree_expr(T_LT, $1, $3); }
303	| cexpr LE cexpr
304		{ $$ = tree_expr(T_LE, $1, $3); }
305	| cexpr '>' cexpr
306		{ $$ = tree_expr(T_GT, $1, $3); }
307	| cexpr GE cexpr
308		{ $$ = tree_expr(T_GE, $1, $3); }
309	| cexpr LSHIFT cexpr
310		{ $$ = tree_expr(T_LSHIFT, $1, $3); }
311	| cexpr RSHIFT cexpr
312		{ $$ = tree_expr(T_RSHIFT, $1, $3); }
313	| cexpr '-' cexpr
314		{ $$ = tree_expr(T_SUB, $1, $3); }
315	| cexpr '+' cexpr
316		{ $$ = tree_expr(T_ADD, $1, $3); }
317	| cexpr '*' cexpr
318		{ $$ = tree_expr(T_MUL, $1, $3); }
319	| cexpr DIV cexpr
320		{ $$ = tree_expr(T_DIV, $1, $3); }
321	| cexpr '/' cexpr
322		{ $$ = tree_expr(T_DIV, $1, $3); }
323	| cexpr '%' cexpr
324		{ $$ = tree_expr(T_MOD, $1, $3); }
325	|  '!' cexpr
326		{ $$ = tree_expr(T_NOT, $2, NULL); }
327	|  '~' cexpr
328		{ $$ = tree_expr(T_BITNOT, $2, NULL); }
329	| '(' cexpr ')'
330		{ $$ = $2; }
331	| func
332	| NUMBER
333		{ $$ = tree_num($1.s, $1.file, $1.line); }
334	| ID
335       		{
336			/* iteration variable */
337			$$ = tree_name($1.s, IT_NONE, $1.file, $1.line);
338		}
339	| globid
340	| QUOTE
341		{ $$ = tree_quote($1.s, $1.file, $1.line); }
342	;
343
344func	: ID '(' ')'
345		{ $$ = tree_func($1.s, NULL, $1.file, $1.line); }
346	| ID '(' exprlist ')'
347		{ $$ = tree_func($1.s, $3, $1.file, $1.line); }
348	| PATHFUNC '(' parglist ')'
349		{ $$ = tree_func($1.s, $3, $1.file, $1.line); }
350	| pfunc
351	;
352
353parglist: parg
354	| parglist ',' parg
355		{ $$ = tree_expr(T_LIST, $1, $3); }
356	;
357
358parg	: pfunc
359	| pname
360		{ $$ = tree_pname($1); }
361	| QUOTE
362		{ $$ = tree_quote($1.s, $1.file, $1.line); }
363	| ID '(' exprlist ')'
364		{ $$ = tree_func($1.s, $3, $1.file, $1.line); }
365	;
366
367/*
368 * these functions are in the grammar so we can force the arg to be
369 * a path or an event.  they show up as functions in the parse tree.
370 */
371pfunc	: ASRU '(' pname ')'
372		{ $$ = tree_func($1.s, tree_pname($3), $1.file, $1.line); }
373	| FRU '(' pname ')'
374		{ $$ = tree_func($1.s, tree_pname($3), $1.file, $1.line); }
375	| COUNT '(' event ')'
376		{ $$ = tree_func($1.s, $3, $1.file, $1.line); }
377	;
378
379globid	: '$' ID
380       		{ $$ = tree_globid($2.s, $2.file, $2.line); }
381	;
382
383iterid	: ID
384       		{ $$ = tree_name($1.s, IT_VERTICAL, $1.file, $1.line); }
385	| ID '[' ']'
386       		{ $$ = tree_name($1.s, IT_VERTICAL, $1.file, $1.line); }
387	| ID '[' cexpr ']'
388       		{
389			$$ = tree_name_iterator(
390			   tree_name($1.s, IT_VERTICAL, $1.file, $1.line), $3);
391		}
392	| ID '<' '>'
393       		{ $$ = tree_name($1.s, IT_HORIZONTAL, $1.file, $1.line); }
394	| ID '<' ID '>'
395       		{
396			$$ = tree_name_iterator(
397			    tree_name($1.s, IT_HORIZONTAL, $1.file, $1.line),
398			    tree_name($3.s, IT_NONE, $3.file, $3.line));
399		}
400	| ID '-' iterid
401		{
402			/* hack to allow dashes in path name components */
403			$$ = tree_name_repairdash2($1.s, $3);
404		}
405	;
406
407/* iname is an ID where we can peel numbers off the end */
408iname	: ID
409       		{ $$ = tree_iname($1.s, $1.file, $1.line); }
410	;
411
412/* base case of ID.ID instead of just ID requires ename to contain one dot */
413ename	: ID '.' enameid
414       		{
415			$$ = tree_name_append(
416			    tree_name($1.s, IT_ENAME, $1.file, $1.line),
417			    tree_name($3.s, IT_NONE, $3.file, $3.line));
418		}
419	| ename '.' enameid
420		{
421			$$ = tree_name_append($1,
422			    tree_name($3.s, IT_NONE, $3.file, $3.line));
423		}
424	| ename '-' enameid
425		{
426			/*
427			 * hack to allow dashes in class names.  when we
428			 * detect the dash here, we know we're in a class
429			 * name because the left recursion of this rule
430			 * means we've already matched at least:
431			 * 	ID '.' ID
432			 * so the ename here has an incomplete final
433			 * component (because the lexer stopped at the
434			 * dash).  so we repair that final component here.
435			 */
436			$$ = tree_name_repairdash($1, $3.s);
437		}
438	;
439
440/* like an ID, but we let reserved words act unreserved in enames */
441enameid	: ID
442	| PROP
443	| MASK
444	| EVENT
445	| ENGINE
446	| ASRU
447	| FRU
448	| CONFIG
449	| IF
450	;
451
452/* pname is a pathname, like x/y, x<i>/y[0], etc */
453pname	: iterid
454	| pname '/' iterid
455		{ $$ = tree_name_append($1, $3); }
456	;
457
458/* ipname is an "instanced" pathname, like x0/y1 */
459ipname	: iname
460	| ipname '/' iname
461		{ $$ = tree_name_append($1, $3); }
462	;
463
464%%
465