1 // 2 // Copyright (C) 2013 LunarG, Inc. 3 // Copyright (C) 2015-2018 Google, Inc. 4 // All rights reserved. 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions 8 // are met: 9 // 10 // Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // 13 // Redistributions in binary form must reproduce the above 14 // copyright notice, this list of conditions and the following 15 // disclaimer in the documentation and/or other materials provided 16 // with the distribution. 17 // 18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 19 // contributors may be used to endorse or promote products derived 20 // from this software without specific prior written permission. 21 // 22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 // POSSIBILITY OF SUCH DAMAGE. 34 // 35 /****************************************************************************\ 36 Copyright (c) 2002, NVIDIA Corporation. 37 38 NVIDIA Corporation("NVIDIA") supplies this software to you in 39 consideration of your agreement to the following terms, and your use, 40 installation, modification or redistribution of this NVIDIA software 41 constitutes acceptance of these terms. If you do not agree with these 42 terms, please do not use, install, modify or redistribute this NVIDIA 43 software. 44 45 In consideration of your agreement to abide by the following terms, and 46 subject to these terms, NVIDIA grants you a personal, non-exclusive 47 license, under NVIDIA's copyrights in this original NVIDIA software (the 48 "NVIDIA Software"), to use, reproduce, modify and redistribute the 49 NVIDIA Software, with or without modifications, in source and/or binary 50 forms; provided that if you redistribute the NVIDIA Software, you must 51 retain the copyright notice of NVIDIA, this notice and the following 52 text and disclaimers in all such redistributions of the NVIDIA Software. 53 Neither the name, trademarks, service marks nor logos of NVIDIA 54 Corporation may be used to endorse or promote products derived from the 55 NVIDIA Software without specific prior written permission from NVIDIA. 56 Except as expressly stated in this notice, no other rights or licenses 57 express or implied, are granted by NVIDIA herein, including but not 58 limited to any patent rights that may be infringed by your derivative 59 works or by other works in which the NVIDIA Software may be 60 incorporated. No hardware is licensed hereunder. 61 62 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT 63 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 64 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, 65 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 66 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER 67 PRODUCTS. 68 69 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, 70 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 71 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 72 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY 73 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE 74 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, 75 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 76 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 77 \****************************************************************************/ 78 79 #ifndef PPCONTEXT_H 80 #define PPCONTEXT_H 81 82 #include <stack> 83 #include <unordered_map> 84 #include <sstream> 85 86 #include "../ParseHelper.h" 87 #include "PpTokens.h" 88 89 /* windows only pragma */ 90 #ifdef _MSC_VER 91 #pragma warning(disable : 4127) 92 #endif 93 94 namespace glslang { 95 96 class TPpToken { 97 public: TPpToken()98 TPpToken() { clear(); } clear()99 void clear() 100 { 101 space = false; 102 i64val = 0; 103 loc.init(); 104 name[0] = 0; 105 } 106 107 // Used for comparing macro definitions, so checks what is relevant for that. 108 bool operator==(const TPpToken& right) const 109 { 110 return space == right.space && 111 ival == right.ival && dval == right.dval && i64val == right.i64val && 112 strncmp(name, right.name, MaxTokenLength) == 0; 113 } 114 bool operator!=(const TPpToken& right) const { return ! operator==(right); } 115 116 TSourceLoc loc; 117 // True if a space (for white space or a removed comment) should also be 118 // recognized, in front of the token returned: 119 bool space; 120 // Numeric value of the token: 121 union { 122 int ival; 123 double dval; 124 long long i64val; 125 }; 126 // Text string of the token: 127 char name[MaxTokenLength + 1]; 128 }; 129 130 class TStringAtomMap { 131 // 132 // Implementation is in PpAtom.cpp 133 // 134 // Maintain a bi-directional mapping between relevant preprocessor strings and 135 // "atoms" which a unique integers (small, contiguous, not hash-like) per string. 136 // 137 public: 138 TStringAtomMap(); 139 140 // Map string -> atom. 141 // Return 0 if no existing string. getAtom(const char * s)142 int getAtom(const char* s) const 143 { 144 auto it = atomMap.find(s); 145 return it == atomMap.end() ? 0 : it->second; 146 } 147 148 // Map a new or existing string -> atom, inventing a new atom if necessary. getAddAtom(const char * s)149 int getAddAtom(const char* s) 150 { 151 int atom = getAtom(s); 152 if (atom == 0) { 153 atom = nextAtom++; 154 addAtomFixed(s, atom); 155 } 156 return atom; 157 } 158 159 // Map atom -> string. getString(int atom)160 const char* getString(int atom) const { return stringMap[atom]->c_str(); } 161 162 protected: 163 TStringAtomMap(TStringAtomMap&); 164 TStringAtomMap& operator=(TStringAtomMap&); 165 166 TUnorderedMap<TString, int> atomMap; 167 TVector<const TString*> stringMap; // these point into the TString in atomMap 168 int nextAtom; 169 170 // Bad source characters can lead to bad atoms, so gracefully handle those by 171 // pre-filling the table with them (to avoid if tests later). 172 TString badToken; 173 174 // Add bi-directional mappings: 175 // - string -> atom 176 // - atom -> string addAtomFixed(const char * s,int atom)177 void addAtomFixed(const char* s, int atom) 178 { 179 auto it = atomMap.insert(std::pair<TString, int>(s, atom)).first; 180 if (stringMap.size() < (size_t)atom + 1) 181 stringMap.resize(atom + 100, &badToken); 182 stringMap[atom] = &it->first; 183 } 184 }; 185 186 class TInputScanner; 187 188 enum MacroExpandResult { 189 MacroExpandNotStarted, // macro not expanded, which might not be an error 190 MacroExpandError, // a clear error occurred while expanding, no expansion 191 MacroExpandStarted, // macro expansion process has started 192 MacroExpandUndef // macro is undefined and will be expanded 193 }; 194 195 // This class is the result of turning a huge pile of C code communicating through globals 196 // into a class. This was done to allowing instancing to attain thread safety. 197 // Don't expect too much in terms of OO design. 198 class TPpContext { 199 public: 200 TPpContext(TParseContextBase&, const std::string& rootFileName, TShader::Includer&); 201 virtual ~TPpContext(); 202 203 void setPreamble(const char* preamble, size_t length); 204 205 int tokenize(TPpToken& ppToken); 206 int tokenPaste(int token, TPpToken&); 207 208 class tInput { 209 public: tInput(TPpContext * p)210 tInput(TPpContext* p) : done(false), pp(p) { } ~tInput()211 virtual ~tInput() { } 212 213 virtual int scan(TPpToken*) = 0; 214 virtual int getch() = 0; 215 virtual void ungetch() = 0; peekPasting()216 virtual bool peekPasting() { return false; } // true when about to see ## peekContinuedPasting(int)217 virtual bool peekContinuedPasting(int) { return false; } // true when non-spaced tokens can paste endOfReplacementList()218 virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define) isMacroInput()219 virtual bool isMacroInput() { return false; } 220 221 // Will be called when we start reading tokens from this instance notifyActivated()222 virtual void notifyActivated() {} 223 // Will be called when we do not read tokens from this instance anymore notifyDeleted()224 virtual void notifyDeleted() {} 225 protected: 226 bool done; 227 TPpContext* pp; 228 }; 229 230 void setInput(TInputScanner& input, bool versionWillBeError); 231 pushInput(tInput * in)232 void pushInput(tInput* in) 233 { 234 inputStack.push_back(in); 235 in->notifyActivated(); 236 } popInput()237 void popInput() 238 { 239 inputStack.back()->notifyDeleted(); 240 delete inputStack.back(); 241 inputStack.pop_back(); 242 } 243 244 // 245 // From PpTokens.cpp 246 // 247 248 // Capture the needed parts of a token stream for macro recording/playback. 249 class TokenStream { 250 public: 251 // Manage a stream of these 'Token', which capture the relevant parts 252 // of a TPpToken, plus its atom. 253 class Token { 254 public: Token(int atom,const TPpToken & ppToken)255 Token(int atom, const TPpToken& ppToken) : 256 atom(atom), 257 space(ppToken.space), 258 i64val(ppToken.i64val), 259 name(ppToken.name) { } get(TPpToken & ppToken)260 int get(TPpToken& ppToken) 261 { 262 ppToken.clear(); 263 ppToken.space = space; 264 ppToken.i64val = i64val; 265 snprintf(ppToken.name, sizeof(ppToken.name), "%s", name.c_str()); 266 return atom; 267 } isAtom(int a)268 bool isAtom(int a) const { return atom == a; } getAtom()269 int getAtom() const { return atom; } nonSpaced()270 bool nonSpaced() const { return !space; } 271 protected: Token()272 Token() {} 273 int atom; 274 bool space; // did a space precede the token? 275 long long i64val; 276 TString name; 277 }; 278 TokenStream()279 TokenStream() : currentPos(0) { } 280 281 void putToken(int token, TPpToken* ppToken); peekToken(int atom)282 bool peekToken(int atom) { return !atEnd() && stream[currentPos].isAtom(atom); } peekContinuedPasting(int atom)283 bool peekContinuedPasting(int atom) 284 { 285 // This is basically necessary because, for example, the PP 286 // tokenizer only accepts valid numeric-literals plus suffixes, so 287 // separates numeric-literals plus bad suffix into two tokens, which 288 // should get both pasted together as one token when token pasting. 289 // 290 // The following code is a bit more generalized than the above example. 291 if (!atEnd() && atom == PpAtomIdentifier && stream[currentPos].nonSpaced()) { 292 switch(stream[currentPos].getAtom()) { 293 case PpAtomConstInt: 294 case PpAtomConstUint: 295 case PpAtomConstInt64: 296 case PpAtomConstUint64: 297 case PpAtomConstInt16: 298 case PpAtomConstUint16: 299 case PpAtomConstFloat: 300 case PpAtomConstDouble: 301 case PpAtomConstFloat16: 302 case PpAtomConstString: 303 case PpAtomIdentifier: 304 return true; 305 default: 306 break; 307 } 308 } 309 310 return false; 311 } 312 int getToken(TParseContextBase&, TPpToken*); atEnd()313 bool atEnd() { return currentPos >= stream.size(); } 314 bool peekTokenizedPasting(bool lastTokenPastes); 315 bool peekUntokenizedPasting(); reset()316 void reset() { currentPos = 0; } 317 318 protected: 319 TVector<Token> stream; 320 size_t currentPos; 321 }; 322 323 // 324 // From Pp.cpp 325 // 326 327 struct MacroSymbol { MacroSymbolMacroSymbol328 MacroSymbol() : functionLike(0), busy(0), undef(0) { } 329 TVector<int> args; 330 TokenStream body; 331 unsigned functionLike : 1; // 0 means object-like, 1 means function-like 332 unsigned busy : 1; 333 unsigned undef : 1; 334 }; 335 336 typedef TMap<int, MacroSymbol> TSymbolMap; 337 TSymbolMap macroDefs; // map atoms to macro definitions lookupMacroDef(int atom)338 MacroSymbol* lookupMacroDef(int atom) 339 { 340 auto existingMacroIt = macroDefs.find(atom); 341 return (existingMacroIt == macroDefs.end()) ? nullptr : &(existingMacroIt->second); 342 } addMacroDef(int atom,MacroSymbol & macroDef)343 void addMacroDef(int atom, MacroSymbol& macroDef) { macroDefs[atom] = macroDef; } 344 345 protected: 346 TPpContext(TPpContext&); 347 TPpContext& operator=(TPpContext&); 348 349 TStringAtomMap atomStrings; 350 char* preamble; // string to parse, all before line 1 of string 0, it is 0 if no preamble 351 int preambleLength; 352 char** strings; // official strings of shader, starting a string 0 line 1 353 size_t* lengths; 354 int numStrings; // how many official strings there are 355 int currentString; // which string we're currently parsing (-1 for preamble) 356 357 // Scanner data: 358 int previous_token; 359 TParseContextBase& parseContext; 360 361 // Get the next token from *stack* of input sources, popping input sources 362 // that are out of tokens, down until an input source is found that has a token. 363 // Return EndOfInput when there are no more tokens to be found by doing this. scanToken(TPpToken * ppToken)364 int scanToken(TPpToken* ppToken) 365 { 366 int token = EndOfInput; 367 368 while (! inputStack.empty()) { 369 token = inputStack.back()->scan(ppToken); 370 if (token != EndOfInput || inputStack.empty()) 371 break; 372 popInput(); 373 } 374 375 return token; 376 } getChar()377 int getChar() { return inputStack.back()->getch(); } ungetChar()378 void ungetChar() { inputStack.back()->ungetch(); } peekPasting()379 bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); } peekContinuedPasting(int a)380 bool peekContinuedPasting(int a) 381 { 382 return !inputStack.empty() && inputStack.back()->peekContinuedPasting(a); 383 } endOfReplacementList()384 bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); } isMacroInput()385 bool isMacroInput() { return inputStack.size() > 0 && inputStack.back()->isMacroInput(); } 386 387 static const int maxIfNesting = 65; 388 389 int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor) 390 bool elseSeen[maxIfNesting]; // Keep a track of whether an else has been seen at a particular depth 391 int elsetracker; // #if-#else and #endif constructs...Counter. 392 393 class tMacroInput : public tInput { 394 public: tMacroInput(TPpContext * pp)395 tMacroInput(TPpContext* pp) : tInput(pp), prepaste(false), postpaste(false) { } ~tMacroInput()396 virtual ~tMacroInput() 397 { 398 for (size_t i = 0; i < args.size(); ++i) 399 delete args[i]; 400 for (size_t i = 0; i < expandedArgs.size(); ++i) 401 delete expandedArgs[i]; 402 } 403 404 virtual int scan(TPpToken*) override; getch()405 virtual int getch() override { assert(0); return EndOfInput; } ungetch()406 virtual void ungetch() override { assert(0); } peekPasting()407 bool peekPasting() override { return prepaste; } peekContinuedPasting(int a)408 bool peekContinuedPasting(int a) override { return mac->body.peekContinuedPasting(a); } endOfReplacementList()409 bool endOfReplacementList() override { return mac->body.atEnd(); } isMacroInput()410 bool isMacroInput() override { return true; } 411 412 MacroSymbol *mac; 413 TVector<TokenStream*> args; 414 TVector<TokenStream*> expandedArgs; 415 416 protected: 417 bool prepaste; // true if we are just before ## 418 bool postpaste; // true if we are right after ## 419 }; 420 421 class tMarkerInput : public tInput { 422 public: tMarkerInput(TPpContext * pp)423 tMarkerInput(TPpContext* pp) : tInput(pp) { } scan(TPpToken *)424 virtual int scan(TPpToken*) override 425 { 426 if (done) 427 return EndOfInput; 428 done = true; 429 430 return marker; 431 } getch()432 virtual int getch() override { assert(0); return EndOfInput; } ungetch()433 virtual void ungetch() override { assert(0); } 434 static const int marker = -3; 435 }; 436 437 class tZeroInput : public tInput { 438 public: tZeroInput(TPpContext * pp)439 tZeroInput(TPpContext* pp) : tInput(pp) { } 440 virtual int scan(TPpToken*) override; getch()441 virtual int getch() override { assert(0); return EndOfInput; } ungetch()442 virtual void ungetch() override { assert(0); } 443 }; 444 445 std::vector<tInput*> inputStack; 446 bool errorOnVersion; 447 bool versionSeen; 448 449 // 450 // from Pp.cpp 451 // 452 453 // Used to obtain #include content. 454 TShader::Includer& includer; 455 456 int CPPdefine(TPpToken * ppToken); 457 int CPPundef(TPpToken * ppToken); 458 int CPPelse(int matchelse, TPpToken * ppToken); 459 int extraTokenCheck(int atom, TPpToken* ppToken, int token); 460 int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); 461 int evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); 462 int CPPif (TPpToken * ppToken); 463 int CPPifdef(int defined, TPpToken * ppToken); 464 int CPPinclude(TPpToken * ppToken); 465 int CPPline(TPpToken * ppToken); 466 int CPPerror(TPpToken * ppToken); 467 int CPPpragma(TPpToken * ppToken); 468 int CPPversion(TPpToken * ppToken); 469 int CPPextension(TPpToken * ppToken); 470 int readCPPline(TPpToken * ppToken); 471 int scanHeaderName(TPpToken* ppToken, char delimit); 472 TokenStream* PrescanMacroArg(TokenStream&, TPpToken*, bool newLineOkay); 473 MacroExpandResult MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay); 474 475 // 476 // From PpTokens.cpp 477 // 478 void pushTokenStreamInput(TokenStream&, bool pasting = false); 479 void UngetToken(int token, TPpToken*); 480 481 class tTokenInput : public tInput { 482 public: tTokenInput(TPpContext * pp,TokenStream * t,bool prepasting)483 tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) : 484 tInput(pp), 485 tokens(t), 486 lastTokenPastes(prepasting) { } scan(TPpToken * ppToken)487 virtual int scan(TPpToken *ppToken) override { return tokens->getToken(pp->parseContext, ppToken); } getch()488 virtual int getch() override { assert(0); return EndOfInput; } ungetch()489 virtual void ungetch() override { assert(0); } peekPasting()490 virtual bool peekPasting() override { return tokens->peekTokenizedPasting(lastTokenPastes); } peekContinuedPasting(int a)491 bool peekContinuedPasting(int a) override { return tokens->peekContinuedPasting(a); } 492 protected: 493 TokenStream* tokens; 494 bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token 495 }; 496 497 class tUngotTokenInput : public tInput { 498 public: tUngotTokenInput(TPpContext * pp,int t,TPpToken * p)499 tUngotTokenInput(TPpContext* pp, int t, TPpToken* p) : tInput(pp), token(t), lval(*p) { } 500 virtual int scan(TPpToken *) override; getch()501 virtual int getch() override { assert(0); return EndOfInput; } ungetch()502 virtual void ungetch() override { assert(0); } 503 protected: 504 int token; 505 TPpToken lval; 506 }; 507 508 // 509 // From PpScanner.cpp 510 // 511 class tStringInput : public tInput { 512 public: tStringInput(TPpContext * pp,TInputScanner & i)513 tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { } 514 virtual int scan(TPpToken*) override; 515 516 // Scanner used to get source stream characters. 517 // - Escaped newlines are handled here, invisibly to the caller. 518 // - All forms of newline are handled, and turned into just a '\n'. getch()519 int getch() override 520 { 521 int ch = input->get(); 522 523 if (ch == '\\') { 524 // Move past escaped newlines, as many as sequentially exist 525 do { 526 if (input->peek() == '\r' || input->peek() == '\n') { 527 bool allowed = pp->parseContext.lineContinuationCheck(input->getSourceLoc(), pp->inComment); 528 if (! allowed && pp->inComment) 529 return '\\'; 530 531 // escape one newline now 532 ch = input->get(); 533 int nextch = input->get(); 534 if (ch == '\r' && nextch == '\n') 535 ch = input->get(); 536 else 537 ch = nextch; 538 } else 539 return '\\'; 540 } while (ch == '\\'); 541 } 542 543 // handle any non-escaped newline 544 if (ch == '\r' || ch == '\n') { 545 if (ch == '\r' && input->peek() == '\n') 546 input->get(); 547 return '\n'; 548 } 549 550 return ch; 551 } 552 553 // Scanner used to backup the source stream characters. Newlines are 554 // handled here, invisibly to the caller, meaning have to undo exactly 555 // what getch() above does (e.g., don't leave things in the middle of a 556 // sequence of escaped newlines). ungetch()557 void ungetch() override 558 { 559 input->unget(); 560 561 do { 562 int ch = input->peek(); 563 if (ch == '\r' || ch == '\n') { 564 if (ch == '\n') { 565 // correct for two-character newline 566 input->unget(); 567 if (input->peek() != '\r') 568 input->get(); 569 } 570 // now in front of a complete newline, move past an escape character 571 input->unget(); 572 if (input->peek() == '\\') 573 input->unget(); 574 else { 575 input->get(); 576 break; 577 } 578 } else 579 break; 580 } while (true); 581 } 582 583 protected: 584 TInputScanner* input; 585 }; 586 587 // Holds a reference to included file data, as well as a 588 // prologue and an epilogue string. This can be scanned using the tInput 589 // interface and acts as a single source string. 590 class TokenizableIncludeFile : public tInput { 591 public: 592 // Copies prologue and epilogue. The includedFile must remain valid 593 // until this TokenizableIncludeFile is no longer used. TokenizableIncludeFile(const TSourceLoc & startLoc,const std::string & prologue,TShader::Includer::IncludeResult * includedFile,const std::string & epilogue,TPpContext * pp)594 TokenizableIncludeFile(const TSourceLoc& startLoc, 595 const std::string& prologue, 596 TShader::Includer::IncludeResult* includedFile, 597 const std::string& epilogue, 598 TPpContext* pp) 599 : tInput(pp), 600 prologue_(prologue), 601 epilogue_(epilogue), 602 includedFile_(includedFile), 603 scanner(3, strings, lengths, nullptr, 0, 0, true), 604 prevScanner(nullptr), 605 stringInput(pp, scanner) 606 { 607 strings[0] = prologue_.data(); 608 strings[1] = includedFile_->headerData; 609 strings[2] = epilogue_.data(); 610 611 lengths[0] = prologue_.size(); 612 lengths[1] = includedFile_->headerLength; 613 lengths[2] = epilogue_.size(); 614 615 scanner.setLine(startLoc.line); 616 scanner.setString(startLoc.string); 617 618 scanner.setFile(startLoc.getFilenameStr(), 0); 619 scanner.setFile(startLoc.getFilenameStr(), 1); 620 scanner.setFile(startLoc.getFilenameStr(), 2); 621 } 622 623 // tInput methods: scan(TPpToken * t)624 int scan(TPpToken* t) override { return stringInput.scan(t); } getch()625 int getch() override { return stringInput.getch(); } ungetch()626 void ungetch() override { stringInput.ungetch(); } 627 notifyActivated()628 void notifyActivated() override 629 { 630 prevScanner = pp->parseContext.getScanner(); 631 pp->parseContext.setScanner(&scanner); 632 pp->push_include(includedFile_); 633 } 634 notifyDeleted()635 void notifyDeleted() override 636 { 637 pp->parseContext.setScanner(prevScanner); 638 pp->pop_include(); 639 } 640 641 private: 642 TokenizableIncludeFile& operator=(const TokenizableIncludeFile&); 643 644 // Stores the prologue for this string. 645 const std::string prologue_; 646 647 // Stores the epilogue for this string. 648 const std::string epilogue_; 649 650 // Points to the IncludeResult that this TokenizableIncludeFile represents. 651 TShader::Includer::IncludeResult* includedFile_; 652 653 // Will point to prologue_, includedFile_->headerData and epilogue_ 654 // This is passed to scanner constructor. 655 // These do not own the storage and it must remain valid until this 656 // object has been destroyed. 657 const char* strings[3]; 658 // Length of str_, passed to scanner constructor. 659 size_t lengths[3]; 660 // Scans over str_. 661 TInputScanner scanner; 662 // The previous effective scanner before the scanner in this instance 663 // has been activated. 664 TInputScanner* prevScanner; 665 // Delegate object implementing the tInput interface. 666 tStringInput stringInput; 667 }; 668 669 int ScanFromString(char* s); 670 void missingEndifCheck(); 671 int lFloatConst(int len, int ch, TPpToken* ppToken); 672 int characterLiteral(TPpToken* ppToken); 673 push_include(TShader::Includer::IncludeResult * result)674 void push_include(TShader::Includer::IncludeResult* result) 675 { 676 currentSourceFile = result->headerName; 677 includeStack.push(result); 678 } 679 pop_include()680 void pop_include() 681 { 682 TShader::Includer::IncludeResult* include = includeStack.top(); 683 includeStack.pop(); 684 includer.releaseInclude(include); 685 if (includeStack.empty()) { 686 currentSourceFile = rootFileName; 687 } else { 688 currentSourceFile = includeStack.top()->headerName; 689 } 690 } 691 692 bool inComment; 693 std::string rootFileName; 694 std::stack<TShader::Includer::IncludeResult*> includeStack; 695 std::string currentSourceFile; 696 697 std::istringstream strtodStream; 698 bool disableEscapeSequences; 699 }; 700 701 } // end namespace glslang 702 703 #endif // PPCONTEXT_H 704