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