2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 // Copyright (C) 2013 LunarG, Inc.
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
10 // Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
13 // Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following
15 // disclaimer in the documentation and/or other materials provided
16 // with the distribution.
18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 // contributors may be used to endorse or promote products derived
20 // from this software without specific prior written permission.
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 // POSSIBILITY OF SUCH DAMAGE.
35 /****************************************************************************\
36 Copyright (c) 2002, NVIDIA Corporation.
38 NVIDIA Corporation("NVIDIA") supplies this software to you in
39 consideration of your agreement to the following terms, and your use,
40 installation, modification or redistribution of this NVIDIA software
41 constitutes acceptance of these terms. If you do not agree with these
42 terms, please do not use, install, modify or redistribute this NVIDIA
45 In consideration of your agreement to abide by the following terms, and
46 subject to these terms, NVIDIA grants you a personal, non-exclusive
47 license, under NVIDIA's copyrights in this original NVIDIA software (the
48 "NVIDIA Software"), to use, reproduce, modify and redistribute the
49 NVIDIA Software, with or without modifications, in source and/or binary
50 forms; provided that if you redistribute the NVIDIA Software, you must
51 retain the copyright notice of NVIDIA, this notice and the following
52 text and disclaimers in all such redistributions of the NVIDIA Software.
53 Neither the name, trademarks, service marks nor logos of NVIDIA
54 Corporation may be used to endorse or promote products derived from the
55 NVIDIA Software without specific prior written permission from NVIDIA.
56 Except as expressly stated in this notice, no other rights or licenses
57 express or implied, are granted by NVIDIA herein, including but not
58 limited to any patent rights that may be infringed by your derivative
59 works or by other works in which the NVIDIA Software may be
60 incorporated. No hardware is licensed hereunder.
62 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
63 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
64 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
65 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
66 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
69 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
70 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
71 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
72 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
73 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
74 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
75 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
76 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
77 \****************************************************************************/
79 #define _CRT_SECURE_NO_WARNINGS
86 #include "PpContext.h"
92 int TPpContext::CPPdefine(TPpToken* ppToken)
97 int token = scanToken(ppToken);
98 if (token != PpAtomIdentifier) {
99 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", "");
102 if (ppToken->loc.string >= 0) {
103 // We are in user code; check for reserved name use:
104 parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define");
107 // save the macro name
108 const int defAtom = atomStrings.getAddAtom(ppToken->name);
110 // gather parameters to the macro, between (...)
111 token = scanToken(ppToken);
112 if (token == '(' && ! ppToken->space) {
115 token = scanToken(ppToken);
116 if (mac.args.size() == 0 && token == ')')
118 if (token != PpAtomIdentifier) {
119 parseContext.ppError(ppToken->loc, "bad argument", "#define", "");
124 const int argAtom = atomStrings.getAddAtom(ppToken->name);
126 // check for duplication of parameter name
127 bool duplicate = false;
128 for (size_t a = 0; a < mac.args.size(); ++a) {
129 if (mac.args[a] == argAtom) {
130 parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", "");
136 mac.args.push_back(argAtom);
137 token = scanToken(ppToken);
138 } while (token == ',');
140 parseContext.ppError(ppToken->loc, "missing parenthesis", "#define", "");
145 token = scanToken(ppToken);
148 // record the definition of the macro
149 TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
150 while (token != '\n' && token != EndOfInput) {
151 mac.body.putToken(token, ppToken);
152 token = scanToken(ppToken);
153 if (token != '\n' && ppToken->space)
154 mac.body.putToken(' ', ppToken);
157 // check for duplicate definition
158 MacroSymbol* existing = lookupMacroDef(defAtom);
159 if (existing != nullptr) {
160 if (! existing->undef) {
161 // Already defined -- need to make sure they are identical:
162 // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
163 // ordering, spelling, and white-space separation, where all white-space separations are considered identical."
164 if (existing->args.size() != mac.args.size() || existing->emptyArgs != mac.emptyArgs)
165 parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", atomStrings.getString(defAtom));
167 if (existing->args != mac.args)
168 parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", atomStrings.getString(defAtom));
169 existing->body.reset();
176 oldToken = existing->body.getToken(parseContext, &oldPpToken);
177 newToken = mac.body.getToken(parseContext, &newPpToken);
178 if (oldToken != newToken || oldPpToken != newPpToken) {
179 parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", atomStrings.getString(defAtom));
182 } while (newToken > 0);
187 addMacroDef(defAtom, mac);
193 int TPpContext::CPPundef(TPpToken* ppToken)
195 int token = scanToken(ppToken);
196 if (token != PpAtomIdentifier) {
197 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", "");
202 parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef");
204 MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
205 if (macro != nullptr)
207 token = scanToken(ppToken);
209 parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", "");
215 /* Skip forward to appropriate spot. This is used both
216 ** to skip to a #endif after seeing an #else, AND to skip to a #else,
217 ** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false.
219 int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
222 int token = scanToken(ppToken);
224 while (token != EndOfInput) {
226 while (token != '\n' && token != EndOfInput)
227 token = scanToken(ppToken);
229 if (token == EndOfInput)
232 token = scanToken(ppToken);
236 if ((token = scanToken(ppToken)) != PpAtomIdentifier)
239 int nextAtom = atomStrings.getAtom(ppToken->name);
240 if (nextAtom == PpAtomIf || nextAtom == PpAtomIfdef || nextAtom == PpAtomIfndef) {
244 } else if (nextAtom == PpAtomEndif) {
245 token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
246 elseSeen[elsetracker] = false;
249 // found the #endif we are looking for
256 } else if (matchelse && depth == 0) {
257 if (nextAtom == PpAtomElse) {
258 elseSeen[elsetracker] = true;
259 token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
260 // found the #else we are looking for
262 } else if (nextAtom == PpAtomElif) {
263 if (elseSeen[elsetracker])
264 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
265 /* we decrement ifdepth here, because CPPif will increment
266 * it and we really want to leave it alone */
269 elseSeen[elsetracker] = false;
273 return CPPif(ppToken);
275 } else if (nextAtom == PpAtomElse) {
276 if (elseSeen[elsetracker])
277 parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
279 elseSeen[elsetracker] = true;
280 token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
281 } else if (nextAtom == PpAtomElif) {
282 if (elseSeen[elsetracker])
283 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
290 // Call when there should be no more tokens left on a line.
291 int TPpContext::extraTokenCheck(int contextAtom, TPpToken* ppToken, int token)
293 if (token != '\n' && token != EndOfInput) {
294 static const char* message = "unexpected tokens following directive";
297 if (contextAtom == PpAtomElse)
299 else if (contextAtom == PpAtomElif)
301 else if (contextAtom == PpAtomEndif)
303 else if (contextAtom == PpAtomIf)
305 else if (contextAtom == PpAtomLine)
310 if (parseContext.relaxedErrors())
311 parseContext.ppWarn(ppToken->loc, message, label, "");
313 parseContext.ppError(ppToken->loc, message, label, "");
315 while (token != '\n' && token != EndOfInput)
316 token = scanToken(ppToken);
324 COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
330 int op_logor(int a, int b) { return a || b; }
331 int op_logand(int a, int b) { return a && b; }
332 int op_or(int a, int b) { return a | b; }
333 int op_xor(int a, int b) { return a ^ b; }
334 int op_and(int a, int b) { return a & b; }
335 int op_eq(int a, int b) { return a == b; }
336 int op_ne(int a, int b) { return a != b; }
337 int op_ge(int a, int b) { return a >= b; }
338 int op_le(int a, int b) { return a <= b; }
339 int op_gt(int a, int b) { return a > b; }
340 int op_lt(int a, int b) { return a < b; }
341 int op_shl(int a, int b) { return a << b; }
342 int op_shr(int a, int b) { return a >> b; }
343 int op_add(int a, int b) { return a + b; }
344 int op_sub(int a, int b) { return a - b; }
345 int op_mul(int a, int b) { return a * b; }
346 int op_div(int a, int b) { return a / b; }
347 int op_mod(int a, int b) { return a % b; }
348 int op_pos(int a) { return a; }
349 int op_neg(int a) { return -a; }
350 int op_cmpl(int a) { return ~a; }
351 int op_not(int a) { return !a; }
356 int token, precedence, (*op)(int, int);
358 { PpAtomOr, LOGOR, op_logor },
359 { PpAtomAnd, LOGAND, op_logand },
361 { '^', XOR, op_xor },
362 { '&', AND, op_and },
363 { PpAtomEQ, EQUAL, op_eq },
364 { PpAtomNE, EQUAL, op_ne },
365 { '>', RELATION, op_gt },
366 { PpAtomGE, RELATION, op_ge },
367 { '<', RELATION, op_lt },
368 { PpAtomLE, RELATION, op_le },
369 { PpAtomLeft, SHIFT, op_shl },
370 { PpAtomRight, SHIFT, op_shr },
371 { '+', ADD, op_add },
372 { '-', ADD, op_sub },
373 { '*', MUL, op_mul },
374 { '/', MUL, op_div },
375 { '%', MUL, op_mod },
379 int token, (*op)(int);
387 #define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0]))
389 int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
391 TSourceLoc loc = ppToken->loc; // because we sometimes read the newline before reporting the error
392 if (token == PpAtomIdentifier) {
393 if (strcmp("defined", ppToken->name) == 0) {
395 token = scanToken(ppToken);
398 token = scanToken(ppToken);
400 if (token != PpAtomIdentifier) {
401 parseContext.ppError(loc, "incorrect directive, expected identifier", "preprocessor evaluation", "");
408 MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
409 res = macro != nullptr ? !macro->undef : 0;
410 token = scanToken(ppToken);
413 parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
419 token = scanToken(ppToken);
422 token = evalToToken(token, shortCircuit, res, err, ppToken);
423 return eval(token, precedence, shortCircuit, res, err, ppToken);
425 } else if (token == PpAtomConstInt) {
427 token = scanToken(ppToken);
428 } else if (token == '(') {
429 token = scanToken(ppToken);
430 token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
433 parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
439 token = scanToken(ppToken);
442 int op = NUM_ELEMENTS(unop) - 1;
443 for (; op >= 0; op--) {
444 if (unop[op].token == token)
448 token = scanToken(ppToken);
449 token = eval(token, UNARY, shortCircuit, res, err, ppToken);
450 res = unop[op].op(res);
452 parseContext.ppError(loc, "bad expression", "preprocessor evaluation", "");
460 token = evalToToken(token, shortCircuit, res, err, ppToken);
462 // Perform evaluation of binary operation, if there is one, otherwise we are done.
464 if (token == ')' || token == '\n')
467 for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
468 if (binop[op].token == token)
471 if (op < 0 || binop[op].precedence <= precedence)
475 // Setup short-circuiting, needed for ES, unless already in a short circuit.
476 // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
477 if (! shortCircuit) {
478 if ((token == PpAtomOr && leftSide == 1) ||
479 (token == PpAtomAnd && leftSide == 0))
483 token = scanToken(ppToken);
484 token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);
486 if (binop[op].op == op_div || binop[op].op == op_mod) {
488 parseContext.ppError(loc, "division by 0", "preprocessor evaluation", "");
492 res = binop[op].op(leftSide, res);
498 // Expand macros, skipping empty expansions, to get to the first real token in those expansions.
499 int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
501 while (token == PpAtomIdentifier && strcmp("defined", ppToken->name) != 0) {
502 int macroReturn = MacroExpand(ppToken, true, false);
503 if (macroReturn == 0) {
504 parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", "");
507 token = scanToken(ppToken);
510 if (macroReturn == -1) {
511 if (! shortCircuit && parseContext.profile == EEsProfile) {
512 const char* message = "undefined macro in expression not allowed in es profile";
513 if (parseContext.relaxedErrors())
514 parseContext.ppWarn(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
516 parseContext.ppError(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
519 token = scanToken(ppToken);
526 int TPpContext::CPPif(TPpToken* ppToken)
528 int token = scanToken(ppToken);
531 if (ifdepth > maxIfNesting) {
532 parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
537 token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken);
538 token = extraTokenCheck(PpAtomIf, ppToken, token);
540 token = CPPelse(1, ppToken);
546 int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
548 int token = scanToken(ppToken);
549 if (++ifdepth > maxIfNesting) {
550 parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
554 if (token != PpAtomIdentifier) {
556 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", "");
558 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
560 MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
561 token = scanToken(ppToken);
563 parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
564 while (token != '\n' && token != EndOfInput)
565 token = scanToken(ppToken);
567 if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined)
568 token = CPPelse(1, ppToken);
574 // Handle #include ...
575 // TODO: Handle macro expansions for the header name
576 int TPpContext::CPPinclude(TPpToken* ppToken)
578 const TSourceLoc directiveLoc = ppToken->loc;
579 bool startWithLocalSearch = true; // to additionally include the extra "" paths
580 int token = scanToken(ppToken);
582 // handle <header-name>-style #include
584 startWithLocalSearch = false;
585 token = scanHeaderName(ppToken, '>');
587 // otherwise ppToken already has the header name and it was "header-name" style
589 if (token != PpAtomConstString) {
590 parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", "");
594 // Make a copy of the name because it will be overwritten by the next token scan.
595 const std::string filename = ppToken->name;
597 // See if the directive was well formed
598 token = scanToken(ppToken);
600 if (token == EndOfInput)
601 parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str());
603 parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str());
607 // Process well-formed directive
609 // Find the inclusion, first look in "Local" ("") paths, if requested,
610 // otherwise, only search the "System" (<>) paths.
611 TShader::Includer::IncludeResult* res = nullptr;
612 if (startWithLocalSearch)
613 res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
614 if (! res || res->headerName.empty()) {
615 includer.releaseInclude(res);
616 res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
619 // Process the results
620 if (res && !res->headerName.empty()) {
621 if (res->headerData && res->headerLength) {
622 // path for processing one or more tokens from an included header, hand off 'res'
623 const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
624 std::ostringstream prologue;
625 std::ostringstream epilogue;
626 prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n";
627 epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
628 "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
629 pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
630 // There's no "current" location anymore.
631 parseContext.setCurrentColumn(0);
633 // things are okay, but there is nothing to process
634 includer.releaseInclude(res);
637 // error path, clean up
638 std::string message =
639 res ? std::string(res->headerData, res->headerLength)
640 : std::string("Could not process include directive");
641 parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str());
642 includer.releaseInclude(res);
649 int TPpContext::CPPline(TPpToken* ppToken)
651 // "#line must have, after macro substitution, one of the following forms:
653 // "#line line source-string-number"
655 int token = scanToken(ppToken);
656 const TSourceLoc directiveLoc = ppToken->loc;
658 parseContext.ppError(ppToken->loc, "must by followed by an integral literal", "#line", "");
662 int lineRes = 0; // Line number after macro expansion.
664 bool hasFile = false;
665 int fileRes = 0; // Source file number after macro expansion.
666 const char* sourceName = nullptr; // Optional source file name.
667 bool lineErr = false;
668 bool fileErr = false;
669 token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken);
675 if (parseContext.lineDirectiveShouldSetNextLine())
677 parseContext.setCurrentLine(lineRes);
680 if (token == PpAtomConstString) {
681 parseContext.ppRequireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line");
682 // We need to save a copy of the string instead of pointing
683 // to the name field of the token since the name field
684 // will likely be overwritten by the next token scan.
685 sourceName = atomStrings.getString(atomStrings.getAddAtom(ppToken->name));
686 parseContext.setCurrentSourceName(sourceName);
688 token = scanToken(ppToken);
690 token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
692 parseContext.setCurrentString(fileRes);
698 if (!fileErr && !lineErr) {
699 parseContext.notifyLineDirective(directiveLoc.line, lineToken, hasFile, fileRes, sourceName);
701 token = extraTokenCheck(PpAtomLine, ppToken, token);
707 int TPpContext::CPPerror(TPpToken* ppToken)
709 int token = scanToken(ppToken);
711 TSourceLoc loc = ppToken->loc;
713 while (token != '\n' && token != EndOfInput) {
714 if (token == PpAtomConstInt || token == PpAtomConstUint ||
715 token == PpAtomConstInt64 || token == PpAtomConstUint64 ||
716 #ifdef AMD_EXTENSIONS
717 token == PpAtomConstFloat16 ||
719 token == PpAtomConstFloat || token == PpAtomConstDouble) {
720 message.append(ppToken->name);
721 } else if (token == PpAtomIdentifier || token == PpAtomConstString) {
722 message.append(ppToken->name);
724 message.append(atomStrings.getString(token));
727 token = scanToken(ppToken);
729 parseContext.notifyErrorDirective(loc.line, message.c_str());
730 // store this msg into the shader's information log..set the Compile Error flag!!!!
731 parseContext.ppError(loc, message.c_str(), "#error", "");
737 int TPpContext::CPPpragma(TPpToken* ppToken)
740 TVector<TString> tokens;
742 TSourceLoc loc = ppToken->loc; // because we go to the next line before processing
743 int token = scanToken(ppToken);
744 while (token != '\n' && token != EndOfInput) {
746 case PpAtomIdentifier:
748 case PpAtomConstUint:
749 case PpAtomConstInt64:
750 case PpAtomConstUint64:
751 case PpAtomConstFloat:
752 case PpAtomConstDouble:
753 #ifdef AMD_EXTENSIONS
754 case PpAtomConstFloat16:
756 tokens.push_back(ppToken->name);
759 SrcStrName[0] = (char)token;
760 SrcStrName[1] = '\0';
761 tokens.push_back(SrcStrName);
763 token = scanToken(ppToken);
766 if (token == EndOfInput)
767 parseContext.ppError(loc, "directive must end with a newline", "#pragma", "");
769 parseContext.handlePragma(loc, tokens);
774 // #version: This is just for error checking: the version and profile are decided before preprocessing starts
775 int TPpContext::CPPversion(TPpToken* ppToken)
777 int token = scanToken(ppToken);
779 if (errorOnVersion || versionSeen) {
780 if (parseContext.isReadingHLSL())
781 parseContext.ppError(ppToken->loc, "invalid preprocessor command", "#version", "");
783 parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", "");
788 parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
793 if (token != PpAtomConstInt)
794 parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
796 ppToken->ival = atoi(ppToken->name);
797 int versionNumber = ppToken->ival;
798 int line = ppToken->loc.line;
799 token = scanToken(ppToken);
802 parseContext.notifyVersion(line, versionNumber, nullptr);
805 int profileAtom = atomStrings.getAtom(ppToken->name);
806 if (profileAtom != PpAtomCore &&
807 profileAtom != PpAtomCompatibility &&
808 profileAtom != PpAtomEs)
809 parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
810 parseContext.notifyVersion(line, versionNumber, ppToken->name);
811 token = scanToken(ppToken);
816 parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
823 int TPpContext::CPPextension(TPpToken* ppToken)
825 int line = ppToken->loc.line;
826 int token = scanToken(ppToken);
827 char extensionName[MaxTokenLength + 1];
830 parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", "");
834 if (token != PpAtomIdentifier)
835 parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
837 assert(strlen(ppToken->name) <= MaxTokenLength);
838 strcpy(extensionName, ppToken->name);
840 token = scanToken(ppToken);
842 parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", "");
846 token = scanToken(ppToken);
847 if (token != PpAtomIdentifier) {
848 parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", "");
852 parseContext.updateExtensionBehavior(line, extensionName, ppToken->name);
853 parseContext.notifyExtensionDirective(line, extensionName, ppToken->name);
855 token = scanToken(ppToken);
859 parseContext.ppError(ppToken->loc, "extra tokens -- expected newline", "#extension","");
864 int TPpContext::readCPPline(TPpToken* ppToken)
866 int token = scanToken(ppToken);
868 if (token == PpAtomIdentifier) {
869 switch (atomStrings.getAtom(ppToken->name)) {
871 token = CPPdefine(ppToken);
874 if (elsetracker[elseSeen])
875 parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
876 elsetracker[elseSeen] = true;
878 parseContext.ppError(ppToken->loc, "mismatched statements", "#else", "");
879 token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken));
880 token = CPPelse(0, ppToken);
884 parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", "");
885 if (elseSeen[elsetracker])
886 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
887 // this token is really a dont care, but we still need to eat the tokens
888 token = scanToken(ppToken);
889 while (token != '\n' && token != EndOfInput)
890 token = scanToken(ppToken);
891 token = CPPelse(0, ppToken);
895 parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
897 elseSeen[elsetracker] = false;
901 token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
904 token = CPPif(ppToken);
907 token = CPPifdef(1, ppToken);
910 token = CPPifdef(0, ppToken);
913 if(!parseContext.isReadingHLSL()) {
914 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include");
916 token = CPPinclude(ppToken);
919 token = CPPline(ppToken);
922 token = CPPpragma(ppToken);
925 token = CPPundef(ppToken);
928 token = CPPerror(ppToken);
931 token = CPPversion(ppToken);
933 case PpAtomExtension:
934 token = CPPextension(ppToken);
937 parseContext.ppError(ppToken->loc, "invalid directive:", "#", ppToken->name);
940 } else if (token != '\n' && token != EndOfInput)
941 parseContext.ppError(ppToken->loc, "invalid directive", "#", "");
943 while (token != '\n' && token != EndOfInput)
944 token = scanToken(ppToken);
949 // Context-dependent parsing of a #include <header-name>.
950 // Assumes no macro expansions etc. are being done; the name is just on the current input.
951 // Always creates a name and returns PpAtomicConstString, unless we run out of input.
952 int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit)
954 bool tooLong = false;
956 if (inputStack.empty())
960 ppToken->name[0] = '\0';
962 int ch = inputStack.back()->getch();
966 ppToken->name[len] = '\0';
968 parseContext.ppError(ppToken->loc, "header name too long", "", "");
969 return PpAtomConstString;
970 } else if (ch == EndOfInput)
973 // found a character to expand the name with
974 if (len < MaxTokenLength)
975 ppToken->name[len++] = (char)ch;
981 // Macro-expand a macro argument 'arg' to create 'expandedArg'.
982 // Does not replace 'arg'.
983 // Returns nullptr if no expanded argument is created.
984 TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
986 // expand the argument
987 TokenStream* expandedArg = new TokenStream;
988 pushInput(new tMarkerInput(this));
989 pushTokenStreamInput(arg);
991 while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) {
992 token = tokenPaste(token, *ppToken);
993 if (token == tMarkerInput::marker || token == EndOfInput)
995 if (token == PpAtomIdentifier && MacroExpand(ppToken, false, newLineOkay) != 0)
997 expandedArg->putToken(token, ppToken);
1000 if (token == EndOfInput) {
1001 // MacroExpand ate the marker, so had bad input, recover
1003 expandedArg = nullptr;
1005 // remove the marker
1013 // Return the next token for a macro expansion, handling macro arguments,
1014 // whose semantics are dependent on being adjacent to ##.
1016 int TPpContext::tMacroInput::scan(TPpToken* ppToken)
1020 token = mac->body.getToken(pp->parseContext, ppToken);
1021 } while (token == ' '); // handle white space in macro
1023 // Hash operators basically turn off a round of macro substitution
1024 // (the round done on the argument before the round done on the RHS of the
1025 // macro definition):
1027 // "A parameter in the replacement list, unless preceded by a # or ##
1028 // preprocessing token or followed by a ## preprocessing token (see below),
1029 // is replaced by the corresponding argument after all macros contained
1030 // therein have been expanded."
1032 // "If, in the replacement list, a parameter is immediately preceded or
1033 // followed by a ## preprocessing token, the parameter is replaced by the
1034 // corresponding argument's preprocessing token sequence."
1036 bool pasting = false;
1038 // don't expand next token
1044 // already know we should be on a ##, verify
1045 assert(token == PpAtomPaste);
1050 // see if are preceding a ##
1051 if (mac->body.peekUntokenizedPasting()) {
1056 // TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding
1057 if (token == PpAtomIdentifier) {
1059 for (i = (int)mac->args.size() - 1; i >= 0; i--)
1060 if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0)
1063 TokenStream* arg = expandedArgs[i];
1064 if (arg == nullptr || pasting)
1066 pp->pushTokenStreamInput(*arg, prepaste);
1068 return pp->scanToken(ppToken);
1072 if (token == EndOfInput)
1078 // return a textual zero, for scanning a macro that was never defined
1079 int TPpContext::tZeroInput::scan(TPpToken* ppToken)
1084 strcpy(ppToken->name, "0");
1086 ppToken->space = false;
1089 return PpAtomConstInt;
1093 // Check a token to see if it is a macro that should be expanded.
1094 // If it is, and defined, push a tInput that will produce the appropriate expansion
1096 // If it is, but undefined, and expandUndef is requested, push a tInput that will
1097 // expand to 0 and return -1.
1098 // Otherwise, return 0 to indicate no expansion, which is not necessarily an error.
1100 int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)
1102 ppToken->space = false;
1103 int macroAtom = atomStrings.getAtom(ppToken->name);
1104 switch (macroAtom) {
1105 case PpAtomLineMacro:
1106 ppToken->ival = parseContext.getCurrentLoc().line;
1107 snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1108 UngetToken(PpAtomConstInt, ppToken);
1111 case PpAtomFileMacro: {
1112 if (parseContext.getCurrentLoc().name)
1113 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
1114 ppToken->ival = parseContext.getCurrentLoc().string;
1115 snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str());
1116 UngetToken(PpAtomConstInt, ppToken);
1120 case PpAtomVersionMacro:
1121 ppToken->ival = parseContext.version;
1122 snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1123 UngetToken(PpAtomConstInt, ppToken);
1130 MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
1134 // no recursive expansions
1135 if (macro != nullptr && macro->busy)
1138 // not expanding undefined macros
1139 if ((macro == nullptr || macro->undef) && ! expandUndef)
1142 // 0 is the value of an undefined macro
1143 if ((macro == nullptr || macro->undef) && expandUndef) {
1144 pushInput(new tZeroInput(this));
1148 tMacroInput *in = new tMacroInput(this);
1150 TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error
1152 if (macro->args.size() > 0 || macro->emptyArgs) {
1153 token = scanToken(ppToken);
1155 while (token == '\n')
1156 token = scanToken(ppToken);
1159 parseContext.ppError(loc, "expected '(' following", "macro expansion", atomStrings.getString(macroAtom));
1160 UngetToken(token, ppToken);
1164 in->args.resize(in->mac->args.size());
1165 for (size_t i = 0; i < in->mac->args.size(); i++)
1166 in->args[i] = new TokenStream;
1167 in->expandedArgs.resize(in->mac->args.size());
1168 for (size_t i = 0; i < in->mac->args.size(); i++)
1169 in->expandedArgs[i] = nullptr;
1171 bool tokenRecorded = false;
1175 token = scanToken(ppToken);
1176 if (token == EndOfInput || token == tMarkerInput::marker) {
1177 parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
1181 if (token == '\n') {
1182 if (! newLineOkay) {
1183 parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom));
1190 parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom));
1194 if (in->mac->args.size() == 0 && token != ')')
1196 if (depth == 0 && (token == ',' || token == ')'))
1202 in->args[arg]->putToken(token, ppToken);
1203 tokenRecorded = true;
1206 if (in->mac->args.size() == 1 && tokenRecorded == 0)
1212 } while (arg < in->mac->args.size());
1214 if (arg < in->mac->args.size())
1215 parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom));
1216 else if (token != ')') {
1218 while (token != EndOfInput && (depth > 0 || token != ')')) {
1221 token = scanToken(ppToken);
1226 if (token == EndOfInput) {
1227 parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
1231 parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom));
1234 // We need both expanded and non-expanded forms of the argument, for whether or
1235 // not token pasting will be applied later when the argument is consumed next to ##.
1236 for (size_t i = 0; i < in->mac->args.size(); i++)
1237 in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay);
1242 macro->body.reset();
1247 } // end namespace glslang