Home | History | Annotate | Download | only in preprocessor
      1 //
      2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
      3 // Copyright (C) 2013 LunarG, Inc.
      4 // All rights reserved.
      5 //
      6 // Redistribution and use in source and binary forms, with or without
      7 // modification, are permitted provided that the following conditions
      8 // are met:
      9 //
     10 //    Redistributions of source code must retain the above copyright
     11 //    notice, this list of conditions and the following disclaimer.
     12 //
     13 //    Redistributions in binary form must reproduce the above
     14 //    copyright notice, this list of conditions and the following
     15 //    disclaimer in the documentation and/or other materials provided
     16 //    with the distribution.
     17 //
     18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
     19 //    contributors may be used to endorse or promote products derived
     20 //    from this software without specific prior written permission.
     21 //
     22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     33 // POSSIBILITY OF SUCH DAMAGE.
     34 //
     35 /****************************************************************************\
     36 Copyright (c) 2002, NVIDIA Corporation.
     37 
     38 NVIDIA Corporation("NVIDIA") supplies this software to you in
     39 consideration of your agreement to the following terms, and your use,
     40 installation, modification or redistribution of this NVIDIA software
     41 constitutes acceptance of these terms.  If you do not agree with these
     42 terms, please do not use, install, modify or redistribute this NVIDIA
     43 software.
     44 
     45 In consideration of your agreement to abide by the following terms, and
     46 subject to these terms, NVIDIA grants you a personal, non-exclusive
     47 license, under NVIDIA's copyrights in this original NVIDIA software (the
     48 "NVIDIA Software"), to use, reproduce, modify and redistribute the
     49 NVIDIA Software, with or without modifications, in source and/or binary
     50 forms; provided that if you redistribute the NVIDIA Software, you must
     51 retain the copyright notice of NVIDIA, this notice and the following
     52 text and disclaimers in all such redistributions of the NVIDIA Software.
     53 Neither the name, trademarks, service marks nor logos of NVIDIA
     54 Corporation may be used to endorse or promote products derived from the
     55 NVIDIA Software without specific prior written permission from NVIDIA.
     56 Except as expressly stated in this notice, no other rights or licenses
     57 express or implied, are granted by NVIDIA herein, including but not
     58 limited to any patent rights that may be infringed by your derivative
     59 works or by other works in which the NVIDIA Software may be
     60 incorporated. No hardware is licensed hereunder.
     61 
     62 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
     63 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
     64 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
     65 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
     66 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
     67 PRODUCTS.
     68 
     69 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
     70 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
     71 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
     72 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
     73 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
     74 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
     75 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
     76 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     77 \****************************************************************************/
     78 
     79 //
     80 // For recording and playing back the stream of tokens in a macro definition.
     81 //
     82 
     83 #ifndef _CRT_SECURE_NO_WARNINGS
     84 #define _CRT_SECURE_NO_WARNINGS
     85 #endif
     86 #if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/)
     87 #define snprintf sprintf_s
     88 #endif
     89 
     90 #include <cassert>
     91 #include <cstdlib>
     92 #include <cstring>
     93 #include <cctype>
     94 
     95 #include "PpContext.h"
     96 #include "PpTokens.h"
     97 
     98 namespace glslang {
     99 
    100 // push onto back of stream
    101 void TPpContext::TokenStream::putSubtoken(char subtoken)
    102 {
    103     data.push_back(static_cast<unsigned char>(subtoken));
    104 }
    105 
    106 // get the next token in stream
    107 int TPpContext::TokenStream::getSubtoken()
    108 {
    109     if (current < data.size())
    110         return data[current++];
    111     else
    112         return EndOfInput;
    113 }
    114 
    115 // back up one position in the stream
    116 void TPpContext::TokenStream::ungetSubtoken()
    117 {
    118     if (current > 0)
    119         --current;
    120 }
    121 
    122 // Add a complete token (including backing string) to the end of a list
    123 // for later playback.
    124 void TPpContext::TokenStream::putToken(int token, TPpToken* ppToken)
    125 {
    126     const char* s;
    127     char* str = NULL;
    128 
    129     assert((token & ~0xff) == 0);
    130     putSubtoken(static_cast<char>(token));
    131 
    132     switch (token) {
    133     case PpAtomIdentifier:
    134     case PpAtomConstString:
    135         s = ppToken->name;
    136         while (*s)
    137             putSubtoken(*s++);
    138         putSubtoken(0);
    139         break;
    140     case PpAtomConstInt:
    141     case PpAtomConstUint:
    142     case PpAtomConstInt64:
    143     case PpAtomConstUint64:
    144 #ifdef AMD_EXTENSIONS
    145     case PpAtomConstInt16:
    146     case PpAtomConstUint16:
    147 #endif
    148     case PpAtomConstFloat:
    149     case PpAtomConstDouble:
    150 #ifdef AMD_EXTENSIONS
    151     case PpAtomConstFloat16:
    152 #endif
    153         str = ppToken->name;
    154         while (*str) {
    155             putSubtoken(*str);
    156             str++;
    157         }
    158         putSubtoken(0);
    159         break;
    160     default:
    161         break;
    162     }
    163 }
    164 
    165 // Read the next token from a token stream.
    166 // (Not the source stream, but a stream used to hold a tokenized macro).
    167 int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken)
    168 {
    169     int len;
    170     int ch;
    171 
    172     int subtoken = getSubtoken();
    173     ppToken->loc = parseContext.getCurrentLoc();
    174     switch (subtoken) {
    175     case '#':
    176         // Check for ##, unless the current # is the last character
    177         if (current < data.size()) {
    178             if (getSubtoken() == '#') {
    179                 parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
    180                 parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
    181                 subtoken = PpAtomPaste;
    182             } else
    183                 ungetSubtoken();
    184         }
    185         break;
    186     case PpAtomConstString:
    187     case PpAtomIdentifier:
    188     case PpAtomConstFloat:
    189     case PpAtomConstDouble:
    190 #ifdef AMD_EXTENSIONS
    191     case PpAtomConstFloat16:
    192 #endif
    193     case PpAtomConstInt:
    194     case PpAtomConstUint:
    195     case PpAtomConstInt64:
    196     case PpAtomConstUint64:
    197 #ifdef AMD_EXTENSIONS
    198     case PpAtomConstInt16:
    199     case PpAtomConstUint16:
    200 #endif
    201         len = 0;
    202         ch = getSubtoken();
    203         while (ch != 0 && ch != EndOfInput) {
    204             if (len < MaxTokenLength) {
    205                 ppToken->name[len] = (char)ch;
    206                 len++;
    207                 ch = getSubtoken();
    208             } else {
    209                 parseContext.error(ppToken->loc, "token too long", "", "");
    210                 break;
    211             }
    212         }
    213         ppToken->name[len] = 0;
    214 
    215         switch (subtoken) {
    216         case PpAtomIdentifier:
    217             break;
    218         case PpAtomConstString:
    219             break;
    220         case PpAtomConstFloat:
    221         case PpAtomConstDouble:
    222 #ifdef AMD_EXTENSIONS
    223         case PpAtomConstFloat16:
    224 #endif
    225             ppToken->dval = atof(ppToken->name);
    226             break;
    227         case PpAtomConstInt:
    228 #ifdef AMD_EXTENSIONS
    229         case PpAtomConstInt16:
    230 #endif
    231             if (len > 0 && ppToken->name[0] == '0') {
    232                 if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
    233                     ppToken->ival = (int)strtol(ppToken->name, 0, 16);
    234                 else
    235                     ppToken->ival = (int)strtol(ppToken->name, 0, 8);
    236             } else
    237                 ppToken->ival = atoi(ppToken->name);
    238             break;
    239         case PpAtomConstUint:
    240 #ifdef AMD_EXTENSIONS
    241         case PpAtomConstUint16:
    242 #endif
    243             if (len > 0 && ppToken->name[0] == '0') {
    244                 if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
    245                     ppToken->ival = (int)strtoul(ppToken->name, 0, 16);
    246                 else
    247                     ppToken->ival = (int)strtoul(ppToken->name, 0, 8);
    248             } else
    249                 ppToken->ival = (int)strtoul(ppToken->name, 0, 10);
    250             break;
    251         case PpAtomConstInt64:
    252             if (len > 0 && ppToken->name[0] == '0') {
    253                 if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
    254                     ppToken->i64val = strtoll(ppToken->name, nullptr, 16);
    255                 else
    256                     ppToken->i64val = strtoll(ppToken->name, nullptr, 8);
    257             } else
    258                 ppToken->i64val = atoll(ppToken->name);
    259             break;
    260         case PpAtomConstUint64:
    261             if (len > 0 && ppToken->name[0] == '0') {
    262                 if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
    263                     ppToken->i64val = (long long)strtoull(ppToken->name, nullptr, 16);
    264                 else
    265                     ppToken->i64val = (long long)strtoull(ppToken->name, nullptr, 8);
    266             } else
    267                 ppToken->i64val = (long long)strtoull(ppToken->name, 0, 10);
    268             break;
    269         }
    270     }
    271 
    272     return subtoken;
    273 }
    274 
    275 // We are pasting if
    276 //   1. we are preceding a pasting operator within this stream
    277 // or
    278 //   2. the entire macro is preceding a pasting operator (lastTokenPastes)
    279 //      and we are also on the last token
    280 bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
    281 {
    282     // 1. preceding ##?
    283 
    284     size_t savePos = current;
    285     int subtoken;
    286     // skip white space
    287     do {
    288         subtoken = getSubtoken();
    289     } while (subtoken == ' ');
    290     current = savePos;
    291     if (subtoken == PpAtomPaste)
    292         return true;
    293 
    294     // 2. last token and we've been told after this there will be a ##
    295 
    296     if (! lastTokenPastes)
    297         return false;
    298     // Getting here means the last token will be pasted, after this
    299 
    300     // Are we at the last non-whitespace token?
    301     savePos = current;
    302     bool moreTokens = false;
    303     do {
    304         subtoken = getSubtoken();
    305         if (subtoken == EndOfInput)
    306             break;
    307         if (subtoken != ' ') {
    308             moreTokens = true;
    309             break;
    310         }
    311     } while (true);
    312     current = savePos;
    313 
    314     return !moreTokens;
    315 }
    316 
    317 // See if the next non-white-space tokens are two consecutive #
    318 bool TPpContext::TokenStream::peekUntokenizedPasting()
    319 {
    320     // don't return early, have to restore this
    321     size_t savePos = current;
    322 
    323     // skip white-space
    324     int subtoken;
    325     do {
    326         subtoken = getSubtoken();
    327     } while (subtoken == ' ');
    328 
    329     // check for ##
    330     bool pasting = false;
    331     if (subtoken == '#') {
    332         subtoken = getSubtoken();
    333         if (subtoken == '#')
    334             pasting = true;
    335     }
    336 
    337     current = savePos;
    338 
    339     return pasting;
    340 }
    341 
    342 void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting)
    343 {
    344     pushInput(new tTokenInput(this, &ts, prepasting));
    345     ts.reset();
    346 }
    347 
    348 int TPpContext::tUngotTokenInput::scan(TPpToken* ppToken)
    349 {
    350     if (done)
    351         return EndOfInput;
    352 
    353     int ret = token;
    354     *ppToken = lval;
    355     done = true;
    356 
    357     return ret;
    358 }
    359 
    360 void TPpContext::UngetToken(int token, TPpToken* ppToken)
    361 {
    362     pushInput(new tUngotTokenInput(this, token, ppToken));
    363 }
    364 
    365 } // end namespace glslang
    366