xref: /illumos-gate/usr/src/cmd/fm/eversholt/common/escparse.y (revision 3d393ee6c37fa10ac512ed6d36109ad616dc7c1a)
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 2008 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
45 
46 #include <stdio.h>
47 #include <ctype.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <time.h>
52 #include <sys/time.h>
53 #include "out.h"
54 #include "stable.h"
55 #include "literals.h"
56 #include "lut.h"
57 #include "esclex.h"
58 #include "tree.h"
59 
60 %}
61 %union {
62 	struct tokstr tok;
63 	struct node *np;
64 }
65 
66 %right '='
67 
68 /*
69  * make sure ':' comes immediately after '?' in precedence declarations
70  */
71 %right '?'
72 %nonassoc ':'
73 
74 %left OR
75 %left AND
76 %left '|'
77 %left '^'
78 %left '&'
79 %left EQ NE
80 %left LE GE '<' '>'
81 %left LSHIFT RSHIFT
82 %left '-' '+'
83 %left '*' '%' DIV '/'
84 %right '!' '~'
85 %left '.'
86 
87 %token <tok> PROP MASK ARROW EVENT ENGINE ASRU FRU COUNT CONFIG
88 %token <tok> ID QUOTE NUMBER IF PATHFUNC
89 %type <tok> enameid
90 %type <np> root stmtlist stmt nvpairlist nvpair nvname nvexpr
91 %type <np> exprlist expr iterid ename pname epname eexprlist ipname iname
92 %type <np> numexpr cexpr func pfunc parglist parg
93 %type <np> eventlist event nork norkexpr globid propbody
94 
95 %%
96 
97 root	: stmtlist
98 		{ (void)tree_root($1); }
99 	;
100 
101 stmtlist   : /*empty*/
102 		{ $$ = NULL; }
103         | stmtlist stmt
104 		{ $$ = tree_expr(T_LIST, $1, $2); }
105 	;
106 
107 stmt	: error ';'
108      		{ $$ = tree_nothing(); }
109 	| IF '(' expr ')' stmt
110 		{ $$ = $5; }
111 	| IF '(' expr ')' '{' stmtlist '}'
112 		{ $$ = $6; }
113 	| EVENT event nvpairlist ';'
114 		{ $$ = tree_decl(T_EVENT, $2, $3, $1.file, $1.line); }
115 	| ENGINE event nvpairlist ';'
116 		{ $$ = tree_decl(T_ENGINE, $2, $3, $1.file, $1.line); }
117 	| PROP propbody ';'
118 		{
119 			$$ = tree_stmt(T_PROP, $2, $1.file, $1.line);
120 		}
121 	| MASK propbody ';'
122 		{
123 			$$ = tree_stmt(T_MASK, $2, $1.file, $1.line);
124 		}
125 	| ASRU pname nvpairlist ';'
126 		{
127 			$$ = tree_decl(T_ASRU, $2, $3, $1.file, $1.line);
128 		}
129 	| FRU pname nvpairlist ';'
130 		{
131 			$$ = tree_decl(T_FRU, $2, $3, $1.file, $1.line);
132 		}
133 	| CONFIG ipname nvpairlist ';'
134 		{
135 			$$ = tree_decl(T_CONFIG, $2, $3, $1.file, $1.line);
136 		}
137 	| /*superfluous semicolons are ignored*/ ';'
138      		{ $$ = tree_nothing(); }
139 	;
140 
141 propbody: eventlist nork ARROW nork eventlist
142 		{
143 			$$ = tree_arrow($1, $2, $4, $5);
144 		}
145 	| propbody nork ARROW nork eventlist
146 		{
147 			$$ = tree_arrow($1, $2, $4, $5);
148 		}
149 	;
150 
151 nork	: /* empty */
152 		{ $$ = NULL; }
153 	| '(' norkexpr ')'
154 		{ $$ = $2; }
155 	;
156 
157 norkexpr: NUMBER
158 		{ $$ = tree_num($1.s, $1.file, $1.line); }
159 	| ID
160 		/* really can only be 'A', enforced by check_arrow() later */
161        		{ $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); }
162 	| '(' norkexpr ')'
163 		{ $$ = $2; }
164 	| norkexpr '-' norkexpr
165 		{ $$ = tree_expr(T_SUB, $1, $3); }
166 	| norkexpr '+' norkexpr
167 		{ $$ = tree_expr(T_ADD, $1, $3); }
168 	| norkexpr '*' norkexpr
169 		{ $$ = tree_expr(T_MUL, $1, $3); }
170 	| norkexpr DIV norkexpr
171 		{ $$ = tree_expr(T_DIV, $1, $3); }
172 	| norkexpr '%' norkexpr
173 		{ $$ = tree_expr(T_MOD, $1, $3); }
174 	;
175 
176 nvpairlist: /* empty */
177 		{ $$ = NULL; }
178 	| nvpair
179 	| nvpairlist ',' nvpair
180 		{ $$ = tree_expr(T_LIST, $1, $3); }
181 	;
182 
183 nvpair	: nvname '=' nvexpr
184 		{ $$ = tree_expr(T_NVPAIR, $1, $3); }
185 	| ENGINE '=' nvexpr
186 		/* "engine" is a reserved word, but a valid property name */
187 		{
188 			$$ = tree_expr(T_NVPAIR,
189 				tree_name($1.s, IT_NONE, $1.file, $1.line), $3);
190 		}
191 	| COUNT '=' nvexpr
192 		/* "count" is a reserved word, but a valid property name */
193 		{
194 			$$ = tree_expr(T_NVPAIR,
195 				tree_name($1.s, IT_NONE, $1.file, $1.line), $3);
196 		}
197 	;
198 
199 nvname	: ID
200 		{ $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); }
201 	| nvname '-' ID
202 		{
203 			/* hack to allow dashes in property names */
204 			$$ = tree_name_repairdash($1, $3.s);
205 		}
206 	;
207 
208 /* the RHS of an nvpair can be a value, or an ename, or an ename@pname */
209 nvexpr	: numexpr
210 	| ename epname
211 		{ $$ = tree_event($1, $2, NULL); }
212 	| pname
213 	| globid
214 	| func
215 	| NUMBER ID
216 		/*
217 		 * ID must be timevals only ("ms", "us", etc.).
218 		 * enforced by tree_timeval().
219 		 */
220 		{ $$ = tree_timeval($1.s, $2.s, $1.file, $1.line); }
221 	| QUOTE
222 		{ $$ = tree_quote($1.s, $1.file, $1.line); }
223 	;
224 
225 /* arithmetic operations, no variables or symbols */
226 numexpr	: numexpr '-' numexpr
227 		{ $$ = tree_expr(T_SUB, $1, $3); }
228 	| numexpr '+' numexpr
229 		{ $$ = tree_expr(T_ADD, $1, $3); }
230 	| numexpr '*' numexpr
231 		{ $$ = tree_expr(T_MUL, $1, $3); }
232 	| numexpr DIV numexpr
233 		{ $$ = tree_expr(T_DIV, $1, $3); }
234 	| numexpr '/' numexpr
235 		{ $$ = tree_expr(T_DIV, $1, $3); }
236 	| numexpr '%' numexpr
237 		{ $$ = tree_expr(T_MOD, $1, $3); }
238  	| '(' numexpr ')'
239 		{ $$ = $2; }
240 	| NUMBER
241 		{ $$ = tree_num($1.s, $1.file, $1.line); }
242 	;
243 
244 eventlist: event
245 	| eventlist ',' event
246 		{ $$ = tree_expr(T_LIST, $1, $3); }
247 	;
248 
249 event	: ename epname eexprlist
250 		{ $$ = tree_event($1, $2, $3); }
251 	;
252 
253 epname	: /* empty */
254 		{ $$ = NULL; }
255 	| '@' pname
256 		{ $$ = $2; }
257 	;
258 
259 eexprlist: /* empty */
260 		{ $$ = NULL; }
261 	| '{' exprlist '}'
262 		{ $$ = $2; }
263 	;
264 
265 exprlist: expr
266 	| exprlist ',' expr
267 		{ $$ = tree_expr(T_LIST, $1, $3); }
268 	;
269 
270 /*
271  * note that expr does not include pname, to avoid reduce/reduce
272  * conflicts between cexpr and iterid involving the use of ID
273  */
274 expr	: cexpr
275 	| NUMBER ID
276 		/*
277 		 * ID must be timevals only ("ms", "us", etc.).
278 		 * enforced by tree_timeval().
279 		 */
280 		{ $$ = tree_timeval($1.s, $2.s, $1.file, $1.line); }
281 	;
282 
283 cexpr	: cexpr '=' cexpr
284 		{ $$ = tree_expr(T_ASSIGN, $1, $3); }
285 	| cexpr '?' cexpr
286 		{ $$ = tree_expr(T_CONDIF, $1, $3); }
287 	| cexpr ':' cexpr
288 		{ $$ = tree_expr(T_CONDELSE, $1, $3); }
289 	| cexpr OR cexpr
290 		{ $$ = tree_expr(T_OR, $1, $3); }
291  	| cexpr AND cexpr
292 		{ $$ = tree_expr(T_AND, $1, $3); }
293 	| cexpr '|' cexpr
294 		{ $$ = tree_expr(T_BITOR, $1, $3); }
295 	| cexpr '^' cexpr
296 		{ $$ = tree_expr(T_BITXOR, $1, $3); }
297 	| cexpr '&' cexpr
298 		{ $$ = tree_expr(T_BITAND, $1, $3); }
299 	| cexpr EQ cexpr
300 		{ $$ = tree_expr(T_EQ, $1, $3); }
301 	| cexpr NE cexpr
302 		{ $$ = tree_expr(T_NE, $1, $3); }
303 	| cexpr '<' cexpr
304 		{ $$ = tree_expr(T_LT, $1, $3); }
305 	| cexpr LE cexpr
306 		{ $$ = tree_expr(T_LE, $1, $3); }
307 	| cexpr '>' cexpr
308 		{ $$ = tree_expr(T_GT, $1, $3); }
309 	| cexpr GE cexpr
310 		{ $$ = tree_expr(T_GE, $1, $3); }
311 	| cexpr LSHIFT cexpr
312 		{ $$ = tree_expr(T_LSHIFT, $1, $3); }
313 	| cexpr RSHIFT cexpr
314 		{ $$ = tree_expr(T_RSHIFT, $1, $3); }
315 	| cexpr '-' cexpr
316 		{ $$ = tree_expr(T_SUB, $1, $3); }
317 	| cexpr '+' cexpr
318 		{ $$ = tree_expr(T_ADD, $1, $3); }
319 	| cexpr '*' cexpr
320 		{ $$ = tree_expr(T_MUL, $1, $3); }
321 	| cexpr DIV cexpr
322 		{ $$ = tree_expr(T_DIV, $1, $3); }
323 	| cexpr '/' cexpr
324 		{ $$ = tree_expr(T_DIV, $1, $3); }
325 	| cexpr '%' cexpr
326 		{ $$ = tree_expr(T_MOD, $1, $3); }
327 	|  '!' cexpr
328 		{ $$ = tree_expr(T_NOT, $2, NULL); }
329 	|  '~' cexpr
330 		{ $$ = tree_expr(T_BITNOT, $2, NULL); }
331 	| '(' cexpr ')'
332 		{ $$ = $2; }
333 	| func
334 	| NUMBER
335 		{ $$ = tree_num($1.s, $1.file, $1.line); }
336 	| ID
337        		{
338 			/* iteration variable */
339 			$$ = tree_name($1.s, IT_NONE, $1.file, $1.line);
340 		}
341 	| globid
342 	| QUOTE
343 		{ $$ = tree_quote($1.s, $1.file, $1.line); }
344 	;
345 
346 func	: ID '(' ')'
347 		{ $$ = tree_func($1.s, NULL, $1.file, $1.line); }
348 	| ID '(' exprlist ')'
349 		{ $$ = tree_func($1.s, $3, $1.file, $1.line); }
350 	| PATHFUNC '(' parglist ')'
351 		{ $$ = tree_func($1.s, $3, $1.file, $1.line); }
352 	| pfunc
353 	;
354 
355 parglist: parg
356 	| parglist ',' parg
357 		{ $$ = tree_expr(T_LIST, $1, $3); }
358 	;
359 
360 parg	: pfunc
361 	| pname
362 		{ $$ = tree_pname($1); }
363 	| QUOTE
364 		{ $$ = tree_quote($1.s, $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  */
371 pfunc	: 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 
379 globid	: '$' ID
380        		{ $$ = tree_globid($2.s, $2.file, $2.line); }
381 	;
382 
383 iterid	: 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 */
408 iname	: 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 */
413 ename	: 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 */
441 enameid	: 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 */
453 pname	: iterid
454 	| pname '/' iterid
455 		{ $$ = tree_name_append($1, $3); }
456 	;
457 
458 /* ipname is an "instanced" pathname, like x0/y1 */
459 ipname	: iname
460 	| ipname '/' iname
461 		{ $$ = tree_name_append($1, $3); }
462 	;
463 
464 %%
465