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