diff options
Diffstat (limited to 'chromium/third_party/glslang/src/glslang/MachineIndependent/preprocessor/PpScanner.cpp')
-rw-r--r-- | chromium/third_party/glslang/src/glslang/MachineIndependent/preprocessor/PpScanner.cpp | 778 |
1 files changed, 778 insertions, 0 deletions
diff --git a/chromium/third_party/glslang/src/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/chromium/third_party/glslang/src/glslang/MachineIndependent/preprocessor/PpScanner.cpp new file mode 100644 index 00000000000..b3d1af6dad2 --- /dev/null +++ b/chromium/third_party/glslang/src/glslang/MachineIndependent/preprocessor/PpScanner.cpp @@ -0,0 +1,778 @@ +// +//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 <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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 hexidecimal + + 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 hexidecimal literal", "", ""); + ival = (ival << 4) | ii; + } else { + if (! AlreadyComplained) { + pp->parseContext.ppError(ppToken->loc, "hexidecimal 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 hexidecimal 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 hexidecimal 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: + 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) { + if (tokenString[0] != 0) + parseContext.tokensBeforeEOF = 1; + + 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 |