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 const TSourceLoc& getSourceLoc() const 208 { 209 if (singleLogical) { 210 return logicalSourceLoc; 211 } else { 212 return loc[std::max(0, std::min(currentSource, numSources - finale - 1))]; 213 } 214 } 215 // Returns the index (starting from 0) of the most recent valid source string we are reading from. 216 int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); } 217 218 void consumeWhiteSpace(bool& foundNonSpaceTab); 219 bool consumeComment(); 220 void consumeWhitespaceComment(bool& foundNonSpaceTab); 221 bool scanVersion(int& version, EProfile& profile, bool& notFirstToken); 222 223 protected: 224 225 // advance one character 226 void advance() 227 { 228 ++currentChar; 229 if (currentChar >= lengths[currentSource]) { 230 ++currentSource; 231 if (currentSource < numSources) { 232 loc[currentSource].string = loc[currentSource - 1].string + 1; 233 loc[currentSource].line = 1; 234 loc[currentSource].column = 0; 235 } 236 while (currentSource < numSources && lengths[currentSource] == 0) { 237 ++currentSource; 238 if (currentSource < numSources) { 239 loc[currentSource].string = loc[currentSource - 1].string + 1; 240 loc[currentSource].line = 1; 241 loc[currentSource].column = 0; 242 } 243 } 244 currentChar = 0; 245 } 246 } 247 248 int numSources; // number of strings in source 249 const unsigned char* const *sources; // array of strings; must be converted to positive values on use, to avoid aliasing with -1 as EndOfInput 250 const size_t *lengths; // length of each string 251 int currentSource; 252 size_t currentChar; 253 254 // This is for reporting what string/line an error occurred on, and can be overridden by #line. 255 // It remembers the last state of each source string as it is left for the next one, so unget() 256 // can restore that state. 257 TSourceLoc* loc; // an array 258 259 int stringBias; // the first string that is the user's string number 0 260 int finale; // number of internal strings after user's last string 261 262 TSourceLoc logicalSourceLoc; 263 bool singleLogical; // treats the strings as a single logical string. 264 // locations will be reported from the first string. 265 266 // Set to true once peek() returns EndOfFile, so that we won't roll back 267 // once we've reached EndOfFile. 268 bool endOfFileReached; 269 }; 270 271 } // end namespace glslang 272 273 #endif // _GLSLANG_SCAN_INCLUDED_ 274