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