1 // 2 //Copyright (C) 2013 LunarG, Inc. 3 //All rights reserved. 4 // 5 //Redistribution and use in source and binary forms, with or without 6 //modification, are permitted provided that the following conditions 7 //are met: 8 // 9 // Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // 12 // Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following 14 // disclaimer in the documentation and/or other materials provided 15 // with the distribution. 16 // 17 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 18 // contributors may be used to endorse or promote products derived 19 // from this software without specific prior written permission. 20 // 21 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 //POSSIBILITY OF SUCH DAMAGE. 33 // 34 /****************************************************************************\ 35 Copyright (c) 2002, NVIDIA Corporation. 36 37 NVIDIA Corporation("NVIDIA") supplies this software to you in 38 consideration of your agreement to the following terms, and your use, 39 installation, modification or redistribution of this NVIDIA software 40 constitutes acceptance of these terms. If you do not agree with these 41 terms, please do not use, install, modify or redistribute this NVIDIA 42 software. 43 44 In consideration of your agreement to abide by the following terms, and 45 subject to these terms, NVIDIA grants you a personal, non-exclusive 46 license, under NVIDIA's copyrights in this original NVIDIA software (the 47 "NVIDIA Software"), to use, reproduce, modify and redistribute the 48 NVIDIA Software, with or without modifications, in source and/or binary 49 forms; provided that if you redistribute the NVIDIA Software, you must 50 retain the copyright notice of NVIDIA, this notice and the following 51 text and disclaimers in all such redistributions of the NVIDIA Software. 52 Neither the name, trademarks, service marks nor logos of NVIDIA 53 Corporation may be used to endorse or promote products derived from the 54 NVIDIA Software without specific prior written permission from NVIDIA. 55 Except as expressly stated in this notice, no other rights or licenses 56 express or implied, are granted by NVIDIA herein, including but not 57 limited to any patent rights that may be infringed by your derivative 58 works or by other works in which the NVIDIA Software may be 59 incorporated. No hardware is licensed hereunder. 60 61 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT 62 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 63 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, 64 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 65 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER 66 PRODUCTS. 67 68 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, 69 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 70 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 71 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY 72 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE 73 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, 74 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 75 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 76 \****************************************************************************/ 77 78 #ifndef PPCONTEXT_H 79 #define PPCONTEXT_H 80 81 #include <stack> 82 #include <unordered_map> 83 84 #include "../ParseHelper.h" 85 86 /* windows only pragma */ 87 #ifdef _MSC_VER 88 #pragma warning(disable : 4127) 89 #endif 90 91 namespace glslang { 92 93 class TPpToken { 94 public: 95 TPpToken() : token(0), space(false), ival(0), dval(0.0), atom(0) 96 { 97 loc.init(); 98 name[0] = 0; 99 } 100 101 bool operator==(const TPpToken& right) 102 { 103 return token == right.token && atom == right.atom && 104 ival == right.ival && dval == right.dval && 105 strcmp(name, right.name) == 0; 106 } 107 bool operator!=(const TPpToken& right) { return ! operator==(right); } 108 109 TSourceLoc loc; 110 int token; 111 bool space; // true if a space (for white space or a removed comment) should also be recognized, in front of the token returned 112 int ival; 113 double dval; 114 long long i64val; 115 int atom; 116 char name[MaxTokenLength + 1]; 117 }; 118 119 class TInputScanner; 120 121 // This class is the result of turning a huge pile of C code communicating through globals 122 // into a class. This was done to allowing instancing to attain thread safety. 123 // Don't expect too much in terms of OO design. 124 class TPpContext { 125 public: 126 TPpContext(TParseContextBase&, const std::string& rootFileName, TShader::Includer&); 127 virtual ~TPpContext(); 128 129 void setPreamble(const char* preamble, size_t length); 130 131 const char* tokenize(TPpToken* ppToken); 132 133 class tInput { 134 public: 135 tInput(TPpContext* p) : done(false), pp(p) { } 136 virtual ~tInput() { } 137 138 virtual int scan(TPpToken*) = 0; 139 virtual int getch() = 0; 140 virtual void ungetch() = 0; 141 142 // Will be called when we start reading tokens from this instance 143 virtual void notifyActivated() {} 144 // Will be called when we do not read tokens from this instance anymore 145 virtual void notifyDeleted() {} 146 protected: 147 bool done; 148 TPpContext* pp; 149 }; 150 151 void setInput(TInputScanner& input, bool versionWillBeError); 152 153 void pushInput(tInput* in) 154 { 155 inputStack.push_back(in); 156 in->notifyActivated(); 157 } 158 void popInput() 159 { 160 inputStack.back()->notifyDeleted(); 161 delete inputStack.back(); 162 inputStack.pop_back(); 163 } 164 165 struct TokenStream { 166 TokenStream() : current(0) { } 167 TVector<unsigned char> data; 168 size_t current; 169 }; 170 171 struct MemoryPool { 172 struct chunk *next; 173 uintptr_t free, end; 174 size_t chunksize; 175 uintptr_t alignmask; 176 }; 177 178 // 179 // From Pp.cpp 180 // 181 182 struct MacroSymbol { 183 MacroSymbol() : argc(0), args(0), body(0), busy(0), undef(0) { } 184 int argc; 185 int *args; 186 TokenStream *body; 187 unsigned busy:1; 188 unsigned undef:1; 189 }; 190 191 struct Symbol { 192 int atom; 193 MacroSymbol mac; 194 }; 195 196 struct SymbolList { 197 struct SymbolList_Rec *next; 198 Symbol *symb; 199 }; 200 201 MemoryPool *pool; 202 typedef TMap<int, Symbol*> TSymbolMap; 203 TSymbolMap symbols; // this has light use... just defined macros 204 205 protected: 206 TPpContext(TPpContext&); 207 TPpContext& operator=(TPpContext&); 208 209 char* preamble; // string to parse, all before line 1 of string 0, it is 0 if no preamble 210 int preambleLength; 211 char** strings; // official strings of shader, starting a string 0 line 1 212 size_t* lengths; 213 int numStrings; // how many official strings there are 214 int currentString; // which string we're currently parsing (-1 for preamble) 215 216 // Scanner data: 217 int previous_token; 218 TParseContextBase& parseContext; 219 220 // Get the next token from *stack* of input sources, popping input sources 221 // that are out of tokens, down until an input source is found that has a token. 222 // Return EndOfInput when there are no more tokens to be found by doing this. 223 int scanToken(TPpToken* ppToken) 224 { 225 int token = EndOfInput; 226 227 while (! inputStack.empty()) { 228 token = inputStack.back()->scan(ppToken); 229 if (token != EndOfInput || inputStack.empty()) 230 break; 231 popInput(); 232 } 233 234 return token; 235 } 236 int getChar() { return inputStack.back()->getch(); } 237 void ungetChar() { inputStack.back()->ungetch(); } 238 239 static const int maxMacroArgs = 64; 240 static const int maxIfNesting = 64; 241 242 int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor) 243 bool elseSeen[maxIfNesting]; // Keep a track of whether an else has been seen at a particular depth 244 int elsetracker; // #if-#else and #endif constructs...Counter. 245 246 class tMacroInput : public tInput { 247 public: 248 tMacroInput(TPpContext* pp) : tInput(pp) { } 249 virtual ~tMacroInput() 250 { 251 for (size_t i = 0; i < args.size(); ++i) 252 delete args[i]; 253 } 254 255 virtual int scan(TPpToken*); 256 virtual int getch() { assert(0); return EndOfInput; } 257 virtual void ungetch() { assert(0); } 258 MacroSymbol *mac; 259 TVector<TokenStream*> args; 260 }; 261 262 class tMarkerInput : public tInput { 263 public: 264 tMarkerInput(TPpContext* pp) : tInput(pp) { } 265 virtual int scan(TPpToken*) 266 { 267 if (done) 268 return EndOfInput; 269 done = true; 270 271 return marker; 272 } 273 virtual int getch() { assert(0); return EndOfInput; } 274 virtual void ungetch() { assert(0); } 275 static const int marker = -3; 276 }; 277 278 class tZeroInput : public tInput { 279 public: 280 tZeroInput(TPpContext* pp) : tInput(pp) { } 281 virtual int scan(TPpToken*); 282 virtual int getch() { assert(0); return EndOfInput; } 283 virtual void ungetch() { assert(0); } 284 }; 285 286 std::vector<tInput*> inputStack; 287 bool errorOnVersion; 288 bool versionSeen; 289 290 // 291 // from Pp.cpp 292 // 293 294 // Used to obtain #include content. 295 TShader::Includer& includer; 296 297 int InitCPP(); 298 int CPPdefine(TPpToken * ppToken); 299 int CPPundef(TPpToken * ppToken); 300 int CPPelse(int matchelse, TPpToken * ppToken); 301 int extraTokenCheck(int atom, TPpToken* ppToken, int token); 302 int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); 303 int evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); 304 int CPPif (TPpToken * ppToken); 305 int CPPifdef(int defined, TPpToken * ppToken); 306 int CPPinclude(TPpToken * ppToken); 307 int CPPline(TPpToken * ppToken); 308 int CPPerror(TPpToken * ppToken); 309 int CPPpragma(TPpToken * ppToken); 310 int CPPversion(TPpToken * ppToken); 311 int CPPextension(TPpToken * ppToken); 312 int readCPPline(TPpToken * ppToken); 313 TokenStream* PrescanMacroArg(TokenStream *a, TPpToken * ppToken, bool newLineOkay); 314 int MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay); 315 316 // 317 // from PpSymbols.cpp 318 // 319 Symbol *NewSymbol(int name); 320 Symbol *AddSymbol(int atom); 321 Symbol *LookUpSymbol(int atom); 322 323 // 324 // From PpTokens.cpp 325 // 326 void lAddByte(TokenStream *fTok, unsigned char fVal); 327 int lReadByte(TokenStream *pTok); 328 void lUnreadByte(TokenStream *pTok); 329 void RecordToken(TokenStream* pTok, int token, TPpToken* ppToken); 330 void RewindTokenStream(TokenStream *pTok); 331 int ReadToken(TokenStream* pTok, TPpToken* ppToken); 332 void pushTokenStreamInput(TokenStream *ts); 333 void UngetToken(int token, TPpToken* ppToken); 334 335 class tTokenInput : public tInput { 336 public: 337 tTokenInput(TPpContext* pp, TokenStream* t) : tInput(pp), tokens(t) { } 338 virtual int scan(TPpToken *); 339 virtual int getch() { assert(0); return EndOfInput; } 340 virtual void ungetch() { assert(0); } 341 protected: 342 TokenStream *tokens; 343 }; 344 345 class tUngotTokenInput : public tInput { 346 public: 347 tUngotTokenInput(TPpContext* pp, int t, TPpToken* p) : tInput(pp), token(t), lval(*p) { } 348 virtual int scan(TPpToken *); 349 virtual int getch() { assert(0); return EndOfInput; } 350 virtual void ungetch() { assert(0); } 351 protected: 352 int token; 353 TPpToken lval; 354 }; 355 356 // 357 // From PpScanner.cpp 358 // 359 class tStringInput : public tInput { 360 public: 361 tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { } 362 virtual int scan(TPpToken*); 363 364 // Scanner used to get source stream characters. 365 // - Escaped newlines are handled here, invisibly to the caller. 366 // - All forms of newline are handled, and turned into just a '\n'. 367 int getch() 368 { 369 int ch = input->get(); 370 371 if (ch == '\\') { 372 // Move past escaped newlines, as many as sequentially exist 373 do { 374 if (input->peek() == '\r' || input->peek() == '\n') { 375 bool allowed = pp->parseContext.lineContinuationCheck(input->getSourceLoc(), pp->inComment); 376 if (! allowed && pp->inComment) 377 return '\\'; 378 379 // escape one newline now 380 ch = input->get(); 381 int nextch = input->get(); 382 if (ch == '\r' && nextch == '\n') 383 ch = input->get(); 384 else 385 ch = nextch; 386 } else 387 return '\\'; 388 } while (ch == '\\'); 389 } 390 391 // handle any non-escaped newline 392 if (ch == '\r' || ch == '\n') { 393 if (ch == '\r' && input->peek() == '\n') 394 input->get(); 395 return '\n'; 396 } 397 398 return ch; 399 } 400 401 // Scanner used to backup the source stream characters. Newlines are 402 // handled here, invisibly to the caller, meaning have to undo exactly 403 // what getch() above does (e.g., don't leave things in the middle of a 404 // sequence of escaped newlines). 405 void ungetch() 406 { 407 input->unget(); 408 409 do { 410 int ch = input->peek(); 411 if (ch == '\r' || ch == '\n') { 412 if (ch == '\n') { 413 // correct for two-character newline 414 input->unget(); 415 if (input->peek() != '\r') 416 input->get(); 417 } 418 // now in front of a complete newline, move past an escape character 419 input->unget(); 420 if (input->peek() == '\\') 421 input->unget(); 422 else { 423 input->get(); 424 break; 425 } 426 } else 427 break; 428 } while (true); 429 } 430 431 protected: 432 TInputScanner* input; 433 }; 434 435 // Holds a reference to included file data, as well as a 436 // prologue and an epilogue string. This can be scanned using the tInput 437 // interface and acts as a single source string. 438 class TokenizableIncludeFile : public tInput { 439 public: 440 // Copies prologue and epilogue. The includedFile must remain valid 441 // until this TokenizableIncludeFile is no longer used. 442 TokenizableIncludeFile(const TSourceLoc& startLoc, 443 const std::string& prologue, 444 TShader::Includer::IncludeResult* includedFile, 445 const std::string& epilogue, 446 TPpContext* pp) 447 : tInput(pp), 448 prologue_(prologue), 449 includedFile_(includedFile), 450 epilogue_(epilogue), 451 scanner(3, strings, lengths, names, 0, 0, true), 452 prevScanner(nullptr), 453 stringInput(pp, scanner) 454 { 455 strings[0] = prologue_.data(); 456 strings[1] = includedFile_->file_data; 457 strings[2] = epilogue_.data(); 458 459 lengths[0] = prologue_.size(); 460 lengths[1] = includedFile_->file_length; 461 lengths[2] = epilogue_.size(); 462 463 scanner.setLine(startLoc.line); 464 scanner.setString(startLoc.string); 465 466 scanner.setFile(startLoc.name, 0); 467 scanner.setFile(startLoc.name, 1); 468 scanner.setFile(startLoc.name, 2); 469 } 470 471 // tInput methods: 472 int scan(TPpToken* t) override { return stringInput.scan(t); } 473 int getch() override { return stringInput.getch(); } 474 void ungetch() override { stringInput.ungetch(); } 475 476 void notifyActivated() override 477 { 478 prevScanner = pp->parseContext.getScanner(); 479 pp->parseContext.setScanner(&scanner); 480 pp->push_include(includedFile_); 481 } 482 483 void notifyDeleted() override 484 { 485 pp->parseContext.setScanner(prevScanner); 486 pp->pop_include(); 487 } 488 489 private: 490 TokenizableIncludeFile& operator=(const TokenizableIncludeFile&); 491 492 // Stores the prologue for this string. 493 const std::string prologue_; 494 495 // Stores the epilogue for this string. 496 const std::string epilogue_; 497 498 // Points to the IncludeResult that this TokenizableIncludeFile represents. 499 TShader::Includer::IncludeResult* includedFile_; 500 501 // Will point to prologue_, includedFile_->file_data and epilogue_ 502 // This is passed to scanner constructor. 503 // These do not own the storage and it must remain valid until this 504 // object has been destroyed. 505 const char* strings[3]; 506 // Length of str_, passed to scanner constructor. 507 size_t lengths[3]; 508 // String names 509 const char* names[3]; 510 // Scans over str_. 511 TInputScanner scanner; 512 // The previous effective scanner before the scanner in this instance 513 // has been activated. 514 TInputScanner* prevScanner; 515 // Delegate object implementing the tInput interface. 516 tStringInput stringInput; 517 }; 518 519 int InitScanner(); 520 int ScanFromString(char* s); 521 void missingEndifCheck(); 522 int lFloatConst(int len, int ch, TPpToken* ppToken); 523 524 void push_include(TShader::Includer::IncludeResult* result) 525 { 526 currentSourceFile = result->file_name; 527 includeStack.push(result); 528 } 529 530 void pop_include() 531 { 532 TShader::Includer::IncludeResult* include = includeStack.top(); 533 includeStack.pop(); 534 includer.releaseInclude(include); 535 if (includeStack.empty()) { 536 currentSourceFile = rootFileName; 537 } else { 538 currentSourceFile = includeStack.top()->file_name; 539 } 540 } 541 542 bool inComment; 543 544 // 545 // From PpAtom.cpp 546 // 547 typedef TUnorderedMap<TString, int> TAtomMap; 548 typedef TVector<const TString*> TStringMap; 549 550 TAtomMap atomMap; 551 TStringMap stringMap; 552 std::stack<TShader::Includer::IncludeResult*> includeStack; 553 std::string currentSourceFile; 554 std::string rootFileName; 555 int nextAtom; 556 void InitAtomTable(); 557 void AddAtomFixed(const char* s, int atom); 558 int LookUpAddString(const char* s); 559 const char* GetAtomString(int atom); 560 561 // 562 // From PpMemory.cpp 563 // 564 MemoryPool *mem_CreatePool(size_t chunksize, unsigned align); 565 void mem_FreePool(MemoryPool*); 566 void *mem_Alloc(MemoryPool* p, size_t size); 567 int mem_AddCleanup(MemoryPool* p, void (*fn)(void *, void*), void* arg1, void* arg2); 568 }; 569 570 } // end namespace glslang 571 572 #endif // PPCONTEXT_H 573