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 88 /* windows only pragma */ 89 #ifdef _MSC_VER 90 #pragma warning(disable : 4127) 91 #endif 92 93 namespace glslang { 94 95 class TPpToken { 96 public: TPpToken()97 TPpToken() { clear(); } clear()98 void clear() 99 { 100 space = false; 101 i64val = 0; 102 loc.init(); 103 name[0] = 0; 104 } 105 106 // Used for comparing macro definitions, so checks what is relevant for that. 107 bool operator==(const TPpToken& right) 108 { 109 return space == right.space && 110 ival == right.ival && dval == right.dval && i64val == right.i64val && 111 strncmp(name, right.name, MaxTokenLength) == 0; 112 } 113 bool operator!=(const TPpToken& right) { return ! operator==(right); } 114 115 TSourceLoc loc; 116 // True if a space (for white space or a removed comment) should also be 117 // recognized, in front of the token returned: 118 bool space; 119 // Numeric value of the token: 120 union { 121 int ival; 122 double dval; 123 long long i64val; 124 }; 125 // Text string of the token: 126 char name[MaxTokenLength + 1]; 127 }; 128 129 class TStringAtomMap { 130 // 131 // Implementation is in PpAtom.cpp 132 // 133 // Maintain a bi-directional mapping between relevant preprocessor strings and 134 // "atoms" which a unique integers (small, contiguous, not hash-like) per string. 135 // 136 public: 137 TStringAtomMap(); 138 139 // Map string -> atom. 140 // Return 0 if no existing string. getAtom(const char * s)141 int getAtom(const char* s) const 142 { 143 auto it = atomMap.find(s); 144 return it == atomMap.end() ? 0 : it->second; 145 } 146 147 // Map a new or existing string -> atom, inventing a new atom if necessary. getAddAtom(const char * s)148 int getAddAtom(const char* s) 149 { 150 int atom = getAtom(s); 151 if (atom == 0) { 152 atom = nextAtom++; 153 addAtomFixed(s, atom); 154 } 155 return atom; 156 } 157 158 // Map atom -> string. getString(int atom)159 const char* getString(int atom) const { return stringMap[atom]->c_str(); } 160 161 protected: 162 TStringAtomMap(TStringAtomMap&); 163 TStringAtomMap& operator=(TStringAtomMap&); 164 165 TUnorderedMap<TString, int> atomMap; 166 TVector<const TString*> stringMap; // these point into the TString in atomMap 167 int nextAtom; 168 169 // Bad source characters can lead to bad atoms, so gracefully handle those by 170 // pre-filling the table with them (to avoid if tests later). 171 TString badToken; 172 173 // Add bi-directional mappings: 174 // - string -> atom 175 // - atom -> string addAtomFixed(const char * s,int atom)176 void addAtomFixed(const char* s, int atom) 177 { 178 auto it = atomMap.insert(std::pair<TString, int>(s, atom)).first; 179 if (stringMap.size() < (size_t)atom + 1) 180 stringMap.resize(atom + 100, &badToken); 181 stringMap[atom] = &it->first; 182 } 183 }; 184 185 class TInputScanner; 186 187 enum MacroExpandResult { 188 MacroExpandNotStarted, // macro not expanded, which might not be an error 189 MacroExpandError, // a clear error occurred while expanding, no expansion 190 MacroExpandStarted, // macro expansion process has started 191 MacroExpandUndef // macro is undefined and will be expanded 192 }; 193 194 // This class is the result of turning a huge pile of C code communicating through globals 195 // into a class. This was done to allowing instancing to attain thread safety. 196 // Don't expect too much in terms of OO design. 197 class TPpContext { 198 public: 199 TPpContext(TParseContextBase&, const std::string& rootFileName, TShader::Includer&); 200 virtual ~TPpContext(); 201 202 void setPreamble(const char* preamble, size_t length); 203 204 int tokenize(TPpToken& ppToken); 205 int tokenPaste(int token, TPpToken&); 206 207 class tInput { 208 public: tInput(TPpContext * p)209 tInput(TPpContext* p) : done(false), pp(p) { } ~tInput()210 virtual ~tInput() { } 211 212 virtual int scan(TPpToken*) = 0; 213 virtual int getch() = 0; 214 virtual void ungetch() = 0; peekPasting()215 virtual bool peekPasting() { return false; } // true when about to see ## endOfReplacementList()216 virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define) isMacroInput()217 virtual bool isMacroInput() { return false; } 218 219 // Will be called when we start reading tokens from this instance notifyActivated()220 virtual void notifyActivated() {} 221 // Will be called when we do not read tokens from this instance anymore notifyDeleted()222 virtual void notifyDeleted() {} 223 protected: 224 bool done; 225 TPpContext* pp; 226 }; 227 228 void setInput(TInputScanner& input, bool versionWillBeError); 229 pushInput(tInput * in)230 void pushInput(tInput* in) 231 { 232 inputStack.push_back(in); 233 in->notifyActivated(); 234 } popInput()235 void popInput() 236 { 237 inputStack.back()->notifyDeleted(); 238 delete inputStack.back(); 239 inputStack.pop_back(); 240 } 241 242 // 243 // From PpTokens.cpp 244 // 245 246 class TokenStream { 247 public: TokenStream()248 TokenStream() : current(0) { } 249 250 void putToken(int token, TPpToken* ppToken); 251 int getToken(TParseContextBase&, TPpToken*); atEnd()252 bool atEnd() { return current >= data.size(); } 253 bool peekTokenizedPasting(bool lastTokenPastes); 254 bool peekUntokenizedPasting(); reset()255 void reset() { current = 0; } 256 257 protected: 258 void putSubtoken(char); 259 int getSubtoken(); 260 void ungetSubtoken(); 261 262 TVector<unsigned char> data; 263 size_t current; 264 }; 265 266 // 267 // From Pp.cpp 268 // 269 270 struct MacroSymbol { MacroSymbolMacroSymbol271 MacroSymbol() : functionLike(0), busy(0), undef(0) { } 272 TVector<int> args; 273 TokenStream body; 274 unsigned functionLike : 1; // 0 means object-like, 1 means function-like 275 unsigned busy : 1; 276 unsigned undef : 1; 277 }; 278 279 typedef TMap<int, MacroSymbol> TSymbolMap; 280 TSymbolMap macroDefs; // map atoms to macro definitions lookupMacroDef(int atom)281 MacroSymbol* lookupMacroDef(int atom) 282 { 283 auto existingMacroIt = macroDefs.find(atom); 284 return (existingMacroIt == macroDefs.end()) ? nullptr : &(existingMacroIt->second); 285 } addMacroDef(int atom,MacroSymbol & macroDef)286 void addMacroDef(int atom, MacroSymbol& macroDef) { macroDefs[atom] = macroDef; } 287 288 protected: 289 TPpContext(TPpContext&); 290 TPpContext& operator=(TPpContext&); 291 292 TStringAtomMap atomStrings; 293 char* preamble; // string to parse, all before line 1 of string 0, it is 0 if no preamble 294 int preambleLength; 295 char** strings; // official strings of shader, starting a string 0 line 1 296 size_t* lengths; 297 int numStrings; // how many official strings there are 298 int currentString; // which string we're currently parsing (-1 for preamble) 299 300 // Scanner data: 301 int previous_token; 302 TParseContextBase& parseContext; 303 304 // Get the next token from *stack* of input sources, popping input sources 305 // that are out of tokens, down until an input source is found that has a token. 306 // Return EndOfInput when there are no more tokens to be found by doing this. scanToken(TPpToken * ppToken)307 int scanToken(TPpToken* ppToken) 308 { 309 int token = EndOfInput; 310 311 while (! inputStack.empty()) { 312 token = inputStack.back()->scan(ppToken); 313 if (token != EndOfInput || inputStack.empty()) 314 break; 315 popInput(); 316 } 317 318 return token; 319 } getChar()320 int getChar() { return inputStack.back()->getch(); } ungetChar()321 void ungetChar() { inputStack.back()->ungetch(); } peekPasting()322 bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); } endOfReplacementList()323 bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); } isMacroInput()324 bool isMacroInput() { return inputStack.size() > 0 && inputStack.back()->isMacroInput(); } 325 326 static const int maxIfNesting = 65; 327 328 int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor) 329 bool elseSeen[maxIfNesting]; // Keep a track of whether an else has been seen at a particular depth 330 int elsetracker; // #if-#else and #endif constructs...Counter. 331 332 class tMacroInput : public tInput { 333 public: tMacroInput(TPpContext * pp)334 tMacroInput(TPpContext* pp) : tInput(pp), prepaste(false), postpaste(false) { } ~tMacroInput()335 virtual ~tMacroInput() 336 { 337 for (size_t i = 0; i < args.size(); ++i) 338 delete args[i]; 339 for (size_t i = 0; i < expandedArgs.size(); ++i) 340 delete expandedArgs[i]; 341 } 342 343 virtual int scan(TPpToken*) override; getch()344 virtual int getch() override { assert(0); return EndOfInput; } ungetch()345 virtual void ungetch() override { assert(0); } peekPasting()346 bool peekPasting() override { return prepaste; } endOfReplacementList()347 bool endOfReplacementList() override { return mac->body.atEnd(); } isMacroInput()348 bool isMacroInput() override { return true; } 349 350 MacroSymbol *mac; 351 TVector<TokenStream*> args; 352 TVector<TokenStream*> expandedArgs; 353 354 protected: 355 bool prepaste; // true if we are just before ## 356 bool postpaste; // true if we are right after ## 357 }; 358 359 class tMarkerInput : public tInput { 360 public: tMarkerInput(TPpContext * pp)361 tMarkerInput(TPpContext* pp) : tInput(pp) { } scan(TPpToken *)362 virtual int scan(TPpToken*) override 363 { 364 if (done) 365 return EndOfInput; 366 done = true; 367 368 return marker; 369 } getch()370 virtual int getch() override { assert(0); return EndOfInput; } ungetch()371 virtual void ungetch() override { assert(0); } 372 static const int marker = -3; 373 }; 374 375 class tZeroInput : public tInput { 376 public: tZeroInput(TPpContext * pp)377 tZeroInput(TPpContext* pp) : tInput(pp) { } 378 virtual int scan(TPpToken*) override; getch()379 virtual int getch() override { assert(0); return EndOfInput; } ungetch()380 virtual void ungetch() override { assert(0); } 381 }; 382 383 std::vector<tInput*> inputStack; 384 bool errorOnVersion; 385 bool versionSeen; 386 387 // 388 // from Pp.cpp 389 // 390 391 // Used to obtain #include content. 392 TShader::Includer& includer; 393 394 int CPPdefine(TPpToken * ppToken); 395 int CPPundef(TPpToken * ppToken); 396 int CPPelse(int matchelse, TPpToken * ppToken); 397 int extraTokenCheck(int atom, TPpToken* ppToken, int token); 398 int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); 399 int evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); 400 int CPPif (TPpToken * ppToken); 401 int CPPifdef(int defined, TPpToken * ppToken); 402 int CPPinclude(TPpToken * ppToken); 403 int CPPline(TPpToken * ppToken); 404 int CPPerror(TPpToken * ppToken); 405 int CPPpragma(TPpToken * ppToken); 406 int CPPversion(TPpToken * ppToken); 407 int CPPextension(TPpToken * ppToken); 408 int readCPPline(TPpToken * ppToken); 409 int scanHeaderName(TPpToken* ppToken, char delimit); 410 TokenStream* PrescanMacroArg(TokenStream&, TPpToken*, bool newLineOkay); 411 MacroExpandResult MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay); 412 413 // 414 // From PpTokens.cpp 415 // 416 void pushTokenStreamInput(TokenStream&, bool pasting = false); 417 void UngetToken(int token, TPpToken*); 418 419 class tTokenInput : public tInput { 420 public: tTokenInput(TPpContext * pp,TokenStream * t,bool prepasting)421 tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) : tInput(pp), tokens(t), lastTokenPastes(prepasting) { } scan(TPpToken * ppToken)422 virtual int scan(TPpToken *ppToken) override { return tokens->getToken(pp->parseContext, ppToken); } getch()423 virtual int getch() override { assert(0); return EndOfInput; } ungetch()424 virtual void ungetch() override { assert(0); } peekPasting()425 virtual bool peekPasting() override { return tokens->peekTokenizedPasting(lastTokenPastes); } 426 protected: 427 TokenStream* tokens; 428 bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token 429 }; 430 431 class tUngotTokenInput : public tInput { 432 public: tUngotTokenInput(TPpContext * pp,int t,TPpToken * p)433 tUngotTokenInput(TPpContext* pp, int t, TPpToken* p) : tInput(pp), token(t), lval(*p) { } 434 virtual int scan(TPpToken *) override; getch()435 virtual int getch() override { assert(0); return EndOfInput; } ungetch()436 virtual void ungetch() override { assert(0); } 437 protected: 438 int token; 439 TPpToken lval; 440 }; 441 442 // 443 // From PpScanner.cpp 444 // 445 class tStringInput : public tInput { 446 public: tStringInput(TPpContext * pp,TInputScanner & i)447 tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { } 448 virtual int scan(TPpToken*) override; 449 450 // Scanner used to get source stream characters. 451 // - Escaped newlines are handled here, invisibly to the caller. 452 // - All forms of newline are handled, and turned into just a '\n'. getch()453 int getch() override 454 { 455 int ch = input->get(); 456 457 if (ch == '\\') { 458 // Move past escaped newlines, as many as sequentially exist 459 do { 460 if (input->peek() == '\r' || input->peek() == '\n') { 461 bool allowed = pp->parseContext.lineContinuationCheck(input->getSourceLoc(), pp->inComment); 462 if (! allowed && pp->inComment) 463 return '\\'; 464 465 // escape one newline now 466 ch = input->get(); 467 int nextch = input->get(); 468 if (ch == '\r' && nextch == '\n') 469 ch = input->get(); 470 else 471 ch = nextch; 472 } else 473 return '\\'; 474 } while (ch == '\\'); 475 } 476 477 // handle any non-escaped newline 478 if (ch == '\r' || ch == '\n') { 479 if (ch == '\r' && input->peek() == '\n') 480 input->get(); 481 return '\n'; 482 } 483 484 return ch; 485 } 486 487 // Scanner used to backup the source stream characters. Newlines are 488 // handled here, invisibly to the caller, meaning have to undo exactly 489 // what getch() above does (e.g., don't leave things in the middle of a 490 // sequence of escaped newlines). ungetch()491 void ungetch() override 492 { 493 input->unget(); 494 495 do { 496 int ch = input->peek(); 497 if (ch == '\r' || ch == '\n') { 498 if (ch == '\n') { 499 // correct for two-character newline 500 input->unget(); 501 if (input->peek() != '\r') 502 input->get(); 503 } 504 // now in front of a complete newline, move past an escape character 505 input->unget(); 506 if (input->peek() == '\\') 507 input->unget(); 508 else { 509 input->get(); 510 break; 511 } 512 } else 513 break; 514 } while (true); 515 } 516 517 protected: 518 TInputScanner* input; 519 }; 520 521 // Holds a reference to included file data, as well as a 522 // prologue and an epilogue string. This can be scanned using the tInput 523 // interface and acts as a single source string. 524 class TokenizableIncludeFile : public tInput { 525 public: 526 // Copies prologue and epilogue. The includedFile must remain valid 527 // 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)528 TokenizableIncludeFile(const TSourceLoc& startLoc, 529 const std::string& prologue, 530 TShader::Includer::IncludeResult* includedFile, 531 const std::string& epilogue, 532 TPpContext* pp) 533 : tInput(pp), 534 prologue_(prologue), 535 epilogue_(epilogue), 536 includedFile_(includedFile), 537 scanner(3, strings, lengths, nullptr, 0, 0, true), 538 prevScanner(nullptr), 539 stringInput(pp, scanner) 540 { 541 strings[0] = prologue_.data(); 542 strings[1] = includedFile_->headerData; 543 strings[2] = epilogue_.data(); 544 545 lengths[0] = prologue_.size(); 546 lengths[1] = includedFile_->headerLength; 547 lengths[2] = epilogue_.size(); 548 549 scanner.setLine(startLoc.line); 550 scanner.setString(startLoc.string); 551 552 scanner.setFile(startLoc.name->c_str(), 0); 553 scanner.setFile(startLoc.name->c_str(), 1); 554 scanner.setFile(startLoc.name->c_str(), 2); 555 } 556 557 // tInput methods: scan(TPpToken * t)558 int scan(TPpToken* t) override { return stringInput.scan(t); } getch()559 int getch() override { return stringInput.getch(); } ungetch()560 void ungetch() override { stringInput.ungetch(); } 561 notifyActivated()562 void notifyActivated() override 563 { 564 prevScanner = pp->parseContext.getScanner(); 565 pp->parseContext.setScanner(&scanner); 566 pp->push_include(includedFile_); 567 } 568 notifyDeleted()569 void notifyDeleted() override 570 { 571 pp->parseContext.setScanner(prevScanner); 572 pp->pop_include(); 573 } 574 575 private: 576 TokenizableIncludeFile& operator=(const TokenizableIncludeFile&); 577 578 // Stores the prologue for this string. 579 const std::string prologue_; 580 581 // Stores the epilogue for this string. 582 const std::string epilogue_; 583 584 // Points to the IncludeResult that this TokenizableIncludeFile represents. 585 TShader::Includer::IncludeResult* includedFile_; 586 587 // Will point to prologue_, includedFile_->headerData and epilogue_ 588 // This is passed to scanner constructor. 589 // These do not own the storage and it must remain valid until this 590 // object has been destroyed. 591 const char* strings[3]; 592 // Length of str_, passed to scanner constructor. 593 size_t lengths[3]; 594 // Scans over str_. 595 TInputScanner scanner; 596 // The previous effective scanner before the scanner in this instance 597 // has been activated. 598 TInputScanner* prevScanner; 599 // Delegate object implementing the tInput interface. 600 tStringInput stringInput; 601 }; 602 603 int ScanFromString(char* s); 604 void missingEndifCheck(); 605 int lFloatConst(int len, int ch, TPpToken* ppToken); 606 int characterLiteral(TPpToken* ppToken); 607 push_include(TShader::Includer::IncludeResult * result)608 void push_include(TShader::Includer::IncludeResult* result) 609 { 610 currentSourceFile = result->headerName; 611 includeStack.push(result); 612 } 613 pop_include()614 void pop_include() 615 { 616 TShader::Includer::IncludeResult* include = includeStack.top(); 617 includeStack.pop(); 618 includer.releaseInclude(include); 619 if (includeStack.empty()) { 620 currentSourceFile = rootFileName; 621 } else { 622 currentSourceFile = includeStack.top()->headerName; 623 } 624 } 625 626 bool inComment; 627 std::string rootFileName; 628 std::stack<TShader::Includer::IncludeResult*> includeStack; 629 std::string currentSourceFile; 630 631 std::istringstream strtodStream; 632 }; 633 634 } // end namespace glslang 635 636 #endif // PPCONTEXT_H 637