Scan.h 9.5 KB

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