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 
95 root	: stmtlist
96 		{ (void)tree_root($1); }
97 	;
98 
99 stmtlist   : /*empty*/
100 		{ $$ = NULL; }
101         | stmtlist stmt
102 		{ $$ = tree_expr(T_LIST, $1, $2); }
103 	;
104 
105 stmt	: 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 
139 propbody: 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 
149 nork	: /* empty */
150 		{ $$ = NULL; }
151 	| '(' norkexpr ')'
152 		{ $$ = $2; }
153 	;
154 
155 norkexpr: 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 
174 nvpairlist: /* empty */
175 		{ $$ = NULL; }
176 	| nvpair
177 	| nvpairlist ',' nvpair
178 		{ $$ = tree_expr(T_LIST, $1, $3); }
179 	;
180 
181 nvpair	: 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 
197 nvname	: 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 */
207 nvexpr	: 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 */
224 numexpr	: 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 
242 eventlist: event
243 	| eventlist ',' event
244 		{ $$ = tree_expr(T_LIST, $1, $3); }
245 	;
246 
247 event	: ename epname eexprlist
248 		{ $$ = tree_event($1, $2, $3); }
249 	;
250 
251 epname	: /* empty */
252 		{ $$ = NULL; }
253 	| '@' pname
254 		{ $$ = $2; }
255 	;
256 
257 eexprlist: /* empty */
258 		{ $$ = NULL; }
259 	| '{' exprlist '}'
260 		{ $$ = $2; }
261 	;
262 
263 exprlist: 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  */
272 expr	: 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 
281 cexpr	: 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 
344 func	: 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 
353 parglist: parg
354 	| parglist ',' parg
355 		{ $$ = tree_expr(T_LIST, $1, $3); }
356 	;
357 
358 parg	: 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  */
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