| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346 |
- //
- // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
- // Copyright (C) 2013 LunarG, Inc.
- // 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 <sstream>
- #include <cstdlib>
- #include <cstring>
- #include <cctype>
- #include <climits>
- #include "PpContext.h"
- #include "PpTokens.h"
- namespace glslang {
- // Handle #define
- int TPpContext::CPPdefine(TPpToken* ppToken)
- {
- MacroSymbol mac;
- // get the macro name
- int token = scanToken(ppToken);
- if (token != PpAtomIdentifier) {
- parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", "");
- return token;
- }
- if (ppToken->loc.string >= 0) {
- // We are in user code; check for reserved name use:
- parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define");
- }
- // save the macro name
- const int defAtom = atomStrings.getAddAtom(ppToken->name);
- TSourceLoc defineLoc = ppToken->loc; // because ppToken might go to the next line before we report errors
- // gather parameters to the macro, between (...)
- token = scanToken(ppToken);
- if (token == '(' && !ppToken->space) {
- mac.functionLike = 1;
- do {
- token = scanToken(ppToken);
- if (mac.args.size() == 0 && token == ')')
- break;
- if (token != PpAtomIdentifier) {
- parseContext.ppError(ppToken->loc, "bad argument", "#define", "");
- return token;
- }
- const int argAtom = atomStrings.getAddAtom(ppToken->name);
- // check for duplication of parameter name
- bool duplicate = false;
- for (size_t a = 0; a < mac.args.size(); ++a) {
- if (mac.args[a] == argAtom) {
- parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", "");
- duplicate = true;
- break;
- }
- }
- if (! duplicate)
- mac.args.push_back(argAtom);
- token = scanToken(ppToken);
- } while (token == ',');
- if (token != ')') {
- parseContext.ppError(ppToken->loc, "missing parenthesis", "#define", "");
- return token;
- }
- token = scanToken(ppToken);
- } else if (token != '\n' && token != EndOfInput && !ppToken->space) {
- parseContext.ppWarn(ppToken->loc, "missing space after macro name", "#define", "");
- return token;
- }
- // record the definition of the macro
- while (token != '\n' && token != EndOfInput) {
- mac.body.putToken(token, ppToken);
- token = scanToken(ppToken);
- if (token != '\n' && ppToken->space)
- mac.body.putToken(' ', ppToken);
- }
- // check for duplicate definition
- MacroSymbol* existing = lookupMacroDef(defAtom);
- if (existing != nullptr) {
- if (! existing->undef) {
- // Already defined -- need to make sure they are identical:
- // "Two replacement lists are identical if and only if the
- // preprocessing tokens in both have the same number,
- // ordering, spelling, and white-space separation, where all
- // white-space separations are considered identical."
- if (existing->functionLike != mac.functionLike) {
- parseContext.ppError(defineLoc, "Macro redefined; function-like versus object-like:", "#define",
- atomStrings.getString(defAtom));
- } else if (existing->args.size() != mac.args.size()) {
- parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define",
- atomStrings.getString(defAtom));
- } else {
- if (existing->args != mac.args) {
- parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define",
- atomStrings.getString(defAtom));
- }
- // set up to compare the two
- existing->body.reset();
- mac.body.reset();
- int newToken;
- bool firstToken = true;
- do {
- int oldToken;
- TPpToken oldPpToken;
- TPpToken newPpToken;
- oldToken = existing->body.getToken(parseContext, &oldPpToken);
- newToken = mac.body.getToken(parseContext, &newPpToken);
- // for the first token, preceding spaces don't matter
- if (firstToken) {
- newPpToken.space = oldPpToken.space;
- firstToken = false;
- }
- if (oldToken != newToken || oldPpToken != newPpToken) {
- parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define",
- atomStrings.getString(defAtom));
- break;
- }
- } while (newToken != EndOfInput);
- }
- }
- *existing = mac;
- } else
- addMacroDef(defAtom, mac);
- return '\n';
- }
- // Handle #undef
- int TPpContext::CPPundef(TPpToken* ppToken)
- {
- int token = scanToken(ppToken);
- if (token != PpAtomIdentifier) {
- parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", "");
- return token;
- }
- parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef");
- MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
- if (macro != nullptr)
- macro->undef = 1;
- token = scanToken(ppToken);
- if (token != '\n')
- parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", "");
- return token;
- }
- // Handle #else
- /* Skip forward to appropriate spot. This is used both
- ** to skip to a #endif after seeing an #else, AND to skip to a #else,
- ** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false.
- */
- int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
- {
- int depth = 0;
- int token = scanToken(ppToken);
- while (token != EndOfInput) {
- if (token != '#') {
- while (token != '\n' && token != EndOfInput)
- token = scanToken(ppToken);
- if (token == EndOfInput)
- return token;
- token = scanToken(ppToken);
- continue;
- }
- if ((token = scanToken(ppToken)) != PpAtomIdentifier)
- continue;
- int nextAtom = atomStrings.getAtom(ppToken->name);
- if (nextAtom == PpAtomIf || nextAtom == PpAtomIfdef || nextAtom == PpAtomIfndef) {
- depth++;
- if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) {
- parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if/#ifdef/#ifndef", "");
- return EndOfInput;
- } else {
- ifdepth++;
- elsetracker++;
- }
- } else if (nextAtom == PpAtomEndif) {
- token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
- elseSeen[elsetracker] = false;
- --elsetracker;
- if (depth == 0) {
- // found the #endif we are looking for
- if (ifdepth > 0)
- --ifdepth;
- break;
- }
- --depth;
- --ifdepth;
- } else if (matchelse && depth == 0) {
- if (nextAtom == PpAtomElse) {
- elseSeen[elsetracker] = true;
- token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
- // found the #else we are looking for
- break;
- } else if (nextAtom == PpAtomElif) {
- if (elseSeen[elsetracker])
- parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
- /* we decrement ifdepth here, because CPPif will increment
- * it and we really want to leave it alone */
- if (ifdepth > 0) {
- --ifdepth;
- elseSeen[elsetracker] = false;
- --elsetracker;
- }
- return CPPif(ppToken);
- }
- } else if (nextAtom == PpAtomElse) {
- if (elseSeen[elsetracker])
- parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
- else
- elseSeen[elsetracker] = true;
- token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
- } else if (nextAtom == PpAtomElif) {
- if (elseSeen[elsetracker])
- parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
- }
- }
- return token;
- }
- // Call when there should be no more tokens left on a line.
- int TPpContext::extraTokenCheck(int contextAtom, TPpToken* ppToken, int token)
- {
- if (token != '\n' && token != EndOfInput) {
- static const char* message = "unexpected tokens following directive";
- const char* label;
- if (contextAtom == PpAtomElse)
- label = "#else";
- else if (contextAtom == PpAtomElif)
- label = "#elif";
- else if (contextAtom == PpAtomEndif)
- label = "#endif";
- else if (contextAtom == PpAtomIf)
- label = "#if";
- else if (contextAtom == PpAtomLine)
- label = "#line";
- else
- label = "";
- if (parseContext.relaxedErrors())
- parseContext.ppWarn(ppToken->loc, message, label, "");
- else
- parseContext.ppError(ppToken->loc, message, label, "");
- while (token != '\n' && token != EndOfInput)
- token = scanToken(ppToken);
- }
- return token;
- }
- enum eval_prec {
- MIN_PRECEDENCE,
- COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
- MAX_PRECEDENCE
- };
- namespace {
- int op_logor(int a, int b) { return a || b; }
- int op_logand(int a, int b) { return a && b; }
- int op_or(int a, int b) { return a | b; }
- int op_xor(int a, int b) { return a ^ b; }
- int op_and(int a, int b) { return a & b; }
- int op_eq(int a, int b) { return a == b; }
- int op_ne(int a, int b) { return a != b; }
- int op_ge(int a, int b) { return a >= b; }
- int op_le(int a, int b) { return a <= b; }
- int op_gt(int a, int b) { return a > b; }
- int op_lt(int a, int b) { return a < b; }
- int op_shl(int a, int b) { return a << b; }
- int op_shr(int a, int b) { return a >> b; }
- int op_add(int a, int b) { return a + b; }
- int op_sub(int a, int b) { return a - b; }
- int op_mul(int a, int b) { return a * b; }
- int op_div(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a / b; }
- int op_mod(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a % b; }
- int op_pos(int a) { return a; }
- int op_neg(int a) { return -a; }
- int op_cmpl(int a) { return ~a; }
- int op_not(int a) { return !a; }
- };
- struct TBinop {
- int token, precedence, (*op)(int, int);
- } binop[] = {
- { PpAtomOr, LOGOR, op_logor },
- { PpAtomAnd, LOGAND, op_logand },
- { '|', OR, op_or },
- { '^', XOR, op_xor },
- { '&', AND, op_and },
- { PpAtomEQ, EQUAL, op_eq },
- { PpAtomNE, EQUAL, op_ne },
- { '>', RELATION, op_gt },
- { PpAtomGE, RELATION, op_ge },
- { '<', RELATION, op_lt },
- { PpAtomLE, RELATION, op_le },
- { PpAtomLeft, SHIFT, op_shl },
- { PpAtomRight, SHIFT, op_shr },
- { '+', ADD, op_add },
- { '-', ADD, op_sub },
- { '*', MUL, op_mul },
- { '/', MUL, op_div },
- { '%', MUL, op_mod },
- };
- struct TUnop {
- int token, (*op)(int);
- } unop[] = {
- { '+', op_pos },
- { '-', op_neg },
- { '~', op_cmpl },
- { '!', op_not },
- };
- #define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0]))
- int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
- {
- TSourceLoc loc = ppToken->loc; // because we sometimes read the newline before reporting the error
- if (token == PpAtomIdentifier) {
- if (strcmp("defined", ppToken->name) == 0) {
- if (! parseContext.isReadingHLSL() && isMacroInput()) {
- if (parseContext.relaxedErrors())
- parseContext.ppWarn(ppToken->loc, "nonportable when expanded from macros for preprocessor expression",
- "defined", "");
- else
- parseContext.ppError(ppToken->loc, "cannot use in preprocessor expression when expanded from macros",
- "defined", "");
- }
- bool needclose = 0;
- token = scanToken(ppToken);
- if (token == '(') {
- needclose = true;
- token = scanToken(ppToken);
- }
- if (token != PpAtomIdentifier) {
- parseContext.ppError(loc, "incorrect directive, expected identifier", "preprocessor evaluation", "");
- err = true;
- res = 0;
- return token;
- }
- MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
- res = macro != nullptr ? !macro->undef : 0;
- token = scanToken(ppToken);
- if (needclose) {
- if (token != ')') {
- parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
- err = true;
- res = 0;
- return token;
- }
- token = scanToken(ppToken);
- }
- } else {
- token = tokenPaste(token, *ppToken);
- token = evalToToken(token, shortCircuit, res, err, ppToken);
- return eval(token, precedence, shortCircuit, res, err, ppToken);
- }
- } else if (token == PpAtomConstInt) {
- res = ppToken->ival;
- token = scanToken(ppToken);
- } else if (token == '(') {
- token = scanToken(ppToken);
- token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
- if (! err) {
- if (token != ')') {
- parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
- err = true;
- res = 0;
- return token;
- }
- token = scanToken(ppToken);
- }
- } else {
- int op = NUM_ELEMENTS(unop) - 1;
- for (; op >= 0; op--) {
- if (unop[op].token == token)
- break;
- }
- if (op >= 0) {
- token = scanToken(ppToken);
- token = eval(token, UNARY, shortCircuit, res, err, ppToken);
- res = unop[op].op(res);
- } else {
- parseContext.ppError(loc, "bad expression", "preprocessor evaluation", "");
- err = true;
- res = 0;
- return token;
- }
- }
- token = evalToToken(token, shortCircuit, res, err, ppToken);
- // Perform evaluation of binary operation, if there is one, otherwise we are done.
- while (! err) {
- if (token == ')' || token == '\n')
- break;
- int op;
- for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
- if (binop[op].token == token)
- break;
- }
- if (op < 0 || binop[op].precedence <= precedence)
- break;
- int leftSide = res;
- // Setup short-circuiting, needed for ES, unless already in a short circuit.
- // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
- if (! shortCircuit) {
- if ((token == PpAtomOr && leftSide == 1) ||
- (token == PpAtomAnd && leftSide == 0))
- shortCircuit = true;
- }
- token = scanToken(ppToken);
- token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);
- if (binop[op].op == op_div || binop[op].op == op_mod) {
- if (res == 0) {
- parseContext.ppError(loc, "division by 0", "preprocessor evaluation", "");
- res = 1;
- }
- }
- res = binop[op].op(leftSide, res);
- }
- return token;
- }
- // Expand macros, skipping empty expansions, to get to the first real token in those expansions.
- int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
- {
- while (token == PpAtomIdentifier && strcmp("defined", ppToken->name) != 0) {
- switch (MacroExpand(ppToken, true, false)) {
- case MacroExpandNotStarted:
- case MacroExpandError:
- parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", "");
- err = true;
- res = 0;
- break;
- case MacroExpandStarted:
- break;
- case MacroExpandUndef:
- if (! shortCircuit && parseContext.isEsProfile()) {
- const char* message = "undefined macro in expression not allowed in es profile";
- if (parseContext.relaxedErrors())
- parseContext.ppWarn(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
- else
- parseContext.ppError(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
- }
- break;
- }
- token = scanToken(ppToken);
- if (err)
- break;
- }
- return token;
- }
- // Handle #if
- int TPpContext::CPPif(TPpToken* ppToken)
- {
- int token = scanToken(ppToken);
- if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) {
- parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
- return EndOfInput;
- } else {
- elsetracker++;
- ifdepth++;
- }
- int res = 0;
- bool err = false;
- token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken);
- token = extraTokenCheck(PpAtomIf, ppToken, token);
- if (!res && !err)
- token = CPPelse(1, ppToken);
- return token;
- }
- // Handle #ifdef
- int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
- {
- int token = scanToken(ppToken);
- if (ifdepth > maxIfNesting || elsetracker > maxIfNesting) {
- parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
- return EndOfInput;
- } else {
- elsetracker++;
- ifdepth++;
- }
- if (token != PpAtomIdentifier) {
- if (defined)
- parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", "");
- else
- parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
- } else {
- MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
- token = scanToken(ppToken);
- if (token != '\n') {
- parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
- while (token != '\n' && token != EndOfInput)
- token = scanToken(ppToken);
- }
- if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined)
- token = CPPelse(1, ppToken);
- }
- return token;
- }
- // Handle #include ...
- // TODO: Handle macro expansions for the header name
- int TPpContext::CPPinclude(TPpToken* ppToken)
- {
- const TSourceLoc directiveLoc = ppToken->loc;
- bool startWithLocalSearch = true; // to additionally include the extra "" paths
- int token;
- // Find the first non-whitespace char after #include
- int ch = getChar();
- while (ch == ' ' || ch == '\t') {
- ch = getChar();
- }
- if (ch == '<') {
- // <header-name> style
- startWithLocalSearch = false;
- token = scanHeaderName(ppToken, '>');
- } else if (ch == '"') {
- // "header-name" style
- token = scanHeaderName(ppToken, '"');
- } else {
- // unexpected, get the full token to generate the error
- ungetChar();
- token = scanToken(ppToken);
- }
- if (token != PpAtomConstString) {
- parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", "");
- return token;
- }
- // Make a copy of the name because it will be overwritten by the next token scan.
- const std::string filename = ppToken->name;
- // See if the directive was well formed
- token = scanToken(ppToken);
- if (token != '\n') {
- if (token == EndOfInput)
- parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str());
- else
- parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str());
- return token;
- }
- // Process well-formed directive
- // Find the inclusion, first look in "Local" ("") paths, if requested,
- // otherwise, only search the "System" (<>) paths.
- TShader::Includer::IncludeResult* res = nullptr;
- if (startWithLocalSearch)
- res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
- if (res == nullptr || res->headerName.empty()) {
- includer.releaseInclude(res);
- res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
- }
- // Process the results
- if (res != nullptr && !res->headerName.empty()) {
- if (res->headerData != nullptr && res->headerLength > 0) {
- // path for processing one or more tokens from an included header, hand off 'res'
- const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
- std::ostringstream prologue;
- std::ostringstream epilogue;
- prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n";
- epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
- "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
- pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
- parseContext.intermediate.addIncludeText(res->headerName.c_str(), res->headerData, res->headerLength);
- // There's no "current" location anymore.
- parseContext.setCurrentColumn(0);
- } else {
- // things are okay, but there is nothing to process
- includer.releaseInclude(res);
- }
- } else {
- // error path, clean up
- std::string message =
- res != nullptr ? std::string(res->headerData, res->headerLength)
- : std::string("Could not process include directive");
- parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str());
- includer.releaseInclude(res);
- }
- return token;
- }
- // Handle #line
- int TPpContext::CPPline(TPpToken* ppToken)
- {
- // "#line must have, after macro substitution, one of the following forms:
- // "#line line
- // "#line line source-string-number"
- int token = scanToken(ppToken);
- const TSourceLoc directiveLoc = ppToken->loc;
- if (token == '\n') {
- parseContext.ppError(ppToken->loc, "must by followed by an integral literal", "#line", "");
- return token;
- }
- int lineRes = 0; // Line number after macro expansion.
- int lineToken = 0;
- bool hasFile = false;
- int fileRes = 0; // Source file number after macro expansion.
- const char* sourceName = nullptr; // Optional source file name.
- bool lineErr = false;
- bool fileErr = false;
- disableEscapeSequences = true;
- token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken);
- disableEscapeSequences = false;
- if (! lineErr) {
- lineToken = lineRes;
- if (token == '\n')
- ++lineRes;
- if (parseContext.lineDirectiveShouldSetNextLine())
- --lineRes;
- parseContext.setCurrentLine(lineRes);
- if (token != '\n') {
- #ifndef GLSLANG_WEB
- if (token == PpAtomConstString) {
- parseContext.ppRequireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line");
- // We need to save a copy of the string instead of pointing
- // to the name field of the token since the name field
- // will likely be overwritten by the next token scan.
- sourceName = atomStrings.getString(atomStrings.getAddAtom(ppToken->name));
- parseContext.setCurrentSourceName(sourceName);
- hasFile = true;
- token = scanToken(ppToken);
- } else
- #endif
- {
- token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
- if (! fileErr) {
- parseContext.setCurrentString(fileRes);
- hasFile = true;
- }
- }
- }
- }
- if (!fileErr && !lineErr) {
- parseContext.notifyLineDirective(directiveLoc.line, lineToken, hasFile, fileRes, sourceName);
- }
- token = extraTokenCheck(PpAtomLine, ppToken, token);
- return token;
- }
- // Handle #error
- int TPpContext::CPPerror(TPpToken* ppToken)
- {
- disableEscapeSequences = true;
- int token = scanToken(ppToken);
- disableEscapeSequences = false;
- std::string message;
- TSourceLoc loc = ppToken->loc;
- while (token != '\n' && token != EndOfInput) {
- if (token == PpAtomConstInt16 || token == PpAtomConstUint16 ||
- token == PpAtomConstInt || token == PpAtomConstUint ||
- token == PpAtomConstInt64 || token == PpAtomConstUint64 ||
- token == PpAtomConstFloat16 ||
- token == PpAtomConstFloat || token == PpAtomConstDouble) {
- message.append(ppToken->name);
- } else if (token == PpAtomIdentifier || token == PpAtomConstString) {
- message.append(ppToken->name);
- } else {
- message.append(atomStrings.getString(token));
- }
- message.append(" ");
- token = scanToken(ppToken);
- }
- parseContext.notifyErrorDirective(loc.line, message.c_str());
- // store this msg into the shader's information log..set the Compile Error flag!!!!
- parseContext.ppError(loc, message.c_str(), "#error", "");
- return '\n';
- }
- // Handle #pragma
- int TPpContext::CPPpragma(TPpToken* ppToken)
- {
- char SrcStrName[2];
- TVector<TString> tokens;
- TSourceLoc loc = ppToken->loc; // because we go to the next line before processing
- int token = scanToken(ppToken);
- while (token != '\n' && token != EndOfInput) {
- switch (token) {
- case PpAtomIdentifier:
- case PpAtomConstInt:
- case PpAtomConstUint:
- case PpAtomConstInt64:
- case PpAtomConstUint64:
- case PpAtomConstInt16:
- case PpAtomConstUint16:
- case PpAtomConstFloat:
- case PpAtomConstDouble:
- case PpAtomConstFloat16:
- tokens.push_back(ppToken->name);
- break;
- default:
- SrcStrName[0] = (char)token;
- SrcStrName[1] = '\0';
- tokens.push_back(SrcStrName);
- }
- token = scanToken(ppToken);
- }
- if (token == EndOfInput)
- parseContext.ppError(loc, "directive must end with a newline", "#pragma", "");
- else
- parseContext.handlePragma(loc, tokens);
- return token;
- }
- // #version: This is just for error checking: the version and profile are decided before preprocessing starts
- int TPpContext::CPPversion(TPpToken* ppToken)
- {
- int token = scanToken(ppToken);
- if (errorOnVersion || versionSeen) {
- if (parseContext.isReadingHLSL())
- parseContext.ppError(ppToken->loc, "invalid preprocessor command", "#version", "");
- else
- parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", "");
- }
- versionSeen = true;
- if (token == '\n') {
- parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
- return token;
- }
- if (token != PpAtomConstInt)
- parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
- ppToken->ival = atoi(ppToken->name);
- int versionNumber = ppToken->ival;
- int line = ppToken->loc.line;
- token = scanToken(ppToken);
- if (token == '\n') {
- parseContext.notifyVersion(line, versionNumber, nullptr);
- return token;
- } else {
- int profileAtom = atomStrings.getAtom(ppToken->name);
- if (profileAtom != PpAtomCore &&
- profileAtom != PpAtomCompatibility &&
- profileAtom != PpAtomEs)
- parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
- parseContext.notifyVersion(line, versionNumber, ppToken->name);
- token = scanToken(ppToken);
- if (token == '\n')
- return token;
- else
- parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
- }
- return token;
- }
- // Handle #extension
- int TPpContext::CPPextension(TPpToken* ppToken)
- {
- int line = ppToken->loc.line;
- int token = scanToken(ppToken);
- char extensionName[MaxTokenLength + 1];
- if (token=='\n') {
- parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", "");
- return token;
- }
- if (token != PpAtomIdentifier)
- parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
- snprintf(extensionName, sizeof(extensionName), "%s", ppToken->name);
- token = scanToken(ppToken);
- if (token != ':') {
- parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", "");
- return token;
- }
- token = scanToken(ppToken);
- if (token != PpAtomIdentifier) {
- parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", "");
- return token;
- }
- parseContext.updateExtensionBehavior(line, extensionName, ppToken->name);
- parseContext.notifyExtensionDirective(line, extensionName, ppToken->name);
- token = scanToken(ppToken);
- if (token == '\n')
- return token;
- else
- parseContext.ppError(ppToken->loc, "extra tokens -- expected newline", "#extension","");
- return token;
- }
- int TPpContext::readCPPline(TPpToken* ppToken)
- {
- int token = scanToken(ppToken);
- if (token == PpAtomIdentifier) {
- switch (atomStrings.getAtom(ppToken->name)) {
- case PpAtomDefine:
- token = CPPdefine(ppToken);
- break;
- case PpAtomElse:
- if (elseSeen[elsetracker])
- parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
- elseSeen[elsetracker] = true;
- if (ifdepth == 0)
- parseContext.ppError(ppToken->loc, "mismatched statements", "#else", "");
- token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken));
- token = CPPelse(0, ppToken);
- break;
- case PpAtomElif:
- if (ifdepth == 0)
- parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", "");
- if (elseSeen[elsetracker])
- parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
- // this token is really a dont care, but we still need to eat the tokens
- token = scanToken(ppToken);
- while (token != '\n' && token != EndOfInput)
- token = scanToken(ppToken);
- token = CPPelse(0, ppToken);
- break;
- case PpAtomEndif:
- if (ifdepth == 0)
- parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
- else {
- elseSeen[elsetracker] = false;
- --elsetracker;
- --ifdepth;
- }
- token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
- break;
- case PpAtomIf:
- token = CPPif(ppToken);
- break;
- case PpAtomIfdef:
- token = CPPifdef(1, ppToken);
- break;
- case PpAtomIfndef:
- token = CPPifdef(0, ppToken);
- break;
- case PpAtomLine:
- token = CPPline(ppToken);
- break;
- #ifndef GLSLANG_WEB
- case PpAtomInclude:
- if(!parseContext.isReadingHLSL()) {
- parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include");
- }
- token = CPPinclude(ppToken);
- break;
- case PpAtomPragma:
- token = CPPpragma(ppToken);
- break;
- #endif
- case PpAtomUndef:
- token = CPPundef(ppToken);
- break;
- case PpAtomError:
- token = CPPerror(ppToken);
- break;
- case PpAtomVersion:
- token = CPPversion(ppToken);
- break;
- case PpAtomExtension:
- token = CPPextension(ppToken);
- break;
- default:
- parseContext.ppError(ppToken->loc, "invalid directive:", "#", ppToken->name);
- break;
- }
- } else if (token != '\n' && token != EndOfInput)
- parseContext.ppError(ppToken->loc, "invalid directive", "#", "");
- while (token != '\n' && token != EndOfInput)
- token = scanToken(ppToken);
- return token;
- }
- // Context-dependent parsing of a #include <header-name>.
- // Assumes no macro expansions etc. are being done; the name is just on the current input.
- // Always creates a name and returns PpAtomicConstString, unless we run out of input.
- int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit)
- {
- bool tooLong = false;
- if (inputStack.empty())
- return EndOfInput;
- int len = 0;
- ppToken->name[0] = '\0';
- do {
- int ch = inputStack.back()->getch();
- // done yet?
- if (ch == delimit) {
- ppToken->name[len] = '\0';
- if (tooLong)
- parseContext.ppError(ppToken->loc, "header name too long", "", "");
- return PpAtomConstString;
- } else if (ch == EndOfInput)
- return EndOfInput;
- // found a character to expand the name with
- if (len < MaxTokenLength)
- ppToken->name[len++] = (char)ch;
- else
- tooLong = true;
- } while (true);
- }
- // Macro-expand a macro argument 'arg' to create 'expandedArg'.
- // Does not replace 'arg'.
- // Returns nullptr if no expanded argument is created.
- TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
- {
- // expand the argument
- TokenStream* expandedArg = new TokenStream;
- pushInput(new tMarkerInput(this));
- pushTokenStreamInput(arg);
- int token;
- while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) {
- token = tokenPaste(token, *ppToken);
- if (token == PpAtomIdentifier) {
- switch (MacroExpand(ppToken, false, newLineOkay)) {
- case MacroExpandNotStarted:
- break;
- case MacroExpandError:
- // toss the rest of the pushed-input argument by scanning until tMarkerInput
- while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput)
- ;
- break;
- case MacroExpandStarted:
- case MacroExpandUndef:
- continue;
- }
- }
- if (token == tMarkerInput::marker || token == EndOfInput)
- break;
- expandedArg->putToken(token, ppToken);
- }
- if (token != tMarkerInput::marker) {
- // Error, or MacroExpand ate the marker, so had bad input, recover
- delete expandedArg;
- expandedArg = nullptr;
- }
- return expandedArg;
- }
- //
- // Return the next token for a macro expansion, handling macro arguments,
- // whose semantics are dependent on being adjacent to ##.
- //
- int TPpContext::tMacroInput::scan(TPpToken* ppToken)
- {
- int token;
- do {
- token = mac->body.getToken(pp->parseContext, ppToken);
- } while (token == ' '); // handle white space in macro
- // Hash operators basically turn off a round of macro substitution
- // (the round done on the argument before the round done on the RHS of the
- // macro definition):
- //
- // "A parameter in the replacement list, unless preceded by a # or ##
- // preprocessing token or followed by a ## preprocessing token (see below),
- // is replaced by the corresponding argument after all macros contained
- // therein have been expanded."
- //
- // "If, in the replacement list, a parameter is immediately preceded or
- // followed by a ## preprocessing token, the parameter is replaced by the
- // corresponding argument's preprocessing token sequence."
- bool pasting = false;
- if (postpaste) {
- // don't expand next token
- pasting = true;
- postpaste = false;
- }
- if (prepaste) {
- // already know we should be on a ##, verify
- assert(token == PpAtomPaste);
- prepaste = false;
- postpaste = true;
- }
- // see if are preceding a ##
- if (mac->body.peekUntokenizedPasting()) {
- prepaste = true;
- pasting = true;
- }
- // HLSL does expand macros before concatenation
- if (pasting && pp->parseContext.isReadingHLSL())
- pasting = false;
- // TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding
- if (token == PpAtomIdentifier) {
- int i;
- for (i = (int)mac->args.size() - 1; i >= 0; i--)
- if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0)
- break;
- if (i >= 0) {
- TokenStream* arg = expandedArgs[i];
- if (arg == nullptr || pasting)
- arg = args[i];
- pp->pushTokenStreamInput(*arg, prepaste);
- return pp->scanToken(ppToken);
- }
- }
- if (token == EndOfInput)
- mac->busy = 0;
- return token;
- }
- // return a textual zero, for scanning a macro that was never defined
- int TPpContext::tZeroInput::scan(TPpToken* ppToken)
- {
- if (done)
- return EndOfInput;
- ppToken->name[0] = '0';
- ppToken->name[1] = 0;
- ppToken->ival = 0;
- ppToken->space = false;
- done = true;
- return PpAtomConstInt;
- }
- //
- // Check a token to see if it is a macro that should be expanded:
- // - If it is, and defined, push a tInput that will produce the appropriate
- // expansion and return MacroExpandStarted.
- // - If it is, but undefined, and expandUndef is requested, push a tInput
- // that will expand to 0 and return MacroExpandUndef.
- // - Otherwise, there is no expansion, and there are two cases:
- // * It might be okay there is no expansion, and no specific error was
- // detected. Returns MacroExpandNotStarted.
- // * The expansion was started, but could not be completed, due to an error
- // that cannot be recovered from. Returns MacroExpandError.
- //
- MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)
- {
- ppToken->space = false;
- int macroAtom = atomStrings.getAtom(ppToken->name);
- switch (macroAtom) {
- case PpAtomLineMacro:
- // Arguments which are macro have been replaced in the first stage.
- if (ppToken->ival == 0)
- ppToken->ival = parseContext.getCurrentLoc().line;
- snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
- UngetToken(PpAtomConstInt, ppToken);
- return MacroExpandStarted;
- case PpAtomFileMacro: {
- if (parseContext.getCurrentLoc().name)
- parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
- ppToken->ival = parseContext.getCurrentLoc().string;
- snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str());
- UngetToken(PpAtomConstInt, ppToken);
- return MacroExpandStarted;
- }
- case PpAtomVersionMacro:
- ppToken->ival = parseContext.version;
- snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
- UngetToken(PpAtomConstInt, ppToken);
- return MacroExpandStarted;
- default:
- break;
- }
- MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
- // no recursive expansions
- if (macro != nullptr && macro->busy)
- return MacroExpandNotStarted;
- // not expanding undefined macros
- if ((macro == nullptr || macro->undef) && ! expandUndef)
- return MacroExpandNotStarted;
- // 0 is the value of an undefined macro
- if ((macro == nullptr || macro->undef) && expandUndef) {
- pushInput(new tZeroInput(this));
- return MacroExpandUndef;
- }
- tMacroInput *in = new tMacroInput(this);
- TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error
- in->mac = macro;
- if (macro->functionLike) {
- // We don't know yet if this will be a successful call of a
- // function-like macro; need to look for a '(', but without trashing
- // the passed in ppToken, until we know we are no longer speculative.
- TPpToken parenToken;
- int token = scanToken(&parenToken);
- if (newLineOkay) {
- while (token == '\n')
- token = scanToken(&parenToken);
- }
- if (token != '(') {
- // Function-like macro called with object-like syntax: okay, don't expand.
- // (We ate exactly one token that might not be white space; put it back.
- UngetToken(token, &parenToken);
- delete in;
- return MacroExpandNotStarted;
- }
- in->args.resize(in->mac->args.size());
- for (size_t i = 0; i < in->mac->args.size(); i++)
- in->args[i] = new TokenStream;
- in->expandedArgs.resize(in->mac->args.size());
- for (size_t i = 0; i < in->mac->args.size(); i++)
- in->expandedArgs[i] = nullptr;
- size_t arg = 0;
- bool tokenRecorded = false;
- do {
- TVector<char> nestStack;
- while (true) {
- token = scanToken(ppToken);
- if (token == EndOfInput || token == tMarkerInput::marker) {
- parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
- delete in;
- return MacroExpandError;
- }
- if (token == '\n') {
- if (! newLineOkay) {
- parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom));
- delete in;
- return MacroExpandError;
- }
- continue;
- }
- if (token == '#') {
- parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom));
- delete in;
- return MacroExpandError;
- }
- if (in->mac->args.size() == 0 && token != ')')
- break;
- if (nestStack.size() == 0 && (token == ',' || token == ')'))
- break;
- if (token == '(')
- nestStack.push_back(')');
- else if (token == '{' && parseContext.isReadingHLSL())
- nestStack.push_back('}');
- else if (nestStack.size() > 0 && token == nestStack.back())
- nestStack.pop_back();
- //Macro replacement list is expanded in the last stage.
- if (atomStrings.getAtom(ppToken->name) == PpAtomLineMacro)
- ppToken->ival = parseContext.getCurrentLoc().line;
- in->args[arg]->putToken(token, ppToken);
- tokenRecorded = true;
- }
- // end of single argument scan
- if (token == ')') {
- // closing paren of call
- if (in->mac->args.size() == 1 && !tokenRecorded)
- break;
- arg++;
- break;
- }
- arg++;
- } while (arg < in->mac->args.size());
- // end of all arguments scan
- if (arg < in->mac->args.size())
- parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom));
- else if (token != ')') {
- // Error recover code; find end of call, if possible
- int depth = 0;
- while (token != EndOfInput && (depth > 0 || token != ')')) {
- if (token == ')' || token == '}')
- depth--;
- token = scanToken(ppToken);
- if (token == '(' || token == '{')
- depth++;
- }
- if (token == EndOfInput) {
- parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
- delete in;
- return MacroExpandError;
- }
- parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom));
- }
- // We need both expanded and non-expanded forms of the argument, for whether or
- // not token pasting will be applied later when the argument is consumed next to ##.
- for (size_t i = 0; i < in->mac->args.size(); i++)
- in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay);
- }
- pushInput(in);
- macro->busy = 1;
- macro->body.reset();
- return MacroExpandStarted;
- }
- } // end namespace glslang
|