| // |
| //Copyright (C) 2002-2005 3Dlabs Inc. Ltd. |
| //Copyright (C) 2013 LunarG, Inc. |
| //All rights reserved. |
| // |
| //Redistribution and use in source and binary forms, with or without |
| //modification, are permitted provided that the following conditions |
| //are met: |
| // |
| // Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // |
| // Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following |
| // disclaimer in the documentation and/or other materials provided |
| // with the distribution. |
| // |
| // Neither the name of 3Dlabs Inc. Ltd. nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| //POSSIBILITY OF SUCH DAMAGE. |
| // |
| /****************************************************************************\ |
| Copyright (c) 2002, NVIDIA Corporation. |
| |
| NVIDIA Corporation("NVIDIA") supplies this software to you in |
| consideration of your agreement to the following terms, and your use, |
| installation, modification or redistribution of this NVIDIA software |
| constitutes acceptance of these terms. If you do not agree with these |
| terms, please do not use, install, modify or redistribute this NVIDIA |
| software. |
| |
| In consideration of your agreement to abide by the following terms, and |
| subject to these terms, NVIDIA grants you a personal, non-exclusive |
| license, under NVIDIA's copyrights in this original NVIDIA software (the |
| "NVIDIA Software"), to use, reproduce, modify and redistribute the |
| NVIDIA Software, with or without modifications, in source and/or binary |
| forms; provided that if you redistribute the NVIDIA Software, you must |
| retain the copyright notice of NVIDIA, this notice and the following |
| text and disclaimers in all such redistributions of the NVIDIA Software. |
| Neither the name, trademarks, service marks nor logos of NVIDIA |
| Corporation may be used to endorse or promote products derived from the |
| NVIDIA Software without specific prior written permission from NVIDIA. |
| Except as expressly stated in this notice, no other rights or licenses |
| express or implied, are granted by NVIDIA herein, including but not |
| limited to any patent rights that may be infringed by your derivative |
| works or by other works in which the NVIDIA Software may be |
| incorporated. No hardware is licensed hereunder. |
| |
| THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT |
| WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, |
| NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR |
| ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER |
| PRODUCTS. |
| |
| IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, |
| INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
| TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY |
| OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE |
| NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, |
| TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF |
| NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| \****************************************************************************/ |
| // |
| // scanner.c |
| // |
| |
| #define _CRT_SECURE_NO_WARNINGS |
| |
| #include <cstdlib> |
| #include <cstring> |
| |
| #include "PpContext.h" |
| #include "PpTokens.h" |
| #include "../Scan.h" |
| |
| namespace glslang { |
| |
| int TPpContext::InitScanner() |
| { |
| // Add various atoms needed by the CPP line scanner: |
| if (!InitCPP()) |
| return 0; |
| |
| previous_token = '\n'; |
| |
| return 1; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////// Floating point constants: ///////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| /* |
| * lFloatConst() - Scan a single- or double-precision floating point constant. Assumes that the scanner |
| * has seen at least one digit, followed by either a decimal '.' or the |
| * letter 'e', or a precision ending (e.g., F or LF). |
| */ |
| |
| int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) |
| { |
| bool HasDecimalOrExponent = false; |
| int declen; |
| int str_len; |
| int isDouble = 0; |
| |
| declen = 0; |
| |
| str_len=len; |
| char* str = ppToken->name; |
| if (ch == '.') { |
| HasDecimalOrExponent = true; |
| str[len++] = (char)ch; |
| ch = getChar(); |
| while (ch >= '0' && ch <= '9') { |
| if (len < MaxTokenLength) { |
| declen++; |
| if (len > 0 || ch != '0') { |
| str[len] = (char)ch; |
| len++; |
| str_len++; |
| } |
| ch = getChar(); |
| } else { |
| parseContext.ppError(ppToken->loc, "float literal too long", "", ""); |
| len = 1; |
| str_len = 1; |
| } |
| } |
| } |
| |
| // Exponent: |
| |
| if (ch == 'e' || ch == 'E') { |
| HasDecimalOrExponent = true; |
| if (len >= MaxTokenLength) { |
| parseContext.ppError(ppToken->loc, "float literal too long", "", ""); |
| len = 1; |
| str_len = 1; |
| } else { |
| str[len++] = (char)ch; |
| ch = getChar(); |
| if (ch == '+') { |
| str[len++] = (char)ch; |
| ch = getChar(); |
| } else if (ch == '-') { |
| str[len++] = (char)ch; |
| ch = getChar(); |
| } |
| if (ch >= '0' && ch <= '9') { |
| while (ch >= '0' && ch <= '9') { |
| if (len < MaxTokenLength) { |
| str[len++] = (char)ch; |
| ch = getChar(); |
| } else { |
| parseContext.ppError(ppToken->loc, "float literal too long", "", ""); |
| len = 1; |
| str_len = 1; |
| } |
| } |
| } else { |
| parseContext.ppError(ppToken->loc, "bad character in float exponent", "", ""); |
| } |
| } |
| } |
| |
| if (len == 0) { |
| ppToken->dval = 0.0; |
| strcpy(str, "0.0"); |
| } else { |
| if (ch == 'l' || ch == 'L') { |
| parseContext.doubleCheck(ppToken->loc, "double floating-point suffix"); |
| if (! HasDecimalOrExponent) |
| parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); |
| int ch2 = getChar(); |
| if (ch2 != 'f' && ch2 != 'F') { |
| ungetChar(); |
| ungetChar(); |
| } else { |
| if (len < MaxTokenLength) { |
| str[len++] = (char)ch; |
| str[len++] = (char)ch2; |
| isDouble = 1; |
| } else { |
| parseContext.ppError(ppToken->loc, "float literal too long", "", ""); |
| len = 1,str_len=1; |
| } |
| } |
| } else if (ch == 'f' || ch == 'F') { |
| parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix"); |
| if (! parseContext.relaxedErrors()) |
| parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix"); |
| if (! HasDecimalOrExponent) |
| parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); |
| if (len < MaxTokenLength) |
| str[len++] = (char)ch; |
| else { |
| parseContext.ppError(ppToken->loc, "float literal too long", "", ""); |
| len = 1,str_len=1; |
| } |
| } else |
| ungetChar(); |
| |
| str[len]='\0'; |
| |
| ppToken->dval = strtod(str, nullptr); |
| } |
| |
| if (isDouble) |
| return PpAtomConstDouble; |
| else |
| return PpAtomConstFloat; |
| } |
| |
| // |
| // Scanner used to tokenize source stream. |
| // |
| int TPpContext::tStringInput::scan(TPpToken* ppToken) |
| { |
| char* tokenText = ppToken->name; |
| int AlreadyComplained = 0; |
| int len = 0; |
| int ch = 0; |
| int ii = 0; |
| unsigned long long ival = 0; |
| bool enableInt64 = pp->parseContext.version >= 450 && pp->parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_int64); |
| |
| ppToken->ival = 0; |
| ppToken->i64val = 0; |
| ppToken->space = false; |
| ch = getch(); |
| for (;;) { |
| while (ch == ' ' || ch == '\t') { |
| ppToken->space = true; |
| ch = getch(); |
| } |
| |
| ppToken->loc = pp->parseContext.getCurrentLoc(); |
| len = 0; |
| switch (ch) { |
| default: |
| // Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token) |
| return ch; |
| |
| case 'A': case 'B': case 'C': case 'D': case 'E': |
| case 'F': case 'G': case 'H': case 'I': case 'J': |
| case 'K': case 'L': case 'M': case 'N': case 'O': |
| case 'P': case 'Q': case 'R': case 'S': case 'T': |
| case 'U': case 'V': case 'W': case 'X': case 'Y': |
| case 'Z': case '_': |
| case 'a': case 'b': case 'c': case 'd': case 'e': |
| case 'f': case 'g': case 'h': case 'i': case 'j': |
| case 'k': case 'l': case 'm': case 'n': case 'o': |
| case 'p': case 'q': case 'r': case 's': case 't': |
| case 'u': case 'v': case 'w': case 'x': case 'y': |
| case 'z': |
| do { |
| if (len < MaxTokenLength) { |
| tokenText[len++] = (char)ch; |
| ch = getch(); |
| } else { |
| if (! AlreadyComplained) { |
| pp->parseContext.ppError(ppToken->loc, "name too long", "", ""); |
| AlreadyComplained = 1; |
| } |
| ch = getch(); |
| } |
| } while ((ch >= 'a' && ch <= 'z') || |
| (ch >= 'A' && ch <= 'Z') || |
| (ch >= '0' && ch <= '9') || |
| ch == '_'); |
| |
| // line continuation with no token before or after makes len == 0, and need to start over skipping white space, etc. |
| if (len == 0) |
| continue; |
| |
| tokenText[len] = '\0'; |
| ungetch(); |
| ppToken->atom = pp->LookUpAddString(tokenText); |
| return PpAtomIdentifier; |
| case '0': |
| ppToken->name[len++] = (char)ch; |
| ch = getch(); |
| if (ch == 'x' || ch == 'X') { |
| // must be hexadecimal |
| |
| bool isUnsigned = false; |
| bool isInt64 = false; |
| ppToken->name[len++] = (char)ch; |
| ch = getch(); |
| if ((ch >= '0' && ch <= '9') || |
| (ch >= 'A' && ch <= 'F') || |
| (ch >= 'a' && ch <= 'f')) { |
| |
| ival = 0; |
| do { |
| if (ival <= 0x0fffffff || (enableInt64 && ival <= 0x0fffffffffffffffull)) { |
| ppToken->name[len++] = (char)ch; |
| if (ch >= '0' && ch <= '9') { |
| ii = ch - '0'; |
| } else if (ch >= 'A' && ch <= 'F') { |
| ii = ch - 'A' + 10; |
| } else if (ch >= 'a' && ch <= 'f') { |
| ii = ch - 'a' + 10; |
| } else |
| pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", ""); |
| ival = (ival << 4) | ii; |
| } else { |
| if (! AlreadyComplained) { |
| pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", ""); |
| AlreadyComplained = 1; |
| } |
| ival = 0xffffffffffffffffull; |
| } |
| ch = getch(); |
| } while ((ch >= '0' && ch <= '9') || |
| (ch >= 'A' && ch <= 'F') || |
| (ch >= 'a' && ch <= 'f')); |
| } else { |
| pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", ""); |
| } |
| if (ch == 'u' || ch == 'U') { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| isUnsigned = true; |
| |
| if (enableInt64) { |
| int nextCh = getch(); |
| if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)nextCh; |
| isInt64 = true; |
| } else |
| ungetch(); |
| } |
| } |
| else if (enableInt64 && (ch == 'l' || ch == 'L')) { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| isInt64 = true; |
| } else |
| ungetch(); |
| ppToken->name[len] = '\0'; |
| |
| if (isInt64) { |
| ppToken->i64val = ival; |
| return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64; |
| } else { |
| ppToken->ival = (int)ival; |
| return isUnsigned ? PpAtomConstUint : PpAtomConstInt; |
| } |
| } else { |
| // could be octal integer or floating point, speculative pursue octal until it must be floating point |
| |
| bool isUnsigned = false; |
| bool isInt64 = false; |
| bool octalOverflow = false; |
| bool nonOctal = false; |
| ival = 0; |
| |
| // see how much octal-like stuff we can read |
| while (ch >= '0' && ch <= '7') { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| else if (! AlreadyComplained) { |
| pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", ""); |
| AlreadyComplained = 1; |
| } |
| if (ival <= 0x1fffffff || (enableInt64 && ival <= 0x1fffffffffffffffull)) { |
| ii = ch - '0'; |
| ival = (ival << 3) | ii; |
| } else |
| octalOverflow = true; |
| ch = getch(); |
| } |
| |
| // could be part of a float... |
| if (ch == '8' || ch == '9') { |
| nonOctal = true; |
| do { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| else if (! AlreadyComplained) { |
| pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", ""); |
| AlreadyComplained = 1; |
| } |
| ch = getch(); |
| } while (ch >= '0' && ch <= '9'); |
| } |
| if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F') |
| return pp->lFloatConst(len, ch, ppToken); |
| |
| // wasn't a float, so must be octal... |
| if (nonOctal) |
| pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", ""); |
| |
| if (ch == 'u' || ch == 'U') { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| isUnsigned = true; |
| |
| if (enableInt64) { |
| int nextCh = getch(); |
| if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)nextCh; |
| isInt64 = true; |
| } else |
| ungetch(); |
| } |
| } |
| else if (enableInt64 && (ch == 'l' || ch == 'L')) { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| isInt64 = true; |
| } else |
| ungetch(); |
| ppToken->name[len] = '\0'; |
| |
| if (octalOverflow) |
| pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", ""); |
| |
| if (isInt64) { |
| ppToken->i64val = ival; |
| return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64; |
| } else { |
| ppToken->ival = (int)ival; |
| return isUnsigned ? PpAtomConstUint : PpAtomConstInt; |
| } |
| } |
| break; |
| case '1': case '2': case '3': case '4': |
| case '5': case '6': case '7': case '8': case '9': |
| // can't be hexadecimal or octal, is either decimal or floating point |
| |
| do { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| else if (! AlreadyComplained) { |
| pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", ""); |
| AlreadyComplained = 1; |
| } |
| ch = getch(); |
| } while (ch >= '0' && ch <= '9'); |
| if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F') { |
| return pp->lFloatConst(len, ch, ppToken); |
| } else { |
| // Finish handling signed and unsigned integers |
| int numericLen = len; |
| bool isUnsigned = false; |
| bool isInt64 = false; |
| if (ch == 'u' || ch == 'U') { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| isUnsigned = true; |
| |
| if (enableInt64) { |
| int nextCh = getch(); |
| if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)nextCh; |
| isInt64 = true; |
| } else |
| ungetch(); |
| } |
| } else if (enableInt64 && (ch == 'l' || ch == 'L')) { |
| if (len < MaxTokenLength) |
| ppToken->name[len++] = (char)ch; |
| isInt64 = true; |
| } else |
| ungetch(); |
| |
| ppToken->name[len] = '\0'; |
| ival = 0; |
| const unsigned oneTenthMaxInt = 0xFFFFFFFFu / 10; |
| const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt; |
| const unsigned long long oneTenthMaxInt64 = 0xFFFFFFFFFFFFFFFFull / 10; |
| const unsigned long long remainderMaxInt64 = 0xFFFFFFFFFFFFFFFFull - 10 * oneTenthMaxInt64; |
| for (int i = 0; i < numericLen; i++) { |
| ch = ppToken->name[i] - '0'; |
| if ((enableInt64 == false && ((ival > oneTenthMaxInt) || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt))) || |
| (enableInt64 && ((ival > oneTenthMaxInt64) || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64)))) { |
| pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", ""); |
| ival = 0xFFFFFFFFFFFFFFFFull; |
| break; |
| } else |
| ival = ival * 10 + ch; |
| } |
| |
| if (isInt64) { |
| ppToken->i64val = ival; |
| return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64; |
| } else { |
| ppToken->ival = (int)ival; |
| return isUnsigned ? PpAtomConstUint : PpAtomConstInt; |
| } |
| } |
| break; |
| case '-': |
| ch = getch(); |
| if (ch == '-') { |
| return PpAtomDecrement; |
| } else if (ch == '=') { |
| return PpAtomSub; |
| } else { |
| ungetch(); |
| return '-'; |
| } |
| case '+': |
| ch = getch(); |
| if (ch == '+') { |
| return PpAtomIncrement; |
| } else if (ch == '=') { |
| return PpAtomAdd; |
| } else { |
| ungetch(); |
| return '+'; |
| } |
| case '*': |
| ch = getch(); |
| if (ch == '=') { |
| return PpAtomMul; |
| } else { |
| ungetch(); |
| return '*'; |
| } |
| case '%': |
| ch = getch(); |
| if (ch == '=') { |
| return PpAtomMod; |
| } else { |
| ungetch(); |
| return '%'; |
| } |
| case '^': |
| ch = getch(); |
| if (ch == '^') { |
| return PpAtomXor; |
| } else { |
| if (ch == '=') |
| return PpAtomXorAssign; |
| else{ |
| ungetch(); |
| return '^'; |
| } |
| } |
| |
| case '=': |
| ch = getch(); |
| if (ch == '=') { |
| return PpAtomEQ; |
| } else { |
| ungetch(); |
| return '='; |
| } |
| case '!': |
| ch = getch(); |
| if (ch == '=') { |
| return PpAtomNE; |
| } else { |
| ungetch(); |
| return '!'; |
| } |
| case '|': |
| ch = getch(); |
| if (ch == '|') { |
| return PpAtomOr; |
| } else if (ch == '=') { |
| return PpAtomOrAssign; |
| } else { |
| ungetch(); |
| return '|'; |
| } |
| case '&': |
| ch = getch(); |
| if (ch == '&') { |
| return PpAtomAnd; |
| } else if (ch == '=') { |
| return PpAtomAndAssign; |
| } else { |
| ungetch(); |
| return '&'; |
| } |
| case '<': |
| ch = getch(); |
| if (ch == '<') { |
| ch = getch(); |
| if (ch == '=') |
| return PpAtomLeftAssign; |
| else { |
| ungetch(); |
| return PpAtomLeft; |
| } |
| } else if (ch == '=') { |
| return PpAtomLE; |
| } else { |
| ungetch(); |
| return '<'; |
| } |
| case '>': |
| ch = getch(); |
| if (ch == '>') { |
| ch = getch(); |
| if (ch == '=') |
| return PpAtomRightAssign; |
| else { |
| ungetch(); |
| return PpAtomRight; |
| } |
| } else if (ch == '=') { |
| return PpAtomGE; |
| } else { |
| ungetch(); |
| return '>'; |
| } |
| case '.': |
| ch = getch(); |
| if (ch >= '0' && ch <= '9') { |
| ungetch(); |
| return pp->lFloatConst(0, '.', ppToken); |
| } else { |
| ungetch(); |
| return '.'; |
| } |
| case '/': |
| ch = getch(); |
| if (ch == '/') { |
| pp->inComment = true; |
| do { |
| ch = getch(); |
| } while (ch != '\n' && ch != EndOfInput); |
| ppToken->space = true; |
| pp->inComment = false; |
| |
| return ch; |
| } else if (ch == '*') { |
| ch = getch(); |
| do { |
| while (ch != '*') { |
| if (ch == EndOfInput) { |
| pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", ""); |
| return ch; |
| } |
| ch = getch(); |
| } |
| ch = getch(); |
| if (ch == EndOfInput) { |
| pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", ""); |
| return ch; |
| } |
| } while (ch != '/'); |
| ppToken->space = true; |
| // loop again to get the next token... |
| break; |
| } else if (ch == '=') { |
| return PpAtomDiv; |
| } else { |
| ungetch(); |
| return '/'; |
| } |
| break; |
| case '"': |
| ch = getch(); |
| while (ch != '"' && ch != '\n' && ch != EndOfInput) { |
| if (len < MaxTokenLength) { |
| tokenText[len] = (char)ch; |
| len++; |
| ch = getch(); |
| } else |
| break; |
| }; |
| tokenText[len] = '\0'; |
| if (ch != '"') { |
| ungetch(); |
| pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", ""); |
| } |
| return PpAtomConstString; |
| } |
| |
| ch = getch(); |
| } |
| } |
| |
| // |
| // The main functional entry point into the preprocessor, which will |
| // scan the source strings to figure out and return the next processing token. |
| // |
| // Return string pointer to next token. |
| // Return 0 when no more tokens. |
| // |
| const char* TPpContext::tokenize(TPpToken* ppToken) |
| { |
| int token = '\n'; |
| |
| for(;;) { |
| token = scanToken(ppToken); |
| ppToken->token = token; |
| if (token == EndOfInput) { |
| missingEndifCheck(); |
| return nullptr; |
| } |
| if (token == '#') { |
| if (previous_token == '\n') { |
| token = readCPPline(ppToken); |
| if (token == EndOfInput) { |
| missingEndifCheck(); |
| return nullptr; |
| } |
| continue; |
| } else { |
| parseContext.ppError(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", ""); |
| return nullptr; |
| } |
| } |
| previous_token = token; |
| |
| if (token == '\n') |
| continue; |
| |
| // expand macros |
| if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, true) != 0) |
| continue; |
| |
| const char* tokenString = nullptr; |
| switch (token) { |
| case PpAtomIdentifier: |
| case PpAtomConstInt: |
| case PpAtomConstUint: |
| case PpAtomConstFloat: |
| case PpAtomConstInt64: |
| case PpAtomConstUint64: |
| case PpAtomConstDouble: |
| tokenString = ppToken->name; |
| break; |
| case PpAtomConstString: |
| if (parseContext.intermediate.getSource() == EShSourceHlsl) { |
| // HLSL allows string literals. |
| tokenString = ppToken->name; |
| } else { |
| parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", ""); |
| } |
| break; |
| case '\'': |
| parseContext.ppError(ppToken->loc, "character literals not supported", "\'", ""); |
| break; |
| default: |
| tokenString = GetAtomString(token); |
| break; |
| } |
| |
| if (tokenString) |
| return tokenString; |
| } |
| } |
| |
| // Checks if we've seen balanced #if...#endif |
| void TPpContext::missingEndifCheck() |
| { |
| if (ifdepth > 0) |
| parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", ""); |
| } |
| |
| } // end namespace glslang |