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