1 #include "recipe.h" 2 #include "lexer.h" 3 #include "token.h" 4 #include "funcs.h" 5 6 static const char rcsid[]="$Id: recipeparse.C,v 1.11 2010/06/01 00:13:28 mrsam Exp $"; 7 ParseRecipe(Lexer & l)8int Recipe::ParseRecipe(Lexer &l) 9 { 10 lex= &l; 11 lex->token(cur_tok); 12 try 13 { 14 topNode=ParseStatementList(); 15 } 16 catch (const char *p) 17 { 18 l.errmsg(p); 19 return (-1); 20 } 21 #if NEED_NONCONST_EXCEPTIONS 22 catch (char *p) 23 { 24 l.errmsg(p); 25 return (-1); 26 } 27 #endif 28 if (cur_tok.Type() != cur_tok.eof) 29 { 30 l.errmsg("Syntax error."); 31 return (-1); 32 } 33 return (0); 34 } 35 ParseStatementList()36RecipeNode *Recipe::ParseStatementList() 37 { 38 RecipeNode *n=alloc(RecipeNode::statementlist); 39 Token::tokentype type; 40 41 while ( (type=cur_tok.Type()) != cur_tok.rbrace && type != cur_tok.eof) 42 { 43 if (type == cur_tok.semicolon) 44 { 45 lex->token(cur_tok); 46 continue; 47 } 48 49 RecipeNode *o=ParseStatement(); 50 51 n->AppendSibling(o); 52 } 53 return (n); 54 } 55 ParseStatement()56RecipeNode *Recipe::ParseStatement() 57 { 58 RecipeNode *n, *o; 59 60 switch (cur_tok.Type()) { 61 case Token::tokenif: 62 lex->token(cur_tok); 63 if (cur_tok.Type() != Token::lparen) 64 throw "Syntax error after if"; 65 66 lex->token(cur_tok); 67 68 n=alloc(RecipeNode::ifelse); 69 o=ParseExpr(); 70 71 n->AppendSibling(o); 72 73 if (cur_tok.Type() != Token::rparen) 74 throw "Missing )"; 75 76 lex->token(cur_tok); 77 if (cur_tok.Type() != Token::semicolon) // Newline/semicolon 78 throw "Syntax error after )"; 79 80 lex->token(cur_tok); 81 n->AppendSibling(ParseSubStatement()); 82 if (cur_tok.Type() == Token::tokenelse) 83 { 84 lex->token(cur_tok); 85 if (cur_tok.Type() != Token::semicolon) // Newline/semicolon 86 throw "Syntax error after else"; 87 88 lex->token(cur_tok); 89 n->AppendSibling(ParseSubStatement()); 90 } 91 else if (cur_tok.Type() == Token::tokenelsif) 92 { 93 cur_tok.Type(Token::tokenif); 94 n->AppendSibling(ParseStatement()); 95 } 96 return (n); 97 case Token::tokenwhile: 98 lex->token(cur_tok); 99 if (cur_tok.Type() != Token::lparen) 100 throw "Syntax error after while"; 101 102 lex->token(cur_tok); 103 104 n=alloc(RecipeNode::whileloop); 105 o=ParseExpr(); 106 n->AppendSibling(o); 107 108 if (cur_tok.Type() != Token::rparen) 109 throw "Missing )"; 110 111 lex->token(cur_tok); 112 if (cur_tok.Type() != Token::semicolon) // Newline/semicolon 113 throw "Syntax error after else"; 114 115 lex->token(cur_tok); 116 n->AppendSibling(ParseSubStatement()); 117 return (n); 118 case Token::lbrace: 119 lex->token(cur_tok); 120 n=ParseStatementList(); 121 if (cur_tok.Type() != Token::rbrace) 122 throw "Missing }"; 123 124 lex->token(cur_tok); 125 if (cur_tok.Type() != Token::semicolon) 126 { 127 throw "Syntax error after }"; 128 } 129 lex->token(cur_tok); 130 return (n); 131 case Token::tokento: 132 lex->token(cur_tok); 133 n=alloc(RecipeNode::deliver); 134 o=ParseExpr(); 135 n->AppendSibling(o); 136 if (cur_tok.Type() != Token::semicolon) 137 throw "Syntax error."; 138 139 lex->token(cur_tok); 140 return (n); 141 case Token::tokencc: 142 lex->token(cur_tok); 143 n=alloc(RecipeNode::delivercc); 144 o=ParseExpr(); 145 n->AppendSibling(o); 146 if (cur_tok.Type() != Token::semicolon) 147 throw "Syntax error."; 148 149 lex->token(cur_tok); 150 return (n); 151 case Token::exception: 152 lex->token(cur_tok); 153 if (cur_tok.Type() != Token::lbrace) 154 throw "Syntax error."; 155 156 n=alloc(RecipeNode::exception); 157 o=ParseStatement(); 158 n->AppendSibling(o); 159 return (n); 160 case Token::echo: 161 lex->token(cur_tok); 162 n=alloc(RecipeNode::echo); 163 n->AppendSibling( ParseExpr()); 164 if (cur_tok.Type() != Token::semicolon) 165 throw "Syntax error."; 166 lex->token(cur_tok); 167 return (n); 168 case Token::tokenxfilter: 169 lex->token(cur_tok); 170 n=alloc(RecipeNode::xfilter); 171 n->AppendSibling( ParseExpr()); 172 if (cur_tok.Type() != Token::semicolon) 173 throw "Syntax error."; 174 lex->token(cur_tok); 175 return (n); 176 case Token::dotlock: 177 lex->token(cur_tok); 178 n=alloc(RecipeNode::dotlock); 179 n->AppendSibling( ParseExpr()); 180 if (cur_tok.Type() != Token::lbrace) 181 throw "Syntax error."; 182 n->AppendSibling( ParseStatement() ); 183 return (n); 184 case Token::flock: 185 lex->token(cur_tok); 186 n=alloc(RecipeNode::flock); 187 n->AppendSibling( ParseExpr()); 188 if (cur_tok.Type() != Token::lbrace) 189 throw "Syntax error."; 190 n->AppendSibling( ParseStatement() ); 191 return (n); 192 case Token::logfile: 193 lex->token(cur_tok); 194 n=alloc(RecipeNode::logfile); 195 n->AppendSibling( ParseExpr()); 196 if (cur_tok.Type() != Token::semicolon) 197 throw "Syntax error."; 198 lex->token(cur_tok); 199 return (n); 200 case Token::log: 201 lex->token(cur_tok); 202 n=alloc(RecipeNode::log); 203 n->AppendSibling( ParseExpr()); 204 if (cur_tok.Type() != Token::semicolon) 205 throw "Syntax error."; 206 lex->token(cur_tok); 207 return (n); 208 case Token::include: 209 lex->token(cur_tok); 210 n=alloc(RecipeNode::include); 211 n->AppendSibling( ParseExpr()); 212 if (cur_tok.Type() != Token::semicolon) 213 throw "Syntax error."; 214 lex->token(cur_tok); 215 return (n); 216 case Token::exit: 217 lex->token(cur_tok); 218 n=alloc(RecipeNode::exit); 219 if (cur_tok.Type() != Token::semicolon) 220 throw "Syntax error."; 221 lex->token(cur_tok); 222 return (n); 223 case Token::foreach: 224 lex->token(cur_tok); 225 n=alloc(RecipeNode::foreach); 226 n->AppendSibling( ParseExpr()); 227 if (n->firstChild->nodeType != RecipeNode::strregexp && 228 n->firstChild->nodeType != RecipeNode::regexpr) 229 throw "Syntax error."; 230 if (cur_tok.Type() != Token::semicolon) 231 throw "Syntax error."; 232 lex->token(cur_tok); 233 n->AppendSibling( ParseSubStatement() ); 234 return (n); 235 case Token::importtoken: 236 lex->token(cur_tok); 237 n=alloc(RecipeNode::importtoken); 238 n->AppendSibling( ParseExpr()); 239 if (cur_tok.Type() != Token::semicolon) 240 throw "Syntax error."; 241 lex->token(cur_tok); 242 return (n); 243 case Token::unset: 244 lex->token(cur_tok); 245 n=alloc(RecipeNode::unset); 246 n->AppendSibling( ParseExpr()); 247 if (cur_tok.Type() != Token::semicolon) 248 throw "Syntax error."; 249 lex->token(cur_tok); 250 return (n); 251 default: 252 break; 253 } 254 n=ParseExpr(); 255 if (cur_tok.Type() != Token::semicolon) 256 throw "Syntax error."; 257 lex->token(cur_tok); 258 return (n); 259 } 260 ParseSubStatement()261RecipeNode *Recipe::ParseSubStatement() 262 { 263 if (cur_tok.Type() == Token::semicolon) 264 { 265 lex->token(cur_tok); 266 return alloc(RecipeNode::statementlist); 267 } 268 return ParseStatement(); 269 } 270 ParseAssign()271RecipeNode *Recipe::ParseAssign() 272 { 273 RecipeNode *n=ParseLogicalOr(); 274 275 while (cur_tok.Type() == Token::equals) 276 { 277 lex->token(cur_tok); 278 279 if (n->nodeType != RecipeNode::qstring) 280 throw "Syntax error before ="; 281 282 RecipeNode *o=alloc(RecipeNode::assignment); 283 o->AppendSibling(n); 284 285 n=ParseLogicalOr(); 286 o->AppendSibling(n); 287 n=o; 288 } 289 return (n); 290 } 291 ParseLogicalOr()292RecipeNode *Recipe::ParseLogicalOr() 293 { 294 RecipeNode *n=ParseLogicalAnd(); 295 296 while (cur_tok.Type() == Token::lor) 297 { 298 lex->token(cur_tok); 299 300 RecipeNode *o=alloc(RecipeNode::logicalor); 301 302 o->AppendSibling(n); 303 304 n=ParseLogicalAnd(); 305 o->AppendSibling(n); 306 n=o; 307 } 308 return (n); 309 } 310 ParseLogicalAnd()311RecipeNode *Recipe::ParseLogicalAnd() 312 { 313 RecipeNode *n=ParseComparison(); 314 315 while (cur_tok.Type() == Token::land) 316 { 317 lex->token(cur_tok); 318 319 RecipeNode *o=alloc(RecipeNode::logicaland); 320 321 o->AppendSibling(n); 322 323 n=ParseComparison(); 324 o->AppendSibling(n); 325 n=o; 326 } 327 return (n); 328 } 329 ParseComparison()330RecipeNode *Recipe::ParseComparison() 331 { 332 RecipeNode *n=ParseBitwiseOr(); 333 RecipeNode *o; 334 335 switch (cur_tok.Type()) { 336 case Token::lt: 337 o=alloc(RecipeNode::lessthan); 338 break; 339 case Token::le: 340 o=alloc(RecipeNode::lessthanoreq); 341 break; 342 case Token::gt: 343 o=alloc(RecipeNode::greaterthan); 344 break; 345 case Token::ge: 346 o=alloc(RecipeNode::greaterthanoreq); 347 break; 348 case Token::eq: 349 o=alloc(RecipeNode::equal); 350 break; 351 case Token::ne: 352 o=alloc(RecipeNode::notequal); 353 break; 354 case Token::slt: 355 o=alloc(RecipeNode::strlessthan); 356 break; 357 case Token::sle: 358 o=alloc(RecipeNode::strlessthanoreq); 359 break; 360 case Token::sgt: 361 o=alloc(RecipeNode::strgreaterthan); 362 break; 363 case Token::sge: 364 o=alloc(RecipeNode::strgreaterthanoreq); 365 break; 366 case Token::seq: 367 o=alloc(RecipeNode::strequal); 368 break; 369 case Token::sne: 370 o=alloc(RecipeNode::strnotequal); 371 break; 372 default: 373 return (n); 374 } 375 376 lex->token(cur_tok); 377 o->AppendSibling(n); 378 n=ParseBitwiseOr(); 379 o->AppendSibling(n); 380 return (o); 381 } 382 ParseBitwiseOr()383RecipeNode *Recipe::ParseBitwiseOr() 384 { 385 RecipeNode *n=ParseBitwiseAnd(); 386 387 while (cur_tok.Type() == Token::bor) 388 { 389 lex->token(cur_tok); 390 391 RecipeNode *o=alloc(RecipeNode::bitwiseor); 392 393 o->AppendSibling(n); 394 395 n=ParseBitwiseAnd(); 396 o->AppendSibling(n); 397 n=o; 398 } 399 return (n); 400 } 401 ParseBitwiseAnd()402RecipeNode *Recipe::ParseBitwiseAnd() 403 { 404 RecipeNode *n=ParseAddSub(); 405 406 while (cur_tok.Type() == Token::band) 407 { 408 lex->token(cur_tok); 409 410 RecipeNode *o=alloc(RecipeNode::bitwiseand); 411 412 o->AppendSibling(n); 413 414 n=ParseAddSub(); 415 o->AppendSibling(n); 416 n=o; 417 } 418 return (n); 419 } 420 ParseAddSub()421RecipeNode *Recipe::ParseAddSub() 422 { 423 RecipeNode *n=ParseMultDiv(); 424 RecipeNode *o; 425 426 for (;;) { 427 switch (cur_tok.Type()) { 428 case Token::plus: 429 o=alloc(RecipeNode::add); 430 break; 431 case Token::minus: 432 o=alloc(RecipeNode::subtract); 433 break; 434 default: 435 return (n); 436 } 437 438 lex->token(cur_tok); 439 o->AppendSibling(n); 440 n=ParseMultDiv(); 441 o->AppendSibling(n); 442 n=o; 443 } 444 } 445 ParseMultDiv()446RecipeNode *Recipe::ParseMultDiv() 447 { 448 RecipeNode *n=ParseStrRegExp(); 449 RecipeNode *o; 450 451 for (;;) { 452 switch (cur_tok.Type()) { 453 case Token::mult: 454 o=alloc(RecipeNode::multiply); 455 break; 456 case Token::divi: 457 o=alloc(RecipeNode::divide); 458 break; 459 default: 460 return (n); 461 } 462 463 lex->token(cur_tok); 464 o->AppendSibling(n); 465 n=ParseElement(); 466 o->AppendSibling(n); 467 n=o; 468 } 469 } 470 ParseStrRegExp()471RecipeNode *Recipe::ParseStrRegExp() 472 { 473 RecipeNode *n=ParseElement(); 474 475 while ( cur_tok.Type() == Token::strregexp) 476 { 477 RecipeNode *o; 478 479 o=alloc(RecipeNode::strregexp); 480 lex->token(cur_tok); 481 o->AppendSibling(n); 482 if (cur_tok.Type() != Token::regexpr) 483 throw "Syntax error after =~"; 484 485 n=ParseElement(); 486 o->AppendSibling(n); 487 n=o; 488 } 489 return (n); 490 } 491 ParseElement()492RecipeNode *Recipe::ParseElement() 493 { 494 RecipeNode *n, *o; 495 496 switch (cur_tok.Type()) { 497 case Token::length: 498 n=alloc(RecipeNode::strlength); 499 lex->token(cur_tok); 500 o=ParseElement(); 501 n->AppendSibling(o); 502 return (n); 503 case Token::substr: 504 n=alloc(RecipeNode::strsubstr); 505 lex->token(cur_tok); 506 if (cur_tok.Type() != Token::lparen) 507 throw "Missing ("; 508 509 lex->token(cur_tok); 510 o=ParseExpr(); 511 n->AppendSibling(o); 512 if (cur_tok.Type() != Token::comma) 513 throw "Missing ,"; 514 515 lex->token(cur_tok); 516 o=ParseExpr(); 517 n->AppendSibling(o); 518 if (cur_tok.Type() == Token::comma) 519 { 520 lex->token(cur_tok); 521 o=ParseExpr(); 522 n->AppendSibling(o); 523 } 524 if (cur_tok.Type() != Token::rparen) 525 throw "Missing )"; 526 527 lex->token(cur_tok); 528 return (n); 529 case Token::getaddr: 530 lex->token(cur_tok); 531 n=alloc(RecipeNode::getaddr); 532 n->AppendSibling(ParseElement()); 533 return (n); 534 case Token::escape: 535 lex->token(cur_tok); 536 n=alloc(RecipeNode::escape); 537 n->AppendSibling(ParseElement()); 538 return (n); 539 case Token::regexpr: 540 n=alloc(RecipeNode::regexpr); 541 n->str=cur_tok.String(); 542 lex->token(cur_tok); 543 return (n); 544 case Token::lparen: 545 lex->token(cur_tok); 546 n=ParseExpr(); 547 if (cur_tok.Type() != Token::rparen) 548 throw "Missing )"; 549 550 lex->token(cur_tok); 551 return (n); 552 case Token::logicalnot: 553 lex->token(cur_tok); 554 n=alloc(RecipeNode::logicalnot); 555 o=ParseElement(); 556 n->AppendSibling(o); 557 return (n); 558 case Token::bitwisenot: 559 lex->token(cur_tok); 560 n=alloc(RecipeNode::bitwisenot); 561 o=ParseElement(); 562 n->AppendSibling(o); 563 return (n); 564 case Token::lookup: 565 n=alloc(RecipeNode::lookup); 566 lex->token(cur_tok); 567 if (cur_tok.Type() != Token::lparen) 568 throw "Missing ("; 569 570 lex->token(cur_tok); 571 o=ParseExpr(); 572 n->AppendSibling(o); 573 if (cur_tok.Type() != Token::comma) 574 throw "Missing ,"; 575 576 lex->token(cur_tok); 577 o=ParseExpr(); 578 n->AppendSibling(o); 579 if (cur_tok.Type() == Token::comma) 580 { 581 lex->token(cur_tok); 582 o=ParseExpr(); 583 n->AppendSibling(o); 584 } 585 if (cur_tok.Type() != Token::rparen) 586 throw "Missing )"; 587 lex->token(cur_tok); 588 return (n); 589 case Token::to_lower: 590 lex->token(cur_tok); 591 n=alloc(RecipeNode::to_lower); 592 n->AppendSibling(ParseElement()); 593 return (n); 594 case Token::to_upper: 595 lex->token(cur_tok); 596 n=alloc(RecipeNode::to_upper); 597 n->AppendSibling(ParseElement()); 598 return (n); 599 case Token::hasaddr: 600 lex->token(cur_tok); 601 n=alloc(RecipeNode::hasaddr); 602 n->AppendSibling(ParseElement()); 603 return (n); 604 #ifdef DbObj 605 case Token::gdbmopen: 606 lex->token(cur_tok); 607 if (cur_tok.Type() != Token::lparen) 608 throw "Missing (."; 609 610 lex->token(cur_tok); 611 n=alloc(RecipeNode::gdbmopen); 612 o=ParseExpr(); 613 n->AppendSibling(o); 614 if (cur_tok.Type() == Token::comma) 615 { 616 lex->token(cur_tok); 617 o=ParseExpr(); 618 n->AppendSibling(o); 619 } 620 if (cur_tok.Type() != Token::rparen) 621 throw "Missing )"; 622 lex->token(cur_tok); 623 return (n); 624 case Token::gdbmclose: 625 lex->token(cur_tok); 626 return (alloc(RecipeNode::gdbmclose)); 627 case Token::gdbmfetch: 628 lex->token(cur_tok); 629 if (cur_tok.Type() != Token::lparen) 630 throw "Missing (."; 631 632 lex->token(cur_tok); 633 n=alloc(RecipeNode::gdbmfetch); 634 o=ParseExpr(); 635 n->AppendSibling(o); 636 if (cur_tok.Type() == Token::comma) 637 { 638 lex->token(cur_tok); 639 o=ParseExpr(); 640 n->AppendSibling(o); 641 } 642 if (cur_tok.Type() == Token::comma) 643 { 644 lex->token(cur_tok); 645 o=ParseExpr(); 646 n->AppendSibling(o); 647 } 648 if (cur_tok.Type() != Token::rparen) 649 throw "Missing )"; 650 lex->token(cur_tok); 651 return (n); 652 case Token::gdbmstore: 653 lex->token(cur_tok); 654 if (cur_tok.Type() != Token::lparen) 655 throw "Missing (."; 656 657 lex->token(cur_tok); 658 n=alloc(RecipeNode::gdbmstore); 659 o=ParseExpr(); 660 n->AppendSibling(o); 661 if (cur_tok.Type() != Token::comma) 662 throw "Missing ,."; 663 664 lex->token(cur_tok); 665 o=ParseExpr(); 666 n->AppendSibling(o); 667 if (cur_tok.Type() != Token::rparen) 668 throw "Missing )"; 669 lex->token(cur_tok); 670 return (n); 671 #else 672 case Token::gdbmopen: 673 case Token::gdbmclose: 674 case Token::gdbmfetch: 675 case Token::gdbmstore: 676 throw "GDBM/DB support is not available."; 677 #endif 678 case Token::timetoken: 679 lex->token(cur_tok); 680 return (alloc(RecipeNode::timetoken)); 681 default: 682 break; 683 } 684 return (ParseString()); 685 } 686 687 //////////////////////////////////////////////////////////////////////////// 688 // 689 // Parse a string. Consecutive strings are automatically concatenated. 690 // 691 //////////////////////////////////////////////////////////////////////////// 692 ParseString()693RecipeNode *Recipe::ParseString() 694 { 695 RecipeNode *n=NULL; 696 RecipeNode *s=NULL; 697 698 for (;;) 699 { 700 if (s && s->nodeType != RecipeNode::concat) 701 { 702 n=alloc(RecipeNode::concat); 703 n->AppendSibling(s); 704 s=n; 705 } 706 707 switch (cur_tok.Type()) { 708 case Token::qstring: 709 n=alloc(RecipeNode::qstring); 710 break; 711 case Token::sqstring: 712 n=alloc(RecipeNode::sqstring); 713 break; 714 case Token::btstring: 715 n=alloc(RecipeNode::btstring); 716 break; 717 default: 718 throw "Syntax error."; 719 } 720 721 n->str=cur_tok.String(); 722 lex->token(cur_tok); 723 if (s) s->AppendSibling(n); 724 else s=n; 725 726 switch (cur_tok.Type()) { 727 case Token::qstring: 728 case Token::sqstring: 729 case Token::btstring: 730 continue; 731 default: 732 break; 733 } 734 break; 735 } 736 return (s); 737 } 738