summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp')
-rw-r--r--src/3rdparty/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp1246
1 files changed, 1246 insertions, 0 deletions
diff --git a/src/3rdparty/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/src/3rdparty/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp
new file mode 100644
index 0000000..f6f52d7
--- /dev/null
+++ b/src/3rdparty/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp
@@ -0,0 +1,1246 @@
+//
+// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
+// Copyright (C) 2013 LunarG, Inc.
+// Copyright (C) 2017 ARM Limited.
+// Copyright (C) 2015-2018 Google, 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.
+\****************************************************************************/
+
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <cstdlib>
+#include <cstring>
+
+#include "PpContext.h"
+#include "PpTokens.h"
+#include "../Scan.h"
+
+namespace glslang {
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Floating point constants: /////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+//
+// 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).
+//
+// This is technically not correct, as the preprocessor should just
+// accept the numeric literal along with whatever suffix it has, but
+// currently, it stops on seeing a bad suffix, treating that as the
+// next token. This effects things like token pasting, where it is
+// relevant how many tokens something was broken into.
+//
+// See peekContinuedPasting().
+int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
+{
+ const auto saveName = [&](int ch) {
+ if (len <= MaxTokenLength)
+ ppToken->name[len++] = static_cast<char>(ch);
+ };
+
+ // find the range of non-zero digits before the decimal point
+ int startNonZero = 0;
+ while (startNonZero < len && ppToken->name[startNonZero] == '0')
+ ++startNonZero;
+ int endNonZero = len;
+ while (endNonZero > startNonZero && ppToken->name[endNonZero-1] == '0')
+ --endNonZero;
+ int numWholeNumberDigits = endNonZero - startNonZero;
+
+ // accumulate the range's value
+ bool fastPath = numWholeNumberDigits <= 15; // when the number gets too complex, set to false
+ unsigned long long wholeNumber = 0;
+ if (fastPath) {
+ for (int i = startNonZero; i < endNonZero; ++i)
+ wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
+ }
+ int decimalShift = len - endNonZero;
+
+ // Decimal point:
+ bool hasDecimalOrExponent = false;
+ if (ch == '.') {
+ hasDecimalOrExponent = true;
+ saveName(ch);
+ ch = getChar();
+ int firstDecimal = len;
+
+ // 1.#INF or -1.#INF
+ if (ch == '#' && (ifdepth > 0 || parseContext.intermediate.getSource() == EShSourceHlsl)) {
+ if ((len < 2) ||
+ (len == 2 && ppToken->name[0] != '1') ||
+ (len == 3 && ppToken->name[1] != '1' && !(ppToken->name[0] == '-' || ppToken->name[0] == '+')) ||
+ (len > 3))
+ parseContext.ppError(ppToken->loc, "unexpected use of", "#", "");
+ else {
+ // we have 1.# or -1.# or +1.#, check for 'INF'
+ if ((ch = getChar()) != 'I' ||
+ (ch = getChar()) != 'N' ||
+ (ch = getChar()) != 'F')
+ parseContext.ppError(ppToken->loc, "expected 'INF'", "#", "");
+ else {
+ // we have [+-].#INF, and we are targeting IEEE 754, so wrap it up:
+ saveName('I');
+ saveName('N');
+ saveName('F');
+ ppToken->name[len] = '\0';
+ if (ppToken->name[0] == '-')
+ ppToken->i64val = 0xfff0000000000000; // -Infinity
+ else
+ ppToken->i64val = 0x7ff0000000000000; // +Infinity
+ return PpAtomConstFloat;
+ }
+ }
+ }
+
+ // Consume leading-zero digits after the decimal point
+ while (ch == '0') {
+ saveName(ch);
+ ch = getChar();
+ }
+ int startNonZeroDecimal = len;
+ int endNonZeroDecimal = len;
+
+ // Consume remaining digits, up to the exponent
+ while (ch >= '0' && ch <= '9') {
+ saveName(ch);
+ if (ch != '0')
+ endNonZeroDecimal = len;
+ ch = getChar();
+ }
+
+ // Compute accumulation up to the last non-zero digit
+ if (endNonZeroDecimal > startNonZeroDecimal) {
+ numWholeNumberDigits += endNonZeroDecimal - endNonZero - 1; // don't include the "."
+ if (numWholeNumberDigits > 15)
+ fastPath = false;
+ if (fastPath) {
+ for (int i = endNonZero; i < endNonZeroDecimal; ++i) {
+ if (ppToken->name[i] != '.')
+ wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
+ }
+ }
+ decimalShift = firstDecimal - endNonZeroDecimal;
+ }
+ }
+
+ // Exponent:
+ bool negativeExponent = false;
+ double exponentValue = 0.0;
+ int exponent = 0;
+ {
+ if (ch == 'e' || ch == 'E') {
+ hasDecimalOrExponent = true;
+ saveName(ch);
+ ch = getChar();
+ if (ch == '+' || ch == '-') {
+ negativeExponent = ch == '-';
+ saveName(ch);
+ ch = getChar();
+ }
+ if (ch >= '0' && ch <= '9') {
+ while (ch >= '0' && ch <= '9') {
+ exponent = exponent * 10 + (ch - '0');
+ saveName(ch);
+ ch = getChar();
+ }
+ } else {
+ parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
+ }
+ }
+
+ // Compensate for location of decimal
+ if (negativeExponent)
+ exponent -= decimalShift;
+ else {
+ exponent += decimalShift;
+ if (exponent < 0) {
+ negativeExponent = true;
+ exponent = -exponent;
+ }
+ }
+ if (exponent > 22)
+ fastPath = false;
+
+ if (fastPath) {
+ // Compute the floating-point value of the exponent
+ exponentValue = 1.0;
+ if (exponent > 0) {
+ double expFactor = 10;
+ while (exponent > 0) {
+ if (exponent & 0x1)
+ exponentValue *= expFactor;
+ expFactor *= expFactor;
+ exponent >>= 1;
+ }
+ }
+ }
+ }
+
+ // Suffix:
+ bool isDouble = false;
+ bool isFloat16 = false;
+ if (ch == 'l' || ch == 'L') {
+ if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
+ parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
+ if (ifdepth == 0 && !hasDecimalOrExponent)
+ parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
+ if (parseContext.intermediate.getSource() == EShSourceGlsl) {
+ int ch2 = getChar();
+ if (ch2 != 'f' && ch2 != 'F') {
+ ungetChar();
+ ungetChar();
+ } else {
+ saveName(ch);
+ saveName(ch2);
+ isDouble = true;
+ }
+ } else if (parseContext.intermediate.getSource() == EShSourceHlsl) {
+ saveName(ch);
+ isDouble = true;
+ }
+ } else if (ch == 'h' || ch == 'H') {
+ if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
+ parseContext.float16Check(ppToken->loc, "half floating-point suffix");
+ if (ifdepth == 0 && !hasDecimalOrExponent)
+ parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
+ if (parseContext.intermediate.getSource() == EShSourceGlsl) {
+ int ch2 = getChar();
+ if (ch2 != 'f' && ch2 != 'F') {
+ ungetChar();
+ ungetChar();
+ } else {
+ saveName(ch);
+ saveName(ch2);
+ isFloat16 = true;
+ }
+ } else if (parseContext.intermediate.getSource() == EShSourceHlsl) {
+ saveName(ch);
+ isFloat16 = true;
+ }
+ } else if (ch == 'f' || ch == 'F') {
+ if (ifdepth == 0)
+ parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
+ if (ifdepth == 0 && !parseContext.relaxedErrors())
+ parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
+ if (ifdepth == 0 && !hasDecimalOrExponent)
+ parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
+ saveName(ch);
+ } else
+ ungetChar();
+
+ // Patch up the name and length for overflow
+
+ if (len > MaxTokenLength) {
+ len = MaxTokenLength;
+ parseContext.ppError(ppToken->loc, "float literal too long", "", "");
+ }
+ ppToken->name[len] = '\0';
+
+ // Compute the numerical value
+ if (fastPath) {
+ // compute the floating-point value of the exponent
+ if (exponentValue == 0.0)
+ ppToken->dval = (double)wholeNumber;
+ else if (negativeExponent)
+ ppToken->dval = (double)wholeNumber / exponentValue;
+ else
+ ppToken->dval = (double)wholeNumber * exponentValue;
+ } else {
+ // slow path
+ ppToken->dval = 0.0;
+
+ // remove suffix
+ TString numstr(ppToken->name);
+ if (numstr.back() == 'f' || numstr.back() == 'F')
+ numstr.pop_back();
+ if (numstr.back() == 'h' || numstr.back() == 'H')
+ numstr.pop_back();
+ if (numstr.back() == 'l' || numstr.back() == 'L')
+ numstr.pop_back();
+
+ // use platform library
+ strtodStream.clear();
+ strtodStream.str(numstr.c_str());
+ strtodStream >> ppToken->dval;
+ if (strtodStream.fail()) {
+ // Assume failure combined with a large exponent was overflow, in
+ // an attempt to set INF.
+ if (!negativeExponent && exponent + numWholeNumberDigits > 300)
+ ppToken->i64val = 0x7ff0000000000000; // +Infinity
+ // Assume failure combined with a small exponent was overflow.
+ if (negativeExponent && exponent + numWholeNumberDigits > 300)
+ ppToken->dval = 0.0;
+ // Unknown reason for failure. Theory is that either
+ // - the 0.0 is still there, or
+ // - something reasonable was written that is better than 0.0
+ }
+ }
+
+ // Return the right token type
+ if (isDouble)
+ return PpAtomConstDouble;
+ else if (isFloat16)
+ return PpAtomConstFloat16;
+ else
+ return PpAtomConstFloat;
+}
+
+// Recognize a character literal.
+//
+// The first ' has already been accepted, read the rest, through the closing '.
+//
+// Always returns PpAtomConstInt.
+//
+int TPpContext::characterLiteral(TPpToken* ppToken)
+{
+ ppToken->name[0] = 0;
+ ppToken->ival = 0;
+
+ if (parseContext.intermediate.getSource() != EShSourceHlsl) {
+ // illegal, except in macro definition, for which case we report the character
+ return '\'';
+ }
+
+ int ch = getChar();
+ switch (ch) {
+ case '\'':
+ // As empty sequence: ''
+ parseContext.ppError(ppToken->loc, "unexpected", "\'", "");
+ return PpAtomConstInt;
+ case '\\':
+ // As escape sequence: '\XXX'
+ switch (ch = getChar()) {
+ case 'a':
+ ppToken->ival = 7;
+ break;
+ case 'b':
+ ppToken->ival = 8;
+ break;
+ case 't':
+ ppToken->ival = 9;
+ break;
+ case 'n':
+ ppToken->ival = 10;
+ break;
+ case 'v':
+ ppToken->ival = 11;
+ break;
+ case 'f':
+ ppToken->ival = 12;
+ break;
+ case 'r':
+ ppToken->ival = 13;
+ break;
+ case 'x':
+ case '0':
+ parseContext.ppError(ppToken->loc, "octal and hex sequences not supported", "\\", "");
+ break;
+ default:
+ // This catches '\'', '\"', '\?', etc.
+ // Also, things like '\C' mean the same thing as 'C'
+ // (after the above cases are filtered out).
+ ppToken->ival = ch;
+ break;
+ }
+ break;
+ default:
+ ppToken->ival = ch;
+ break;
+ }
+ ppToken->name[0] = (char)ppToken->ival;
+ ppToken->name[1] = '\0';
+ ch = getChar();
+ if (ch != '\'') {
+ parseContext.ppError(ppToken->loc, "expected", "\'", "");
+ // Look ahead for a closing '
+ do {
+ ch = getChar();
+ } while (ch != '\'' && ch != EndOfInput && ch != '\n');
+ }
+
+ return PpAtomConstInt;
+}
+
+//
+// Scanner used to tokenize source stream.
+//
+// N.B. Invalid numeric suffixes are not consumed.//
+// This is technically not correct, as the preprocessor should just
+// accept the numeric literal along with whatever suffix it has, but
+// currently, it stops on seeing a bad suffix, treating that as the
+// next token. This effects things like token pasting, where it is
+// relevant how many tokens something was broken into.
+// See peekContinuedPasting().
+//
+int TPpContext::tStringInput::scan(TPpToken* ppToken)
+{
+ int AlreadyComplained = 0;
+ int len = 0;
+ int ch = 0;
+ int ii = 0;
+ unsigned long long ival = 0;
+ const auto floatingPointChar = [&](int ch) { return ch == '.' || ch == 'e' || ch == 'E' ||
+ ch == 'f' || ch == 'F' ||
+ ch == 'h' || ch == 'H'; };
+
+ static const char* const Int64_Extensions[] = {
+ E_GL_ARB_gpu_shader_int64,
+ E_GL_EXT_shader_explicit_arithmetic_types,
+ E_GL_EXT_shader_explicit_arithmetic_types_int64 };
+ static const int Num_Int64_Extensions = sizeof(Int64_Extensions) / sizeof(Int64_Extensions[0]);
+
+ static const char* const Int16_Extensions[] = {
+#ifdef AMD_EXTENSIONS
+ E_GL_AMD_gpu_shader_int16,
+#endif
+ E_GL_EXT_shader_explicit_arithmetic_types,
+ E_GL_EXT_shader_explicit_arithmetic_types_int16 };
+ static const int Num_Int16_Extensions = sizeof(Int16_Extensions) / sizeof(Int16_Extensions[0]);
+
+ 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)
+ if (ch > PpAtomMaxSingle)
+ ch = PpAtomBadToken;
+ 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) {
+ ppToken->name[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;
+
+ ppToken->name[len] = '\0';
+ ungetch();
+ 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;
+ bool isInt16 = 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 (len < MaxTokenLength && 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) {
+ if(len < MaxTokenLength)
+ pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
+ else
+ pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too long", "", "");
+ 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;
+
+ int nextCh = getch();
+ if (nextCh == 'l' || nextCh == 'L') {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)nextCh;
+ isInt64 = true;
+ } else
+ ungetch();
+
+#ifdef AMD_EXTENSIONS
+ nextCh = getch();
+ if ((nextCh == 's' || nextCh == 'S') &&
+ pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)nextCh;
+ isInt16 = true;
+ } else
+ ungetch();
+#endif
+ } else if (ch == 'l' || ch == 'L') {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)ch;
+ isInt64 = true;
+#ifdef AMD_EXTENSIONS
+ } else if ((ch == 's' || ch == 'S') &&
+ pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)ch;
+ isInt16 = true;
+#endif
+ } else
+ ungetch();
+ ppToken->name[len] = '\0';
+
+ if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (pp->ifdepth == 0) {
+ pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
+ "64-bit hexadecimal literal");
+ pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
+ Num_Int64_Extensions, Int64_Extensions, "64-bit hexadecimal literal");
+ }
+ ppToken->i64val = ival;
+ return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
+ } else if (isInt16) {
+ if (pp->ifdepth == 0) {
+ if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
+ "16-bit hexadecimal literal");
+ pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
+ Num_Int16_Extensions, Int16_Extensions, "16-bit hexadecimal literal");
+ }
+ }
+ ppToken->ival = (int)ival;
+ return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
+ } else {
+ if (ival > 0xffffffffu && !AlreadyComplained)
+ pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
+ 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 isInt16 = 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 <= 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 (floatingPointChar(ch))
+ 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;
+
+ int nextCh = getch();
+ if (nextCh == 'l' || nextCh == 'L') {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)nextCh;
+ isInt64 = true;
+ } else
+ ungetch();
+
+#ifdef AMD_EXTENSIONS
+ nextCh = getch();
+ if ((nextCh == 's' || nextCh == 'S') &&
+ pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)nextCh;
+ isInt16 = true;
+ } else
+ ungetch();
+#endif
+ } else if (ch == 'l' || ch == 'L') {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)ch;
+ isInt64 = true;
+#ifdef AMD_EXTENSIONS
+ } else if ((ch == 's' || ch == 'S') &&
+ pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)ch;
+ isInt16 = true;
+#endif
+ } else
+ ungetch();
+ ppToken->name[len] = '\0';
+
+ if (!isInt64 && ival > 0xffffffffu)
+ octalOverflow = true;
+
+ if (octalOverflow)
+ pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", "");
+
+ if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (pp->ifdepth == 0) {
+ pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
+ "64-bit octal literal");
+ pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
+ Num_Int64_Extensions, Int64_Extensions, "64-bit octal literal");
+ }
+ ppToken->i64val = ival;
+ return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
+ } else if (isInt16) {
+ if (pp->ifdepth == 0) {
+ if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
+ "16-bit octal literal");
+ pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
+ Num_Int16_Extensions, Int16_Extensions, "16-bit octal literal");
+ }
+ }
+ ppToken->ival = (int)ival;
+ return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
+ } 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 (floatingPointChar(ch))
+ return pp->lFloatConst(len, ch, ppToken);
+ else {
+ // Finish handling signed and unsigned integers
+ int numericLen = len;
+ bool isUnsigned = false;
+ bool isInt64 = false;
+ bool isInt16 = false;
+ if (ch == 'u' || ch == 'U') {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)ch;
+ isUnsigned = true;
+
+ int nextCh = getch();
+ if (nextCh == 'l' || nextCh == 'L') {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)nextCh;
+ isInt64 = true;
+ } else
+ ungetch();
+
+#ifdef AMD_EXTENSIONS
+ nextCh = getch();
+ if ((nextCh == 's' || nextCh == 'S') &&
+ pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)nextCh;
+ isInt16 = true;
+ } else
+ ungetch();
+#endif
+ } else if (ch == 'l' || ch == 'L') {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)ch;
+ isInt64 = true;
+#ifdef AMD_EXTENSIONS
+ } else if ((ch == 's' || ch == 'S') &&
+ pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (len < MaxTokenLength)
+ ppToken->name[len++] = (char)ch;
+ isInt16 = true;
+#endif
+ } 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;
+ const unsigned short oneTenthMaxInt16 = 0xFFFFu / 10;
+ const unsigned short remainderMaxInt16 = 0xFFFFu - 10 * oneTenthMaxInt16;
+ for (int i = 0; i < numericLen; i++) {
+ ch = ppToken->name[i] - '0';
+ bool overflow = false;
+ if (isInt64)
+ overflow = (ival > oneTenthMaxInt64 || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64));
+ else if (isInt16)
+ overflow = (ival > oneTenthMaxInt16 || (ival == oneTenthMaxInt16 && (unsigned short)ch > remainderMaxInt16));
+ else
+ overflow = (ival > oneTenthMaxInt || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt));
+ if (overflow) {
+ pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", "");
+ ival = 0xFFFFFFFFFFFFFFFFull;
+ break;
+ } else
+ ival = ival * 10 + ch;
+ }
+
+ if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ if (pp->ifdepth == 0) {
+ pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
+ "64-bit literal");
+ pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
+ Num_Int64_Extensions, Int64_Extensions, "64-bit literal");
+ }
+ ppToken->i64val = ival;
+ return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
+ } else if (isInt16) {
+ if (pp->ifdepth == 0 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) {
+ pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile,
+ "16-bit literal");
+ pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0,
+ Num_Int16_Extensions, Int16_Extensions, "16-bit literal");
+ }
+ ppToken->ival = (int)ival;
+ return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16;
+ } else {
+ ppToken->ival = (int)ival;
+ return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
+ }
+ }
+ break;
+ case '-':
+ ch = getch();
+ if (ch == '-') {
+ return PpAtomDecrement;
+ } else if (ch == '=') {
+ return PPAtomSubAssign;
+ } else {
+ ungetch();
+ return '-';
+ }
+ case '+':
+ ch = getch();
+ if (ch == '+') {
+ return PpAtomIncrement;
+ } else if (ch == '=') {
+ return PPAtomAddAssign;
+ } else {
+ ungetch();
+ return '+';
+ }
+ case '*':
+ ch = getch();
+ if (ch == '=') {
+ return PPAtomMulAssign;
+ } else {
+ ungetch();
+ return '*';
+ }
+ case '%':
+ ch = getch();
+ if (ch == '=') {
+ return PPAtomModAssign;
+ } 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 PPAtomDivAssign;
+ } else {
+ ungetch();
+ return '/';
+ }
+ break;
+ case '\'':
+ return pp->characterLiteral(ppToken);
+ case '"':
+ // TODO: If this gets enhanced to handle escape sequences, or
+ // anything that is different than what #include needs, then
+ // #include needs to use scanHeaderName() for this.
+ ch = getch();
+ while (ch != '"' && ch != '\n' && ch != EndOfInput) {
+ if (len < MaxTokenLength) {
+ ppToken->name[len] = (char)ch;
+ len++;
+ ch = getch();
+ } else
+ break;
+ };
+ ppToken->name[len] = '\0';
+ if (ch != '"') {
+ ungetch();
+ pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
+ }
+ return PpAtomConstString;
+ case ':':
+ ch = getch();
+ if (ch == ':')
+ return PpAtomColonColon;
+ ungetch();
+ return ':';
+ }
+
+ 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 the token, or EndOfInput when no more tokens.
+//
+int TPpContext::tokenize(TPpToken& ppToken)
+{
+ for(;;) {
+ int token = scanToken(&ppToken);
+
+ // Handle token-pasting logic
+ token = tokenPaste(token, ppToken);
+
+ if (token == EndOfInput) {
+ missingEndifCheck();
+ return EndOfInput;
+ }
+ if (token == '#') {
+ if (previous_token == '\n') {
+ token = readCPPline(&ppToken);
+ if (token == EndOfInput) {
+ missingEndifCheck();
+ return EndOfInput;
+ }
+ continue;
+ } else {
+ parseContext.ppError(ppToken.loc, "preprocessor directive cannot be preceded by another token", "#", "");
+ return EndOfInput;
+ }
+ }
+ previous_token = token;
+
+ if (token == '\n')
+ continue;
+
+ // expand macros
+ if (token == PpAtomIdentifier) {
+ switch (MacroExpand(&ppToken, false, true)) {
+ case MacroExpandNotStarted:
+ break;
+ case MacroExpandError:
+ return EndOfInput;
+ case MacroExpandStarted:
+ case MacroExpandUndef:
+ continue;
+ }
+ }
+
+ switch (token) {
+ case PpAtomIdentifier:
+ case PpAtomConstInt:
+ case PpAtomConstUint:
+ case PpAtomConstFloat:
+ case PpAtomConstInt64:
+ case PpAtomConstUint64:
+ case PpAtomConstInt16:
+ case PpAtomConstUint16:
+ case PpAtomConstDouble:
+ case PpAtomConstFloat16:
+ if (ppToken.name[0] == '\0')
+ continue;
+ break;
+ case PpAtomConstString:
+ if (ifdepth == 0 && parseContext.intermediate.getSource() != EShSourceHlsl) {
+ // HLSL allows string literals.
+ parseContext.ppError(ppToken.loc, "string literals not supported", "\"\"", "");
+ continue;
+ }
+ break;
+ case '\'':
+ parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
+ continue;
+ default:
+ snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(token));
+ break;
+ }
+
+ return token;
+ }
+}
+
+//
+// Do all token-pasting related combining of two pasted tokens when getting a
+// stream of tokens from a replacement list. Degenerates to no processing if a
+// replacement list is not the source of the token stream.
+//
+int TPpContext::tokenPaste(int token, TPpToken& ppToken)
+{
+ // starting with ## is illegal, skip to next token
+ if (token == PpAtomPaste) {
+ parseContext.ppError(ppToken.loc, "unexpected location", "##", "");
+ return scanToken(&ppToken);
+ }
+
+ int resultToken = token; // "foo" pasted with "35" is an identifier, not a number
+
+ // ## can be chained, process all in the chain at once
+ while (peekPasting()) {
+ TPpToken pastedPpToken;
+
+ // next token has to be ##
+ token = scanToken(&pastedPpToken);
+ assert(token == PpAtomPaste);
+
+ // This covers end of macro expansion
+ if (endOfReplacementList()) {
+ parseContext.ppError(ppToken.loc, "unexpected location; end of replacement list", "##", "");
+ break;
+ }
+
+ // Get the token(s) after the ##.
+ // Because of "space" semantics, and prior tokenization, what
+ // appeared a single token, e.g. "3A", might have been tokenized
+ // into two tokens "3" and "A", but the "A" will have 'space' set to
+ // false. Accumulate all of these to recreate the original lexical
+ // appearing token.
+ do {
+ token = scanToken(&pastedPpToken);
+
+ // This covers end of argument expansion
+ if (token == tMarkerInput::marker) {
+ parseContext.ppError(ppToken.loc, "unexpected location; end of argument", "##", "");
+ return resultToken;
+ }
+
+ // get the token text
+ switch (resultToken) {
+ case PpAtomIdentifier:
+ // already have the correct text in token.names
+ break;
+ case '=':
+ case '!':
+ case '-':
+ case '~':
+ case '+':
+ case '*':
+ case '/':
+ case '%':
+ case '<':
+ case '>':
+ case '|':
+ case '^':
+ case '&':
+ case PpAtomRight:
+ case PpAtomLeft:
+ case PpAtomAnd:
+ case PpAtomOr:
+ case PpAtomXor:
+ snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(resultToken));
+ snprintf(pastedPpToken.name, sizeof(pastedPpToken.name), "%s", atomStrings.getString(token));
+ break;
+ default:
+ parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", "");
+ return resultToken;
+ }
+
+ // combine the tokens
+ if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) {
+ parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", "");
+ return resultToken;
+ }
+ snprintf(&ppToken.name[0] + strlen(ppToken.name), sizeof(ppToken.name) - strlen(ppToken.name),
+ "%s", pastedPpToken.name);
+
+ // correct the kind of token we are making, if needed (identifiers stay identifiers)
+ if (resultToken != PpAtomIdentifier) {
+ int newToken = atomStrings.getAtom(ppToken.name);
+ if (newToken > 0)
+ resultToken = newToken;
+ else
+ parseContext.ppError(ppToken.loc, "combined token is invalid", "##", "");
+ }
+ } while (peekContinuedPasting(resultToken));
+ }
+
+ return resultToken;
+}
+
+// Checks if we've seen balanced #if...#endif
+void TPpContext::missingEndifCheck()
+{
+ if (ifdepth > 0)
+ parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", "");
+}
+
+} // end namespace glslang