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