Home | History | Annotate | Download | only in MachineIndependent
      1 //
      2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
      3 // Copyright (C) 2013 LunarG, Inc.
      4 //
      5 // All rights reserved.
      6 //
      7 // Redistribution and use in source and binary forms, with or without
      8 // modification, are permitted provided that the following conditions
      9 // are met:
     10 //
     11 //    Redistributions of source code must retain the above copyright
     12 //    notice, this list of conditions and the following disclaimer.
     13 //
     14 //    Redistributions in binary form must reproduce the above
     15 //    copyright notice, this list of conditions and the following
     16 //    disclaimer in the documentation and/or other materials provided
     17 //    with the distribution.
     18 //
     19 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
     20 //    contributors may be used to endorse or promote products derived
     21 //    from this software without specific prior written permission.
     22 //
     23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     34 // POSSIBILITY OF SUCH DAMAGE.
     35 //
     36 #ifndef _GLSLANG_SCAN_INCLUDED_
     37 #define _GLSLANG_SCAN_INCLUDED_
     38 
     39 #include "Versions.h"
     40 
     41 namespace glslang {
     42 
     43 // Use a global end-of-input character, so no translation is needed across
     44 // layers of encapsulation.  Characters are all 8 bit, and positive, so there is
     45 // no aliasing of character 255 onto -1, for example.
     46 const int EndOfInput = -1;
     47 
     48 //
     49 // A character scanner that seamlessly, on read-only strings, reads across an
     50 // array of strings without assuming null termination.
     51 //
     52 class TInputScanner {
     53 public:
     54     TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0, bool single = false) :
     55         numSources(n),
     56         sources(reinterpret_cast<const unsigned char* const *>(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters
     57         lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single), endOfFileReached(false)
     58     {
     59         loc = new TSourceLoc[numSources];
     60         for (int i = 0; i < numSources; ++i) {
     61             loc[i].init();
     62         }
     63         if (names != nullptr) {
     64             for (int i = 0; i < numSources; ++i)
     65                 loc[i].name = names[i];
     66         }
     67         loc[currentSource].string = -stringBias;
     68         loc[currentSource].line = 1;
     69         loc[currentSource].column = 0;
     70         logicalSourceLoc.string = 0;
     71         logicalSourceLoc.line = 1;
     72         logicalSourceLoc.column = 0;
     73         logicalSourceLoc.name = loc[0].name;
     74     }
     75 
     76     virtual ~TInputScanner()
     77     {
     78         delete [] loc;
     79     }
     80 
     81     // retrieve the next character and advance one character
     82     int get()
     83     {
     84         int ret = peek();
     85         if (ret == EndOfInput)
     86             return ret;
     87         ++loc[currentSource].column;
     88         ++logicalSourceLoc.column;
     89         if (ret == '\n') {
     90             ++loc[currentSource].line;
     91             ++logicalSourceLoc.line;
     92             logicalSourceLoc.column = 0;
     93             loc[currentSource].column = 0;
     94         }
     95         advance();
     96 
     97         return ret;
     98     }
     99 
    100     // retrieve the next character, no advance
    101     int peek()
    102     {
    103         if (currentSource >= numSources) {
    104             endOfFileReached = true;
    105             return EndOfInput;
    106         }
    107         // Make sure we do not read off the end of a string.
    108         // N.B. Sources can have a length of 0.
    109         int sourceToRead = currentSource;
    110         size_t charToRead = currentChar;
    111         while(charToRead >= lengths[sourceToRead]) {
    112             charToRead = 0;
    113             sourceToRead += 1;
    114             if (sourceToRead >= numSources) {
    115                 return EndOfInput;
    116             }
    117         }
    118 
    119         // Here, we care about making negative valued characters positive
    120         return sources[sourceToRead][charToRead];
    121     }
    122 
    123     // go back one character
    124     void unget()
    125     {
    126         // Do not roll back once we've reached the end of the file.
    127         if (endOfFileReached)
    128             return;
    129 
    130         if (currentChar > 0) {
    131             --currentChar;
    132             --loc[currentSource].column;
    133             --logicalSourceLoc.column;
    134             if (loc[currentSource].column < 0) {
    135                 // We've moved back past a new line. Find the
    136                 // previous newline (or start of the file) to compute
    137                 // the column count on the now current line.
    138                 size_t chIndex = currentChar;
    139                 while (chIndex > 0) {
    140                     if (sources[currentSource][chIndex] == '\n') {
    141                         break;
    142                     }
    143                     --chIndex;
    144                 }
    145                 logicalSourceLoc.column = (int)(currentChar - chIndex);
    146                 loc[currentSource].column = (int)(currentChar - chIndex);
    147             }
    148         } else {
    149             do {
    150                 --currentSource;
    151             } while (currentSource > 0 && lengths[currentSource] == 0);
    152             if (lengths[currentSource] == 0) {
    153                 // set to 0 if we've backed up to the start of an empty string
    154                 currentChar = 0;
    155             } else
    156                 currentChar = lengths[currentSource] - 1;
    157         }
    158         if (peek() == '\n') {
    159             --loc[currentSource].line;
    160             --logicalSourceLoc.line;
    161         }
    162     }
    163 
    164     // for #line override
    165     void setLine(int newLine)
    166     {
    167         logicalSourceLoc.line = newLine;
    168         loc[getLastValidSourceIndex()].line = newLine;
    169     }
    170 
    171     // for #line override in filename based parsing
    172     void setFile(const char* filename)
    173     {
    174         logicalSourceLoc.name = filename;
    175         loc[getLastValidSourceIndex()].name = filename;
    176     }
    177 
    178     void setFile(const char* filename, int i)
    179     {
    180         if (i == getLastValidSourceIndex()) {
    181             logicalSourceLoc.name = filename;
    182         }
    183         loc[i].name = filename;
    184     }
    185 
    186     void setString(int newString)
    187     {
    188         logicalSourceLoc.string = newString;
    189         loc[getLastValidSourceIndex()].string = newString;
    190         logicalSourceLoc.name = nullptr;
    191         loc[getLastValidSourceIndex()].name = nullptr;
    192     }
    193 
    194     // for #include content indentation
    195     void setColumn(int col)
    196     {
    197         logicalSourceLoc.column = col;
    198         loc[getLastValidSourceIndex()].column = col;
    199     }
    200 
    201     void setEndOfInput()
    202     {
    203         endOfFileReached = true;
    204         currentSource = numSources;
    205     }
    206 
    207     bool atEndOfInput() const { return endOfFileReached; }
    208 
    209     const TSourceLoc& getSourceLoc() const
    210     {
    211         if (singleLogical) {
    212             return logicalSourceLoc;
    213         } else {
    214             return loc[std::max(0, std::min(currentSource, numSources - finale - 1))];
    215         }
    216     }
    217     // Returns the index (starting from 0) of the most recent valid source string we are reading from.
    218     int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); }
    219 
    220     void consumeWhiteSpace(bool& foundNonSpaceTab);
    221     bool consumeComment();
    222     void consumeWhitespaceComment(bool& foundNonSpaceTab);
    223     bool scanVersion(int& version, EProfile& profile, bool& notFirstToken);
    224 
    225 protected:
    226 
    227     // advance one character
    228     void advance()
    229     {
    230         ++currentChar;
    231         if (currentChar >= lengths[currentSource]) {
    232             ++currentSource;
    233             if (currentSource < numSources) {
    234                 loc[currentSource].string = loc[currentSource - 1].string + 1;
    235                 loc[currentSource].line = 1;
    236                 loc[currentSource].column = 0;
    237             }
    238             while (currentSource < numSources && lengths[currentSource] == 0) {
    239                 ++currentSource;
    240                 if (currentSource < numSources) {
    241                     loc[currentSource].string = loc[currentSource - 1].string + 1;
    242                     loc[currentSource].line = 1;
    243                     loc[currentSource].column = 0;
    244                 }
    245             }
    246             currentChar = 0;
    247         }
    248     }
    249 
    250     int numSources;                      // number of strings in source
    251     const unsigned char* const *sources; // array of strings; must be converted to positive values on use, to avoid aliasing with -1 as EndOfInput
    252     const size_t *lengths;               // length of each string
    253     int currentSource;
    254     size_t currentChar;
    255 
    256     // This is for reporting what string/line an error occurred on, and can be overridden by #line.
    257     // It remembers the last state of each source string as it is left for the next one, so unget()
    258     // can restore that state.
    259     TSourceLoc* loc;  // an array
    260 
    261     int stringBias;   // the first string that is the user's string number 0
    262     int finale;       // number of internal strings after user's last string
    263 
    264     TSourceLoc logicalSourceLoc;
    265     bool singleLogical; // treats the strings as a single logical string.
    266                         // locations will be reported from the first string.
    267 
    268     // Set to true once peek() returns EndOfFile, so that we won't roll back
    269     // once we've reached EndOfFile.
    270     bool endOfFileReached;
    271 };
    272 
    273 } // end namespace glslang
    274 
    275 #endif // _GLSLANG_SCAN_INCLUDED_
    276