Home | History | Annotate | Download | only in preprocessor
      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 long long ival = 0;
    242     bool enableInt64 = pp->parseContext.version >= 450 && pp->parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_int64);
    243 
    244     ppToken->ival = 0;
    245     ppToken->i64val = 0;
    246     ppToken->space = false;
    247     ch = getch();
    248     for (;;) {
    249         while (ch == ' ' || ch == '\t') {
    250             ppToken->space = true;
    251             ch = getch();
    252         }
    253 
    254         ppToken->loc = pp->parseContext.getCurrentLoc();
    255         len = 0;
    256         switch (ch) {
    257         default:
    258             // Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token)
    259             return ch;
    260 
    261         case 'A': case 'B': case 'C': case 'D': case 'E':
    262         case 'F': case 'G': case 'H': case 'I': case 'J':
    263         case 'K': case 'L': case 'M': case 'N': case 'O':
    264         case 'P': case 'Q': case 'R': case 'S': case 'T':
    265         case 'U': case 'V': case 'W': case 'X': case 'Y':
    266         case 'Z': case '_':
    267         case 'a': case 'b': case 'c': case 'd': case 'e':
    268         case 'f': case 'g': case 'h': case 'i': case 'j':
    269         case 'k': case 'l': case 'm': case 'n': case 'o':
    270         case 'p': case 'q': case 'r': case 's': case 't':
    271         case 'u': case 'v': case 'w': case 'x': case 'y':
    272         case 'z':
    273             do {
    274                 if (len < MaxTokenLength) {
    275                     tokenText[len++] = (char)ch;
    276                     ch = getch();
    277                 } else {
    278                     if (! AlreadyComplained) {
    279                         pp->parseContext.ppError(ppToken->loc, "name too long", "", "");
    280                         AlreadyComplained = 1;
    281                     }
    282                     ch = getch();
    283                 }
    284             } while ((ch >= 'a' && ch <= 'z') ||
    285                      (ch >= 'A' && ch <= 'Z') ||
    286                      (ch >= '0' && ch <= '9') ||
    287                      ch == '_');
    288 
    289             // line continuation with no token before or after makes len == 0, and need to start over skipping white space, etc.
    290             if (len == 0)
    291                 continue;
    292 
    293             tokenText[len] = '\0';
    294             ungetch();
    295             ppToken->atom = pp->LookUpAddString(tokenText);
    296             return PpAtomIdentifier;
    297         case '0':
    298             ppToken->name[len++] = (char)ch;
    299             ch = getch();
    300             if (ch == 'x' || ch == 'X') {
    301                 // must be hexidecimal
    302 
    303                 bool isUnsigned = false;
    304                 bool isInt64 = false;
    305                 ppToken->name[len++] = (char)ch;
    306                 ch = getch();
    307                 if ((ch >= '0' && ch <= '9') ||
    308                     (ch >= 'A' && ch <= 'F') ||
    309                     (ch >= 'a' && ch <= 'f')) {
    310 
    311                     ival = 0;
    312                     do {
    313                         if (ival <= 0x0fffffff || (enableInt64 && ival <= 0x0fffffffffffffffull)) {
    314                             ppToken->name[len++] = (char)ch;
    315                             if (ch >= '0' && ch <= '9') {
    316                                 ii = ch - '0';
    317                             } else if (ch >= 'A' && ch <= 'F') {
    318                                 ii = ch - 'A' + 10;
    319                             } else if (ch >= 'a' && ch <= 'f') {
    320                                 ii = ch - 'a' + 10;
    321                             } else
    322                                 pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
    323                             ival = (ival << 4) | ii;
    324                         } else {
    325                             if (! AlreadyComplained) {
    326                                 pp->parseContext.ppError(ppToken->loc, "hexidecimal literal too big", "", "");
    327                                 AlreadyComplained = 1;
    328                             }
    329                             ival = 0xffffffffffffffffull;
    330                         }
    331                         ch = getch();
    332                     } while ((ch >= '0' && ch <= '9') ||
    333                              (ch >= 'A' && ch <= 'F') ||
    334                              (ch >= 'a' && ch <= 'f'));
    335                 } else {
    336                     pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
    337                 }
    338                 if (ch == 'u' || ch == 'U') {
    339                     if (len < MaxTokenLength)
    340                         ppToken->name[len++] = (char)ch;
    341                     isUnsigned = true;
    342 
    343                     if (enableInt64) {
    344                         int nextCh = getch();
    345                         if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
    346                             if (len < MaxTokenLength)
    347                                 ppToken->name[len++] = (char)nextCh;
    348                             isInt64 = true;
    349                         } else
    350                             ungetch();
    351                     }
    352                 }
    353                 else if (enableInt64 && (ch == 'l' || ch == 'L')) {
    354                     if (len < MaxTokenLength)
    355                         ppToken->name[len++] = (char)ch;
    356                     isInt64 = true;
    357                 } else
    358                     ungetch();
    359                 ppToken->name[len] = '\0';
    360 
    361                 if (isInt64) {
    362                     ppToken->i64val = ival;
    363                     return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
    364                 } else {
    365                     ppToken->ival = (int)ival;
    366                     return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
    367                 }
    368             } else {
    369                 // could be octal integer or floating point, speculative pursue octal until it must be floating point
    370 
    371                 bool isUnsigned = false;
    372                 bool isInt64 = false;
    373                 bool octalOverflow = false;
    374                 bool nonOctal = false;
    375                 ival = 0;
    376 
    377                 // see how much octal-like stuff we can read
    378                 while (ch >= '0' && ch <= '7') {
    379                     if (len < MaxTokenLength)
    380                         ppToken->name[len++] = (char)ch;
    381                     else if (! AlreadyComplained) {
    382                         pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
    383                         AlreadyComplained = 1;
    384                     }
    385                     if (ival <= 0x1fffffff || (enableInt64 && ival <= 0x1fffffffffffffffull)) {
    386                         ii = ch - '0';
    387                         ival = (ival << 3) | ii;
    388                     } else
    389                         octalOverflow = true;
    390                     ch = getch();
    391                 }
    392 
    393                 // could be part of a float...
    394                 if (ch == '8' || ch == '9') {
    395                     nonOctal = true;
    396                     do {
    397                         if (len < MaxTokenLength)
    398                             ppToken->name[len++] = (char)ch;
    399                         else if (! AlreadyComplained) {
    400                             pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
    401                             AlreadyComplained = 1;
    402                         }
    403                         ch = getch();
    404                     } while (ch >= '0' && ch <= '9');
    405                 }
    406                 if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F')
    407                     return pp->lFloatConst(len, ch, ppToken);
    408 
    409                 // wasn't a float, so must be octal...
    410                 if (nonOctal)
    411                     pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", "");
    412 
    413                 if (ch == 'u' || ch == 'U') {
    414                     if (len < MaxTokenLength)
    415                         ppToken->name[len++] = (char)ch;
    416                     isUnsigned = true;
    417 
    418                     if (enableInt64) {
    419                         int nextCh = getch();
    420                         if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
    421                             if (len < MaxTokenLength)
    422                                 ppToken->name[len++] = (char)nextCh;
    423                             isInt64 = true;
    424                         } else
    425                             ungetch();
    426                     }
    427                 }
    428                 else if (enableInt64 && (ch == 'l' || ch == 'L')) {
    429                     if (len < MaxTokenLength)
    430                         ppToken->name[len++] = (char)ch;
    431                     isInt64 = true;
    432                 } else
    433                     ungetch();
    434                 ppToken->name[len] = '\0';
    435 
    436                 if (octalOverflow)
    437                     pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", "");
    438 
    439                 if (isInt64) {
    440                     ppToken->i64val = ival;
    441                     return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
    442                 } else {
    443                     ppToken->ival = (int)ival;
    444                     return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
    445                 }
    446             }
    447             break;
    448         case '1': case '2': case '3': case '4':
    449         case '5': case '6': case '7': case '8': case '9':
    450             // can't be hexidecimal or octal, is either decimal or floating point
    451 
    452             do {
    453                 if (len < MaxTokenLength)
    454                     ppToken->name[len++] = (char)ch;
    455                 else if (! AlreadyComplained) {
    456                     pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
    457                     AlreadyComplained = 1;
    458                 }
    459                 ch = getch();
    460             } while (ch >= '0' && ch <= '9');
    461             if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F') {
    462                 return pp->lFloatConst(len, ch, ppToken);
    463             } else {
    464                 // Finish handling signed and unsigned integers
    465                 int numericLen = len;
    466                 bool isUnsigned = false;
    467                 bool isInt64 = false;
    468                 if (ch == 'u' || ch == 'U') {
    469                     if (len < MaxTokenLength)
    470                         ppToken->name[len++] = (char)ch;
    471                     isUnsigned = true;
    472 
    473                     if (enableInt64) {
    474                         int nextCh = getch();
    475                         if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
    476                             if (len < MaxTokenLength)
    477                                 ppToken->name[len++] = (char)nextCh;
    478                             isInt64 = true;
    479                         } else
    480                             ungetch();
    481                     }
    482                 } else if (enableInt64 && (ch == 'l' || ch == 'L')) {
    483                     if (len < MaxTokenLength)
    484                         ppToken->name[len++] = (char)ch;
    485                     isInt64 = true;
    486                 } else
    487                     ungetch();
    488 
    489                 ppToken->name[len] = '\0';
    490                 ival = 0;
    491                 const unsigned oneTenthMaxInt  = 0xFFFFFFFFu / 10;
    492                 const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt;
    493                 const unsigned long long oneTenthMaxInt64  = 0xFFFFFFFFFFFFFFFFull / 10;
    494                 const unsigned long long remainderMaxInt64 = 0xFFFFFFFFFFFFFFFFull - 10 * oneTenthMaxInt64;
    495                 for (int i = 0; i < numericLen; i++) {
    496                     ch = ppToken->name[i] - '0';
    497                     if ((enableInt64 == false && ((ival > oneTenthMaxInt) || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt))) ||
    498                         (enableInt64 && ((ival > oneTenthMaxInt64) || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64)))) {
    499                         pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", "");
    500                         ival = 0xFFFFFFFFFFFFFFFFull;
    501                         break;
    502                     } else
    503                         ival = ival * 10 + ch;
    504                 }
    505 
    506                 if (isInt64) {
    507                     ppToken->i64val = ival;
    508                     return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
    509                 } else {
    510                     ppToken->ival = (int)ival;
    511                     return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
    512                 }
    513             }
    514             break;
    515         case '-':
    516             ch = getch();
    517             if (ch == '-') {
    518                 return PpAtomDecrement;
    519             } else if (ch == '=') {
    520                 return PpAtomSub;
    521             } else {
    522                 ungetch();
    523                 return '-';
    524             }
    525         case '+':
    526             ch = getch();
    527             if (ch == '+') {
    528                 return PpAtomIncrement;
    529             } else if (ch == '=') {
    530                 return PpAtomAdd;
    531             } else {
    532                 ungetch();
    533                 return '+';
    534             }
    535         case '*':
    536             ch = getch();
    537             if (ch == '=') {
    538                 return PpAtomMul;
    539             } else {
    540                 ungetch();
    541                 return '*';
    542             }
    543         case '%':
    544             ch = getch();
    545             if (ch == '=') {
    546                 return PpAtomMod;
    547             } else {
    548                 ungetch();
    549                 return '%';
    550             }
    551         case '^':
    552             ch = getch();
    553             if (ch == '^') {
    554                 return PpAtomXor;
    555             } else {
    556                 if (ch == '=')
    557                     return PpAtomXorAssign;
    558                 else{
    559                     ungetch();
    560                     return '^';
    561                 }
    562             }
    563 
    564         case '=':
    565             ch = getch();
    566             if (ch == '=') {
    567                 return PpAtomEQ;
    568             } else {
    569                 ungetch();
    570                 return '=';
    571             }
    572         case '!':
    573             ch = getch();
    574             if (ch == '=') {
    575                 return PpAtomNE;
    576             } else {
    577                 ungetch();
    578                 return '!';
    579             }
    580         case '|':
    581             ch = getch();
    582             if (ch == '|') {
    583                 return PpAtomOr;
    584             } else if (ch == '=') {
    585                 return PpAtomOrAssign;
    586             } else {
    587                 ungetch();
    588                 return '|';
    589             }
    590         case '&':
    591             ch = getch();
    592             if (ch == '&') {
    593                 return PpAtomAnd;
    594             } else if (ch == '=') {
    595                 return PpAtomAndAssign;
    596             } else {
    597                 ungetch();
    598                 return '&';
    599             }
    600         case '<':
    601             ch = getch();
    602             if (ch == '<') {
    603                 ch = getch();
    604                 if (ch == '=')
    605                     return PpAtomLeftAssign;
    606                 else {
    607                     ungetch();
    608                     return PpAtomLeft;
    609                 }
    610             } else if (ch == '=') {
    611                 return PpAtomLE;
    612             } else {
    613                 ungetch();
    614                 return '<';
    615             }
    616         case '>':
    617             ch = getch();
    618             if (ch == '>') {
    619                 ch = getch();
    620                 if (ch == '=')
    621                     return PpAtomRightAssign;
    622                 else {
    623                     ungetch();
    624                     return PpAtomRight;
    625                 }
    626             } else if (ch == '=') {
    627                 return PpAtomGE;
    628             } else {
    629                 ungetch();
    630                 return '>';
    631             }
    632         case '.':
    633             ch = getch();
    634             if (ch >= '0' && ch <= '9') {
    635                 ungetch();
    636                 return pp->lFloatConst(0, '.', ppToken);
    637             } else {
    638                 ungetch();
    639                 return '.';
    640             }
    641         case '/':
    642             ch = getch();
    643             if (ch == '/') {
    644                 pp->inComment = true;
    645                 do {
    646                     ch = getch();
    647                 } while (ch != '\n' && ch != EndOfInput);
    648                 ppToken->space = true;
    649                 pp->inComment = false;
    650 
    651                 return ch;
    652             } else if (ch == '*') {
    653                 ch = getch();
    654                 do {
    655                     while (ch != '*') {
    656                         if (ch == EndOfInput) {
    657                             pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
    658                             return ch;
    659                         }
    660                         ch = getch();
    661                     }
    662                     ch = getch();
    663                     if (ch == EndOfInput) {
    664                         pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
    665                         return ch;
    666                     }
    667                 } while (ch != '/');
    668                 ppToken->space = true;
    669                 // loop again to get the next token...
    670                 break;
    671             } else if (ch == '=') {
    672                 return PpAtomDiv;
    673             } else {
    674                 ungetch();
    675                 return '/';
    676             }
    677             break;
    678         case '"':
    679             ch = getch();
    680             while (ch != '"' && ch != '\n' && ch != EndOfInput) {
    681                 if (len < MaxTokenLength) {
    682                     tokenText[len] = (char)ch;
    683                     len++;
    684                     ch = getch();
    685                 } else
    686                     break;
    687             };
    688             tokenText[len] = '\0';
    689             if (ch != '"') {
    690                 ungetch();
    691                 pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
    692             }
    693             return PpAtomConstString;
    694         }
    695 
    696         ch = getch();
    697     }
    698 }
    699 
    700 //
    701 // The main functional entry-point into the preprocessor, which will
    702 // scan the source strings to figure out and return the next processing token.
    703 //
    704 // Return string pointer to next token.
    705 // Return 0 when no more tokens.
    706 //
    707 const char* TPpContext::tokenize(TPpToken* ppToken)
    708 {
    709     int token = '\n';
    710 
    711     for(;;) {
    712         token = scanToken(ppToken);
    713         ppToken->token = token;
    714         if (token == EndOfInput) {
    715             missingEndifCheck();
    716             return nullptr;
    717         }
    718         if (token == '#') {
    719             if (previous_token == '\n') {
    720                 token = readCPPline(ppToken);
    721                 if (token == EndOfInput) {
    722                     missingEndifCheck();
    723                     return nullptr;
    724                 }
    725                 continue;
    726             } else {
    727                 parseContext.ppError(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", "");
    728                 return nullptr;
    729             }
    730         }
    731         previous_token = token;
    732 
    733         if (token == '\n')
    734             continue;
    735 
    736         // expand macros
    737         if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, true) != 0)
    738             continue;
    739 
    740         const char* tokenString = nullptr;
    741         switch (token) {
    742         case PpAtomIdentifier:
    743         case PpAtomConstInt:
    744         case PpAtomConstUint:
    745         case PpAtomConstFloat:
    746         case PpAtomConstInt64:
    747         case PpAtomConstUint64:
    748         case PpAtomConstDouble:
    749             tokenString = ppToken->name;
    750             break;
    751         case PpAtomConstString:
    752             parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", "");
    753             break;
    754         case '\'':
    755             parseContext.ppError(ppToken->loc, "character literals not supported", "\'", "");
    756             break;
    757         default:
    758             tokenString = GetAtomString(token);
    759             break;
    760         }
    761 
    762         if (tokenString) {
    763             if (tokenString[0] != 0)
    764                 parseContext.tokensBeforeEOF = 1;
    765 
    766             return tokenString;
    767         }
    768     }
    769 }
    770 
    771 // Checks if we've seen balanced #if...#endif
    772 void TPpContext::missingEndifCheck()
    773 {
    774     if (ifdepth > 0)
    775         parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", "");
    776 }
    777 
    778 } // end namespace glslang
    779