glslang: Fix over 100 warnings from MSVC warning level 4.
[platform/upstream/glslang.git] / glslang / MachineIndependent / Scan.cpp
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
37 //
38 // GLSL scanning, leveraging the scanning done by the preprocessor.
39 //
40
41 #include <string.h>
42
43 #include "../Include/Types.h"
44 #include "SymbolTable.h"
45 #include "ParseHelper.h"
46 #include "glslang_tab.cpp.h"
47 #include "ScanContext.h"
48 #include "Scan.h"
49
50 // preprocessor includes
51 #include "preprocessor/PpContext.h"
52 #include "preprocessor/PpTokens.h"
53
54 namespace glslang {
55     
56 // read past any white space
57 void TInputScanner::consumeWhiteSpace(bool& foundNonSpaceTab)
58 {
59     int c = peek();  // don't accidentally consume anything other than whitespace
60     while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
61         if (c == '\r' || c == '\n')
62             foundNonSpaceTab = true;
63         get();
64         c = peek();
65     }
66 }
67
68 // return true if a comment was actually consumed
69 bool TInputScanner::consumeComment()
70 {
71     if (peek() != '/')
72         return false;
73
74     get();  // consume the '/'
75     int c = peek();
76     if (c == '/') {
77
78         // a '//' style comment
79         get();  // consume the second '/'
80         c = get();
81         do {
82             while (c > 0 && c != '\\' && c != '\r' && c != '\n')
83                 c = get();
84
85             if (c <= 0 || c == '\r' || c == '\n') {
86                 while (c == '\r' || c == '\n')
87                     c = get();
88
89                 // we reached the end of the comment
90                 break;
91             } else {
92                 // it's a '\', so we need to keep going, after skipping what's escaped
93
94                 // read the skipped character
95                 c = get();
96
97                 // if it's a two-character newline, skip both characters
98                 if (c == '\r' && peek() == '\n')
99                     get();
100                 c = get();
101             }
102         } while (true);
103
104         // put back the last non-comment character
105         if (c > 0)
106             unget();
107
108         return true;
109     } else if (c == '*') {
110
111         // a '/*' style comment
112         get();  // consume the '*'
113         c = get();
114         do {
115             while (c > 0 && c != '*')
116                 c = get();
117             if (c == '*') {
118                 c = get();
119                 if (c == '/')
120                     break;  // end of comment
121                 // not end of comment
122             } else // end of input
123                 break;
124         } while (true);
125
126         return true;
127     } else {
128         // it's not a comment, put the '/' back
129         unget();
130
131         return false;
132     }
133 }
134
135 // skip whitespace, then skip a comment, rinse, repeat
136 void TInputScanner::consumeWhitespaceComment(bool& foundNonSpaceTab)
137 {
138     do {
139         consumeWhiteSpace(foundNonSpaceTab);
140  
141         // if not starting a comment now, then done
142         int c = peek();
143         if (c != '/' || c < 0)
144             return;
145
146         // skip potential comment 
147         foundNonSpaceTab = true;
148         if (! consumeComment())
149             return;
150
151     } while (true);
152 }
153
154 // Returns true if there was non-white space (e.g., a comment, newline) before the #version
155 // or no #version was found; otherwise, returns false.  There is no error case, it always
156 // succeeds, but will leave version == 0 if no #version was found.
157 //
158 // Sets versionNotFirstToken based on whether tokens (beyond white space and comments)
159 // appeared before the #version.
160 //
161 // N.B. does not attempt to leave input in any particular known state.  The assumption
162 // is that scanning will start anew, following the rules for the chosen version/profile,
163 // and with a corresponding parsing context.
164 //
165 bool TInputScanner::scanVersion(int& version, EProfile& profile, bool& notFirstToken)
166 {
167     // This function doesn't have to get all the semantics correct,
168     // just find the #version if there is a correct one present.
169     // The preprocessor will have the responsibility of getting all the semantics right.
170
171     bool versionNotFirst = false;  // means not first WRT comments and white space, nothing more
172     notFirstToken = false;         // means not first WRT to real tokens
173     version = 0;  // means not found
174     profile = ENoProfile;
175
176     bool foundNonSpaceTab = false;
177     bool lookingInMiddle = false;
178     int c;
179     do {
180         if (lookingInMiddle) {
181             notFirstToken = true;
182             // make forward progress by finishing off the current line plus extra new lines
183             if (peek() == '\n' || peek() == '\r') {
184                 while (peek() == '\n' || peek() == '\r')
185                     get();
186             } else
187                 do {
188                     c = get();
189                 } while (c > 0 && c != '\n' && c != '\r');
190                 while (peek() == '\n' || peek() == '\r')
191                     get();
192                 if (peek() < 0)
193                     return true;
194         }
195         lookingInMiddle = true;
196
197         // Nominal start, skipping the desktop allowed comments and white space, but tracking if 
198         // something else was found for ES:
199         consumeWhitespaceComment(foundNonSpaceTab);
200         if (foundNonSpaceTab) 
201             versionNotFirst = true;
202
203         // "#"
204         if (get() != '#') {
205             versionNotFirst = true;
206             continue;
207         }
208
209         // whitespace
210         do {
211             c = get();
212         } while (c == ' ' || c == '\t');
213
214         // "version"
215         if (    c != 'v' ||
216             get() != 'e' ||
217             get() != 'r' ||
218             get() != 's' ||
219             get() != 'i' ||
220             get() != 'o' ||
221             get() != 'n') {
222             versionNotFirst = true;
223             continue;
224         }
225
226         // whitespace
227         do {
228             c = get();
229         } while (c == ' ' || c == '\t');
230
231         // version number
232         while (c >= '0' && c <= '9') {
233             version = 10 * version + (c - '0');
234             c = get();
235         }
236         if (version == 0) {
237             versionNotFirst = true;
238             continue;
239         }
240
241         // whitespace
242         while (c == ' ' || c == '\t')
243             c = get();
244
245         // profile
246         const int maxProfileLength = 13;  // not including any 0
247         char profileString[maxProfileLength];
248         int profileLength;
249         for (profileLength = 0; profileLength < maxProfileLength; ++profileLength) {
250             if (c < 0 || c == ' ' || c == '\t' || c == '\n' || c == '\r')
251                 break;
252             profileString[profileLength] = (char)c;
253             c = get();
254         }
255         if (c > 0 && c != ' ' && c != '\t' && c != '\n' && c != '\r') {
256             versionNotFirst = true;
257             continue;
258         }
259
260         if (profileLength == 2 && strncmp(profileString, "es", profileLength) == 0)
261             profile = EEsProfile;
262         else if (profileLength == 4 && strncmp(profileString, "core", profileLength) == 0)
263             profile = ECoreProfile;
264         else if (profileLength == 13 && strncmp(profileString, "compatibility", profileLength) == 0)
265             profile = ECompatibilityProfile;
266
267         return versionNotFirst;
268     } while (true);
269 }
270
271 // Fill this in when doing glslang-level scanning, to hand back to the parser.
272 class TParserToken {
273 public:
274     explicit TParserToken(YYSTYPE& b) : sType(b) { }
275
276     YYSTYPE& sType;
277 protected:
278     TParserToken(TParserToken&);
279     TParserToken& operator=(TParserToken&);
280 };
281
282 } // end namespace glslang
283
284 // This is the function the glslang parser (i.e., bison) calls to get its next token
285 int yylex(YYSTYPE* glslangTokenDesc, glslang::TParseContext& parseContext)
286 {
287     glslang::TParserToken token(*glslangTokenDesc);
288
289     return parseContext.getScanContext()->tokenize(parseContext.getPpContext(), token);
290 }
291
292 namespace {
293
294 // A single global usable by all threads, by all versions, by all languages.
295 // After a single process-level initialization, this is read only and thread safe
296 std::map<std::string, int>* KeywordMap = 0;
297 std::set<std::string>* ReservedSet = 0;
298
299 };
300
301 namespace glslang {
302
303 void TScanContext::fillInKeywordMap()
304 {
305     if (KeywordMap != 0) {
306         // this is really an error, as this should called only once per process
307         // but, the only risk is if two threads called simultaneously
308         return;
309     }
310     KeywordMap = new std::map<std::string, int>;
311
312     (*KeywordMap)["const"] =                   CONST;
313     (*KeywordMap)["uniform"] =                 UNIFORM;
314     (*KeywordMap)["in"] =                      IN;
315     (*KeywordMap)["out"] =                     OUT;
316     (*KeywordMap)["inout"] =                   INOUT;
317     (*KeywordMap)["struct"] =                  STRUCT;
318     (*KeywordMap)["break"] =                   BREAK;
319     (*KeywordMap)["continue"] =                CONTINUE;
320     (*KeywordMap)["do"] =                      DO;
321     (*KeywordMap)["for"] =                     FOR;
322     (*KeywordMap)["while"] =                   WHILE;
323     (*KeywordMap)["switch"] =                  SWITCH;
324     (*KeywordMap)["case"] =                    CASE;
325     (*KeywordMap)["default"] =                 DEFAULT;
326     (*KeywordMap)["if"] =                      IF;
327     (*KeywordMap)["else"] =                    ELSE;
328     (*KeywordMap)["discard"] =                 DISCARD;
329     (*KeywordMap)["return"] =                  RETURN;
330     (*KeywordMap)["void"] =                    VOID;
331     (*KeywordMap)["bool"] =                    BOOL;
332     (*KeywordMap)["float"] =                   FLOAT;
333     (*KeywordMap)["int"] =                     INT;
334     (*KeywordMap)["bvec2"] =                   BVEC2;
335     (*KeywordMap)["bvec3"] =                   BVEC3;
336     (*KeywordMap)["bvec4"] =                   BVEC4;
337     (*KeywordMap)["vec2"] =                    VEC2;
338     (*KeywordMap)["vec3"] =                    VEC3;
339     (*KeywordMap)["vec4"] =                    VEC4;
340     (*KeywordMap)["ivec2"] =                   IVEC2;
341     (*KeywordMap)["ivec3"] =                   IVEC3;
342     (*KeywordMap)["ivec4"] =                   IVEC4;
343     (*KeywordMap)["mat2"] =                    MAT2;
344     (*KeywordMap)["mat3"] =                    MAT3;
345     (*KeywordMap)["mat4"] =                    MAT4;
346     (*KeywordMap)["sampler2D"] =               SAMPLER2D;
347     (*KeywordMap)["samplerCube"] =             SAMPLERCUBE;
348     (*KeywordMap)["true"] =                    BOOLCONSTANT;
349     (*KeywordMap)["false"] =                   BOOLCONSTANT;
350     (*KeywordMap)["attribute"] =               ATTRIBUTE;
351     (*KeywordMap)["varying"] =                 VARYING;
352     (*KeywordMap)["buffer"] =                  BUFFER;
353     (*KeywordMap)["coherent"] =                COHERENT;
354     (*KeywordMap)["restrict"] =                RESTRICT;
355     (*KeywordMap)["readonly"] =                READONLY;
356     (*KeywordMap)["writeonly"] =               WRITEONLY;
357     (*KeywordMap)["atomic_uint"] =             ATOMIC_UINT;
358     (*KeywordMap)["volatile"] =                VOLATILE;
359     (*KeywordMap)["layout"] =                  LAYOUT;
360     (*KeywordMap)["shared"] =                  SHARED;
361     (*KeywordMap)["patch"] =                   PATCH;
362     (*KeywordMap)["sample"] =                  SAMPLE;
363     (*KeywordMap)["subroutine"] =              SUBROUTINE;
364     (*KeywordMap)["highp"] =                   HIGH_PRECISION;
365     (*KeywordMap)["mediump"] =                 MEDIUM_PRECISION;
366     (*KeywordMap)["lowp"] =                    LOW_PRECISION;
367     (*KeywordMap)["precision"] =               PRECISION;
368     (*KeywordMap)["mat2x2"] =                  MAT2X2;
369     (*KeywordMap)["mat2x3"] =                  MAT2X3;
370     (*KeywordMap)["mat2x4"] =                  MAT2X4;
371     (*KeywordMap)["mat3x2"] =                  MAT3X2;
372     (*KeywordMap)["mat3x3"] =                  MAT3X3;
373     (*KeywordMap)["mat3x4"] =                  MAT3X4;
374     (*KeywordMap)["mat4x2"] =                  MAT4X2;
375     (*KeywordMap)["mat4x3"] =                  MAT4X3;
376     (*KeywordMap)["mat4x4"] =                  MAT4X4;
377     (*KeywordMap)["dmat2"] =                   DMAT2;
378     (*KeywordMap)["dmat3"] =                   DMAT3;
379     (*KeywordMap)["dmat4"] =                   DMAT4;
380     (*KeywordMap)["dmat2x2"] =                 DMAT2X2;
381     (*KeywordMap)["dmat2x3"] =                 DMAT2X3;
382     (*KeywordMap)["dmat2x4"] =                 DMAT2X4;
383     (*KeywordMap)["dmat3x2"] =                 DMAT3X2;
384     (*KeywordMap)["dmat3x3"] =                 DMAT3X3;
385     (*KeywordMap)["dmat3x4"] =                 DMAT3X4;
386     (*KeywordMap)["dmat4x2"] =                 DMAT4X2;
387     (*KeywordMap)["dmat4x3"] =                 DMAT4X3;
388     (*KeywordMap)["dmat4x4"] =                 DMAT4X4;
389     (*KeywordMap)["image1D"] =                 IMAGE1D;
390     (*KeywordMap)["iimage1D"] =                IIMAGE1D;
391     (*KeywordMap)["uimage1D"] =                UIMAGE1D;
392     (*KeywordMap)["image2D"] =                 IMAGE2D;
393     (*KeywordMap)["iimage2D"] =                IIMAGE2D;
394     (*KeywordMap)["uimage2D"] =                UIMAGE2D;
395     (*KeywordMap)["image3D"] =                 IMAGE3D;
396     (*KeywordMap)["iimage3D"] =                IIMAGE3D;
397     (*KeywordMap)["uimage3D"] =                UIMAGE3D;
398     (*KeywordMap)["image2DRect"] =             IMAGE2DRECT;
399     (*KeywordMap)["iimage2DRect"] =            IIMAGE2DRECT;
400     (*KeywordMap)["uimage2DRect"] =            UIMAGE2DRECT;
401     (*KeywordMap)["imageCube"] =               IMAGECUBE;
402     (*KeywordMap)["iimageCube"] =              IIMAGECUBE;
403     (*KeywordMap)["uimageCube"] =              UIMAGECUBE;
404     (*KeywordMap)["imageBuffer"] =             IMAGEBUFFER;
405     (*KeywordMap)["iimageBuffer"] =            IIMAGEBUFFER;
406     (*KeywordMap)["uimageBuffer"] =            UIMAGEBUFFER;
407     (*KeywordMap)["image1DArray"] =            IMAGE1DARRAY;
408     (*KeywordMap)["iimage1DArray"] =           IIMAGE1DARRAY;
409     (*KeywordMap)["uimage1DArray"] =           UIMAGE1DARRAY;
410     (*KeywordMap)["image2DArray"] =            IMAGE2DARRAY;
411     (*KeywordMap)["iimage2DArray"] =           IIMAGE2DARRAY;
412     (*KeywordMap)["uimage2DArray"] =           UIMAGE2DARRAY;
413     (*KeywordMap)["imageCubeArray"] =          IMAGECUBEARRAY;
414     (*KeywordMap)["iimageCubeArray"] =         IIMAGECUBEARRAY;
415     (*KeywordMap)["uimageCubeArray"] =         UIMAGECUBEARRAY;
416     (*KeywordMap)["image2DMS"] =               IMAGE2DMS;
417     (*KeywordMap)["iimage2DMS"] =              IIMAGE2DMS;
418     (*KeywordMap)["uimage2DMS"] =              UIMAGE2DMS;
419     (*KeywordMap)["image2DMSArray"] =          IMAGE2DMSARRAY;
420     (*KeywordMap)["iimage2DMSArray"] =         IIMAGE2DMSARRAY;
421     (*KeywordMap)["uimage2DMSArray"] =         UIMAGE2DMSARRAY;
422     (*KeywordMap)["double"] =                  DOUBLE;
423     (*KeywordMap)["dvec2"] =                   DVEC2;
424     (*KeywordMap)["dvec3"] =                   DVEC3;
425     (*KeywordMap)["dvec4"] =                   DVEC4;
426     (*KeywordMap)["samplerCubeArray"] =        SAMPLERCUBEARRAY;
427     (*KeywordMap)["samplerCubeArrayShadow"] =  SAMPLERCUBEARRAYSHADOW;
428     (*KeywordMap)["isamplerCubeArray"] =       ISAMPLERCUBEARRAY;
429     (*KeywordMap)["usamplerCubeArray"] =       USAMPLERCUBEARRAY;
430     (*KeywordMap)["sampler1DArrayShadow"] =    SAMPLER1DARRAYSHADOW;
431     (*KeywordMap)["isampler1DArray"] =         ISAMPLER1DARRAY;
432     (*KeywordMap)["usampler1D"] =              USAMPLER1D;
433     (*KeywordMap)["isampler1D"] =              ISAMPLER1D;
434     (*KeywordMap)["usampler1DArray"] =         USAMPLER1DARRAY;
435     (*KeywordMap)["samplerBuffer"] =           SAMPLERBUFFER;
436     (*KeywordMap)["uint"] =                    UINT;
437     (*KeywordMap)["uvec2"] =                   UVEC2;
438     (*KeywordMap)["uvec3"] =                   UVEC3;
439     (*KeywordMap)["uvec4"] =                   UVEC4;
440     (*KeywordMap)["samplerCubeShadow"] =       SAMPLERCUBESHADOW;
441     (*KeywordMap)["sampler2DArray"] =          SAMPLER2DARRAY;
442     (*KeywordMap)["sampler2DArrayShadow"] =    SAMPLER2DARRAYSHADOW;
443     (*KeywordMap)["isampler2D"] =              ISAMPLER2D;
444     (*KeywordMap)["isampler3D"] =              ISAMPLER3D;
445     (*KeywordMap)["isamplerCube"] =            ISAMPLERCUBE;
446     (*KeywordMap)["isampler2DArray"] =         ISAMPLER2DARRAY;
447     (*KeywordMap)["usampler2D"] =              USAMPLER2D;
448     (*KeywordMap)["usampler3D"] =              USAMPLER3D;
449     (*KeywordMap)["usamplerCube"] =            USAMPLERCUBE;
450     (*KeywordMap)["usampler2DArray"] =         USAMPLER2DARRAY;
451     (*KeywordMap)["isampler2DRect"] =          ISAMPLER2DRECT;
452     (*KeywordMap)["usampler2DRect"] =          USAMPLER2DRECT;
453     (*KeywordMap)["isamplerBuffer"] =          ISAMPLERBUFFER;
454     (*KeywordMap)["usamplerBuffer"] =          USAMPLERBUFFER;
455     (*KeywordMap)["sampler2DMS"] =             SAMPLER2DMS;
456     (*KeywordMap)["isampler2DMS"] =            ISAMPLER2DMS;
457     (*KeywordMap)["usampler2DMS"] =            USAMPLER2DMS;
458     (*KeywordMap)["sampler2DMSArray"] =        SAMPLER2DMSARRAY;
459     (*KeywordMap)["isampler2DMSArray"] =       ISAMPLER2DMSARRAY;
460     (*KeywordMap)["usampler2DMSArray"] =       USAMPLER2DMSARRAY;
461     (*KeywordMap)["sampler1D"] =               SAMPLER1D;
462     (*KeywordMap)["sampler1DShadow"] =         SAMPLER1DSHADOW;
463     (*KeywordMap)["sampler3D"] =               SAMPLER3D;
464     (*KeywordMap)["sampler2DShadow"] =         SAMPLER2DSHADOW;
465     (*KeywordMap)["sampler2DRect"] =           SAMPLER2DRECT;
466     (*KeywordMap)["sampler2DRectShadow"] =     SAMPLER2DRECTSHADOW;
467     (*KeywordMap)["sampler1DArray"] =          SAMPLER1DARRAY;
468     (*KeywordMap)["samplerExternalOES"] =      SAMPLEREXTERNALOES; // GL_OES_EGL_image_external
469     (*KeywordMap)["noperspective"] =           NOPERSPECTIVE;
470     (*KeywordMap)["smooth"] =                  SMOOTH;
471     (*KeywordMap)["flat"] =                    FLAT;
472     (*KeywordMap)["centroid"] =                CENTROID;
473     (*KeywordMap)["precise"] =                 PRECISE;
474     (*KeywordMap)["invariant"] =               INVARIANT;
475     (*KeywordMap)["packed"] =                  PACKED;
476     (*KeywordMap)["resource"] =                RESOURCE;
477     (*KeywordMap)["superp"] =                  SUPERP;
478
479     ReservedSet = new std::set<std::string>;
480     
481     ReservedSet->insert("common");
482     ReservedSet->insert("partition");
483     ReservedSet->insert("active");
484     ReservedSet->insert("asm");
485     ReservedSet->insert("class");
486     ReservedSet->insert("union");
487     ReservedSet->insert("enum");
488     ReservedSet->insert("typedef");
489     ReservedSet->insert("template");
490     ReservedSet->insert("this");
491     ReservedSet->insert("goto");
492     ReservedSet->insert("inline");
493     ReservedSet->insert("noinline");
494     ReservedSet->insert("public");
495     ReservedSet->insert("static");
496     ReservedSet->insert("extern");
497     ReservedSet->insert("external");
498     ReservedSet->insert("interface");
499     ReservedSet->insert("long");
500     ReservedSet->insert("short");
501     ReservedSet->insert("half");
502     ReservedSet->insert("fixed");
503     ReservedSet->insert("unsigned");
504     ReservedSet->insert("input");
505     ReservedSet->insert("output");
506     ReservedSet->insert("hvec2");
507     ReservedSet->insert("hvec3");
508     ReservedSet->insert("hvec4");
509     ReservedSet->insert("fvec2");
510     ReservedSet->insert("fvec3");
511     ReservedSet->insert("fvec4");
512     ReservedSet->insert("sampler3DRect");
513     ReservedSet->insert("filter");
514     ReservedSet->insert("sizeof");
515     ReservedSet->insert("cast");
516     ReservedSet->insert("namespace");
517     ReservedSet->insert("using");
518 }
519
520 void TScanContext::deleteKeywordMap()
521 {
522     delete KeywordMap;
523     KeywordMap = 0;
524     delete ReservedSet;
525     ReservedSet = 0;
526 }
527
528 int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
529 {
530     do {
531         parserToken = &token;
532         TPpToken ppToken;
533         tokenText = pp->tokenize(&ppToken);
534         if (tokenText == 0)
535             return 0;
536
537         loc = ppToken.loc;
538         parserToken->sType.lex.loc = loc;
539         switch (ppToken.token) {
540         case ';':  afterType = false;   return SEMICOLON;
541         case ',':  afterType = false;   return COMMA;
542         case ':':                       return COLON;
543         case '=':  afterType = false;   return EQUAL;
544         case '(':  afterType = false;   return LEFT_PAREN;
545         case ')':  afterType = false;   return RIGHT_PAREN;
546         case '.':  field = true;        return DOT;
547         case '!':                       return BANG;
548         case '-':                       return DASH;
549         case '~':                       return TILDE;
550         case '+':                       return PLUS;
551         case '*':                       return STAR;
552         case '/':                       return SLASH;
553         case '%':                       return PERCENT;
554         case '<':                       return LEFT_ANGLE;
555         case '>':                       return RIGHT_ANGLE;
556         case '|':                       return VERTICAL_BAR;
557         case '^':                       return CARET;
558         case '&':                       return AMPERSAND;
559         case '?':                       return QUESTION;
560         case '[':                       return LEFT_BRACKET;
561         case ']':                       return RIGHT_BRACKET;
562         case '{':                       return LEFT_BRACE;
563         case '}':                       return RIGHT_BRACE;
564         case '\\':
565             parseContext.error(loc, "illegal use of escape character", "\\", "");
566             break;
567
568         case CPP_AND_OP:                return AND_OP;
569         case CPP_SUB_ASSIGN:            return SUB_ASSIGN;
570         case CPP_MOD_ASSIGN:            return MOD_ASSIGN;
571         case CPP_ADD_ASSIGN:            return ADD_ASSIGN;
572         case CPP_DIV_ASSIGN:            return DIV_ASSIGN;
573         case CPP_MUL_ASSIGN:            return MUL_ASSIGN;
574         case CPP_EQ_OP:                 return EQ_OP;
575         case CPP_XOR_OP:                return XOR_OP;
576         case CPP_GE_OP:                 return GE_OP;
577         case CPP_RIGHT_OP:              return RIGHT_OP;
578         case CPP_LE_OP:                 return LE_OP;
579         case CPP_LEFT_OP:               return LEFT_OP;
580         case CPP_DEC_OP:                return DEC_OP;
581         case CPP_NE_OP:                 return NE_OP;
582         case CPP_OR_OP:                 return OR_OP;
583         case CPP_INC_OP:                return INC_OP;
584         case CPP_RIGHT_ASSIGN:          return RIGHT_ASSIGN;
585         case CPP_LEFT_ASSIGN:           return LEFT_ASSIGN;
586         case CPP_AND_ASSIGN:            return AND_ASSIGN;
587         case CPP_OR_ASSIGN:             return OR_ASSIGN;
588         case CPP_XOR_ASSIGN:            return XOR_ASSIGN;
589                                    
590         case CPP_INTCONSTANT:           parserToken->sType.lex.i = ppToken.ival;       return INTCONSTANT;
591         case CPP_UINTCONSTANT:          parserToken->sType.lex.i = ppToken.ival;       return UINTCONSTANT;
592         case CPP_FLOATCONSTANT:         parserToken->sType.lex.d = ppToken.dval;       return FLOATCONSTANT;
593         case CPP_DOUBLECONSTANT:        parserToken->sType.lex.d = ppToken.dval;       return DOUBLECONSTANT;
594         case CPP_IDENTIFIER:            return tokenizeIdentifier();
595
596         case EOF:                       return 0;
597                                    
598         default:
599             char buf[2];
600             buf[0] = (char)ppToken.token;
601             buf[1] = 0;
602             parseContext.error(loc, "unexpected token", buf, "");
603             break;
604         }
605     } while (true);
606 }
607
608 int TScanContext::tokenizeIdentifier()
609 {
610     if (ReservedSet->find(tokenText) != ReservedSet->end())
611         return reservedWord();
612
613     std::map<std::string, int>::const_iterator it = KeywordMap->find(tokenText);
614     if (it == KeywordMap->end()) {
615         // Should have an identifier of some sort
616         return identifierOrType();
617     }
618     keyword = it->second;
619     field = false;
620
621     switch (keyword) {
622     case CONST:
623     case UNIFORM:
624     case IN:
625     case OUT:
626     case INOUT:
627     case STRUCT:
628     case BREAK:
629     case CONTINUE:
630     case DO:
631     case FOR:
632     case WHILE:
633     case IF:
634     case ELSE:
635     case DISCARD:
636     case RETURN:
637     case CASE:
638         return keyword;
639
640     case SWITCH:
641     case DEFAULT:
642         if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
643             (parseContext.profile != EEsProfile && parseContext.version < 130))
644             reservedWord();
645         return keyword;
646
647     case VOID:
648     case BOOL:
649     case FLOAT:
650     case INT:
651     case BVEC2:
652     case BVEC3:
653     case BVEC4:
654     case VEC2:
655     case VEC3:
656     case VEC4:
657     case IVEC2:
658     case IVEC3:
659     case IVEC4:
660     case MAT2:
661     case MAT3:
662     case MAT4:
663     case SAMPLER2D:
664     case SAMPLERCUBE:
665         afterType = true;
666         return keyword;
667
668     case BOOLCONSTANT:
669         if (strcmp("true", tokenText) == 0)
670             parserToken->sType.lex.b = true;
671         else
672             parserToken->sType.lex.b = false;
673         return keyword;
674
675     case ATTRIBUTE:
676     case VARYING:
677         if (parseContext.profile == EEsProfile && parseContext.version >= 300)
678             reservedWord();
679         return keyword;
680
681     case BUFFER:
682         if ((parseContext.profile == EEsProfile && parseContext.version < 310) || 
683             (parseContext.profile != EEsProfile && parseContext.version < 430))
684             return identifierOrType();
685         return keyword;
686
687     case ATOMIC_UINT:
688         if (parseContext.profile == EEsProfile && parseContext.version >= 310 ||
689             parseContext.extensionsTurnedOn(1, &GL_ARB_shader_atomic_counters))
690             return keyword;
691         return es30ReservedFromGLSL(420);
692
693     case COHERENT:
694     case RESTRICT:
695     case READONLY:
696     case WRITEONLY:
697         if (parseContext.profile == EEsProfile && parseContext.version >= 310)
698             return keyword;
699         return es30ReservedFromGLSL(parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store) ? 130 : 420);
700
701     case VOLATILE:
702         if (parseContext.profile == EEsProfile && parseContext.version >= 310)
703             return keyword;
704         if (! parseContext.symbolTable.atBuiltInLevel() && (parseContext.profile == EEsProfile || (parseContext.version < 420 && ! parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store))))
705             reservedWord();
706         return keyword;
707
708     case LAYOUT:
709     {
710         const int numLayoutExts = 2;
711         const char* layoutExts[numLayoutExts] = { GL_ARB_shading_language_420pack,
712                                                   GL_ARB_explicit_attrib_location };
713         if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
714             (parseContext.profile != EEsProfile && parseContext.version < 140 &&
715             ! parseContext.extensionsTurnedOn(numLayoutExts, layoutExts)))
716             return identifierOrType();
717         return keyword;
718     }
719     case SHARED:
720         if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
721             (parseContext.profile != EEsProfile && parseContext.version < 140))
722             return identifierOrType();
723         return keyword;
724
725     case PATCH:
726         if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionsTurnedOn(1, &GL_ARB_tessellation_shader))
727             return es30ReservedFromGLSL(150);
728         else
729             return es30ReservedFromGLSL(400);
730
731     case SAMPLE:
732     case SUBROUTINE:
733         return es30ReservedFromGLSL(400);
734
735     case HIGH_PRECISION:
736     case MEDIUM_PRECISION:
737     case LOW_PRECISION:
738     case PRECISION:
739         return precisionKeyword();
740
741     case MAT2X2:
742     case MAT2X3:
743     case MAT2X4:
744     case MAT3X2:
745     case MAT3X3:
746     case MAT3X4:
747     case MAT4X2:
748     case MAT4X3:
749     case MAT4X4:        
750         return matNxM();
751
752     case DMAT2:
753     case DMAT3:
754     case DMAT4:
755     case DMAT2X2:
756     case DMAT2X3:
757     case DMAT2X4:
758     case DMAT3X2:
759     case DMAT3X3:
760     case DMAT3X4:
761     case DMAT4X2:
762     case DMAT4X3:
763     case DMAT4X4:
764         return dMat();
765
766     case IMAGE1D:
767     case IIMAGE1D:
768     case UIMAGE1D:
769     case IMAGE1DARRAY:
770     case IIMAGE1DARRAY:
771     case UIMAGE1DARRAY:
772     case IMAGE2DRECT:
773     case IIMAGE2DRECT:
774     case UIMAGE2DRECT:
775     case IMAGEBUFFER:
776     case IIMAGEBUFFER:
777     case UIMAGEBUFFER:
778         return firstGenerationImage(false);
779
780     case IMAGE2D:
781     case IIMAGE2D:
782     case UIMAGE2D:
783     case IMAGE3D:
784     case IIMAGE3D:
785     case UIMAGE3D:
786     case IMAGECUBE:
787     case IIMAGECUBE:
788     case UIMAGECUBE:
789     case IMAGE2DARRAY:
790     case IIMAGE2DARRAY:
791     case UIMAGE2DARRAY:
792         return firstGenerationImage(true);
793
794     case IMAGECUBEARRAY:
795     case IIMAGECUBEARRAY:
796     case UIMAGECUBEARRAY:        
797     case IMAGE2DMS:
798     case IIMAGE2DMS:
799     case UIMAGE2DMS:
800     case IMAGE2DMSARRAY:
801     case IIMAGE2DMSARRAY:
802     case UIMAGE2DMSARRAY:
803         return secondGenerationImage();
804
805     case DOUBLE:
806     case DVEC2:
807     case DVEC3:
808     case DVEC4:
809         afterType = true;
810         if (parseContext.profile == EEsProfile || parseContext.version < 400)
811             reservedWord();
812         return keyword;
813
814     case SAMPLERCUBEARRAY:
815     case SAMPLERCUBEARRAYSHADOW:
816     case ISAMPLERCUBEARRAY:
817     case USAMPLERCUBEARRAY:
818         afterType = true;
819         if (parseContext.profile == EEsProfile || (parseContext.version < 400 && ! parseContext.extensionsTurnedOn(1, &GL_ARB_texture_cube_map_array)))
820             reservedWord();
821         return keyword;
822
823     case ISAMPLER1D:
824     case ISAMPLER1DARRAY:
825     case SAMPLER1DARRAYSHADOW:
826     case USAMPLER1D:
827     case USAMPLER1DARRAY:
828     case SAMPLERBUFFER:
829         afterType = true;
830         return es30ReservedFromGLSL(130);
831
832     case UINT:
833     case UVEC2:
834     case UVEC3:
835     case UVEC4:
836     case SAMPLERCUBESHADOW:
837     case SAMPLER2DARRAY:
838     case SAMPLER2DARRAYSHADOW:
839     case ISAMPLER2D:
840     case ISAMPLER3D:
841     case ISAMPLERCUBE:
842     case ISAMPLER2DARRAY:
843     case USAMPLER2D:
844     case USAMPLER3D:
845     case USAMPLERCUBE:
846     case USAMPLER2DARRAY:
847         afterType = true;
848         return nonreservedKeyword(300, 130);
849         
850     case ISAMPLER2DRECT:
851     case USAMPLER2DRECT:
852     case ISAMPLERBUFFER:
853     case USAMPLERBUFFER:
854         afterType = true;
855         return es30ReservedFromGLSL(140);
856         
857     case SAMPLER2DMS:
858     case ISAMPLER2DMS:
859     case USAMPLER2DMS:
860         afterType = true;
861         if (parseContext.profile == EEsProfile && parseContext.version >= 310)
862             return keyword;
863         return es30ReservedFromGLSL(150);
864
865     case SAMPLER2DMSARRAY:
866     case ISAMPLER2DMSARRAY:
867     case USAMPLER2DMSARRAY:
868         afterType = true;
869         return es30ReservedFromGLSL(150);
870
871     case SAMPLER1D:
872     case SAMPLER1DSHADOW:
873         afterType = true;
874         if (parseContext.profile == EEsProfile)
875             reservedWord();
876         return keyword;
877
878     case SAMPLER3D:
879         afterType = true;
880         if (parseContext.profile == EEsProfile && parseContext.version < 300) {
881             if (! parseContext.extensionsTurnedOn(1, &GL_OES_texture_3D))
882                 reservedWord();
883         }
884         return keyword;
885
886     case SAMPLER2DSHADOW:
887         afterType = true;
888         if (parseContext.profile == EEsProfile && parseContext.version < 300)
889             reservedWord();
890         return keyword;
891
892     case SAMPLER2DRECT:
893     case SAMPLER2DRECTSHADOW:
894         afterType = true;
895         if (parseContext.profile == EEsProfile)
896             reservedWord();
897         else if (parseContext.version < 140 && ! parseContext.symbolTable.atBuiltInLevel() && ! parseContext.extensionsTurnedOn(1, &GL_ARB_texture_rectangle)) {
898             if (parseContext.messages & EShMsgRelaxedErrors)
899                 parseContext.requireExtensions(loc, 1, &GL_ARB_texture_rectangle, "texture-rectangle sampler keyword");
900             else
901                 reservedWord();
902         }
903         return keyword;
904
905     case SAMPLER1DARRAY:
906         afterType = true;
907         if (parseContext.profile == EEsProfile && parseContext.version == 300)
908             reservedWord();
909         else if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
910                  (parseContext.profile != EEsProfile && parseContext.version < 130))
911             return identifierOrType();
912         return keyword;
913
914     case SAMPLEREXTERNALOES:
915         afterType = true;
916         if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionsTurnedOn(1, &GL_OES_EGL_image_external))
917             return keyword;
918         return identifierOrType();
919
920     case NOPERSPECTIVE:
921         return es30ReservedFromGLSL(130);
922         
923     case SMOOTH:
924         if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
925             (parseContext.profile != EEsProfile && parseContext.version < 130))
926             return identifierOrType();
927         return keyword;
928
929     case FLAT:
930         if (parseContext.profile == EEsProfile && parseContext.version < 300)
931             reservedWord();
932         else if (parseContext.profile != EEsProfile && parseContext.version < 130)
933             return identifierOrType();
934         return keyword;
935
936     case CENTROID:
937         if (parseContext.version < 120)
938             return identifierOrType();
939         return keyword;
940
941     case PRECISE:
942         if (parseContext.profile == EEsProfile && parseContext.version >= 310)
943             reservedWord();
944         else if (parseContext.profile == EEsProfile ||
945             (parseContext.profile != EEsProfile && parseContext.version < 400))
946             return identifierOrType();
947         return keyword;
948
949     case INVARIANT:
950         if (parseContext.profile != EEsProfile && parseContext.version < 120)
951             return identifierOrType();
952         return keyword;
953
954     case PACKED:
955         if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
956             (parseContext.profile != EEsProfile && parseContext.version < 330))
957             return reservedWord();
958         return identifierOrType();
959
960     case RESOURCE:
961     {
962         bool reserved = (parseContext.profile == EEsProfile && parseContext.version >= 300) ||
963                         (parseContext.profile != EEsProfile && parseContext.version >= 420);
964         return identifierOrReserved(reserved);
965     }
966     case SUPERP:
967     {
968         bool reserved = parseContext.profile == EEsProfile || parseContext.version >= 130;
969         return identifierOrReserved(reserved);
970     }
971     
972     default:
973         parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
974         return 0;
975     }
976 }
977
978 int TScanContext::identifierOrType()
979 {
980     parserToken->sType.lex.string = NewPoolTString(tokenText);
981     if (field) {
982         field = false;
983  
984         return FIELD_SELECTION;
985     }
986
987     parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
988     if (afterType == false && parserToken->sType.lex.symbol) {
989         if (const TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
990             if (variable->isUserType()) {
991                 afterType = true;
992
993                 return TYPE_NAME;
994             }
995         }
996     }
997
998     return IDENTIFIER;
999 }
1000
1001 // Give an error for use of a reserved symbol.
1002 // However, allow built-in declarations to use reserved words, to allow
1003 // extension support before the extension is enabled.
1004 int TScanContext::reservedWord()
1005 {
1006     if (! parseContext.symbolTable.atBuiltInLevel())
1007         parseContext.error(loc, "Reserved word.", tokenText, "", "");
1008
1009     return 0;
1010 }
1011
1012 int TScanContext::identifierOrReserved(bool reserved)
1013 {
1014     if (reserved) {
1015         reservedWord();
1016
1017         return 0;
1018     }
1019
1020     if (parseContext.forwardCompatible)
1021         parseContext.warn(loc, "using future reserved keyword", tokenText, "");
1022
1023     return identifierOrType();
1024 }
1025
1026 // For keywords that suddenly showed up on non-ES (not previously reserved)
1027 // but then got reserved by ES 3.0.
1028 int TScanContext::es30ReservedFromGLSL(int version)
1029 {
1030     if (parseContext.symbolTable.atBuiltInLevel())
1031         return keyword;
1032
1033     if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
1034         (parseContext.profile != EEsProfile && parseContext.version < version)) {
1035             if (parseContext.forwardCompatible)
1036                 parseContext.warn(loc, "future reserved word in ES 300 and keyword in GLSL", tokenText, "");
1037
1038             return identifierOrType();
1039     } else if (parseContext.profile == EEsProfile && parseContext.version >= 300)
1040         reservedWord();
1041
1042     return keyword;
1043 }
1044
1045 // For a keyword that was never reserved, until it suddenly
1046 // showed up, both in an es version and a non-ES version.
1047 int TScanContext::nonreservedKeyword(int esVersion, int nonEsVersion)
1048 {
1049     if ((parseContext.profile == EEsProfile && parseContext.version < esVersion) ||
1050         (parseContext.profile != EEsProfile && parseContext.version < nonEsVersion)) {
1051         if (parseContext.forwardCompatible)
1052             parseContext.warn(loc, "using future keyword", tokenText, "");
1053
1054         return identifierOrType();
1055     }
1056
1057     return keyword;
1058 }
1059
1060 int TScanContext::precisionKeyword()
1061 {
1062     if (parseContext.profile == EEsProfile || parseContext.version >= 130)
1063         return keyword;
1064
1065     if (parseContext.forwardCompatible)
1066         parseContext.warn(loc, "using ES precision qualifier keyword", tokenText, "");
1067
1068     return identifierOrType();
1069 }
1070
1071 int TScanContext::matNxM()
1072 {
1073     afterType = true;
1074
1075     if (parseContext.version > 110)
1076         return keyword;
1077
1078     if (parseContext.forwardCompatible)
1079         parseContext.warn(loc, "using future non-square matrix type keyword", tokenText, "");
1080
1081     return identifierOrType();
1082 }
1083
1084 int TScanContext::dMat()
1085 {
1086     afterType = true;
1087
1088     if (parseContext.profile == EEsProfile && parseContext.version >= 300) {
1089         reservedWord();
1090
1091         return keyword;
1092     }
1093
1094     if (parseContext.profile != EEsProfile && parseContext.version >= 400)
1095         return keyword;
1096
1097     if (parseContext.forwardCompatible)
1098         parseContext.warn(loc, "using future type keyword", tokenText, "");
1099
1100     return identifierOrType();
1101 }
1102
1103 int TScanContext::firstGenerationImage(bool inEs310)
1104 {
1105     afterType = true;
1106
1107     if (parseContext.symbolTable.atBuiltInLevel() || 
1108         (parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store))) ||                                                     
1109         (inEs310 && parseContext.profile == EEsProfile && parseContext.version >= 310))
1110         return keyword;
1111
1112     if ((parseContext.profile == EEsProfile && parseContext.version >= 300) ||
1113         (parseContext.profile != EEsProfile && parseContext.version >= 130)) {
1114         reservedWord();
1115
1116         return keyword;
1117     }
1118
1119     if (parseContext.forwardCompatible)
1120         parseContext.warn(loc, "using future type keyword", tokenText, "");
1121
1122     return identifierOrType();
1123 }
1124
1125 int TScanContext::secondGenerationImage()
1126 {
1127     afterType = true;
1128
1129     if (parseContext.profile == EEsProfile && parseContext.version >= 310) {
1130         reservedWord();
1131         return keyword;
1132     }
1133
1134     if (parseContext.symbolTable.atBuiltInLevel() || parseContext.profile != EEsProfile && (parseContext.version >= 420 || parseContext.extensionsTurnedOn(1, &GL_ARB_shader_image_load_store)))
1135         return keyword;
1136
1137     if (parseContext.forwardCompatible)
1138         parseContext.warn(loc, "using future type keyword", tokenText, "");
1139
1140     return identifierOrType();
1141 }
1142
1143 } // end namespace glslang