• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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