• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 // Copyright (C) 2013 LunarG, Inc.
4 // Copyright (C) 2017 ARM Limited.
5 // Copyright (C) 2015-2018 Google, Inc.
6 // Copyright (c) 2023, Mobica Limited
7 //
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
12 // are met:
13 //
14 //    Redistributions of source code must retain the above copyright
15 //    notice, this list of conditions and the following disclaimer.
16 //
17 //    Redistributions in binary form must reproduce the above
18 //    copyright notice, this list of conditions and the following
19 //    disclaimer in the documentation and/or other materials provided
20 //    with the distribution.
21 //
22 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
23 //    contributors may be used to endorse or promote products derived
24 //    from this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 // POSSIBILITY OF SUCH DAMAGE.
38 //
39 /****************************************************************************\
40 Copyright (c) 2002, NVIDIA Corporation.
41 
42 NVIDIA Corporation("NVIDIA") supplies this software to you in
43 consideration of your agreement to the following terms, and your use,
44 installation, modification or redistribution of this NVIDIA software
45 constitutes acceptance of these terms.  If you do not agree with these
46 terms, please do not use, install, modify or redistribute this NVIDIA
47 software.
48 
49 In consideration of your agreement to abide by the following terms, and
50 subject to these terms, NVIDIA grants you a personal, non-exclusive
51 license, under NVIDIA's copyrights in this original NVIDIA software (the
52 "NVIDIA Software"), to use, reproduce, modify and redistribute the
53 NVIDIA Software, with or without modifications, in source and/or binary
54 forms; provided that if you redistribute the NVIDIA Software, you must
55 retain the copyright notice of NVIDIA, this notice and the following
56 text and disclaimers in all such redistributions of the NVIDIA Software.
57 Neither the name, trademarks, service marks nor logos of NVIDIA
58 Corporation may be used to endorse or promote products derived from the
59 NVIDIA Software without specific prior written permission from NVIDIA.
60 Except as expressly stated in this notice, no other rights or licenses
61 express or implied, are granted by NVIDIA herein, including but not
62 limited to any patent rights that may be infringed by your derivative
63 works or by other works in which the NVIDIA Software may be
64 incorporated. No hardware is licensed hereunder.
65 
66 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
67 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
68 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
69 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
70 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
71 PRODUCTS.
72 
73 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
74 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
75 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
76 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
77 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
78 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
79 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
80 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
81 \****************************************************************************/
82 
83 #ifndef _CRT_SECURE_NO_WARNINGS
84 #define _CRT_SECURE_NO_WARNINGS
85 #endif
86 
87 #include <cstdlib>
88 #include <cstring>
89 
90 #include "PpContext.h"
91 #include "PpTokens.h"
92 #include "../Scan.h"
93 
94 namespace glslang {
95 
96 ///////////////////////////////////////////////////////////////////////////////////////////////
97 /////////////////////////////////// Floating point constants: /////////////////////////////////
98 ///////////////////////////////////////////////////////////////////////////////////////////////
99 
100 //
101 // Scan a single- or double-precision floating point constant.
102 // Assumes that the scanner has seen at least one digit,
103 // followed by either a decimal '.' or the letter 'e', or a
104 // precision ending (e.g., F or LF).
105 //
106 // This is technically not correct, as the preprocessor should just
107 // accept the numeric literal along with whatever suffix it has, but
108 // currently, it stops on seeing a bad suffix, treating that as the
109 // next token. This effects things like token pasting, where it is
110 // relevant how many tokens something was broken into.
111 //
112 // See peekContinuedPasting().
lFloatConst(int len,int ch,TPpToken * ppToken)113 int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
114 {
115     const auto saveName = [&](int ch) {
116         if (len <= MaxTokenLength)
117             ppToken->name[len++] = static_cast<char>(ch);
118     };
119 
120     // find the range of non-zero digits before the decimal point
121     int startNonZero = 0;
122     while (startNonZero < len && ppToken->name[startNonZero] == '0')
123         ++startNonZero;
124     int endNonZero = len;
125     while (endNonZero > startNonZero && ppToken->name[endNonZero-1] == '0')
126         --endNonZero;
127     int numWholeNumberDigits = endNonZero - startNonZero;
128 
129     // accumulate the range's value
130     bool fastPath = numWholeNumberDigits <= 15;  // when the number gets too complex, set to false
131     unsigned long long wholeNumber = 0;
132     if (fastPath) {
133         for (int i = startNonZero; i < endNonZero; ++i)
134             wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
135     }
136     int decimalShift = len - endNonZero;
137 
138     // Decimal point:
139     bool hasDecimalOrExponent = false;
140     if (ch == '.') {
141         hasDecimalOrExponent = true;
142         saveName(ch);
143         ch = getChar();
144         int firstDecimal = len;
145 
146 #ifdef ENABLE_HLSL
147         // 1.#INF or -1.#INF
148         if (ch == '#' && (ifdepth > 0 || parseContext.intermediate.getSource() == EShSourceHlsl)) {
149             if ((len <  2) ||
150                 (len == 2 && ppToken->name[0] != '1') ||
151                 (len == 3 && ppToken->name[1] != '1' && !(ppToken->name[0] == '-' || ppToken->name[0] == '+')) ||
152                 (len >  3))
153                 parseContext.ppError(ppToken->loc, "unexpected use of", "#", "");
154             else {
155                 // we have 1.# or -1.# or +1.#, check for 'INF'
156                 if ((ch = getChar()) != 'I' ||
157                     (ch = getChar()) != 'N' ||
158                     (ch = getChar()) != 'F')
159                     parseContext.ppError(ppToken->loc, "expected 'INF'", "#", "");
160                 else {
161                     // we have [+-].#INF, and we are targeting IEEE 754, so wrap it up:
162                     saveName('I');
163                     saveName('N');
164                     saveName('F');
165                     ppToken->name[len] = '\0';
166                     if (ppToken->name[0] == '-')
167                         ppToken->i64val = 0xfff0000000000000; // -Infinity
168                     else
169                         ppToken->i64val = 0x7ff0000000000000; // +Infinity
170                     return PpAtomConstFloat;
171                 }
172             }
173         }
174 #endif
175 
176         // Consume leading-zero digits after the decimal point
177         while (ch == '0') {
178             saveName(ch);
179             ch = getChar();
180         }
181         int startNonZeroDecimal = len;
182         int endNonZeroDecimal = len;
183 
184         // Consume remaining digits, up to the exponent
185         while (ch >= '0' && ch <= '9') {
186             saveName(ch);
187             if (ch != '0')
188                 endNonZeroDecimal = len;
189             ch = getChar();
190         }
191 
192         // Compute accumulation up to the last non-zero digit
193         if (endNonZeroDecimal > startNonZeroDecimal) {
194             numWholeNumberDigits += endNonZeroDecimal - endNonZero - 1; // don't include the "."
195             if (numWholeNumberDigits > 15)
196                 fastPath = false;
197             if (fastPath) {
198                 for (int i = endNonZero; i < endNonZeroDecimal; ++i) {
199                     if (ppToken->name[i] != '.')
200                         wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
201                 }
202             }
203             decimalShift = firstDecimal - endNonZeroDecimal;
204         }
205     }
206 
207     // Exponent:
208     bool negativeExponent = false;
209     double exponentValue = 0.0;
210     int exponent = 0;
211     {
212         if (ch == 'e' || ch == 'E') {
213             hasDecimalOrExponent = true;
214             saveName(ch);
215             ch = getChar();
216             if (ch == '+' || ch == '-') {
217                 negativeExponent = ch == '-';
218                 saveName(ch);
219                 ch = getChar();
220             }
221             if (ch >= '0' && ch <= '9') {
222                 while (ch >= '0' && ch <= '9') {
223                     exponent = exponent * 10 + (ch - '0');
224                     saveName(ch);
225                     ch = getChar();
226                 }
227             } else {
228                 parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
229             }
230         }
231 
232         // Compensate for location of decimal
233         if (negativeExponent)
234             exponent -= decimalShift;
235         else {
236             exponent += decimalShift;
237             if (exponent < 0) {
238                 negativeExponent = true;
239                 exponent = -exponent;
240             }
241         }
242         if (exponent > 22)
243             fastPath = false;
244 
245         if (fastPath) {
246             // Compute the floating-point value of the exponent
247             exponentValue = 1.0;
248             if (exponent > 0) {
249                 double expFactor = 10;
250                 while (exponent > 0) {
251                     if (exponent & 0x1)
252                         exponentValue *= expFactor;
253                     expFactor *= expFactor;
254                     exponent >>= 1;
255                 }
256             }
257         }
258     }
259 
260     // Suffix:
261     bool isDouble = false;
262     bool isFloat16 = false;
263     if (ch == 'l' || ch == 'L') {
264         if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
265             parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
266         if (ifdepth == 0 && !hasDecimalOrExponent)
267             parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
268         if (parseContext.intermediate.getSource() == EShSourceGlsl) {
269             int ch2 = getChar();
270             if (ch2 != 'f' && ch2 != 'F') {
271                 ungetChar();
272                 ungetChar();
273             } else {
274                 saveName(ch);
275                 saveName(ch2);
276                 isDouble = true;
277             }
278         } else if (parseContext.intermediate.getSource() == EShSourceHlsl) {
279             saveName(ch);
280             isDouble = true;
281         }
282     } else if (ch == 'h' || ch == 'H') {
283         if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
284             parseContext.float16Check(ppToken->loc, "half floating-point suffix");
285         if (ifdepth == 0 && !hasDecimalOrExponent)
286             parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
287         if (parseContext.intermediate.getSource() == EShSourceGlsl) {
288             int ch2 = getChar();
289             if (ch2 != 'f' && ch2 != 'F') {
290                 ungetChar();
291                 ungetChar();
292             } else {
293                 saveName(ch);
294                 saveName(ch2);
295                 isFloat16 = true;
296             }
297         } else if (parseContext.intermediate.getSource() == EShSourceHlsl) {
298             saveName(ch);
299             isFloat16 = true;
300         }
301     } else
302     if (ch == 'f' || ch == 'F') {
303         if (ifdepth == 0)
304             parseContext.profileRequires(ppToken->loc,  EEsProfile, 300, nullptr, "floating-point suffix");
305         if (ifdepth == 0 && !parseContext.relaxedErrors())
306             parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
307         if (ifdepth == 0 && !hasDecimalOrExponent)
308             parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
309         saveName(ch);
310     } else
311         ungetChar();
312 
313     // Patch up the name and length for overflow
314 
315     if (len > MaxTokenLength) {
316         len = MaxTokenLength;
317         parseContext.ppError(ppToken->loc, "float literal too long", "", "");
318     }
319     ppToken->name[len] = '\0';
320 
321     // Compute the numerical value
322     if (fastPath) {
323         // compute the floating-point value of the exponent
324         if (exponentValue == 0.0)
325             ppToken->dval = (double)wholeNumber;
326         else if (negativeExponent)
327             ppToken->dval = (double)wholeNumber / exponentValue;
328         else
329             ppToken->dval = (double)wholeNumber * exponentValue;
330     } else {
331         // slow path
332         ppToken->dval = 0.0;
333 
334         // remove suffix
335         TString numstr(ppToken->name);
336         if (numstr.back() == 'f' || numstr.back() == 'F')
337             numstr.pop_back();
338         if (numstr.back() == 'h' || numstr.back() == 'H')
339             numstr.pop_back();
340         if (numstr.back() == 'l' || numstr.back() == 'L')
341             numstr.pop_back();
342 
343         // use platform library
344         strtodStream.clear();
345         strtodStream.str(numstr.c_str());
346         strtodStream >> ppToken->dval;
347         if (strtodStream.fail()) {
348             // Assume failure combined with a large exponent was overflow, in
349             // an attempt to set INF.
350             if (!negativeExponent && exponent + numWholeNumberDigits > 300)
351                 ppToken->i64val = 0x7ff0000000000000; // +Infinity
352             // Assume failure combined with a small exponent was overflow.
353             if (negativeExponent && exponent + numWholeNumberDigits > 300)
354                 ppToken->dval = 0.0;
355             // Unknown reason for failure. Theory is that either
356             //  - the 0.0 is still there, or
357             //  - something reasonable was written that is better than 0.0
358         }
359     }
360 
361     // Return the right token type
362     if (isDouble)
363         return PpAtomConstDouble;
364     else if (isFloat16)
365         return PpAtomConstFloat16;
366     else
367         return PpAtomConstFloat;
368 }
369 
370 // Recognize a character literal.
371 //
372 // The first ' has already been accepted, read the rest, through the closing '.
373 //
374 // Always returns PpAtomConstInt.
375 //
characterLiteral(TPpToken * ppToken)376 int TPpContext::characterLiteral(TPpToken* ppToken)
377 {
378     ppToken->name[0] = 0;
379     ppToken->ival = 0;
380 
381     if (parseContext.intermediate.getSource() != EShSourceHlsl) {
382         // illegal, except in macro definition, for which case we report the character
383         return '\'';
384     }
385 
386     int ch = getChar();
387     switch (ch) {
388     case '\'':
389         // As empty sequence:  ''
390         parseContext.ppError(ppToken->loc, "unexpected", "\'", "");
391         return PpAtomConstInt;
392     case '\\':
393         // As escape sequence:  '\XXX'
394         switch (ch = getChar()) {
395         case 'a':
396             ppToken->ival = 7;
397             break;
398         case 'b':
399             ppToken->ival = 8;
400             break;
401         case 't':
402             ppToken->ival = 9;
403             break;
404         case 'n':
405             ppToken->ival = 10;
406             break;
407         case 'v':
408             ppToken->ival = 11;
409             break;
410         case 'f':
411             ppToken->ival = 12;
412             break;
413         case 'r':
414             ppToken->ival = 13;
415             break;
416         case 'x':
417         case '0':
418             parseContext.ppError(ppToken->loc, "octal and hex sequences not supported", "\\", "");
419             break;
420         default:
421             // This catches '\'', '\"', '\?', etc.
422             // Also, things like '\C' mean the same thing as 'C'
423             // (after the above cases are filtered out).
424             ppToken->ival = ch;
425             break;
426         }
427         break;
428     default:
429         ppToken->ival = ch;
430         break;
431     }
432     ppToken->name[0] = (char)ppToken->ival;
433     ppToken->name[1] = '\0';
434     ch = getChar();
435     if (ch != '\'') {
436         parseContext.ppError(ppToken->loc, "expected", "\'", "");
437         // Look ahead for a closing '
438         do {
439             ch = getChar();
440         } while (ch != '\'' && ch != EndOfInput && ch != '\n');
441     }
442 
443     return PpAtomConstInt;
444 }
445 
446 //
447 // Scanner used to tokenize source stream.
448 //
449 // N.B. Invalid numeric suffixes are not consumed.//
450 // This is technically not correct, as the preprocessor should just
451 // accept the numeric literal along with whatever suffix it has, but
452 // currently, it stops on seeing a bad suffix, treating that as the
453 // next token. This effects things like token pasting, where it is
454 // relevant how many tokens something was broken into.
455 // See peekContinuedPasting().
456 //
scan(TPpToken * ppToken)457 int TPpContext::tStringInput::scan(TPpToken* ppToken)
458 {
459     int AlreadyComplained = 0;
460     int len = 0;
461     int ch = 0;
462     int ii = 0;
463     unsigned long long ival = 0;
464     const auto floatingPointChar = [&](int ch) { return ch == '.' || ch == 'e' || ch == 'E' ||
465                                                                      ch == 'f' || ch == 'F' ||
466                                                                      ch == 'h' || ch == 'H'; };
467 
468     static const char* const Int64_Extensions[] = {
469         E_GL_ARB_gpu_shader_int64,
470         E_GL_EXT_shader_explicit_arithmetic_types,
471         E_GL_EXT_shader_explicit_arithmetic_types_int64 };
472     static const int Num_Int64_Extensions = sizeof(Int64_Extensions) / sizeof(Int64_Extensions[0]);
473 
474     static const char* const Int16_Extensions[] = {
475         E_GL_AMD_gpu_shader_int16,
476         E_GL_EXT_shader_explicit_arithmetic_types,
477         E_GL_EXT_shader_explicit_arithmetic_types_int16 };
478     static const int Num_Int16_Extensions = sizeof(Int16_Extensions) / sizeof(Int16_Extensions[0]);
479 
480     ppToken->clear();
481     ch = getch();
482     for (;;) {
483         while (ch == ' ' || ch == '\t') {
484             ppToken->space = true;
485             ch = getch();
486         }
487 
488         ppToken->loc = pp->parseContext.getCurrentLoc();
489         len = 0;
490         switch (ch) {
491         default:
492             // Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token)
493             if (ch > PpAtomMaxSingle)
494                 ch = PpAtomBadToken;
495             return ch;
496 
497         case 'A': case 'B': case 'C': case 'D': case 'E':
498         case 'F': case 'G': case 'H': case 'I': case 'J':
499         case 'K': case 'L': case 'M': case 'N': case 'O':
500         case 'P': case 'Q': case 'R': case 'S': case 'T':
501         case 'U': case 'V': case 'W': case 'X': case 'Y':
502         case 'Z': case '_':
503         case 'a': case 'b': case 'c': case 'd': case 'e':
504         case 'f': case 'g': case 'h': case 'i': case 'j':
505         case 'k': case 'l': case 'm': case 'n': case 'o':
506         case 'p': case 'q': case 'r': case 's': case 't':
507         case 'u': case 'v': case 'w': case 'x': case 'y':
508         case 'z':
509             do {
510                 if (len < MaxTokenLength) {
511                     ppToken->name[len++] = (char)ch;
512                     ch = getch();
513                 } else {
514                     if (! AlreadyComplained) {
515                         pp->parseContext.ppError(ppToken->loc, "name too long", "", "");
516                         AlreadyComplained = 1;
517                     }
518                     ch = getch();
519                 }
520             } while ((ch >= 'a' && ch <= 'z') ||
521                      (ch >= 'A' && ch <= 'Z') ||
522                      (ch >= '0' && ch <= '9') ||
523                      ch == '_');
524 
525             // line continuation with no token before or after makes len == 0, and need to start over skipping white space, etc.
526             if (len == 0)
527                 continue;
528 
529             ppToken->name[len] = '\0';
530             ungetch();
531             return PpAtomIdentifier;
532         case '0':
533             ppToken->name[len++] = (char)ch;
534             ch = getch();
535             if (ch == 'x' || ch == 'X') {
536                 // must be hexadecimal
537 
538                 bool isUnsigned = false;
539                 bool isInt64 = false;
540                 bool isInt16 = false;
541                 ppToken->name[len++] = (char)ch;
542                 ch = getch();
543                 if ((ch >= '0' && ch <= '9') ||
544                     (ch >= 'A' && ch <= 'F') ||
545                     (ch >= 'a' && ch <= 'f')) {
546 
547                     ival = 0;
548                     do {
549                         if (len < MaxTokenLength && ival <= 0x7fffffffffffffffull) {
550                             ppToken->name[len++] = (char)ch;
551                             if (ch >= '0' && ch <= '9') {
552                                 ii = ch - '0';
553                             } else if (ch >= 'A' && ch <= 'F') {
554                                 ii = ch - 'A' + 10;
555                             } else if (ch >= 'a' && ch <= 'f') {
556                                 ii = ch - 'a' + 10;
557                             } else
558                                 pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", "");
559                             ival = (ival << 4) | ii;
560                         } else {
561                             if (! AlreadyComplained) {
562                                 if(len < MaxTokenLength)
563                                     pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
564                                 else
565                                     pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too long", "", "");
566                                 AlreadyComplained = 1;
567                             }
568                             ival = 0xffffffffffffffffull;
569                         }
570                         ch = getch();
571                     } while ((ch >= '0' && ch <= '9') ||
572                              (ch >= 'A' && ch <= 'F') ||
573                              (ch >= 'a' && ch <= 'f'));
574                 } else {
575                     pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", "");
576                 }
577                 if (ch == 'u' || ch == 'U') {
578                     if (len < MaxTokenLength)
579                         ppToken->name[len++] = (char)ch;
580                     isUnsigned = true;
581 
582                     int nextCh = getch();
583                     if (nextCh == 'l' || nextCh == 'L') {
584                         if (len < MaxTokenLength)
585                             ppToken->name[len++] = (char)nextCh;
586                         isInt64 = true;
587                     } else
588                         ungetch();
589 
590                     nextCh = getch();
591                     if ((nextCh == 's' || nextCh == 'S') &&
592                             pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
593                         if (len < MaxTokenLength)
594                             ppToken->name[len++] = (char)nextCh;
595                         isInt16 = true;
596                     } else
597                         ungetch();
598                 } else if (ch == 'l' || ch == 'L') {
599                     if (len < MaxTokenLength)
600                         ppToken->name[len++] = (char)ch;
601                     isInt64 = true;
602                 } else if ((ch == 's' || ch == 'S') &&
603                            pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
604                     if (len < MaxTokenLength)
605                         ppToken->name[len++] = (char)ch;
606                     isInt16 = true;
607                 } else
608                     ungetch();
609                 ppToken->name[len] = '\0';
610 
611                 if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
612                     if (pp->ifdepth == 0) {
613                         pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
614                                                         "64-bit hexadecimal literal");
615                         pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
616                             Num_Int64_Extensions, Int64_Extensions, "64-bit hexadecimal literal");
617                     }
618                     ppToken->i64val = ival;
619                     return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
620                 } else if (isInt16) {
621                     if (pp->ifdepth == 0) {
622                         if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
623                             pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
624                                                              "16-bit hexadecimal literal");
625                             pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
626                                 Num_Int16_Extensions, Int16_Extensions, "16-bit hexadecimal literal");
627                         }
628                     }
629                     ppToken->ival = (int)ival;
630                     return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
631                 } else {
632                     if (ival > 0xffffffffu && !AlreadyComplained)
633                         pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
634                     ppToken->ival = (int)ival;
635                     return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
636                 }
637             } else if ((ch == 'b' || ch == 'B') && pp->parseContext.intermediate.getSource() == EShSourceHlsl) {
638                 // must be binary
639                 bool isUnsigned = false;
640                 bool isInt64 = false;
641                 bool isInt16 = false;
642                 ppToken->name[len++] = (char)ch;
643                 ch = getch();
644 
645                 // Check value
646                 if ((ch == '0' || ch == '1'))
647                 {
648                     ival = 0;
649                     do {
650                         if (len < MaxTokenLength && ival <= 0x7fffffffffffffffull) {
651                             ppToken->name[len++] = (char)ch;
652                             if (ch == '0' || ch == '1') {
653                                 ii = ch - '0';
654                             } else {
655                                 pp->parseContext.ppError(ppToken->loc, "bad digit in binary literal", "", "");
656                             }
657                             ival = (ival << 1) | ii;
658                         }
659                         else
660                         {
661                             if (! AlreadyComplained) {
662                                 if(len < MaxTokenLength)
663                                     pp->parseContext.ppError(ppToken->loc, "binary literal too big", "", "");
664                                 else
665                                     pp->parseContext.ppError(ppToken->loc, "binary literal too long", "", "");
666                                 AlreadyComplained = 1;
667                             }
668                             ival = 0xffffffffffffffffull;
669                         }
670                         ch = getch();
671                     } while (ch == '0' || ch == '1');
672                 }
673                 else
674                 {
675                    pp->parseContext.ppError(ppToken->loc, "bad digit in binary literal", "", "");
676                 }
677 
678                 // check type
679                 if (ch == 'u' || ch == 'U') {
680                     if (len < MaxTokenLength)
681                         ppToken->name[len++] = (char)ch;
682                     isUnsigned = true;
683 
684                     int nextCh = getch();
685                     if (nextCh == 'l' || nextCh == 'L') {
686                         if (len < MaxTokenLength)
687                             ppToken->name[len++] = (char)nextCh;
688                         isInt64 = true;
689                     } else
690                         ungetch();
691 
692                     nextCh = getch();
693                     if ((nextCh == 's' || nextCh == 'S') &&
694                                 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
695                         if (len < MaxTokenLength)
696                             ppToken->name[len++] = (char)nextCh;
697                         isInt16 = true;
698                     } else
699                         ungetch();
700                 } else if (ch == 'l' || ch == 'L') {
701                     if (len < MaxTokenLength)
702                         ppToken->name[len++] = (char)ch;
703                     isInt64 = true;
704                 } else if ((ch == 's' || ch == 'S') &&
705                                 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
706                     if (len < MaxTokenLength)
707                         ppToken->name[len++] = (char)ch;
708                     isInt16 = true;
709                 } else {
710                     ungetch();
711                 }
712                 ppToken->name[len] = '\0';
713 
714                 // Assign value
715                 if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
716                     if (pp->ifdepth == 0) {
717                         pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
718                                                         "64-bit binary literal");
719                         pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
720                             Num_Int64_Extensions, Int64_Extensions, "64-bit binary literal");
721                     }
722                     ppToken->i64val = ival;
723                     return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
724                 } else if (isInt16) {
725                     if (pp->ifdepth == 0) {
726                         if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
727                             pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
728                                                             "16-bit binary literal");
729                             pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
730                                 Num_Int16_Extensions, Int16_Extensions, "16-bit binary literal");
731                         }
732                     }
733                     ppToken->ival = (int)ival;
734                     return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
735                 } else {
736                     ppToken->ival = (int)ival;
737                     return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
738                 }
739             } else {
740                 // could be octal integer or floating point, speculative pursue octal until it must be floating point
741 
742                 bool isUnsigned = false;
743                 bool isInt64 = false;
744                 bool isInt16 = false;
745                 bool octalOverflow = false;
746                 bool nonOctal = false;
747                 ival = 0;
748 
749                 // see how much octal-like stuff we can read
750                 while (ch >= '0' && ch <= '7') {
751                     if (len < MaxTokenLength)
752                         ppToken->name[len++] = (char)ch;
753                     else if (! AlreadyComplained) {
754                         pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
755                         AlreadyComplained = 1;
756                     }
757                     if (ival <= 0x1fffffffffffffffull) {
758                         ii = ch - '0';
759                         ival = (ival << 3) | ii;
760                     } else
761                         octalOverflow = true;
762                     ch = getch();
763                 }
764 
765                 // could be part of a float...
766                 if (ch == '8' || ch == '9') {
767                     nonOctal = true;
768                     do {
769                         if (len < MaxTokenLength)
770                             ppToken->name[len++] = (char)ch;
771                         else if (! AlreadyComplained) {
772                             pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
773                             AlreadyComplained = 1;
774                         }
775                         ch = getch();
776                     } while (ch >= '0' && ch <= '9');
777                 }
778                 if (floatingPointChar(ch))
779                     return pp->lFloatConst(len, ch, ppToken);
780 
781                 // wasn't a float, so must be octal...
782                 if (nonOctal)
783                     pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", "");
784 
785                 if (ch == 'u' || ch == 'U') {
786                     if (len < MaxTokenLength)
787                         ppToken->name[len++] = (char)ch;
788                     isUnsigned = true;
789 
790                     int nextCh = getch();
791                     if (nextCh == 'l' || nextCh == 'L') {
792                         if (len < MaxTokenLength)
793                             ppToken->name[len++] = (char)nextCh;
794                         isInt64 = true;
795                     } else
796                         ungetch();
797 
798                     nextCh = getch();
799                     if ((nextCh == 's' || nextCh == 'S') &&
800                                 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
801                         if (len < MaxTokenLength)
802                             ppToken->name[len++] = (char)nextCh;
803                         isInt16 = true;
804                     } else
805                         ungetch();
806                 } else if (ch == 'l' || ch == 'L') {
807                     if (len < MaxTokenLength)
808                         ppToken->name[len++] = (char)ch;
809                     isInt64 = true;
810                 } else if ((ch == 's' || ch == 'S') &&
811                                 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
812                     if (len < MaxTokenLength)
813                         ppToken->name[len++] = (char)ch;
814                     isInt16 = true;
815                 } else
816                     ungetch();
817                 ppToken->name[len] = '\0';
818 
819                 if (!isInt64 && ival > 0xffffffffu)
820                     octalOverflow = true;
821 
822                 if (octalOverflow)
823                     pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", "");
824 
825                 if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
826                     if (pp->ifdepth == 0) {
827                         pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
828                                                         "64-bit octal literal");
829                         pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
830                             Num_Int64_Extensions, Int64_Extensions, "64-bit octal literal");
831                     }
832                     ppToken->i64val = ival;
833                     return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
834                 } else if (isInt16) {
835                     if (pp->ifdepth == 0) {
836                         if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
837                             pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
838                                                             "16-bit octal literal");
839                             pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
840                                 Num_Int16_Extensions, Int16_Extensions, "16-bit octal literal");
841                         }
842                     }
843                     ppToken->ival = (int)ival;
844                     return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
845                 } else {
846                     ppToken->ival = (int)ival;
847                     return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
848                 }
849             }
850             break;
851         case '1': case '2': case '3': case '4':
852         case '5': case '6': case '7': case '8': case '9':
853             // can't be hexadecimal or octal, is either decimal or floating point
854 
855             do {
856                 if (len < MaxTokenLength)
857                     ppToken->name[len++] = (char)ch;
858                 else if (! AlreadyComplained) {
859                     pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
860                     AlreadyComplained = 1;
861                 }
862                 ch = getch();
863             } while (ch >= '0' && ch <= '9');
864             if (floatingPointChar(ch))
865                 return pp->lFloatConst(len, ch, ppToken);
866             else {
867                 // Finish handling signed and unsigned integers
868                 int numericLen = len;
869                 bool isUnsigned = false;
870                 bool isInt64 = false;
871                 bool isInt16 = false;
872                 if (ch == 'u' || ch == 'U') {
873                     if (len < MaxTokenLength)
874                         ppToken->name[len++] = (char)ch;
875                     isUnsigned = true;
876 
877                     int nextCh = getch();
878                     if (nextCh == 'l' || nextCh == 'L') {
879                         if (len < MaxTokenLength)
880                             ppToken->name[len++] = (char)nextCh;
881                         isInt64 = true;
882                     } else
883                         ungetch();
884 
885                     nextCh = getch();
886                     if ((nextCh == 's' || nextCh == 'S') &&
887                                 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
888                         if (len < MaxTokenLength)
889                             ppToken->name[len++] = (char)nextCh;
890                         isInt16 = true;
891                     } else
892                         ungetch();
893                 } else if (ch == 'l' || ch == 'L') {
894                     if (len < MaxTokenLength)
895                         ppToken->name[len++] = (char)ch;
896                     isInt64 = true;
897                 } else if ((ch == 's' || ch == 'S') &&
898                                 pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
899                     if (len < MaxTokenLength)
900                         ppToken->name[len++] = (char)ch;
901                     isInt16 = true;
902                 } else
903                     ungetch();
904 
905                 ppToken->name[len] = '\0';
906                 ival = 0;
907                 const unsigned oneTenthMaxInt  = 0xFFFFFFFFu / 10;
908                 const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt;
909                 const unsigned long long oneTenthMaxInt64  = 0xFFFFFFFFFFFFFFFFull / 10;
910                 const unsigned long long remainderMaxInt64 = 0xFFFFFFFFFFFFFFFFull - 10 * oneTenthMaxInt64;
911                 const unsigned short oneTenthMaxInt16  = 0xFFFFu / 10;
912                 const unsigned short remainderMaxInt16 = 0xFFFFu - 10 * oneTenthMaxInt16;
913                 for (int i = 0; i < numericLen; i++) {
914                     ch = ppToken->name[i] - '0';
915                     bool overflow = false;
916                     if (isInt64)
917                         overflow = (ival > oneTenthMaxInt64 || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64));
918                     else if (isInt16)
919                         overflow = (ival > oneTenthMaxInt16 || (ival == oneTenthMaxInt16 && (unsigned short)ch > remainderMaxInt16));
920                     else
921                         overflow = (ival > oneTenthMaxInt || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt));
922                     if (overflow) {
923                         pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", "");
924                         ival = 0xFFFFFFFFFFFFFFFFull;
925                         break;
926                     } else
927                         ival = ival * 10 + ch;
928                 }
929 
930                 if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
931                     if (pp->ifdepth == 0) {
932                         pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
933                                                         "64-bit literal");
934                         pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
935                             Num_Int64_Extensions, Int64_Extensions, "64-bit literal");
936                     }
937                     ppToken->i64val = ival;
938                     return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
939                 } else if (isInt16) {
940                     if (pp->ifdepth == 0 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
941                         pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
942                                                         "16-bit  literal");
943                         pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
944                             Num_Int16_Extensions, Int16_Extensions, "16-bit literal");
945                     }
946                     ppToken->ival = (int)ival;
947                     return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
948                 } else {
949                     ppToken->ival = (int)ival;
950                     return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
951                 }
952             }
953             break;
954         case '-':
955             ch = getch();
956             if (ch == '-') {
957                 return PpAtomDecrement;
958             } else if (ch == '=') {
959                 return PPAtomSubAssign;
960             } else {
961                 ungetch();
962                 return '-';
963             }
964         case '+':
965             ch = getch();
966             if (ch == '+') {
967                 return PpAtomIncrement;
968             } else if (ch == '=') {
969                 return PPAtomAddAssign;
970             } else {
971                 ungetch();
972                 return '+';
973             }
974         case '*':
975             ch = getch();
976             if (ch == '=') {
977                 return PPAtomMulAssign;
978             } else {
979                 ungetch();
980                 return '*';
981             }
982         case '%':
983             ch = getch();
984             if (ch == '=') {
985                 return PPAtomModAssign;
986             } else {
987                 ungetch();
988                 return '%';
989             }
990         case '^':
991             ch = getch();
992             if (ch == '^') {
993                 return PpAtomXor;
994             } else {
995                 if (ch == '=')
996                     return PpAtomXorAssign;
997                 else{
998                     ungetch();
999                     return '^';
1000                 }
1001             }
1002 
1003         case '=':
1004             ch = getch();
1005             if (ch == '=') {
1006                 return PpAtomEQ;
1007             } else {
1008                 ungetch();
1009                 return '=';
1010             }
1011         case '!':
1012             ch = getch();
1013             if (ch == '=') {
1014                 return PpAtomNE;
1015             } else {
1016                 ungetch();
1017                 return '!';
1018             }
1019         case '|':
1020             ch = getch();
1021             if (ch == '|') {
1022                 return PpAtomOr;
1023             } else if (ch == '=') {
1024                 return PpAtomOrAssign;
1025             } else {
1026                 ungetch();
1027                 return '|';
1028             }
1029         case '&':
1030             ch = getch();
1031             if (ch == '&') {
1032                 return PpAtomAnd;
1033             } else if (ch == '=') {
1034                 return PpAtomAndAssign;
1035             } else {
1036                 ungetch();
1037                 return '&';
1038             }
1039         case '<':
1040             ch = getch();
1041             if (ch == '<') {
1042                 ch = getch();
1043                 if (ch == '=')
1044                     return PpAtomLeftAssign;
1045                 else {
1046                     ungetch();
1047                     return PpAtomLeft;
1048                 }
1049             } else if (ch == '=') {
1050                 return PpAtomLE;
1051             } else {
1052                 ungetch();
1053                 return '<';
1054             }
1055         case '>':
1056             ch = getch();
1057             if (ch == '>') {
1058                 ch = getch();
1059                 if (ch == '=')
1060                     return PpAtomRightAssign;
1061                 else {
1062                     ungetch();
1063                     return PpAtomRight;
1064                 }
1065             } else if (ch == '=') {
1066                 return PpAtomGE;
1067             } else {
1068                 ungetch();
1069                 return '>';
1070             }
1071         case '.':
1072             ch = getch();
1073             if (ch >= '0' && ch <= '9') {
1074                 ungetch();
1075                 return pp->lFloatConst(0, '.', ppToken);
1076             } else {
1077                 ungetch();
1078                 return '.';
1079             }
1080         case '/':
1081             ch = getch();
1082             if (ch == '/') {
1083                 pp->inComment = true;
1084                 do {
1085                     ch = getch();
1086                 } while (ch != '\n' && ch != EndOfInput);
1087                 ppToken->space = true;
1088                 pp->inComment = false;
1089 
1090                 return ch;
1091             } else if (ch == '*') {
1092                 ch = getch();
1093                 do {
1094                     while (ch != '*') {
1095                         if (ch == EndOfInput) {
1096                             pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
1097                             return ch;
1098                         }
1099                         ch = getch();
1100                     }
1101                     ch = getch();
1102                     if (ch == EndOfInput) {
1103                         pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
1104                         return ch;
1105                     }
1106                 } while (ch != '/');
1107                 ppToken->space = true;
1108                 // loop again to get the next token...
1109                 break;
1110             } else if (ch == '=') {
1111                 return PPAtomDivAssign;
1112             } else {
1113                 ungetch();
1114                 return '/';
1115             }
1116             break;
1117         case '\'':
1118             return pp->characterLiteral(ppToken);
1119         case '"':
1120             // #include uses scanHeaderName() to ignore these escape sequences.
1121             ch = getch();
1122             while (ch != '"' && ch != '\n' && ch != EndOfInput) {
1123                 if (len < MaxTokenLength) {
1124                     if (ch == '\\' && !pp->disableEscapeSequences) {
1125                         int nextCh = getch();
1126                         switch (nextCh) {
1127                         case '\'': ch = 0x27; break;
1128                         case '"':  ch = 0x22; break;
1129                         case '?':  ch = 0x3f; break;
1130                         case '\\': ch = 0x5c; break;
1131                         case 'a':  ch = 0x07; break;
1132                         case 'b':  ch = 0x08; break;
1133                         case 'f':  ch = 0x0c; break;
1134                         case 'n':  ch = 0x0a; break;
1135                         case 'r':  ch = 0x0d; break;
1136                         case 't':  ch = 0x09; break;
1137                         case 'v':  ch = 0x0b; break;
1138                         case 'x':
1139                             // Hex value, arbitrary number of characters. Terminated by the first
1140                             // non-hex digit
1141                             {
1142                                 int numDigits = 0;
1143                                 ch = 0;
1144                                 while (true) {
1145                                     nextCh = getch();
1146                                     if (nextCh >= '0' && nextCh <= '9')
1147                                         nextCh -= '0';
1148                                     else if (nextCh >= 'A' && nextCh <= 'F')
1149                                         nextCh -= 'A' - 10;
1150                                     else if (nextCh >= 'a' && nextCh <= 'f')
1151                                         nextCh -= 'a' - 10;
1152                                     else {
1153                                         ungetch();
1154                                         break;
1155                                     }
1156                                     numDigits++;
1157                                     ch = ch * 0x10 + nextCh;
1158                                 }
1159                                 if (numDigits == 0) {
1160                                     pp->parseContext.ppError(ppToken->loc, "Expected hex value in escape sequence", "string", "");
1161                                 }
1162                                 break;
1163                             }
1164                         case '0':
1165                         case '1':
1166                         case '2':
1167                         case '3':
1168                         case '4':
1169                         case '5':
1170                         case '6':
1171                         case '7':
1172                             // Octal value, up to three octal digits
1173                             {
1174                                 int numDigits = 1;
1175                                 ch = nextCh - '0';
1176                                 while (numDigits < 3) {
1177                                     nextCh = getch();
1178                                     if (nextCh >= '0' && nextCh <= '7')
1179                                         nextCh -= '0';
1180                                     else {
1181                                         ungetch();
1182                                         break;
1183                                     }
1184                                     numDigits++;
1185                                     ch = ch * 8 + nextCh;
1186                                 }
1187                                 break;
1188                             }
1189                         default:
1190                             pp->parseContext.ppError(ppToken->loc, "Invalid escape sequence", "string", "");
1191                             break;
1192                         }
1193                     }
1194                     ppToken->name[len] = (char)ch;
1195                     len++;
1196                     ch = getch();
1197                 } else
1198                     break;
1199             };
1200             ppToken->name[len] = '\0';
1201             if (ch != '"') {
1202                 ungetch();
1203                 pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
1204             }
1205             return PpAtomConstString;
1206         case ':':
1207             ch = getch();
1208             if (ch == ':')
1209                 return PpAtomColonColon;
1210             ungetch();
1211             return ':';
1212         }
1213 
1214         ch = getch();
1215     }
1216 }
1217 
1218 //
1219 // The main functional entry point into the preprocessor, which will
1220 // scan the source strings to figure out and return the next processing token.
1221 //
1222 // Return the token, or EndOfInput when no more tokens.
1223 //
tokenize(TPpToken & ppToken)1224 int TPpContext::tokenize(TPpToken& ppToken)
1225 {
1226     for(;;) {
1227         int token = scanToken(&ppToken);
1228 
1229         // Handle token-pasting logic
1230         token = tokenPaste(token, ppToken);
1231 
1232         if (token == EndOfInput) {
1233             missingEndifCheck();
1234             return EndOfInput;
1235         }
1236         if (token == '#') {
1237             if (previous_token == '\n') {
1238                 token = readCPPline(&ppToken);
1239                 if (token == EndOfInput) {
1240                     missingEndifCheck();
1241                     return EndOfInput;
1242                 }
1243                 continue;
1244             } else {
1245                 parseContext.ppError(ppToken.loc, "preprocessor directive cannot be preceded by another token", "#", "");
1246                 return EndOfInput;
1247             }
1248         }
1249         previous_token = token;
1250 
1251         if (token == '\n')
1252             continue;
1253 
1254         // expand macros
1255         if (token == PpAtomIdentifier) {
1256             switch (MacroExpand(&ppToken, false, true)) {
1257             case MacroExpandNotStarted:
1258                 break;
1259             case MacroExpandError:
1260                 return EndOfInput;
1261             case MacroExpandStarted:
1262             case MacroExpandUndef:
1263                 continue;
1264             }
1265         }
1266 
1267         switch (token) {
1268         case PpAtomIdentifier:
1269         case PpAtomConstInt:
1270         case PpAtomConstUint:
1271         case PpAtomConstFloat:
1272         case PpAtomConstInt64:
1273         case PpAtomConstUint64:
1274         case PpAtomConstInt16:
1275         case PpAtomConstUint16:
1276         case PpAtomConstDouble:
1277         case PpAtomConstFloat16:
1278             if (ppToken.name[0] == '\0')
1279                 continue;
1280             break;
1281         case PpAtomConstString:
1282             // HLSL allows string literals.
1283             // GLSL allows string literals with GL_EXT_debug_printf.
1284             if (ifdepth == 0 && parseContext.intermediate.getSource() != EShSourceHlsl) {
1285               const char* const string_literal_EXTs[] = { E_GL_EXT_debug_printf, E_GL_EXT_spirv_intrinsics };
1286               parseContext.requireExtensions(ppToken.loc, 2, string_literal_EXTs, "string literal");
1287               if (!parseContext.extensionTurnedOn(E_GL_EXT_debug_printf) &&
1288                   !parseContext.extensionTurnedOn(E_GL_EXT_spirv_intrinsics))
1289                   continue;
1290             }
1291             break;
1292         case '\'':
1293             parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
1294             continue;
1295         default:
1296             snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(token));
1297             break;
1298         }
1299 
1300         return token;
1301     }
1302 }
1303 
1304 //
1305 // Do all token-pasting related combining of two pasted tokens when getting a
1306 // stream of tokens from a replacement list. Degenerates to no processing if a
1307 // replacement list is not the source of the token stream.
1308 //
tokenPaste(int token,TPpToken & ppToken)1309 int TPpContext::tokenPaste(int token, TPpToken& ppToken)
1310 {
1311     // starting with ## is illegal, skip to next token
1312     if (token == PpAtomPaste) {
1313         parseContext.ppError(ppToken.loc, "unexpected location", "##", "");
1314         return scanToken(&ppToken);
1315     }
1316 
1317     int resultToken = token; // "foo" pasted with "35" is an identifier, not a number
1318 
1319     // ## can be chained, process all in the chain at once
1320     while (peekPasting()) {
1321         TPpToken pastedPpToken;
1322 
1323         // next token has to be ##
1324         token = scanToken(&pastedPpToken);
1325         assert(token == PpAtomPaste);
1326 
1327         // This covers end of macro expansion
1328         if (endOfReplacementList()) {
1329             parseContext.ppError(ppToken.loc, "unexpected location; end of replacement list", "##", "");
1330             break;
1331         }
1332 
1333         // Get the token(s) after the ##.
1334         // Because of "space" semantics, and prior tokenization, what
1335         // appeared a single token, e.g. "3A", might have been tokenized
1336         // into two tokens "3" and "A", but the "A" will have 'space' set to
1337         // false.  Accumulate all of these to recreate the original lexical
1338         // appearing token.
1339         do {
1340             token = scanToken(&pastedPpToken);
1341 
1342             // This covers end of argument expansion
1343             if (token == tMarkerInput::marker) {
1344                 parseContext.ppError(ppToken.loc, "unexpected location; end of argument", "##", "");
1345                 return resultToken;
1346             }
1347 
1348             // get the token text
1349             switch (resultToken) {
1350             case PpAtomIdentifier:
1351                 // already have the correct text in token.names
1352                 break;
1353             case '=':
1354             case '!':
1355             case '-':
1356             case '~':
1357             case '+':
1358             case '*':
1359             case '/':
1360             case '%':
1361             case '<':
1362             case '>':
1363             case '|':
1364             case '^':
1365             case '&':
1366             case PpAtomRight:
1367             case PpAtomLeft:
1368             case PpAtomAnd:
1369             case PpAtomOr:
1370             case PpAtomXor:
1371                 snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(resultToken));
1372                 snprintf(pastedPpToken.name, sizeof(pastedPpToken.name), "%s", atomStrings.getString(token));
1373                 break;
1374             default:
1375                 parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", "");
1376                 return resultToken;
1377             }
1378 
1379             // combine the tokens
1380             if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) {
1381                 parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", "");
1382                 return resultToken;
1383             }
1384             snprintf(&ppToken.name[0] + strlen(ppToken.name), sizeof(ppToken.name) - strlen(ppToken.name),
1385                 "%s", pastedPpToken.name);
1386 
1387             // correct the kind of token we are making, if needed (identifiers stay identifiers)
1388             if (resultToken != PpAtomIdentifier) {
1389                 int newToken = atomStrings.getAtom(ppToken.name);
1390                 if (newToken > 0)
1391                     resultToken = newToken;
1392                 else
1393                     parseContext.ppError(ppToken.loc, "combined token is invalid", "##", "");
1394             }
1395         } while (peekContinuedPasting(resultToken));
1396     }
1397 
1398     return resultToken;
1399 }
1400 
1401 // Checks if we've seen balanced #if...#endif
missingEndifCheck()1402 void TPpContext::missingEndifCheck()
1403 {
1404     if (ifdepth > 0)
1405         parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", "");
1406 }
1407 
1408 } // end namespace glslang
1409