Home | History | Annotate | Download | only in preprocessor
      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