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