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 2004 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 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 ; 193 194 nvname : ID 195 { $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); } 196 | nvname '-' ID 197 { 198 /* hack to allow dashes in property names */ 199 $$ = tree_name_repairdash($1, $3.s); 200 } 201 ; 202 203 /* the RHS of an nvpair can be a value, or an ename, or an ename@pname */ 204 nvexpr : numexpr 205 | ename epname 206 { $$ = tree_event($1, $2, NULL); } 207 | pname 208 | NUMBER ID 209 /* 210 * ID must be timevals only ("ms", "us", etc.). 211 * enforced by tree_timeval(). 212 */ 213 { $$ = tree_timeval($1.s, $2.s, $1.file, $1.line); } 214 | QUOTE 215 { $$ = tree_quote($1.s, $1.file, $1.line); } 216 ; 217 218 /* arithmetic operations, no variables or symbols */ 219 numexpr : numexpr '-' numexpr 220 { $$ = tree_expr(T_SUB, $1, $3); } 221 | numexpr '+' numexpr 222 { $$ = tree_expr(T_ADD, $1, $3); } 223 | numexpr '*' numexpr 224 { $$ = tree_expr(T_MUL, $1, $3); } 225 | numexpr DIV numexpr 226 { $$ = tree_expr(T_DIV, $1, $3); } 227 | numexpr '/' numexpr 228 { $$ = tree_expr(T_DIV, $1, $3); } 229 | numexpr '%' numexpr 230 { $$ = tree_expr(T_MOD, $1, $3); } 231 | '(' numexpr ')' 232 { $$ = $2; } 233 | NUMBER 234 { $$ = tree_num($1.s, $1.file, $1.line); } 235 ; 236 237 eventlist: event 238 | eventlist ',' event 239 { $$ = tree_expr(T_LIST, $1, $3); } 240 ; 241 242 event : ename epname eexprlist 243 { $$ = tree_event($1, $2, $3); } 244 ; 245 246 epname : /* empty */ 247 { $$ = NULL; } 248 | '@' pname 249 { $$ = $2; } 250 ; 251 252 eexprlist: /* empty */ 253 { $$ = NULL; } 254 | '{' exprlist '}' 255 { $$ = $2; } 256 ; 257 258 exprlist: expr 259 | exprlist ',' expr 260 { $$ = tree_expr(T_LIST, $1, $3); } 261 ; 262 263 /* 264 * note that expr does not include pname, to avoid reduce/reduce 265 * conflicts between cexpr and iterid involving the use of ID 266 */ 267 expr : cexpr 268 | NUMBER ID 269 /* 270 * ID must be timevals only ("ms", "us", etc.). 271 * enforced by tree_timeval(). 272 */ 273 { $$ = tree_timeval($1.s, $2.s, $1.file, $1.line); } 274 ; 275 276 cexpr : cexpr '=' cexpr 277 { $$ = tree_expr(T_ASSIGN, $1, $3); } 278 | cexpr '?' cexpr 279 { $$ = tree_expr(T_CONDIF, $1, $3); } 280 | cexpr ':' cexpr 281 { $$ = tree_expr(T_CONDELSE, $1, $3); } 282 | cexpr OR cexpr 283 { $$ = tree_expr(T_OR, $1, $3); } 284 | cexpr AND cexpr 285 { $$ = tree_expr(T_AND, $1, $3); } 286 | cexpr '|' cexpr 287 { $$ = tree_expr(T_BITOR, $1, $3); } 288 | cexpr '^' cexpr 289 { $$ = tree_expr(T_BITXOR, $1, $3); } 290 | cexpr '&' cexpr 291 { $$ = tree_expr(T_BITAND, $1, $3); } 292 | cexpr EQ cexpr 293 { $$ = tree_expr(T_EQ, $1, $3); } 294 | cexpr NE cexpr 295 { $$ = tree_expr(T_NE, $1, $3); } 296 | cexpr '<' cexpr 297 { $$ = tree_expr(T_LT, $1, $3); } 298 | cexpr LE cexpr 299 { $$ = tree_expr(T_LE, $1, $3); } 300 | cexpr '>' cexpr 301 { $$ = tree_expr(T_GT, $1, $3); } 302 | cexpr GE cexpr 303 { $$ = tree_expr(T_GE, $1, $3); } 304 | cexpr LSHIFT cexpr 305 { $$ = tree_expr(T_LSHIFT, $1, $3); } 306 | cexpr RSHIFT cexpr 307 { $$ = tree_expr(T_RSHIFT, $1, $3); } 308 | cexpr '-' cexpr 309 { $$ = tree_expr(T_SUB, $1, $3); } 310 | cexpr '+' cexpr 311 { $$ = tree_expr(T_ADD, $1, $3); } 312 | cexpr '*' cexpr 313 { $$ = tree_expr(T_MUL, $1, $3); } 314 | cexpr DIV cexpr 315 { $$ = tree_expr(T_DIV, $1, $3); } 316 | cexpr '/' cexpr 317 { $$ = tree_expr(T_DIV, $1, $3); } 318 | cexpr '%' cexpr 319 { $$ = tree_expr(T_MOD, $1, $3); } 320 | '!' cexpr 321 { $$ = tree_expr(T_NOT, $2, NULL); } 322 | '~' cexpr 323 { $$ = tree_expr(T_BITNOT, $2, NULL); } 324 | '(' cexpr ')' 325 { $$ = $2; } 326 | func 327 | NUMBER 328 { $$ = tree_num($1.s, $1.file, $1.line); } 329 | ID 330 { 331 /* iteration variable */ 332 $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); 333 } 334 | globid 335 | QUOTE 336 { $$ = tree_quote($1.s, $1.file, $1.line); } 337 ; 338 339 func : ID '(' ')' 340 { $$ = tree_func($1.s, NULL, $1.file, $1.line); } 341 | ID '(' exprlist ')' 342 { $$ = tree_func($1.s, $3, $1.file, $1.line); } 343 | PATHFUNC '(' parglist ')' 344 { $$ = tree_func($1.s, $3, $1.file, $1.line); } 345 | pfunc 346 ; 347 348 parglist: parg 349 | parglist ',' parg 350 { $$ = tree_expr(T_LIST, $1, $3); } 351 ; 352 353 parg : pfunc 354 | pname 355 { $$ = tree_pname($1); } 356 | QUOTE 357 { $$ = tree_quote($1.s, $1.file, $1.line); } 358 ; 359 360 /* asru() and fru() show up as functions in the parse tree */ 361 pfunc : ASRU '(' pname ')' 362 { $$ = tree_func($1.s, tree_pname($3), $1.file, $1.line); } 363 | FRU '(' pname ')' 364 { $$ = tree_func($1.s, tree_pname($3), $1.file, $1.line); } 365 ; 366 367 globid : '$' ID 368 { $$ = tree_globid($2.s, $2.file, $2.line); } 369 ; 370 371 iterid : ID 372 { $$ = tree_name($1.s, IT_VERTICAL, $1.file, $1.line); } 373 | ID '[' ']' 374 { $$ = tree_name($1.s, IT_VERTICAL, $1.file, $1.line); } 375 | ID '[' cexpr ']' 376 { 377 $$ = tree_name_iterator( 378 tree_name($1.s, IT_VERTICAL, $1.file, $1.line), $3); 379 } 380 | ID '<' '>' 381 { $$ = tree_name($1.s, IT_HORIZONTAL, $1.file, $1.line); } 382 | ID '<' ID '>' 383 { 384 $$ = tree_name_iterator( 385 tree_name($1.s, IT_HORIZONTAL, $1.file, $1.line), 386 tree_name($3.s, IT_NONE, $3.file, $3.line)); 387 } 388 ; 389 390 /* iname is an ID where we can peel numbers off the end */ 391 iname : ID 392 { $$ = tree_iname($1.s, $1.file, $1.line); } 393 ; 394 395 /* base case of ID.ID instead of just ID requires ename to contain one dot */ 396 ename : ID '.' enameid 397 { 398 $$ = tree_name_append( 399 tree_name($1.s, IT_ENAME, $1.file, $1.line), 400 tree_name($3.s, IT_NONE, $3.file, $3.line)); 401 } 402 | ename '.' enameid 403 { 404 $$ = tree_name_append($1, 405 tree_name($3.s, IT_NONE, $3.file, $3.line)); 406 } 407 | ename '-' enameid 408 { 409 /* 410 * hack to allow dashes in class names. when we 411 * detect the dash here, we know we're in a class 412 * name because the left recursion of this rule 413 * means we've already matched at least: 414 * ID '.' ID 415 * so the ename here has an incomplete final 416 * component (because the lexer stopped at the 417 * dash). so we repair that final component here. 418 */ 419 $$ = tree_name_repairdash($1, $3.s); 420 } 421 ; 422 423 /* like an ID, but we let reserved words act unreserved in enames */ 424 enameid : ID 425 | PROP 426 | MASK 427 | EVENT 428 | ENGINE 429 | ASRU 430 | FRU 431 | CONFIG 432 | IF 433 ; 434 435 /* pname is a pathname, like x/y, x<i>/y[0], etc */ 436 pname : iterid 437 | pname '/' iterid 438 { $$ = tree_name_append($1, $3); } 439 ; 440 441 /* ipname is an "instanced" pathname, like x0/y1 */ 442 ipname : iname 443 | ipname '/' iname 444 { $$ = tree_name_append($1, $3); } 445 ; 446 447 %% 448