1 // 2 // Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include "DirectiveParser.h" 8 9 #include <cassert> 10 #include <cstdlib> 11 #include <sstream> 12 13 #include "DiagnosticsBase.h" 14 #include "DirectiveHandlerBase.h" 15 #include "ExpressionParser.h" 16 #include "MacroExpander.h" 17 #include "Token.h" 18 #include "Tokenizer.h" 19 20 namespace { 21 enum DirectiveType 22 { 23 DIRECTIVE_NONE, 24 DIRECTIVE_DEFINE, 25 DIRECTIVE_UNDEF, 26 DIRECTIVE_IF, 27 DIRECTIVE_IFDEF, 28 DIRECTIVE_IFNDEF, 29 DIRECTIVE_ELSE, 30 DIRECTIVE_ELIF, 31 DIRECTIVE_ENDIF, 32 DIRECTIVE_ERROR, 33 DIRECTIVE_PRAGMA, 34 DIRECTIVE_EXTENSION, 35 DIRECTIVE_VERSION, 36 DIRECTIVE_LINE 37 }; 38 39 DirectiveType getDirective(const pp::Token *token) 40 { 41 static const std::string kDirectiveDefine("define"); 42 static const std::string kDirectiveUndef("undef"); 43 static const std::string kDirectiveIf("if"); 44 static const std::string kDirectiveIfdef("ifdef"); 45 static const std::string kDirectiveIfndef("ifndef"); 46 static const std::string kDirectiveElse("else"); 47 static const std::string kDirectiveElif("elif"); 48 static const std::string kDirectiveEndif("endif"); 49 static const std::string kDirectiveError("error"); 50 static const std::string kDirectivePragma("pragma"); 51 static const std::string kDirectiveExtension("extension"); 52 static const std::string kDirectiveVersion("version"); 53 static const std::string kDirectiveLine("line"); 54 55 if (token->type != pp::Token::IDENTIFIER) 56 return DIRECTIVE_NONE; 57 58 if (token->text == kDirectiveDefine) 59 return DIRECTIVE_DEFINE; 60 if (token->text == kDirectiveUndef) 61 return DIRECTIVE_UNDEF; 62 if (token->text == kDirectiveIf) 63 return DIRECTIVE_IF; 64 if (token->text == kDirectiveIfdef) 65 return DIRECTIVE_IFDEF; 66 if (token->text == kDirectiveIfndef) 67 return DIRECTIVE_IFNDEF; 68 if (token->text == kDirectiveElse) 69 return DIRECTIVE_ELSE; 70 if (token->text == kDirectiveElif) 71 return DIRECTIVE_ELIF; 72 if (token->text == kDirectiveEndif) 73 return DIRECTIVE_ENDIF; 74 if (token->text == kDirectiveError) 75 return DIRECTIVE_ERROR; 76 if (token->text == kDirectivePragma) 77 return DIRECTIVE_PRAGMA; 78 if (token->text == kDirectiveExtension) 79 return DIRECTIVE_EXTENSION; 80 if (token->text == kDirectiveVersion) 81 return DIRECTIVE_VERSION; 82 if (token->text == kDirectiveLine) 83 return DIRECTIVE_LINE; 84 85 return DIRECTIVE_NONE; 86 } 87 88 bool isConditionalDirective(DirectiveType directive) 89 { 90 switch (directive) 91 { 92 case DIRECTIVE_IF: 93 case DIRECTIVE_IFDEF: 94 case DIRECTIVE_IFNDEF: 95 case DIRECTIVE_ELSE: 96 case DIRECTIVE_ELIF: 97 case DIRECTIVE_ENDIF: 98 return true; 99 default: 100 return false; 101 } 102 } 103 104 // Returns true if the token represents End Of Directive. 105 bool isEOD(const pp::Token *token) 106 { 107 return (token->type == '\n') || (token->type == pp::Token::LAST); 108 } 109 110 void skipUntilEOD(pp::Lexer *lexer, pp::Token *token) 111 { 112 while(!isEOD(token)) 113 { 114 lexer->lex(token); 115 } 116 } 117 118 bool isMacroNameReserved(const std::string &name) 119 { 120 // Names prefixed with "GL_" are reserved. 121 if (name.substr(0, 3) == "GL_") 122 return true; 123 124 // Names containing two consecutive underscores are reserved. 125 if (name.find("__") != std::string::npos) 126 return true; 127 128 return false; 129 } 130 131 bool isMacroPredefined(const std::string &name, 132 const pp::MacroSet ¯oSet) 133 { 134 pp::MacroSet::const_iterator iter = macroSet.find(name); 135 return iter != macroSet.end() ? iter->second.predefined : false; 136 } 137 138 } // namespace anonymous 139 140 namespace pp 141 { 142 143 class DefinedParser : public Lexer 144 { 145 public: 146 DefinedParser(Lexer *lexer, 147 const MacroSet *macroSet, 148 Diagnostics *diagnostics) 149 : mLexer(lexer), 150 mMacroSet(macroSet), 151 mDiagnostics(diagnostics) 152 { 153 } 154 155 protected: 156 virtual void lex(Token *token) 157 { 158 static const std::string kDefined("defined"); 159 160 mLexer->lex(token); 161 if (token->type != Token::IDENTIFIER) 162 return; 163 if (token->text != kDefined) 164 return; 165 166 bool paren = false; 167 mLexer->lex(token); 168 if (token->type == '(') 169 { 170 paren = true; 171 mLexer->lex(token); 172 } 173 174 if (token->type != Token::IDENTIFIER) 175 { 176 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 177 token->location, token->text); 178 skipUntilEOD(mLexer, token); 179 return; 180 } 181 MacroSet::const_iterator iter = mMacroSet->find(token->text); 182 std::string expression = iter != mMacroSet->end() ? "1" : "0"; 183 184 if (paren) 185 { 186 mLexer->lex(token); 187 if (token->type != ')') 188 { 189 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 190 token->location, token->text); 191 skipUntilEOD(mLexer, token); 192 return; 193 } 194 } 195 196 // We have a valid defined operator. 197 // Convert the current token into a CONST_INT token. 198 token->type = Token::CONST_INT; 199 token->text = expression; 200 } 201 202 private: 203 Lexer *mLexer; 204 const MacroSet *mMacroSet; 205 Diagnostics *mDiagnostics; 206 }; 207 208 DirectiveParser::DirectiveParser(Tokenizer *tokenizer, 209 MacroSet *macroSet, 210 Diagnostics *diagnostics, 211 DirectiveHandler *directiveHandler) 212 : mPastFirstStatement(false), 213 mTokenizer(tokenizer), 214 mMacroSet(macroSet), 215 mDiagnostics(diagnostics), 216 mDirectiveHandler(directiveHandler) 217 { 218 } 219 220 void DirectiveParser::lex(Token *token) 221 { 222 do 223 { 224 mTokenizer->lex(token); 225 226 if (token->type == Token::PP_HASH) 227 { 228 parseDirective(token); 229 mPastFirstStatement = true; 230 } 231 232 if (token->type == Token::LAST) 233 { 234 if (!mConditionalStack.empty()) 235 { 236 const ConditionalBlock &block = mConditionalStack.back(); 237 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, 238 block.location, block.type); 239 } 240 break; 241 } 242 243 } 244 while (skipping() || (token->type == '\n')); 245 246 mPastFirstStatement = true; 247 } 248 249 void DirectiveParser::parseDirective(Token *token) 250 { 251 assert(token->type == Token::PP_HASH); 252 253 mTokenizer->lex(token); 254 if (isEOD(token)) 255 { 256 // Empty Directive. 257 return; 258 } 259 260 DirectiveType directive = getDirective(token); 261 262 // While in an excluded conditional block/group, 263 // we only parse conditional directives. 264 if (skipping() && !isConditionalDirective(directive)) 265 { 266 skipUntilEOD(mTokenizer, token); 267 return; 268 } 269 270 switch(directive) 271 { 272 case DIRECTIVE_NONE: 273 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, 274 token->location, token->text); 275 skipUntilEOD(mTokenizer, token); 276 break; 277 case DIRECTIVE_DEFINE: 278 parseDefine(token); 279 break; 280 case DIRECTIVE_UNDEF: 281 parseUndef(token); 282 break; 283 case DIRECTIVE_IF: 284 parseIf(token); 285 break; 286 case DIRECTIVE_IFDEF: 287 parseIfdef(token); 288 break; 289 case DIRECTIVE_IFNDEF: 290 parseIfndef(token); 291 break; 292 case DIRECTIVE_ELSE: 293 parseElse(token); 294 break; 295 case DIRECTIVE_ELIF: 296 parseElif(token); 297 break; 298 case DIRECTIVE_ENDIF: 299 parseEndif(token); 300 break; 301 case DIRECTIVE_ERROR: 302 parseError(token); 303 break; 304 case DIRECTIVE_PRAGMA: 305 parsePragma(token); 306 break; 307 case DIRECTIVE_EXTENSION: 308 parseExtension(token); 309 break; 310 case DIRECTIVE_VERSION: 311 parseVersion(token); 312 break; 313 case DIRECTIVE_LINE: 314 parseLine(token); 315 break; 316 default: 317 assert(false); 318 break; 319 } 320 321 skipUntilEOD(mTokenizer, token); 322 if (token->type == Token::LAST) 323 { 324 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, 325 token->location, token->text); 326 } 327 } 328 329 void DirectiveParser::parseDefine(Token *token) 330 { 331 assert(getDirective(token) == DIRECTIVE_DEFINE); 332 333 mTokenizer->lex(token); 334 if (token->type != Token::IDENTIFIER) 335 { 336 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 337 token->location, token->text); 338 return; 339 } 340 if (isMacroPredefined(token->text, *mMacroSet)) 341 { 342 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, 343 token->location, token->text); 344 return; 345 } 346 if (isMacroNameReserved(token->text)) 347 { 348 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, 349 token->location, token->text); 350 return; 351 } 352 353 Macro macro; 354 macro.type = Macro::kTypeObj; 355 macro.name = token->text; 356 357 mTokenizer->lex(token); 358 if (token->type == '(' && !token->hasLeadingSpace()) 359 { 360 // Function-like macro. Collect arguments. 361 macro.type = Macro::kTypeFunc; 362 do 363 { 364 mTokenizer->lex(token); 365 if (token->type != Token::IDENTIFIER) 366 break; 367 macro.parameters.push_back(token->text); 368 369 mTokenizer->lex(token); // Get ','. 370 } 371 while (token->type == ','); 372 373 if (token->type != ')') 374 { 375 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 376 token->location, 377 token->text); 378 return; 379 } 380 mTokenizer->lex(token); // Get ')'. 381 } 382 383 while ((token->type != '\n') && (token->type != Token::LAST)) 384 { 385 // Reset the token location because it is unnecessary in replacement 386 // list. Resetting it also allows us to reuse Token::equals() to 387 // compare macros. 388 token->location = SourceLocation(); 389 macro.replacements.push_back(*token); 390 mTokenizer->lex(token); 391 } 392 if (!macro.replacements.empty()) 393 { 394 // Whitespace preceding the replacement list is not considered part of 395 // the replacement list for either form of macro. 396 macro.replacements.front().setHasLeadingSpace(false); 397 } 398 399 // Check for macro redefinition. 400 MacroSet::const_iterator iter = mMacroSet->find(macro.name); 401 if (iter != mMacroSet->end() && !macro.equals(iter->second)) 402 { 403 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, 404 token->location, 405 macro.name); 406 return; 407 } 408 mMacroSet->insert(std::make_pair(macro.name, macro)); 409 } 410 411 void DirectiveParser::parseUndef(Token *token) 412 { 413 assert(getDirective(token) == DIRECTIVE_UNDEF); 414 415 mTokenizer->lex(token); 416 if (token->type != Token::IDENTIFIER) 417 { 418 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 419 token->location, token->text); 420 return; 421 } 422 423 MacroSet::iterator iter = mMacroSet->find(token->text); 424 if (iter != mMacroSet->end()) 425 { 426 if (iter->second.predefined) 427 { 428 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, 429 token->location, token->text); 430 } 431 else 432 { 433 mMacroSet->erase(iter); 434 } 435 } 436 437 mTokenizer->lex(token); 438 } 439 440 void DirectiveParser::parseIf(Token *token) 441 { 442 assert(getDirective(token) == DIRECTIVE_IF); 443 parseConditionalIf(token); 444 } 445 446 void DirectiveParser::parseIfdef(Token *token) 447 { 448 assert(getDirective(token) == DIRECTIVE_IFDEF); 449 parseConditionalIf(token); 450 } 451 452 void DirectiveParser::parseIfndef(Token *token) 453 { 454 assert(getDirective(token) == DIRECTIVE_IFNDEF); 455 parseConditionalIf(token); 456 } 457 458 void DirectiveParser::parseElse(Token *token) 459 { 460 assert(getDirective(token) == DIRECTIVE_ELSE); 461 462 if (mConditionalStack.empty()) 463 { 464 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, 465 token->location, token->text); 466 skipUntilEOD(mTokenizer, token); 467 return; 468 } 469 470 ConditionalBlock &block = mConditionalStack.back(); 471 if (block.skipBlock) 472 { 473 // No diagnostics. Just skip the whole line. 474 skipUntilEOD(mTokenizer, token); 475 return; 476 } 477 if (block.foundElseGroup) 478 { 479 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, 480 token->location, token->text); 481 skipUntilEOD(mTokenizer, token); 482 return; 483 } 484 485 block.foundElseGroup = true; 486 block.skipGroup = block.foundValidGroup; 487 block.foundValidGroup = true; 488 489 // Warn if there are extra tokens after #else. 490 mTokenizer->lex(token); 491 if (!isEOD(token)) 492 { 493 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, 494 token->location, token->text); 495 skipUntilEOD(mTokenizer, token); 496 } 497 } 498 499 void DirectiveParser::parseElif(Token *token) 500 { 501 assert(getDirective(token) == DIRECTIVE_ELIF); 502 503 if (mConditionalStack.empty()) 504 { 505 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, 506 token->location, token->text); 507 skipUntilEOD(mTokenizer, token); 508 return; 509 } 510 511 ConditionalBlock &block = mConditionalStack.back(); 512 if (block.skipBlock) 513 { 514 // No diagnostics. Just skip the whole line. 515 skipUntilEOD(mTokenizer, token); 516 return; 517 } 518 if (block.foundElseGroup) 519 { 520 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, 521 token->location, token->text); 522 skipUntilEOD(mTokenizer, token); 523 return; 524 } 525 if (block.foundValidGroup) 526 { 527 // Do not parse the expression. 528 // Also be careful not to emit a diagnostic. 529 block.skipGroup = true; 530 skipUntilEOD(mTokenizer, token); 531 return; 532 } 533 534 int expression = parseExpressionIf(token); 535 block.skipGroup = expression == 0; 536 block.foundValidGroup = expression != 0; 537 } 538 539 void DirectiveParser::parseEndif(Token *token) 540 { 541 assert(getDirective(token) == DIRECTIVE_ENDIF); 542 543 if (mConditionalStack.empty()) 544 { 545 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, 546 token->location, token->text); 547 skipUntilEOD(mTokenizer, token); 548 return; 549 } 550 551 mConditionalStack.pop_back(); 552 553 // Warn if there are tokens after #endif. 554 mTokenizer->lex(token); 555 if (!isEOD(token)) 556 { 557 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, 558 token->location, token->text); 559 skipUntilEOD(mTokenizer, token); 560 } 561 } 562 563 void DirectiveParser::parseError(Token *token) 564 { 565 assert(getDirective(token) == DIRECTIVE_ERROR); 566 567 std::ostringstream stream; 568 mTokenizer->lex(token); 569 while ((token->type != '\n') && (token->type != Token::LAST)) 570 { 571 stream << *token; 572 mTokenizer->lex(token); 573 } 574 mDirectiveHandler->handleError(token->location, stream.str()); 575 } 576 577 // Parses pragma of form: #pragma name[(value)]. 578 void DirectiveParser::parsePragma(Token *token) 579 { 580 assert(getDirective(token) == DIRECTIVE_PRAGMA); 581 582 enum State 583 { 584 PRAGMA_NAME, 585 LEFT_PAREN, 586 PRAGMA_VALUE, 587 RIGHT_PAREN 588 }; 589 590 bool valid = true; 591 std::string name, value; 592 int state = PRAGMA_NAME; 593 594 mTokenizer->lex(token); 595 while ((token->type != '\n') && (token->type != Token::LAST)) 596 { 597 switch(state++) 598 { 599 case PRAGMA_NAME: 600 name = token->text; 601 valid = valid && (token->type == Token::IDENTIFIER); 602 break; 603 case LEFT_PAREN: 604 valid = valid && (token->type == '('); 605 break; 606 case PRAGMA_VALUE: 607 value = token->text; 608 valid = valid && (token->type == Token::IDENTIFIER); 609 break; 610 case RIGHT_PAREN: 611 valid = valid && (token->type == ')'); 612 break; 613 default: 614 valid = false; 615 break; 616 } 617 mTokenizer->lex(token); 618 } 619 620 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma. 621 (state == LEFT_PAREN) || // Without value. 622 (state == RIGHT_PAREN + 1)); // With value. 623 if (!valid) 624 { 625 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, 626 token->location, name); 627 } 628 else if (state > PRAGMA_NAME) // Do not notify for empty pragma. 629 { 630 mDirectiveHandler->handlePragma(token->location, name, value); 631 } 632 } 633 634 void DirectiveParser::parseExtension(Token *token) 635 { 636 assert(getDirective(token) == DIRECTIVE_EXTENSION); 637 638 enum State 639 { 640 EXT_NAME, 641 COLON, 642 EXT_BEHAVIOR 643 }; 644 645 bool valid = true; 646 std::string name, behavior; 647 int state = EXT_NAME; 648 649 mTokenizer->lex(token); 650 while ((token->type != '\n') && (token->type != Token::LAST)) 651 { 652 switch (state++) 653 { 654 case EXT_NAME: 655 if (valid && (token->type != Token::IDENTIFIER)) 656 { 657 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, 658 token->location, token->text); 659 valid = false; 660 } 661 if (valid) name = token->text; 662 break; 663 case COLON: 664 if (valid && (token->type != ':')) 665 { 666 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 667 token->location, token->text); 668 valid = false; 669 } 670 break; 671 case EXT_BEHAVIOR: 672 if (valid && (token->type != Token::IDENTIFIER)) 673 { 674 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR, 675 token->location, token->text); 676 valid = false; 677 } 678 if (valid) behavior = token->text; 679 break; 680 default: 681 if (valid) 682 { 683 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 684 token->location, token->text); 685 valid = false; 686 } 687 break; 688 } 689 mTokenizer->lex(token); 690 } 691 if (valid && (state != EXT_BEHAVIOR + 1)) 692 { 693 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, 694 token->location, token->text); 695 valid = false; 696 } 697 if (valid) 698 mDirectiveHandler->handleExtension(token->location, name, behavior); 699 } 700 701 void DirectiveParser::parseVersion(Token *token) 702 { 703 assert(getDirective(token) == DIRECTIVE_VERSION); 704 705 if (mPastFirstStatement) 706 { 707 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, 708 token->location, token->text); 709 skipUntilEOD(mTokenizer, token); 710 return; 711 } 712 713 enum State 714 { 715 VERSION_NUMBER, 716 VERSION_PROFILE, 717 VERSION_ENDLINE 718 }; 719 720 bool valid = true; 721 int version = 0; 722 int state = VERSION_NUMBER; 723 724 mTokenizer->lex(token); 725 while (valid && (token->type != '\n') && (token->type != Token::LAST)) 726 { 727 switch (state) 728 { 729 case VERSION_NUMBER: 730 if (token->type != Token::CONST_INT) 731 { 732 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, 733 token->location, token->text); 734 valid = false; 735 } 736 if (valid && !token->iValue(&version)) 737 { 738 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, 739 token->location, token->text); 740 valid = false; 741 } 742 if (valid) 743 { 744 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE; 745 } 746 break; 747 case VERSION_PROFILE: 748 if (token->type != Token::IDENTIFIER || token->text != "es") 749 { 750 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, 751 token->location, token->text); 752 valid = false; 753 } 754 state = VERSION_ENDLINE; 755 break; 756 default: 757 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 758 token->location, token->text); 759 valid = false; 760 break; 761 } 762 763 mTokenizer->lex(token); 764 } 765 766 if (valid && (state != VERSION_ENDLINE)) 767 { 768 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, 769 token->location, token->text); 770 valid = false; 771 } 772 773 if (valid) 774 { 775 mDirectiveHandler->handleVersion(token->location, version); 776 } 777 } 778 779 void DirectiveParser::parseLine(Token *token) 780 { 781 assert(getDirective(token) == DIRECTIVE_LINE); 782 783 enum State 784 { 785 LINE_NUMBER, 786 FILE_NUMBER 787 }; 788 789 bool valid = true; 790 int line = 0, file = 0; 791 int state = LINE_NUMBER; 792 793 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics); 794 macroExpander.lex(token); 795 while ((token->type != '\n') && (token->type != Token::LAST)) 796 { 797 switch (state++) 798 { 799 case LINE_NUMBER: 800 if (valid && (token->type != Token::CONST_INT)) 801 { 802 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER, 803 token->location, token->text); 804 valid = false; 805 } 806 if (valid && !token->iValue(&line)) 807 { 808 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, 809 token->location, token->text); 810 valid = false; 811 } 812 break; 813 case FILE_NUMBER: 814 if (valid && (token->type != Token::CONST_INT)) 815 { 816 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER, 817 token->location, token->text); 818 valid = false; 819 } 820 if (valid && !token->iValue(&file)) 821 { 822 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, 823 token->location, token->text); 824 valid = false; 825 } 826 break; 827 default: 828 if (valid) 829 { 830 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 831 token->location, token->text); 832 valid = false; 833 } 834 break; 835 } 836 macroExpander.lex(token); 837 } 838 839 if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1)) 840 { 841 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, 842 token->location, token->text); 843 valid = false; 844 } 845 if (valid) 846 { 847 mTokenizer->setLineNumber(line); 848 if (state == FILE_NUMBER + 1) 849 mTokenizer->setFileNumber(file); 850 } 851 } 852 853 bool DirectiveParser::skipping() const 854 { 855 if (mConditionalStack.empty()) 856 return false; 857 858 const ConditionalBlock& block = mConditionalStack.back(); 859 return block.skipBlock || block.skipGroup; 860 } 861 862 void DirectiveParser::parseConditionalIf(Token *token) 863 { 864 ConditionalBlock block; 865 block.type = token->text; 866 block.location = token->location; 867 868 if (skipping()) 869 { 870 // This conditional block is inside another conditional group 871 // which is skipped. As a consequence this whole block is skipped. 872 // Be careful not to parse the conditional expression that might 873 // emit a diagnostic. 874 skipUntilEOD(mTokenizer, token); 875 block.skipBlock = true; 876 } 877 else 878 { 879 DirectiveType directive = getDirective(token); 880 881 int expression = 0; 882 switch (directive) 883 { 884 case DIRECTIVE_IF: 885 expression = parseExpressionIf(token); 886 break; 887 case DIRECTIVE_IFDEF: 888 expression = parseExpressionIfdef(token); 889 break; 890 case DIRECTIVE_IFNDEF: 891 expression = parseExpressionIfdef(token) == 0 ? 1 : 0; 892 break; 893 default: 894 assert(false); 895 break; 896 } 897 block.skipGroup = expression == 0; 898 block.foundValidGroup = expression != 0; 899 } 900 mConditionalStack.push_back(block); 901 } 902 903 int DirectiveParser::parseExpressionIf(Token *token) 904 { 905 assert((getDirective(token) == DIRECTIVE_IF) || 906 (getDirective(token) == DIRECTIVE_ELIF)); 907 908 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics); 909 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics); 910 ExpressionParser expressionParser(¯oExpander, mDiagnostics); 911 912 int expression = 0; 913 macroExpander.lex(token); 914 expressionParser.parse(token, &expression); 915 916 // Warn if there are tokens after #if expression. 917 if (!isEOD(token)) 918 { 919 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, 920 token->location, token->text); 921 skipUntilEOD(mTokenizer, token); 922 } 923 924 return expression; 925 } 926 927 int DirectiveParser::parseExpressionIfdef(Token *token) 928 { 929 assert((getDirective(token) == DIRECTIVE_IFDEF) || 930 (getDirective(token) == DIRECTIVE_IFNDEF)); 931 932 mTokenizer->lex(token); 933 if (token->type != Token::IDENTIFIER) 934 { 935 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, 936 token->location, token->text); 937 skipUntilEOD(mTokenizer, token); 938 return 0; 939 } 940 941 MacroSet::const_iterator iter = mMacroSet->find(token->text); 942 int expression = iter != mMacroSet->end() ? 1 : 0; 943 944 // Warn if there are tokens after #ifdef expression. 945 mTokenizer->lex(token); 946 if (!isEOD(token)) 947 { 948 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, 949 token->location, token->text); 950 skipUntilEOD(mTokenizer, token); 951 } 952 return expression; 953 } 954 955 } // namespace pp 956