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, 55 int b = 0, int f = 0, bool single = false) : numSources(n)56 numSources(n), 57 // up to this point, common usage is "char*", but now we need positive 8-bit characters 58 sources(reinterpret_cast<const unsigned char* const *>(s)), 59 lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single), 60 endOfFileReached(false) 61 { 62 loc = new TSourceLoc[numSources]; 63 for (int i = 0; i < numSources; ++i) { 64 loc[i].init(i - stringBias); 65 } 66 if (names != nullptr) { 67 for (int i = 0; i < numSources; ++i) 68 loc[i].name = names[i] != nullptr ? NewPoolTString(names[i]) : nullptr; 69 } 70 loc[currentSource].line = 1; 71 logicalSourceLoc.init(1); 72 logicalSourceLoc.name = loc[0].name; 73 } 74 ~TInputScanner()75 virtual ~TInputScanner() 76 { 77 delete [] loc; 78 } 79 80 // retrieve the next character and advance one character get()81 int get() 82 { 83 int ret = peek(); 84 if (ret == EndOfInput) 85 return ret; 86 ++loc[currentSource].column; 87 ++logicalSourceLoc.column; 88 if (ret == '\n') { 89 ++loc[currentSource].line; 90 ++logicalSourceLoc.line; 91 logicalSourceLoc.column = 0; 92 loc[currentSource].column = 0; 93 } 94 advance(); 95 96 return ret; 97 } 98 99 // retrieve the next character, no advance peek()100 int peek() 101 { 102 if (currentSource >= numSources) { 103 endOfFileReached = true; 104 return EndOfInput; 105 } 106 // Make sure we do not read off the end of a string. 107 // N.B. Sources can have a length of 0. 108 int sourceToRead = currentSource; 109 size_t charToRead = currentChar; 110 while(charToRead >= lengths[sourceToRead]) { 111 charToRead = 0; 112 sourceToRead += 1; 113 if (sourceToRead >= numSources) { 114 return EndOfInput; 115 } 116 } 117 118 // Here, we care about making negative valued characters positive 119 return sources[sourceToRead][charToRead]; 120 } 121 122 // go back one character unget()123 void unget() 124 { 125 // Do not roll back once we've reached the end of the file. 126 if (endOfFileReached) 127 return; 128 129 if (currentChar > 0) { 130 --currentChar; 131 --loc[currentSource].column; 132 --logicalSourceLoc.column; 133 if (loc[currentSource].column < 0) { 134 // We've moved back past a new line. Find the 135 // previous newline (or start of the file) to compute 136 // the column count on the now current line. 137 size_t chIndex = currentChar; 138 while (chIndex > 0) { 139 if (sources[currentSource][chIndex] == '\n') { 140 break; 141 } 142 --chIndex; 143 } 144 logicalSourceLoc.column = (int)(currentChar - chIndex); 145 loc[currentSource].column = (int)(currentChar - chIndex); 146 } 147 } else { 148 do { 149 --currentSource; 150 } while (currentSource > 0 && lengths[currentSource] == 0); 151 if (lengths[currentSource] == 0) { 152 // set to 0 if we've backed up to the start of an empty string 153 currentChar = 0; 154 } else 155 currentChar = lengths[currentSource] - 1; 156 } 157 if (peek() == '\n') { 158 --loc[currentSource].line; 159 --logicalSourceLoc.line; 160 } 161 } 162 163 // for #line override setLine(int newLine)164 void setLine(int newLine) 165 { 166 logicalSourceLoc.line = newLine; 167 loc[getLastValidSourceIndex()].line = newLine; 168 } 169 170 // for #line override in filename based parsing setFile(const char * filename)171 void setFile(const char* filename) 172 { 173 TString* fn_tstr = NewPoolTString(filename); 174 logicalSourceLoc.name = fn_tstr; 175 loc[getLastValidSourceIndex()].name = fn_tstr; 176 } 177 setFile(const char * filename,int i)178 void setFile(const char* filename, int i) 179 { 180 TString* fn_tstr = NewPoolTString(filename); 181 if (i == getLastValidSourceIndex()) { 182 logicalSourceLoc.name = fn_tstr; 183 } 184 loc[i].name = fn_tstr; 185 } 186 setString(int newString)187 void setString(int newString) 188 { 189 logicalSourceLoc.string = newString; 190 loc[getLastValidSourceIndex()].string = newString; 191 logicalSourceLoc.name = nullptr; 192 loc[getLastValidSourceIndex()].name = nullptr; 193 } 194 195 // for #include content indentation setColumn(int col)196 void setColumn(int col) 197 { 198 logicalSourceLoc.column = col; 199 loc[getLastValidSourceIndex()].column = col; 200 } 201 setEndOfInput()202 void setEndOfInput() 203 { 204 endOfFileReached = true; 205 currentSource = numSources; 206 } 207 atEndOfInput()208 bool atEndOfInput() const { return endOfFileReached; } 209 getSourceLoc()210 const TSourceLoc& getSourceLoc() const 211 { 212 if (singleLogical) { 213 return logicalSourceLoc; 214 } else { 215 return loc[std::max(0, std::min(currentSource, numSources - finale - 1))]; 216 } 217 } 218 // Returns the index (starting from 0) of the most recent valid source string we are reading from. getLastValidSourceIndex()219 int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); } 220 221 void consumeWhiteSpace(bool& foundNonSpaceTab); 222 bool consumeComment(); 223 void consumeWhitespaceComment(bool& foundNonSpaceTab); 224 bool scanVersion(int& version, EProfile& profile, bool& notFirstToken); 225 226 protected: 227 228 // advance one character advance()229 void advance() 230 { 231 ++currentChar; 232 if (currentChar >= lengths[currentSource]) { 233 ++currentSource; 234 if (currentSource < numSources) { 235 loc[currentSource].string = loc[currentSource - 1].string + 1; 236 loc[currentSource].line = 1; 237 loc[currentSource].column = 0; 238 } 239 while (currentSource < numSources && lengths[currentSource] == 0) { 240 ++currentSource; 241 if (currentSource < numSources) { 242 loc[currentSource].string = loc[currentSource - 1].string + 1; 243 loc[currentSource].line = 1; 244 loc[currentSource].column = 0; 245 } 246 } 247 currentChar = 0; 248 } 249 } 250 251 int numSources; // number of strings in source 252 const unsigned char* const *sources; // array of strings; must be converted to positive values on use, to avoid aliasing with -1 as EndOfInput 253 const size_t *lengths; // length of each string 254 int currentSource; 255 size_t currentChar; 256 257 // This is for reporting what string/line an error occurred on, and can be overridden by #line. 258 // It remembers the last state of each source string as it is left for the next one, so unget() 259 // can restore that state. 260 TSourceLoc* loc; // an array 261 262 int stringBias; // the first string that is the user's string number 0 263 int finale; // number of internal strings after user's last string 264 265 TSourceLoc logicalSourceLoc; 266 bool singleLogical; // treats the strings as a single logical string. 267 // locations will be reported from the first string. 268 269 // Set to true once peek() returns EndOfFile, so that we won't roll back 270 // once we've reached EndOfFile. 271 bool endOfFileReached; 272 }; 273 274 } // end namespace glslang 275 276 #endif // _GLSLANG_SCAN_INCLUDED_ 277