2 //Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 //Copyright (C) 2013 LunarG, Inc.
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 \****************************************************************************/
82 #define _CRT_SECURE_NO_WARNINGS
90 #include "PpContext.h"
95 int TPpContext::InitCPP()
97 // Add various atoms needed by the CPP line scanner:
98 bindAtom = LookUpAddString("bind");
99 constAtom = LookUpAddString("const");
100 defaultAtom = LookUpAddString("default");
101 defineAtom = LookUpAddString("define");
102 definedAtom = LookUpAddString("defined");
103 elifAtom = LookUpAddString("elif");
104 elseAtom = LookUpAddString("else");
105 endifAtom = LookUpAddString("endif");
106 ifAtom = LookUpAddString("if");
107 ifdefAtom = LookUpAddString("ifdef");
108 ifndefAtom = LookUpAddString("ifndef");
109 includeAtom = LookUpAddString("include");
110 lineAtom = LookUpAddString("line");
111 pragmaAtom = LookUpAddString("pragma");
112 texunitAtom = LookUpAddString("texunit");
113 undefAtom = LookUpAddString("undef");
114 errorAtom = LookUpAddString("error");
115 __LINE__Atom = LookUpAddString("__LINE__");
116 __FILE__Atom = LookUpAddString("__FILE__");
117 __VERSION__Atom = LookUpAddString("__VERSION__");
118 versionAtom = LookUpAddString("version");
119 coreAtom = LookUpAddString("core");
120 compatibilityAtom = LookUpAddString("compatibility");
121 esAtom = LookUpAddString("es");
122 extensionAtom = LookUpAddString("extension");
123 pool = mem_CreatePool(0, 0);
129 int TPpContext::CPPdefine(TPpToken* ppToken)
135 int token = scanToken(ppToken);
136 if (token != CPP_IDENTIFIER) {
137 parseContext.error(ppToken->loc, "must be followed by macro name", "#define", "");
140 int atom = ppToken->atom;
141 const char* definedName = GetAtomString(atom);
142 if (ppToken->loc.string >= 0) {
143 // We are in user code; check for reserved name use:
144 parseContext.reservedPpErrorCheck(ppToken->loc, definedName, "#define");
147 // gather parameters to the macro, between (...)
148 token = scanToken(ppToken);
149 if (token == '(' && ! ppToken->space) {
151 int args[maxMacroArgs];
153 token = scanToken(ppToken);
154 if (argc == 0 && token == ')')
156 if (token != CPP_IDENTIFIER) {
157 parseContext.error(ppToken->loc, "bad argument", "#define", "");
161 // check for duplication of parameter name
162 bool duplicate = false;
163 for (int a = 0; a < argc; ++a) {
164 if (args[a] == ppToken->atom) {
165 parseContext.error(ppToken->loc, "duplicate macro parameter", "#define", "");
171 if (argc < maxMacroArgs)
172 args[argc++] = ppToken->atom;
174 parseContext.error(ppToken->loc, "too many macro parameters", "#define", "");
176 token = scanToken(ppToken);
177 } while (token == ',');
179 parseContext.error(ppToken->loc, "missing parenthesis", "#define", "");
184 mac.args = (int*)mem_Alloc(pool, argc * sizeof(int));
185 memcpy(mac.args, args, argc * sizeof(int));
186 token = scanToken(ppToken);
189 // record the definition of the macro
190 TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
191 mac.body = new TokenStream;
192 while (token != '\n') {
193 RecordToken(mac.body, token, ppToken);
194 token = scanToken(ppToken);
195 if (token != '\n' && ppToken->space)
196 RecordToken(mac.body, ' ', ppToken);
199 // check for duplicate definition
200 symb = LookUpSymbol(atom);
202 if (! symb->mac.undef) {
203 // Already defined -- need to make sure they are identical:
204 // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
205 // ordering, spelling, and white-space separation, where all white-space separations are considered identical."
206 if (symb->mac.argc != mac.argc)
207 parseContext.error(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(atom));
209 for (int argc = 0; argc < mac.argc; argc++) {
210 if (symb->mac.args[argc] != mac.args[argc])
211 parseContext.error(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(atom));
213 RewindTokenStream(symb->mac.body);
214 RewindTokenStream(mac.body);
220 oldToken = ReadToken(symb->mac.body, &oldPpToken);
221 newToken = ReadToken(mac.body, &newPpToken);
222 if (oldToken != newToken || oldPpToken != newPpToken) {
223 parseContext.error(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(atom));
226 } while (newToken > 0);
230 symb = AddSymbol(atom);
232 delete symb->mac.body;
239 int TPpContext::CPPundef(TPpToken* ppToken)
241 int token = scanToken(ppToken);
243 if (token != CPP_IDENTIFIER) {
244 parseContext.error(ppToken->loc, "must be followed by macro name", "#undef", "");
249 const char* name = GetAtomString(ppToken->atom); // TODO preprocessor simplification: the token text should have been built into the ppToken during scanToken()
250 parseContext.reservedPpErrorCheck(ppToken->loc, name, "#undef");
252 symb = LookUpSymbol(ppToken->atom);
256 token = scanToken(ppToken);
258 parseContext.error(ppToken->loc, "can only be followed by a single macro name", "#undef", "");
264 /* Skip forward to appropriate spot. This is used both
265 ** to skip to a #endif after seeing an #else, AND to skip to a #else,
266 ** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false.
268 int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
272 int token = scanToken(ppToken);
274 while (token != EOF) {
276 while (token != '\n' && token != EOF)
277 token = scanToken(ppToken);
282 token = scanToken(ppToken);
286 if ((token = scanToken(ppToken)) != CPP_IDENTIFIER)
289 atom = ppToken->atom;
290 if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom) {
294 } else if (atom == endifAtom) {
295 token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
296 elseSeen[elsetracker] = false;
299 // found the #endif we are looking for
306 } else if (matchelse && depth == 0) {
307 if (atom == elseAtom) {
308 elseSeen[elsetracker] = true;
309 token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
310 // found the #else we are looking for
312 } else if (atom == elifAtom) {
313 if (elseSeen[elsetracker])
314 parseContext.error(ppToken->loc, "#elif after #else", "#elif", "");
315 /* we decrement ifdepth here, because CPPif will increment
316 * it and we really want to leave it alone */
319 elseSeen[elsetracker] = false;
323 return CPPif(ppToken);
325 } else if (atom == elseAtom) {
326 if (elseSeen[elsetracker])
327 parseContext.error(ppToken->loc, "#else after #else", "#else", "");
329 elseSeen[elsetracker] = true;
330 token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
331 } else if (atom == elifAtom) {
332 if (elseSeen[elsetracker])
333 parseContext.error(ppToken->loc, "#elif after #else", "#elif", "");
340 // Call when there should be no more tokens left on a line.
341 int TPpContext::extraTokenCheck(int atom, TPpToken* ppToken, int token)
344 static const char* message = "unexpected tokens following directive";
347 if (atom == elseAtom)
349 else if (atom == elifAtom)
351 else if (atom == endifAtom)
353 else if (atom == ifAtom)
355 else if (atom == lineAtom)
360 if (parseContext.messages & EShMsgRelaxedErrors)
361 parseContext.warn(ppToken->loc, message, label, "");
363 parseContext.error(ppToken->loc, message, label, "");
365 while (token != '\n')
366 token = scanToken(ppToken);
374 COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
380 int op_logor(int a, int b) { return a || b; }
381 int op_logand(int a, int b) { return a && b; }
382 int op_or(int a, int b) { return a | b; }
383 int op_xor(int a, int b) { return a ^ b; }
384 int op_and(int a, int b) { return a & b; }
385 int op_eq(int a, int b) { return a == b; }
386 int op_ne(int a, int b) { return a != b; }
387 int op_ge(int a, int b) { return a >= b; }
388 int op_le(int a, int b) { return a <= b; }
389 int op_gt(int a, int b) { return a > b; }
390 int op_lt(int a, int b) { return a < b; }
391 int op_shl(int a, int b) { return a << b; }
392 int op_shr(int a, int b) { return a >> b; }
393 int op_add(int a, int b) { return a + b; }
394 int op_sub(int a, int b) { return a - b; }
395 int op_mul(int a, int b) { return a * b; }
396 int op_div(int a, int b) { return a / b; }
397 int op_mod(int a, int b) { return a % b; }
398 int op_pos(int a) { return a; }
399 int op_neg(int a) { return -a; }
400 int op_cmpl(int a) { return ~a; }
401 int op_not(int a) { return !a; }
406 int token, precedence, (*op)(int, int);
408 { CPP_OR_OP, LOGOR, op_logor },
409 { CPP_AND_OP, LOGAND, op_logand },
411 { '^', XOR, op_xor },
412 { '&', AND, op_and },
413 { CPP_EQ_OP, EQUAL, op_eq },
414 { CPP_NE_OP, EQUAL, op_ne },
415 { '>', RELATION, op_gt },
416 { CPP_GE_OP, RELATION, op_ge },
417 { '<', RELATION, op_lt },
418 { CPP_LE_OP, RELATION, op_le },
419 { CPP_LEFT_OP, SHIFT, op_shl },
420 { CPP_RIGHT_OP, SHIFT, op_shr },
421 { '+', ADD, op_add },
422 { '-', ADD, op_sub },
423 { '*', MUL, op_mul },
424 { '/', MUL, op_div },
425 { '%', MUL, op_mod },
429 int token, (*op)(int);
437 #define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0]))
439 int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
441 TSourceLoc loc = ppToken->loc; // because we sometimes read the newline before reporting the error
442 if (token == CPP_IDENTIFIER) {
443 if (ppToken->atom == definedAtom) {
445 token = scanToken(ppToken);
448 token = scanToken(ppToken);
450 if (token != CPP_IDENTIFIER) {
451 parseContext.error(loc, "incorrect directive, expected identifier", "preprocessor evaluation", "");
457 Symbol* s = LookUpSymbol(ppToken->atom);
458 res = s ? ! s->mac.undef : 0;
459 token = scanToken(ppToken);
462 parseContext.error(loc, "expected ')'", "preprocessor evaluation", "");
468 token = scanToken(ppToken);
471 token = evalToToken(token, shortCircuit, res, err, ppToken);
472 return eval(token, precedence, shortCircuit, res, err, ppToken);
474 } else if (token == CPP_INTCONSTANT) {
476 token = scanToken(ppToken);
477 } else if (token == '(') {
478 token = scanToken(ppToken);
479 token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
482 parseContext.error(loc, "expected ')'", "preprocessor evaluation", "");
488 token = scanToken(ppToken);
492 for (op = NUM_ELEMENTS(unop) - 1; op >= 0; op--) {
493 if (unop[op].token == token)
497 token = scanToken(ppToken);
498 token = eval(token, UNARY, shortCircuit, res, err, ppToken);
499 res = unop[op].op(res);
501 parseContext.error(loc, "bad expression", "preprocessor evaluation", "");
509 token = evalToToken(token, shortCircuit, res, err, ppToken);
511 // Perform evaluation of binary operation, if there is one, otherwise we are done.
513 if (token == ')' || token == '\n')
516 for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
517 if (binop[op].token == token)
520 if (op < 0 || binop[op].precedence <= precedence)
524 // Setup short-circuiting, needed for ES, unless already in a short circuit.
525 // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
526 if (! shortCircuit) {
527 if ((token == CPP_OR_OP && leftSide == 1) ||
528 (token == CPP_AND_OP && leftSide == 0))
532 token = scanToken(ppToken);
533 token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);
534 res = binop[op].op(leftSide, res);
540 // Expand macros, skipping empty expansions, to get to the first real token in those expansions.
541 int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
543 while (token == CPP_IDENTIFIER && ppToken->atom != definedAtom) {
544 int macroReturn = MacroExpand(ppToken->atom, ppToken, true, false);
545 if (macroReturn == 0) {
546 parseContext.error(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", "");
549 token = scanToken(ppToken);
552 if (macroReturn == -1) {
553 if (! shortCircuit && parseContext.profile == EEsProfile) {
554 const char* message = "undefined macro in expression not allowed in es profile";
555 const char* name = GetAtomString(ppToken->atom);
556 if (parseContext.messages & EShMsgRelaxedErrors)
557 parseContext.warn(ppToken->loc, message, "preprocessor evaluation", name);
559 parseContext.error(ppToken->loc, message, "preprocessor evaluation", name);
562 token = scanToken(ppToken);
569 int TPpContext::CPPif(TPpToken* ppToken)
571 int token = scanToken(ppToken);
574 ifloc = ppToken->loc;
575 if (ifdepth > maxIfNesting) {
576 parseContext.error(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
581 token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken);
582 token = extraTokenCheck(ifAtom, ppToken, token);
584 token = CPPelse(1, ppToken);
590 int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
592 int token = scanToken(ppToken);
593 int name = ppToken->atom;
594 if (++ifdepth > maxIfNesting) {
595 parseContext.error(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
599 if (token != CPP_IDENTIFIER) {
601 parseContext.error(ppToken->loc, "must be followed by macro name", "#ifdef", "");
603 parseContext.error(ppToken->loc, "must be followed by macro name", "#ifndef", "");
605 Symbol *s = LookUpSymbol(name);
606 token = scanToken(ppToken);
608 parseContext.error(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
609 while (token != '\n')
610 token = scanToken(ppToken);
612 if (((s && !s->mac.undef) ? 1 : 0) != defined)
613 token = CPPelse(1, ppToken);
620 int TPpContext::CPPline(TPpToken* ppToken)
622 // "#line must have, after macro substitution, one of the following forms:
624 // "#line line source-string-number"
626 int token = scanToken(ppToken);
628 parseContext.error(ppToken->loc, "must by followed by an integral literal", "#line", "");
633 bool lineErr = false;
634 token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken);
639 // Desktop, pre-version 3.30: "After processing this directive
640 // (including its new-line), the implementation will behave as if it is compiling at line number line+1 and
641 // source string number source-string-number."
643 // Desktop, version 3.30 and later, and ES: "After processing this directive
644 // (including its new-line), the implementation will behave as if it is compiling at line number line and
645 // source string number source-string-number.
646 if (parseContext.profile == EEsProfile || parseContext.version >= 330)
648 parseContext.setCurrentLine(lineRes);
652 bool fileErr = false;
653 token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
655 parseContext.setCurrentString(fileRes);
659 token = extraTokenCheck(lineAtom, ppToken, token);
665 int TPpContext::CPPerror(TPpToken* ppToken)
667 int token = scanToken(ppToken);
669 TSourceLoc loc = ppToken->loc;
671 while (token != '\n') {
672 if (token == CPP_INTCONSTANT || token == CPP_UINTCONSTANT ||
673 token == CPP_FLOATCONSTANT || token == CPP_DOUBLECONSTANT) {
674 message.append(ppToken->name);
675 } else if (token == CPP_IDENTIFIER || token == CPP_STRCONSTANT) {
676 message.append(GetAtomString(ppToken->atom));
678 message.append(GetAtomString(token));
681 token = scanToken(ppToken);
683 //store this msg into the shader's information log..set the Compile Error flag!!!!
684 parseContext.error(loc, message.c_str(), "#error", "");
690 int TPpContext::CPPpragma(TPpToken* ppToken)
694 TVector<TString> tokens;
696 TSourceLoc loc = ppToken->loc; // because we go to the next line before processing
697 int token = scanToken(ppToken);
698 while (token != '\n' && token != EOF) {
701 SrcStr = GetAtomString(ppToken->atom);
702 tokens.push_back(SrcStr);
704 case CPP_INTCONSTANT:
705 case CPP_UINTCONSTANT:
706 case CPP_FLOATCONSTANT:
707 case CPP_DOUBLECONSTANT:
708 SrcStr = ppToken->name;
709 tokens.push_back(SrcStr);
712 SrcStrName[0] = (char)token;
713 SrcStrName[1] = '\0';
714 tokens.push_back(SrcStrName);
716 token = scanToken(ppToken);
720 parseContext.error(loc, "directive must end with a newline", "#pragma", "");
722 parseContext.handlePragma(loc, tokens);
727 // #version: This is just for error checking: the version and profile are decided before preprocessing starts
728 int TPpContext::CPPversion(TPpToken* ppToken)
730 int token = scanToken(ppToken);
732 if (errorOnVersion || versionSeen)
733 parseContext.error(ppToken->loc, "must occur first in shader", "#version", "");
737 parseContext.error(ppToken->loc, "must be followed by version number", "#version", "");
742 if (token != CPP_INTCONSTANT)
743 parseContext.error(ppToken->loc, "must be followed by version number", "#version", "");
745 ppToken->ival = atoi(ppToken->name);
747 token = scanToken(ppToken);
752 if (ppToken->atom != coreAtom &&
753 ppToken->atom != compatibilityAtom &&
754 ppToken->atom != esAtom)
755 parseContext.error(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
757 token = scanToken(ppToken);
762 parseContext.error(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
769 int TPpContext::CPPextension(TPpToken* ppToken)
771 int token = scanToken(ppToken);
772 char extensionName[80];
775 parseContext.error(ppToken->loc, "extension name not specified", "#extension", "");
779 if (token != CPP_IDENTIFIER)
780 parseContext.error(ppToken->loc, "extension name expected", "#extension", "");
782 strcpy(extensionName, GetAtomString(ppToken->atom));
784 token = scanToken(ppToken);
786 parseContext.error(ppToken->loc, "':' missing after extension name", "#extension", "");
790 token = scanToken(ppToken);
791 if (token != CPP_IDENTIFIER) {
792 parseContext.error(ppToken->loc, "behavior for extension not specified", "#extension", "");
796 parseContext.updateExtensionBehavior(extensionName, GetAtomString(ppToken->atom));
798 token = scanToken(ppToken);
802 parseContext.error(ppToken->loc, "extra tokens -- expected newline", "#extension","");
807 int TPpContext::readCPPline(TPpToken* ppToken)
809 int token = scanToken(ppToken);
810 bool isVersion = false;
812 if (token == CPP_IDENTIFIER) {
813 if (ppToken->atom == defineAtom) {
814 token = CPPdefine(ppToken);
815 } else if (ppToken->atom == elseAtom) {
816 if (elsetracker[elseSeen])
817 parseContext.error(ppToken->loc, "#else after #else", "#else", "");
818 elsetracker[elseSeen] = true;
820 parseContext.error(ppToken->loc, "mismatched statements", "#else", "");
821 token = extraTokenCheck(elseAtom, ppToken, scanToken(ppToken));
822 token = CPPelse(0, ppToken);
823 } else if (ppToken->atom == elifAtom) {
825 parseContext.error(ppToken->loc, "mismatched statements", "#elif", "");
826 if (elseSeen[elsetracker])
827 parseContext.error(ppToken->loc, "#elif after #else", "#elif", "");
828 // this token is really a dont care, but we still need to eat the tokens
829 token = scanToken(ppToken);
830 while (token != '\n')
831 token = scanToken(ppToken);
832 token = CPPelse(0, ppToken);
833 } else if (ppToken->atom == endifAtom) {
834 elseSeen[elsetracker] = false;
837 parseContext.error(ppToken->loc, "mismatched statements", "#endif", "");
840 token = extraTokenCheck(endifAtom, ppToken, scanToken(ppToken));
841 } else if (ppToken->atom == ifAtom) {
842 token = CPPif (ppToken);
843 } else if (ppToken->atom == ifdefAtom) {
844 token = CPPifdef(1, ppToken);
845 } else if (ppToken->atom == ifndefAtom) {
846 token = CPPifdef(0, ppToken);
847 } else if (ppToken->atom == lineAtom) {
848 token = CPPline(ppToken);
849 } else if (ppToken->atom == pragmaAtom) {
850 token = CPPpragma(ppToken);
851 } else if (ppToken->atom == undefAtom) {
852 token = CPPundef(ppToken);
853 } else if (ppToken->atom == errorAtom) {
854 token = CPPerror(ppToken);
855 } else if (ppToken->atom == versionAtom) {
856 token = CPPversion(ppToken);
858 } else if (ppToken->atom == extensionAtom) {
859 token = CPPextension(ppToken);
861 parseContext.error(ppToken->loc, "invalid directive:", "#", GetAtomString(ppToken->atom));
863 } else if (token != '\n' && token != EOF)
864 parseContext.error(ppToken->loc, "invalid directive", "#", "");
866 while (token != '\n' && token != 0 && token != EOF)
867 token = scanToken(ppToken);
872 TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream* a, TPpToken* ppToken, bool newLineOkay)
876 RewindTokenStream(a);
878 token = ReadToken(a, ppToken);
879 if (token == CPP_IDENTIFIER && LookUpSymbol(ppToken->atom))
881 } while (token != tInput::endOfInput);
883 if (token == tInput::endOfInput)
887 pushInput(new tMarkerInput(this));
888 pushTokenStreamInput(a);
889 while ((token = scanToken(ppToken)) != tMarkerInput::marker) {
890 if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, false, newLineOkay) != 0)
892 RecordToken(n, token, ppToken);
901 // Return the next token for a macro expansion, handling macro args.
903 int TPpContext::tMacroInput::scan(TPpToken* ppToken)
907 token = pp->ReadToken(mac->body, ppToken);
908 } while (token == ' '); // handle white space in macro
910 // TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding
911 if (token == CPP_IDENTIFIER) {
913 for (i = mac->argc - 1; i >= 0; i--)
914 if (mac->args[i] == ppToken->atom)
917 pp->pushTokenStreamInput(args[i]);
919 return pp->scanToken(ppToken);
923 if (token == endOfInput)
929 // return a zero, for scanning a macro that was never defined
930 int TPpContext::tZeroInput::scan(TPpToken* ppToken)
935 strcpy(ppToken->name, "0");
937 ppToken->space = false;
940 return CPP_INTCONSTANT;
944 // Check an identifier (atom) to see if it is a macro that should be expanded.
945 // If it is, and defined, push a tInput that will produce the appropriate expansion
947 // If it is, but undefined, and expandUndef is requested, push a tInput that will
948 // expand to 0 and return -1.
949 // Otherwise, return 0 to indicate no expansion, which is not necessarily an error.
951 int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay)
953 Symbol *sym = LookUpSymbol(atom);
957 ppToken->space = false;
958 if (atom == __LINE__Atom) {
959 ppToken->ival = parseContext.getCurrentLoc().line;
960 sprintf(ppToken->name, "%d", ppToken->ival);
961 UngetToken(CPP_INTCONSTANT, ppToken);
966 if (atom == __FILE__Atom) {
967 ppToken->ival = parseContext.getCurrentLoc().string;
968 sprintf(ppToken->name, "%d", ppToken->ival);
969 UngetToken(CPP_INTCONSTANT, ppToken);
974 if (atom == __VERSION__Atom) {
975 ppToken->ival = parseContext.version;
976 sprintf(ppToken->name, "%d", ppToken->ival);
977 UngetToken(CPP_INTCONSTANT, ppToken);
982 // no recursive expansions
983 if (sym && sym->mac.busy)
986 // not expanding undefined macros
987 if ((! sym || sym->mac.undef) && ! expandUndef)
990 // 0 is the value of an undefined macro
991 if ((! sym || sym->mac.undef) && expandUndef) {
992 pushInput(new tZeroInput(this));
996 tMacroInput *in = new tMacroInput(this);
998 TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error
1000 if (sym->mac.args) {
1001 token = scanToken(ppToken);
1003 while (token == '\n')
1004 token = scanToken(ppToken);
1007 parseContext.error(loc, "expected '(' following", "macro expansion", GetAtomString(atom));
1008 UngetToken(token, ppToken);
1009 ppToken->atom = atom;
1014 in->args.resize(in->mac->argc);
1015 for (int i = 0; i < in->mac->argc; i++)
1016 in->args[i] = new TokenStream;
1018 bool tokenRecorded = false;
1022 token = scanToken(ppToken);
1024 parseContext.error(loc, "EOF in macro", "macro expansion", GetAtomString(atom));
1028 if (token == '\n') {
1029 if (! newLineOkay) {
1030 parseContext.error(loc, "end of line in macro substitution:", "macro expansion", GetAtomString(atom));
1037 parseContext.error(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom));
1041 if (in->mac->argc == 0 && token != ')')
1043 if (depth == 0 && (token == ',' || token == ')'))
1049 RecordToken(in->args[arg], token, ppToken);
1050 tokenRecorded = true;
1053 if (in->mac->argc == 1 && tokenRecorded == 0)
1059 } while (arg < in->mac->argc);
1061 if (arg < in->mac->argc)
1062 parseContext.error(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom));
1063 else if (token != ')') {
1065 while (token != EOF && (depth > 0 || token != ')')) {
1068 token = scanToken(ppToken);
1074 parseContext.error(loc, "EOF in macro", "macro expansion", GetAtomString(atom));
1078 parseContext.error(loc, "Too many args in macro", "macro expansion", GetAtomString(atom));
1080 for (int i = 0; i < in->mac->argc; i++)
1081 in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay);
1086 RewindTokenStream(sym->mac.body);
1091 } // end namespace glslang