719365d4aaadf43aa4437c4615b58d4cde3a99a4
[platform/upstream/glslang.git] / glslang / MachineIndependent / preprocessor / PpScanner.cpp
1 //
2 //Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 //Copyright (C) 2013 LunarG, Inc.
4 //All rights reserved.
5 //
6 //Redistribution and use in source and binary forms, with or without
7 //modification, are permitted provided that the following conditions
8 //are met:
9 //
10 //    Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 //
13 //    Redistributions in binary form must reproduce the above
14 //    copyright notice, this list of conditions and the following
15 //    disclaimer in the documentation and/or other materials provided
16 //    with the distribution.
17 //
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 //    contributors may be used to endorse or promote products derived
20 //    from this software without specific prior written permission.
21 //
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 //POSSIBILITY OF SUCH DAMAGE.
34 //
35 /****************************************************************************\
36 Copyright (c) 2002, NVIDIA Corporation.
37
38 NVIDIA Corporation("NVIDIA") supplies this software to you in
39 consideration of your agreement to the following terms, and your use,
40 installation, modification or redistribution of this NVIDIA software
41 constitutes acceptance of these terms.  If you do not agree with these
42 terms, please do not use, install, modify or redistribute this NVIDIA
43 software.
44
45 In consideration of your agreement to abide by the following terms, and
46 subject to these terms, NVIDIA grants you a personal, non-exclusive
47 license, under NVIDIA's copyrights in this original NVIDIA software (the
48 "NVIDIA Software"), to use, reproduce, modify and redistribute the
49 NVIDIA Software, with or without modifications, in source and/or binary
50 forms; provided that if you redistribute the NVIDIA Software, you must
51 retain the copyright notice of NVIDIA, this notice and the following
52 text and disclaimers in all such redistributions of the NVIDIA Software.
53 Neither the name, trademarks, service marks nor logos of NVIDIA
54 Corporation may be used to endorse or promote products derived from the
55 NVIDIA Software without specific prior written permission from NVIDIA.
56 Except as expressly stated in this notice, no other rights or licenses
57 express or implied, are granted by NVIDIA herein, including but not
58 limited to any patent rights that may be infringed by your derivative
59 works or by other works in which the NVIDIA Software may be
60 incorporated. No hardware is licensed hereunder. 
61
62 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
63 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
64 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
65 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
66 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
67 PRODUCTS.
68
69 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
70 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
71 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
72 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
73 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
74 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
75 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
76 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
77 \****************************************************************************/
78 //
79 // scanner.c
80 //
81
82 #define _CRT_SECURE_NO_WARNINGS
83
84 #include <stdarg.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88
89 #include "PpContext.h"
90 #include "PpTokens.h"
91 #include "../Scan.h"
92
93 namespace glslang {
94
95 int TPpContext::InitScanner()
96 {
97     // Add various atoms needed by the CPP line scanner:
98     if (!InitCPP())
99         return 0;
100
101     previous_token = '\n';
102
103     return 1;
104 }
105
106 ///////////////////////////////////////////////////////////////////////////////////////////////
107 /////////////////////////////////// Floating point constants: /////////////////////////////////
108 ///////////////////////////////////////////////////////////////////////////////////////////////
109
110 /*
111 * lFloatConst() - Scan a single- or double-precision floating point constant.  Assumes that the scanner
112 *         has seen at least one digit, followed by either a decimal '.' or the
113 *         letter 'e', or a precision ending (e.g., F or LF).
114 */
115
116 int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
117 {
118     bool HasDecimalOrExponent = false;
119     int declen;
120     int str_len;
121     int isDouble = 0;
122
123     declen = 0;
124
125     str_len=len;
126     char* str = ppToken->name;
127     if (ch == '.') {
128         HasDecimalOrExponent = true;
129         str[len++] = (char)ch;
130         ch = getChar();
131         while (ch >= '0' && ch <= '9') {
132             if (len < MaxTokenLength) {
133                 declen++;
134                 if (len > 0 || ch != '0') {
135                     str[len] = (char)ch;
136                     len++;
137                     str_len++;
138                 }
139                 ch = getChar();
140             } else {
141                 parseContext.ppError(ppToken->loc, "float literal too long", "", "");
142                 len = 1;
143                 str_len = 1;
144             }
145         }
146     }
147
148     // Exponent:
149
150     if (ch == 'e' || ch == 'E') {
151         HasDecimalOrExponent = true;
152         if (len >= MaxTokenLength) {
153             parseContext.ppError(ppToken->loc, "float literal too long", "", "");
154             len = 1;
155             str_len = 1;
156         } else {
157             str[len++] = (char)ch;
158             ch = getChar();
159             if (ch == '+') {
160                 str[len++] = (char)ch;
161                 ch = getChar();
162             } else if (ch == '-') {
163                 str[len++] = (char)ch;
164                 ch = getChar();
165             }
166             if (ch >= '0' && ch <= '9') {
167                 while (ch >= '0' && ch <= '9') {
168                     if (len < MaxTokenLength) {
169                         str[len++] = (char)ch;
170                         ch = getChar();
171                     } else {
172                         parseContext.ppError(ppToken->loc, "float literal too long", "", "");
173                         len = 1;
174                         str_len = 1;
175                     }
176                 }
177             } else {
178                 parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
179             }
180         }
181     }
182
183     if (len == 0) {
184         ppToken->dval = 0.0;
185         strcpy(str, "0.0");
186     } else {
187         if (ch == 'l' || ch == 'L') {
188             parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
189             if (! HasDecimalOrExponent)
190                 parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
191             int ch2 = getChar();
192             if (ch2 != 'f' && ch2 != 'F') {
193                 ungetChar();
194                 ungetChar();
195             } else {
196                 if (len < MaxTokenLength) {
197                     str[len++] = (char)ch;
198                     str[len++] = (char)ch2;
199                     isDouble = 1;
200                 } else {
201                     parseContext.ppError(ppToken->loc, "float literal too long", "", "");
202                     len = 1,str_len=1;
203                 }
204             }
205         } else if (ch == 'f' || ch == 'F') {
206             parseContext.profileRequires(ppToken->loc,  EEsProfile, 300, nullptr, "floating-point suffix");
207             if (! parseContext.relaxedErrors())
208                 parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
209             if (! HasDecimalOrExponent)
210                 parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
211             if (len < MaxTokenLength)
212                 str[len++] = (char)ch;
213             else {
214                 parseContext.ppError(ppToken->loc, "float literal too long", "", "");
215                 len = 1,str_len=1;
216             }
217         } else 
218             ungetChar();
219
220         str[len]='\0';
221
222         ppToken->dval = strtod(str, nullptr);
223     }
224
225     if (isDouble)
226         return PpAtomConstDouble;
227     else
228         return PpAtomConstFloat;
229 }
230
231 //
232 // Scanner used to tokenize source stream.
233 //
234 int TPpContext::tStringInput::scan(TPpToken* ppToken)
235 {
236     char* tokenText = ppToken->name;
237     int AlreadyComplained = 0;
238     int len = 0;
239     int ch = 0;
240     int ii = 0;
241     unsigned ival = 0;
242
243     ppToken->ival = 0;
244     ppToken->space = false;
245     ch = getch();
246     for (;;) {
247         while (ch == ' ' || ch == '\t') {
248             ppToken->space = true;
249             ch = getch();
250         }
251
252         ppToken->loc = pp->parseContext.getCurrentLoc();
253         len = 0;
254         switch (ch) {
255         default:
256             // Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token)
257             return ch;
258
259         case 'A': case 'B': case 'C': case 'D': case 'E':
260         case 'F': case 'G': case 'H': case 'I': case 'J':
261         case 'K': case 'L': case 'M': case 'N': case 'O':
262         case 'P': case 'Q': case 'R': case 'S': case 'T':
263         case 'U': case 'V': case 'W': case 'X': case 'Y':
264         case 'Z': case '_':
265         case 'a': case 'b': case 'c': case 'd': case 'e':
266         case 'f': case 'g': case 'h': case 'i': case 'j':
267         case 'k': case 'l': case 'm': case 'n': case 'o':
268         case 'p': case 'q': case 'r': case 's': case 't':
269         case 'u': case 'v': case 'w': case 'x': case 'y':
270         case 'z':
271             do {
272                 if (len < MaxTokenLength) {
273                     tokenText[len++] = (char)ch;
274                     ch = getch();
275                 } else {
276                     if (! AlreadyComplained) {
277                         pp->parseContext.ppError(ppToken->loc, "name too long", "", "");
278                         AlreadyComplained = 1;
279                     }
280                     ch = getch();
281                 }
282             } while ((ch >= 'a' && ch <= 'z') ||
283                      (ch >= 'A' && ch <= 'Z') ||
284                      (ch >= '0' && ch <= '9') ||
285                      ch == '_');
286
287             // line continuation with no token before or after makes len == 0, and need to start over skipping white space, etc.
288             if (len == 0)
289                 continue;
290
291             tokenText[len] = '\0';
292             ungetch();
293             ppToken->atom = pp->LookUpAddString(tokenText);
294             return PpAtomIdentifier;
295         case '0':
296             ppToken->name[len++] = (char)ch;
297             ch = getch();
298             if (ch == 'x' || ch == 'X') {
299                 // must be hexidecimal
300
301                 bool isUnsigned = false;
302                 ppToken->name[len++] = (char)ch;
303                 ch = getch();
304                 if ((ch >= '0' && ch <= '9') ||
305                     (ch >= 'A' && ch <= 'F') ||
306                     (ch >= 'a' && ch <= 'f')) {
307
308                     ival = 0;
309                     do {
310                         if (ival <= 0x0fffffff) {
311                             ppToken->name[len++] = (char)ch;
312                             if (ch >= '0' && ch <= '9') {
313                                 ii = ch - '0';
314                             } else if (ch >= 'A' && ch <= 'F') {
315                                 ii = ch - 'A' + 10;
316                             } else if (ch >= 'a' && ch <= 'f') {
317                                 ii = ch - 'a' + 10;
318                             } else
319                                 pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
320                             ival = (ival << 4) | ii;
321                         } else {
322                             if (! AlreadyComplained) {
323                                 pp->parseContext.ppError(ppToken->loc, "hexidecimal literal too big", "", "");
324                                 AlreadyComplained = 1;
325                             }
326                             ival = 0xffffffff;
327                         }
328                         ch = getch();
329                     } while ((ch >= '0' && ch <= '9') ||
330                              (ch >= 'A' && ch <= 'F') ||
331                              (ch >= 'a' && ch <= 'f'));
332                 } else {
333                     pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
334                 }
335                 if (ch == 'u' || ch == 'U') {
336                     if (len < MaxTokenLength)
337                         ppToken->name[len++] = (char)ch;
338                     isUnsigned = true;
339                 } else
340                     ungetch();
341                 ppToken->name[len] = '\0';
342                 ppToken->ival = (int)ival;
343
344                 if (isUnsigned)
345                     return PpAtomConstUint;
346                 else
347                     return PpAtomConstInt;
348             } else {
349                 // could be octal integer or floating point, speculative pursue octal until it must be floating point
350
351                 bool isUnsigned = false;
352                 bool octalOverflow = false;
353                 bool nonOctal = false;
354                 ival = 0;
355
356                 // see how much octal-like stuff we can read
357                 while (ch >= '0' && ch <= '7') {
358                     if (len < MaxTokenLength)
359                         ppToken->name[len++] = (char)ch;
360                     else if (! AlreadyComplained) {
361                         pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
362                         AlreadyComplained = 1;
363                     }
364                     if (ival <= 0x1fffffff) {
365                         ii = ch - '0';
366                         ival = (ival << 3) | ii;
367                     } else
368                         octalOverflow = true;
369                     ch = getch();
370                 }
371
372                 // could be part of a float...
373                 if (ch == '8' || ch == '9') {
374                     nonOctal = true;
375                     do {
376                         if (len < MaxTokenLength)
377                             ppToken->name[len++] = (char)ch;
378                         else if (! AlreadyComplained) {
379                             pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
380                             AlreadyComplained = 1;
381                         }
382                         ch = getch();
383                     } while (ch >= '0' && ch <= '9');
384                 }
385                 if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F' || ch == 'l' || ch == 'L') 
386                     return pp->lFloatConst(len, ch, ppToken);
387                 
388                 // wasn't a float, so must be octal...
389                 if (nonOctal)
390                     pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", "");
391
392                 if (ch == 'u' || ch == 'U') {
393                     if (len < MaxTokenLength)
394                         ppToken->name[len++] = (char)ch;
395                     isUnsigned = true;
396                 } else
397                     ungetch();
398                 ppToken->name[len] = '\0';
399
400                 if (octalOverflow)
401                     pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", "");
402
403                 ppToken->ival = (int)ival;
404
405                 if (isUnsigned)
406                     return PpAtomConstUint;
407                 else
408                     return PpAtomConstInt;
409             }
410             break;
411         case '1': case '2': case '3': case '4':
412         case '5': case '6': case '7': case '8': case '9':
413             // can't be hexidecimal or octal, is either decimal or floating point
414
415             do {
416                 if (len < MaxTokenLength)
417                     ppToken->name[len++] = (char)ch;
418                 else if (! AlreadyComplained) {
419                     pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
420                     AlreadyComplained = 1;
421                 }
422                 ch = getch();
423             } while (ch >= '0' && ch <= '9');
424             if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F' || ch == 'l' || ch == 'L') {
425                 return pp->lFloatConst(len, ch, ppToken);
426             } else {
427                 // Finish handling signed and unsigned integers
428                 int numericLen = len;
429                 bool uint = false;
430                 if (ch == 'u' || ch == 'U') {
431                     if (len < MaxTokenLength)
432                         ppToken->name[len++] = (char)ch;
433                     uint = true;
434                 } else
435                     ungetch();
436
437                 ppToken->name[len] = '\0';
438                 ival = 0;
439                 const unsigned oneTenthMaxInt  = 0xFFFFFFFFu / 10;
440                 const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt;
441                 for (int i = 0; i < numericLen; i++) {
442                     ch = ppToken->name[i] - '0';
443                     if ((ival > oneTenthMaxInt) || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt)) {
444                         pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", "");
445                         ival = 0xFFFFFFFFu;
446                         break;
447                     } else
448                         ival = ival * 10 + ch;
449                 }
450                 ppToken->ival = (int)ival;
451
452                 if (uint)
453                     return PpAtomConstUint;
454                 else
455                     return PpAtomConstInt;
456             }
457             break;
458         case '-':
459             ch = getch();
460             if (ch == '-') {
461                 return PpAtomDecrement;
462             } else if (ch == '=') {
463                 return PpAtomSub;
464             } else {
465                 ungetch();
466                 return '-';
467             }
468         case '+':
469             ch = getch();
470             if (ch == '+') {
471                 return PpAtomIncrement;
472             } else if (ch == '=') {
473                 return PpAtomAdd;
474             } else {
475                 ungetch();
476                 return '+';
477             }
478         case '*':
479             ch = getch();
480             if (ch == '=') {
481                 return PpAtomMul;
482             } else {
483                 ungetch();
484                 return '*';
485             }
486         case '%':
487             ch = getch();
488             if (ch == '=') {
489                 return PpAtomMod;
490             } else {
491                 ungetch();
492                 return '%';
493             }
494         case '^':
495             ch = getch();
496             if (ch == '^') {
497                 return PpAtomXor;
498             } else {
499                 if (ch == '=')
500                     return PpAtomXorAssign;
501                 else{
502                     ungetch();
503                     return '^';
504                 }
505             }
506
507         case '=':
508             ch = getch();
509             if (ch == '=') {
510                 return PpAtomEQ;
511             } else {
512                 ungetch();
513                 return '=';
514             }
515         case '!':
516             ch = getch();
517             if (ch == '=') {
518                 return PpAtomNE;
519             } else {
520                 ungetch();
521                 return '!';
522             }
523         case '|':
524             ch = getch();
525             if (ch == '|') {
526                 return PpAtomOr;
527             } else if (ch == '=') {
528                 return PpAtomOrAssign;
529             } else {
530                 ungetch();
531                 return '|';
532             }
533         case '&':
534             ch = getch();
535             if (ch == '&') {
536                 return PpAtomAnd;
537             } else if (ch == '=') {
538                 return PpAtomAndAssign;
539             } else {
540                 ungetch();
541                 return '&';
542             }
543         case '<':
544             ch = getch();
545             if (ch == '<') {
546                 ch = getch();
547                 if (ch == '=')
548                     return PpAtomLeftAssign;
549                 else {
550                     ungetch();
551                     return PpAtomLeft;
552                 }
553             } else if (ch == '=') {
554                 return PpAtomLE;
555             } else {
556                 ungetch();
557                 return '<';
558             }
559         case '>':
560             ch = getch();
561             if (ch == '>') {
562                 ch = getch();
563                 if (ch == '=')
564                     return PpAtomRightAssign;
565                 else {
566                     ungetch();
567                     return PpAtomRight;
568                 }
569             } else if (ch == '=') {
570                 return PpAtomGE;
571             } else {
572                 ungetch();
573                 return '>';
574             }
575         case '.':
576             ch = getch();
577             if (ch >= '0' && ch <= '9') {
578                 ungetch();
579                 return pp->lFloatConst(0, '.', ppToken);
580             } else {
581                 ungetch();
582                 return '.';
583             }
584         case '/':
585             ch = getch();
586             if (ch == '/') {
587                 pp->inComment = true;
588                 do {
589                     ch = getch();
590                 } while (ch != '\n' && ch != EndOfInput);
591                 ppToken->space = true;
592                 pp->inComment = false;
593
594                 return ch;
595             } else if (ch == '*') {
596                 ch = getch();
597                 do {
598                     while (ch != '*') {
599                         if (ch == EndOfInput) {
600                             pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
601                             return ch;
602                         }
603                         ch = getch();
604                     }
605                     ch = getch();
606                     if (ch == EndOfInput) {
607                         pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
608                         return ch;
609                     }
610                 } while (ch != '/');
611                 ppToken->space = true;
612                 // loop again to get the next token...
613                 break;
614             } else if (ch == '=') {
615                 return PpAtomDiv;
616             } else {
617                 ungetch();
618                 return '/';
619             }
620             break;
621         case '"':
622             ch = getch();
623             while (ch != '"' && ch != '\n' && ch != EndOfInput) {
624                 if (len < MaxTokenLength) {
625                     tokenText[len] = (char)ch;
626                     len++;
627                     ch = getch();
628                 } else
629                     break;
630             };
631             tokenText[len] = '\0';
632             if (ch != '"') {
633                 ungetch();
634                 pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
635             }
636             return PpAtomConstString;
637         }
638
639         ch = getch();
640     }
641 }
642
643 //
644 // The main functional entry-point into the preprocessor, which will
645 // scan the source strings to figure out and return the next processing token.
646 //
647 // Return string pointer to next token.
648 // Return 0 when no more tokens.
649 //
650 const char* TPpContext::tokenize(TPpToken* ppToken)
651 {    
652     int token = '\n';
653
654     for(;;) {
655         token = scanToken(ppToken);
656         ppToken->token = token;
657         if (token == EndOfInput) {
658             missingEndifCheck();
659             return nullptr;
660         }
661         if (token == '#') {
662             if (previous_token == '\n') {
663                 token = readCPPline(ppToken);
664                 if (token == EndOfInput) {
665                     missingEndifCheck();
666                     return nullptr;
667                 }
668                 continue;
669             } else {
670                 parseContext.ppError(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", "");
671                 return nullptr;
672             }
673         }
674         previous_token = token;
675
676         if (token == '\n')
677             continue;
678
679         // expand macros
680         if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, true) != 0)
681             continue;
682
683         const char* tokenString = nullptr;
684         switch (token) {
685         case PpAtomIdentifier:
686         case PpAtomConstInt:
687         case PpAtomConstUint:
688         case PpAtomConstFloat:
689         case PpAtomConstDouble:
690             tokenString = ppToken->name;
691             break;
692         case PpAtomConstString:
693             parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", "");
694             break;
695         case '\'':
696             parseContext.ppError(ppToken->loc, "character literals not supported", "\'", "");
697             break;
698         default:
699             tokenString = GetAtomString(token);
700             break;
701         }
702
703         if (tokenString) {
704             if (tokenString[0] != 0)
705                 parseContext.tokensBeforeEOF = 1;
706
707             return tokenString;
708         }
709     }
710 }
711
712 // Checks if we've seen balanced #if...#endif
713 void TPpContext::missingEndifCheck()
714 {
715     if (ifdepth > 0)
716         parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", "");
717 }
718
719 } // end namespace glslang