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 2006 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