2 //Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 //Copyright (C) 2013 LunarG, Inc.
6 //Redistribution and use in source and binary forms, with or without
7 //modification, are permitted provided that the following conditions
10 // Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
35 /****************************************************************************\
36 Copyright (c) 2002, NVIDIA Corporation.
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
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.
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
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 \****************************************************************************/
82 #define _CRT_SECURE_NO_WARNINGS
89 #include "PpContext.h"
95 int TPpContext::InitScanner()
97 // Add various atoms needed by the CPP line scanner:
101 previous_token = '\n';
106 ///////////////////////////////////////////////////////////////////////////////////////////////
107 /////////////////////////////////// Floating point constants: /////////////////////////////////
108 ///////////////////////////////////////////////////////////////////////////////////////////////
111 * lFloatConst() - Scan a single- or double-precision floating point constant. Assumes that the scanner
112 * has seen at least one digit, followed by either a decimal '.' or the
113 * letter 'e', or a precision ending (e.g., F or LF).
116 int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
118 bool HasDecimalOrExponent = false;
126 char* str = ppToken->name;
128 HasDecimalOrExponent = true;
129 str[len++] = (char)ch;
131 while (ch >= '0' && ch <= '9') {
132 if (len < MaxTokenLength) {
134 if (len > 0 || ch != '0') {
141 parseContext.ppError(ppToken->loc, "float literal too long", "", "");
150 if (ch == 'e' || ch == 'E') {
151 HasDecimalOrExponent = true;
152 if (len >= MaxTokenLength) {
153 parseContext.ppError(ppToken->loc, "float literal too long", "", "");
157 str[len++] = (char)ch;
160 str[len++] = (char)ch;
162 } else if (ch == '-') {
163 str[len++] = (char)ch;
166 if (ch >= '0' && ch <= '9') {
167 while (ch >= '0' && ch <= '9') {
168 if (len < MaxTokenLength) {
169 str[len++] = (char)ch;
172 parseContext.ppError(ppToken->loc, "float literal too long", "", "");
178 parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
187 if (ch == 'l' || ch == 'L') {
188 parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
189 if (! HasDecimalOrExponent)
190 parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
192 if (ch2 != 'f' && ch2 != 'F') {
196 if (len < MaxTokenLength) {
197 str[len++] = (char)ch;
198 str[len++] = (char)ch2;
201 parseContext.ppError(ppToken->loc, "float literal too long", "", "");
205 } else if (ch == 'f' || ch == 'F') {
206 parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
207 if (! parseContext.relaxedErrors())
208 parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
209 if (! HasDecimalOrExponent)
210 parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
211 if (len < MaxTokenLength)
212 str[len++] = (char)ch;
214 parseContext.ppError(ppToken->loc, "float literal too long", "", "");
222 ppToken->dval = strtod(str, nullptr);
226 return PpAtomConstDouble;
228 return PpAtomConstFloat;
232 // Scanner used to tokenize source stream.
234 int TPpContext::tStringInput::scan(TPpToken* ppToken)
236 char* tokenText = ppToken->name;
237 int AlreadyComplained = 0;
244 ppToken->space = false;
247 while (ch == ' ' || ch == '\t') {
248 ppToken->space = true;
252 ppToken->loc = pp->parseContext.getCurrentLoc();
256 // Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token)
259 case 'A': case 'B': case 'C': case 'D': case 'E':
260 case 'F': case 'G': case 'H': case 'I': case 'J':
261 case 'K': case 'L': case 'M': case 'N': case 'O':
262 case 'P': case 'Q': case 'R': case 'S': case 'T':
263 case 'U': case 'V': case 'W': case 'X': case 'Y':
265 case 'a': case 'b': case 'c': case 'd': case 'e':
266 case 'f': case 'g': case 'h': case 'i': case 'j':
267 case 'k': case 'l': case 'm': case 'n': case 'o':
268 case 'p': case 'q': case 'r': case 's': case 't':
269 case 'u': case 'v': case 'w': case 'x': case 'y':
272 if (len < MaxTokenLength) {
273 tokenText[len++] = (char)ch;
276 if (! AlreadyComplained) {
277 pp->parseContext.ppError(ppToken->loc, "name too long", "", "");
278 AlreadyComplained = 1;
282 } while ((ch >= 'a' && ch <= 'z') ||
283 (ch >= 'A' && ch <= 'Z') ||
284 (ch >= '0' && ch <= '9') ||
287 // line continuation with no token before or after makes len == 0, and need to start over skipping white space, etc.
291 tokenText[len] = '\0';
293 ppToken->atom = pp->LookUpAddString(tokenText);
294 return PpAtomIdentifier;
296 ppToken->name[len++] = (char)ch;
298 if (ch == 'x' || ch == 'X') {
299 // must be hexidecimal
301 bool isUnsigned = false;
302 ppToken->name[len++] = (char)ch;
304 if ((ch >= '0' && ch <= '9') ||
305 (ch >= 'A' && ch <= 'F') ||
306 (ch >= 'a' && ch <= 'f')) {
310 if (ival <= 0x0fffffff) {
311 ppToken->name[len++] = (char)ch;
312 if (ch >= '0' && ch <= '9') {
314 } else if (ch >= 'A' && ch <= 'F') {
316 } else if (ch >= 'a' && ch <= 'f') {
319 pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
320 ival = (ival << 4) | ii;
322 if (! AlreadyComplained) {
323 pp->parseContext.ppError(ppToken->loc, "hexidecimal literal too big", "", "");
324 AlreadyComplained = 1;
329 } while ((ch >= '0' && ch <= '9') ||
330 (ch >= 'A' && ch <= 'F') ||
331 (ch >= 'a' && ch <= 'f'));
333 pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
335 if (ch == 'u' || ch == 'U') {
336 if (len < MaxTokenLength)
337 ppToken->name[len++] = (char)ch;
341 ppToken->name[len] = '\0';
342 ppToken->ival = (int)ival;
345 return PpAtomConstUint;
347 return PpAtomConstInt;
349 // could be octal integer or floating point, speculative pursue octal until it must be floating point
351 bool isUnsigned = false;
352 bool octalOverflow = false;
353 bool nonOctal = false;
356 // see how much octal-like stuff we can read
357 while (ch >= '0' && ch <= '7') {
358 if (len < MaxTokenLength)
359 ppToken->name[len++] = (char)ch;
360 else if (! AlreadyComplained) {
361 pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
362 AlreadyComplained = 1;
364 if (ival <= 0x1fffffff) {
366 ival = (ival << 3) | ii;
368 octalOverflow = true;
372 // could be part of a float...
373 if (ch == '8' || ch == '9') {
376 if (len < MaxTokenLength)
377 ppToken->name[len++] = (char)ch;
378 else if (! AlreadyComplained) {
379 pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
380 AlreadyComplained = 1;
383 } while (ch >= '0' && ch <= '9');
385 if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F' || ch == 'l' || ch == 'L')
386 return pp->lFloatConst(len, ch, ppToken);
388 // wasn't a float, so must be octal...
390 pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", "");
392 if (ch == 'u' || ch == 'U') {
393 if (len < MaxTokenLength)
394 ppToken->name[len++] = (char)ch;
398 ppToken->name[len] = '\0';
401 pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", "");
403 ppToken->ival = (int)ival;
406 return PpAtomConstUint;
408 return PpAtomConstInt;
411 case '1': case '2': case '3': case '4':
412 case '5': case '6': case '7': case '8': case '9':
413 // can't be hexidecimal or octal, is either decimal or floating point
416 if (len < MaxTokenLength)
417 ppToken->name[len++] = (char)ch;
418 else if (! AlreadyComplained) {
419 pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
420 AlreadyComplained = 1;
423 } while (ch >= '0' && ch <= '9');
424 if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F' || ch == 'l' || ch == 'L') {
425 return pp->lFloatConst(len, ch, ppToken);
427 // Finish handling signed and unsigned integers
428 int numericLen = len;
430 if (ch == 'u' || ch == 'U') {
431 if (len < MaxTokenLength)
432 ppToken->name[len++] = (char)ch;
437 ppToken->name[len] = '\0';
439 const unsigned oneTenthMaxInt = 0xFFFFFFFFu / 10;
440 const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt;
441 for (int i = 0; i < numericLen; i++) {
442 ch = ppToken->name[i] - '0';
443 if ((ival > oneTenthMaxInt) || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt)) {
444 pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", "");
448 ival = ival * 10 + ch;
450 ppToken->ival = (int)ival;
453 return PpAtomConstUint;
455 return PpAtomConstInt;
461 return PpAtomDecrement;
462 } else if (ch == '=') {
471 return PpAtomIncrement;
472 } else if (ch == '=') {
500 return PpAtomXorAssign;
527 } else if (ch == '=') {
528 return PpAtomOrAssign;
537 } else if (ch == '=') {
538 return PpAtomAndAssign;
548 return PpAtomLeftAssign;
553 } else if (ch == '=') {
564 return PpAtomRightAssign;
569 } else if (ch == '=') {
577 if (ch >= '0' && ch <= '9') {
579 return pp->lFloatConst(0, '.', ppToken);
587 pp->inComment = true;
590 } while (ch != '\n' && ch != EndOfInput);
591 ppToken->space = true;
592 pp->inComment = false;
595 } else if (ch == '*') {
599 if (ch == EndOfInput) {
600 pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
606 if (ch == EndOfInput) {
607 pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
611 ppToken->space = true;
612 // loop again to get the next token...
614 } else if (ch == '=') {
623 while (ch != '"' && ch != '\n' && ch != EndOfInput) {
624 if (len < MaxTokenLength) {
625 tokenText[len] = (char)ch;
631 tokenText[len] = '\0';
634 pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
636 return PpAtomConstString;
644 // The main functional entry-point into the preprocessor, which will
645 // scan the source strings to figure out and return the next processing token.
647 // Return string pointer to next token.
648 // Return 0 when no more tokens.
650 const char* TPpContext::tokenize(TPpToken* ppToken)
655 token = scanToken(ppToken);
656 ppToken->token = token;
657 if (token == EndOfInput) {
662 if (previous_token == '\n') {
663 token = readCPPline(ppToken);
664 if (token == EndOfInput) {
670 parseContext.ppError(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", "");
674 previous_token = token;
680 if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, true) != 0)
683 const char* tokenString = nullptr;
685 case PpAtomIdentifier:
687 case PpAtomConstUint:
688 case PpAtomConstFloat:
689 case PpAtomConstDouble:
690 tokenString = ppToken->name;
692 case PpAtomConstString:
693 parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", "");
696 parseContext.ppError(ppToken->loc, "character literals not supported", "\'", "");
699 tokenString = GetAtomString(token);
704 if (tokenString[0] != 0)
705 parseContext.tokensBeforeEOF = 1;
712 // Checks if we've seen balanced #if...#endif
713 void TPpContext::missingEndifCheck()
716 parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", "");
719 } // end namespace glslang