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