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