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 /* 24 * awk -- YACC grammar 25 * 26 * Copyright (c) 1995 by Sun Microsystems, Inc. 27 * 28 * Copyright 1986, 1992 by Mortice Kern Systems Inc. All rights reserved. 29 * 30 * This Software is unpublished, valuable, confidential property of 31 * Mortice Kern Systems Inc. Use is authorized only in accordance 32 * with the terms and conditions of the source licence agreement 33 * protecting this Software. Any unauthorized use or disclosure of 34 * this Software is strictly prohibited and will result in the 35 * termination of the licence agreement. 36 * 37 * NOTE: this grammar correctly produces NO shift/reduce conflicts from YACC. 38 * 39 */ 40 41 /* 42 * Do not use any character constants as tokens, so the resulting C file 43 * is codeset independent. 44 */ 45 46 #ident "%Z%%M% %I% %E% SMI" 47 #include "awk.h" 48 static NODE * fliplist ANSI((NODE *np)); 49 %} 50 51 %union { 52 NODE *node; 53 }; 54 55 /* 56 * Do not use any character constants as tokens, so the resulting C file 57 * is codeset independent. 58 * 59 * Declare terminal symbols before their operator 60 * precedences to get them in a contiguous block 61 * for giant switches in action() and exprreduce(). 62 */ 63 /* Tokens from exprreduce() */ 64 %token <node> PARM ARRAY UFUNC FIELD IN INDEX CONCAT 65 %token <node> NOT AND OR EXP QUEST 66 %token <node> EQ NE GE LE GT LT 67 %token <node> ADD SUB MUL DIV REM INC DEC PRE_INC PRE_DEC 68 %token <node> GETLINE CALLFUNC RE TILDE NRE 69 70 /* Tokens shared by exprreduce() and action() */ 71 %token ASG 72 73 /* Tokens from action() */ 74 %token <node> PRINT PRINTF 75 %token <node> EXIT RETURN BREAK CONTINUE NEXT 76 %token <node> DELETE WHILE DO FOR FORIN IF 77 78 /* 79 * Terminal symbols not used in action() and exprrreduce() 80 * switch statements. 81 */ 82 %token <node> CONSTANT VAR FUNC 83 %token <node> DEFFUNC BEGIN END CLOSE ELSE PACT 84 %right ELSE 85 %token DOT CALLUFUNC 86 87 /* 88 * Tokens not used in grammar 89 */ 90 %token KEYWORD SVAR 91 %token PIPESYM 92 93 /* 94 * Tokens representing character constants 95 * TILDE, '~', taken care of above 96 */ 97 %token BAR /* '|' */ 98 CARAT /* '^' */ 99 LANGLE /* '<' */ 100 RANGLE /* '>' */ 101 PLUSC /* '+' */ 102 HYPHEN /* '-' */ 103 STAR /* '*' */ 104 SLASH /* '/' */ 105 PERCENT /* '%' */ 106 EXCLAMATION /* '!' */ 107 DOLLAR /* '$' */ 108 LSQUARE /* '[' */ 109 RSQUARE /* ']' */ 110 LPAREN /* '(' */ 111 RPAREN /* ')' */ 112 SEMI /* ';' */ 113 LBRACE /* '{' */ 114 RBRACE /* '}' */ 115 116 /* 117 * Priorities of operators 118 * Lowest to highest 119 */ 120 %left COMMA 121 %right BAR PIPE WRITE APPEND 122 %right ASG AADD ASUB AMUL ADIV AREM AEXP 123 %right QUEST COLON 124 %left OR 125 %left AND 126 %left IN 127 %left CARAT 128 %left TILDE NRE 129 %left EQ NE LANGLE RANGLE GE LE 130 %left CONCAT 131 %left PLUSC HYPHEN 132 %left STAR SLASH PERCENT 133 %right UPLUS UMINUS 134 %right EXCLAMATION 135 %right EXP 136 %right INC DEC URE 137 %left DOLLAR LSQUARE RSQUARE 138 %left LPAREN RPAREN 139 140 %type <node> prog rule pattern expr rvalue lvalue fexpr varlist varlist2 141 %type <node> statement statlist fileout exprlist eexprlist simplepattern 142 %type <node> getline optvar var 143 %type <node> dummy 144 145 %start dummy 146 %% 147 148 dummy: 149 prog = { 150 yytree = fliplist(yytree); 151 } 152 ; 153 prog: 154 rule = { 155 yytree = $1; 156 } 157 | rule SEMI prog = { 158 if ($1 != NNULL) { 159 if (yytree != NNULL) 160 yytree = node(COMMA, $1, yytree); else 161 yytree = $1; 162 } 163 } 164 ; 165 166 rule: pattern LBRACE statlist RBRACE = { 167 $$ = node(PACT, $1, $3); 168 doing_begin = 0; 169 } 170 | LBRACE statlist RBRACE = { 171 npattern++; 172 $$ = node(PACT, NNULL, $2); 173 } 174 | pattern = { 175 $$ = node(PACT, $1, node(PRINT, NNULL, NNULL)); 176 doing_begin = 0; 177 } 178 | DEFFUNC VAR 179 { $2->n_type = UFUNC; funparm = 1; } 180 LPAREN varlist RPAREN 181 { funparm = 0; } 182 LBRACE statlist { uexit($5); } RBRACE = { 183 $2->n_ufunc = node(DEFFUNC, $5, fliplist($9)); 184 $$ = NNULL; 185 } 186 | DEFFUNC UFUNC = { 187 awkerr((char *) gettext("function \"%S\" redefined"), $2->n_name); 188 /* NOTREACHED */ 189 } 190 | = { 191 $$ = NNULL; 192 } 193 ; 194 195 pattern: 196 simplepattern 197 | expr COMMA expr = { 198 ++npattern; 199 $$ = node(COMMA, $1, $3); 200 } 201 ; 202 203 simplepattern: 204 BEGIN = { 205 $$ = node(BEGIN, NNULL, NNULL); 206 doing_begin++; 207 } 208 | END = { 209 ++npattern; 210 $$ = node(END, NNULL, NNULL); 211 } 212 | expr = { 213 ++npattern; 214 $$ = $1; 215 } 216 ; 217 218 eexprlist: 219 exprlist 220 | = { 221 $$ = NNULL; 222 } 223 ; 224 225 exprlist: 226 expr %prec COMMA 227 | exprlist COMMA expr = { 228 $$ = node(COMMA, $1, $3); 229 } 230 ; 231 232 varlist: 233 = { 234 $$ = NNULL; 235 } 236 | varlist2 237 ; 238 239 varlist2: 240 var 241 | var COMMA varlist2 = { 242 $$ = node(COMMA, $1, $3); 243 } 244 ; 245 246 fexpr: 247 expr 248 | = { 249 $$ = NNULL; 250 } 251 ; 252 253 /* 254 * Normal expression (includes regular expression) 255 */ 256 expr: 257 expr PLUSC expr = { 258 $$ = node(ADD, $1, $3); 259 } 260 | expr HYPHEN expr = { 261 $$ = node(SUB, $1, $3); 262 } 263 | expr STAR expr = { 264 $$ = node(MUL, $1, $3); 265 } 266 | expr SLASH expr = { 267 $$ = node(DIV, $1, $3); 268 } 269 | expr PERCENT expr = { 270 $$ = node(REM, $1, $3); 271 } 272 | expr EXP expr = { 273 $$ = node(EXP, $1, $3); 274 } 275 | expr AND expr = { 276 $$ = node(AND, $1, $3); 277 } 278 | expr OR expr = { 279 $$ = node(OR, $1, $3); 280 } 281 | expr QUEST expr COLON expr = { 282 $$ = node(QUEST, $1, node(COLON, $3, $5)); 283 } 284 | lvalue ASG expr = { 285 $$ = node(ASG, $1, $3); 286 } 287 | lvalue AADD expr = { 288 $$ = node(AADD, $1, $3); 289 } 290 | lvalue ASUB expr = { 291 $$ = node(ASUB, $1, $3); 292 } 293 | lvalue AMUL expr = { 294 $$ = node(AMUL, $1, $3); 295 } 296 | lvalue ADIV expr = { 297 $$ = node(ADIV, $1, $3); 298 } 299 | lvalue AREM expr = { 300 $$ = node(AREM, $1, $3); 301 } 302 | lvalue AEXP expr = { 303 $$ = node(AEXP, $1, $3); 304 } 305 | lvalue INC = { 306 $$ = node(INC, $1, NNULL); 307 } 308 | lvalue DEC = { 309 $$ = node(DEC, $1, NNULL); 310 } 311 | expr EQ expr = { 312 $$ = node(EQ, $1, $3); 313 } 314 | expr NE expr = { 315 $$ = node(NE, $1, $3); 316 } 317 | expr RANGLE expr = { 318 $$ = node(GT, $1, $3); 319 } 320 | expr LANGLE expr = { 321 $$ = node(LT, $1, $3); 322 } 323 | expr GE expr = { 324 $$ = node(GE, $1, $3); 325 } 326 | expr LE expr = { 327 $$ = node(LE, $1, $3); 328 } 329 | expr TILDE expr = { 330 $$ = node(TILDE, $1, $3); 331 } 332 | expr NRE expr = { 333 $$ = node(NRE, $1, $3); 334 } 335 | expr IN var = { 336 $$ = node(IN, $3, $1); 337 } 338 | LPAREN exprlist RPAREN IN var = { 339 $$ = node(IN, $5, $2); 340 } 341 | getline 342 | rvalue 343 | expr CONCAT expr = { 344 $$ = node(CONCAT, $1, $3); 345 } 346 ; 347 348 lvalue: 349 DOLLAR rvalue = { 350 $$ = node(FIELD, $2, NNULL); 351 } 352 /* 353 * Prevents conflict with FOR LPAREN var IN var RPAREN production 354 */ 355 | var %prec COMMA 356 | var LSQUARE exprlist RSQUARE = { 357 $$ = node(INDEX, $1, $3); 358 } 359 ; 360 361 var: 362 VAR 363 | PARM 364 ; 365 366 rvalue: 367 lvalue %prec COMMA 368 | CONSTANT 369 | LPAREN expr RPAREN term = { 370 $$ = $2; 371 } 372 | EXCLAMATION expr = { 373 $$ = node(NOT, $2, NNULL); 374 } 375 | HYPHEN expr %prec UMINUS = { 376 $$ = node(SUB, const0, $2); 377 } 378 | PLUSC expr %prec UPLUS = { 379 $$ = $2; 380 } 381 | DEC lvalue = { 382 $$ = node(PRE_DEC, $2, NNULL); 383 } 384 | INC lvalue = { 385 $$ = node(PRE_INC, $2, NNULL); 386 } 387 | FUNC = { 388 $$ = node(CALLFUNC, $1, NNULL); 389 } 390 | FUNC LPAREN eexprlist RPAREN term = { 391 $$ = node(CALLFUNC, $1, $3); 392 } 393 | UFUNC LPAREN eexprlist RPAREN term = { 394 $$ = node(CALLUFUNC, $1, $3); 395 } 396 | VAR LPAREN eexprlist RPAREN term = { 397 $$ = node(CALLUFUNC, $1, $3); 398 } 399 | SLASH {redelim='/';} URE SLASH %prec URE = { 400 $$ = $<node>3; 401 } 402 ; 403 404 statement: 405 FOR LPAREN fexpr SEMI fexpr SEMI fexpr RPAREN statement = { 406 $$ = node(FOR, node(COMMA, $3, node(COMMA, $5, $7)), $9); 407 } 408 | FOR LPAREN var IN var RPAREN statement = { 409 register NODE *np; 410 411 /* 412 * attempt to optimize statements for the form 413 * for (i in x) delete x[i] 414 * to 415 * delete x 416 */ 417 np = $7; 418 if (np != NNULL 419 && np->n_type == DELETE 420 && (np = np->n_left)->n_type == INDEX 421 && np->n_left == $5 422 && np->n_right == $3) 423 $$ = node(DELETE, $5, NNULL); 424 else 425 $$ = node(FORIN, node(IN, $3, $5), $7); 426 } 427 | WHILE LPAREN expr RPAREN statement = { 428 $$ = node(WHILE, $3, $5); 429 } 430 | DO statement WHILE LPAREN expr RPAREN = { 431 $$ = node(DO, $5, $2); 432 } 433 | IF LPAREN expr RPAREN statement ELSE statement = { 434 $$ = node(IF, $3, node(ELSE, $5, $7)); 435 } 436 | IF LPAREN expr RPAREN statement %prec ELSE = { 437 $$ = node(IF, $3, node(ELSE, $5, NNULL)); 438 } 439 | CONTINUE SEMI = { 440 $$ = node(CONTINUE, NNULL, NNULL); 441 } 442 | BREAK SEMI = { 443 $$ = node(BREAK, NNULL, NNULL); 444 } 445 | NEXT SEMI = { 446 $$ = node(NEXT, NNULL, NNULL); 447 } 448 | DELETE lvalue SEMI = { 449 $$ = node(DELETE, $2, NNULL); 450 } 451 | RETURN fexpr SEMI = { 452 $$ = node(RETURN, $2, NNULL); 453 } 454 | EXIT fexpr SEMI = { 455 $$ = node(EXIT, $2, NNULL); 456 } 457 | PRINT eexprlist fileout SEMI = { 458 $$ = node(PRINT, $2, $3); 459 } 460 | PRINT LPAREN exprlist RPAREN fileout SEMI = { 461 $$ = node(PRINT, $3, $5); 462 } 463 | PRINTF exprlist fileout SEMI = { 464 $$ = node(PRINTF, $2, $3); 465 } 466 | PRINTF LPAREN exprlist RPAREN fileout SEMI = { 467 $$ = node(PRINTF, $3, $5); 468 } 469 | expr SEMI = { 470 $$ = $1; 471 } 472 | SEMI = { 473 $$ = NNULL; 474 } 475 | LBRACE statlist RBRACE = { 476 $$ = $2; 477 } 478 ; 479 480 481 statlist: 482 statement 483 | statlist statement = { 484 if ($1 == NNULL) 485 $$ = $2; 486 else if ($2 == NNULL) 487 $$ = $1; 488 else 489 $$ = node(COMMA, $1, $2); 490 } 491 ; 492 493 fileout: 494 WRITE expr = { 495 $$ = node(WRITE, $2, NNULL); 496 } 497 | APPEND expr = { 498 $$ = node(APPEND, $2, NNULL); 499 } 500 | PIPE expr = { 501 $$ = node(PIPE, $2, NNULL); 502 } 503 | = { 504 $$ = NNULL; 505 } 506 ; 507 508 getline: 509 GETLINE optvar %prec WRITE = { 510 $$ = node(GETLINE, $2, NNULL); 511 } 512 | expr BAR GETLINE optvar = { 513 $$ = node(GETLINE, $4, node(PIPESYM, $1, NNULL)); 514 } 515 | GETLINE optvar LANGLE expr = { 516 $$ = node(GETLINE, $2, node(LT, $4, NNULL)); 517 } 518 ; 519 520 optvar: 521 lvalue 522 | = { 523 $$ = NNULL; 524 } 525 ; 526 527 term: 528 {catterm = 1;} 529 ; 530 %% 531 /* 532 * Flip a left-recursively generated list 533 * so that it can easily be traversed from left 534 * to right without recursion. 535 */ 536 static NODE * 537 fliplist(np) 538 register NODE *np; 539 { 540 int type; 541 542 if (np!=NNULL && !isleaf(np->n_flags) 543 #if 0 544 && (type = np->n_type)!=FUNC && type!=UFUNC 545 #endif 546 ) { 547 np->n_right = fliplist(np->n_right); 548 if ((type=np->n_type)==COMMA) { 549 register NODE *lp; 550 551 while ((lp = np->n_left)!=NNULL && lp->n_type==COMMA) { 552 register NODE* *spp; 553 554 lp->n_right = fliplist(lp->n_right); 555 for (spp = &lp->n_right; 556 *spp != NNULL && (*spp)->n_type==COMMA; 557 spp = &(*spp)->n_right) 558 ; 559 np->n_left = *spp; 560 *spp = np; 561 np = lp; 562 } 563 } 564 if (np->n_left != NULL && 565 (type = np->n_left->n_type)!= FUNC && type!=UFUNC) 566 np->n_left = fliplist(np->n_left); 567 } 568 return (np); 569 } 570