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