1 //
2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 // Copyright (C) 2013 LunarG, Inc.
4 // Copyright (C) 2015-2018 Google, Inc.
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //    Redistributions of source code must retain the above copyright
12 //    notice, this list of conditions and the following disclaimer.
13 //
14 //    Redistributions in binary form must reproduce the above
15 //    copyright notice, this list of conditions and the following
16 //    disclaimer in the documentation and/or other materials provided
17 //    with the distribution.
18 //
19 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20 //    contributors may be used to endorse or promote products derived
21 //    from this software without specific prior written permission.
22 //
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 // POSSIBILITY OF SUCH DAMAGE.
35 //
36 /****************************************************************************\
37 Copyright (c) 2002, NVIDIA Corporation.
38 
39 NVIDIA Corporation("NVIDIA") supplies this software to you in
40 consideration of your agreement to the following terms, and your use,
41 installation, modification or redistribution of this NVIDIA software
42 constitutes acceptance of these terms.  If you do not agree with these
43 terms, please do not use, install, modify or redistribute this NVIDIA
44 software.
45 
46 In consideration of your agreement to abide by the following terms, and
47 subject to these terms, NVIDIA grants you a personal, non-exclusive
48 license, under NVIDIA's copyrights in this original NVIDIA software (the
49 "NVIDIA Software"), to use, reproduce, modify and redistribute the
50 NVIDIA Software, with or without modifications, in source and/or binary
51 forms; provided that if you redistribute the NVIDIA Software, you must
52 retain the copyright notice of NVIDIA, this notice and the following
53 text and disclaimers in all such redistributions of the NVIDIA Software.
54 Neither the name, trademarks, service marks nor logos of NVIDIA
55 Corporation may be used to endorse or promote products derived from the
56 NVIDIA Software without specific prior written permission from NVIDIA.
57 Except as expressly stated in this notice, no other rights or licenses
58 express or implied, are granted by NVIDIA herein, including but not
59 limited to any patent rights that may be infringed by your derivative
60 works or by other works in which the NVIDIA Software may be
61 incorporated. No hardware is licensed hereunder.
62 
63 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
64 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
65 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
66 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
67 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
68 PRODUCTS.
69 
70 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
71 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
72 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
73 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
74 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
75 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
76 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
77 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
78 \****************************************************************************/
79 
80 #ifndef _CRT_SECURE_NO_WARNINGS
81 #define _CRT_SECURE_NO_WARNINGS
82 #endif
83 
84 #include <sstream>
85 #include <cstdlib>
86 #include <cstring>
87 #include <cctype>
88 #include <climits>
89 
90 #include "PpContext.h"
91 #include "PpTokens.h"
92 
93 namespace glslang {
94 
95 // Handle #define
CPPdefine(TPpToken* ppToken)96 int TPpContext::CPPdefine(TPpToken* ppToken)
97 {
98     MacroSymbol mac;
99 
100     // get the macro name
101     int token = scanToken(ppToken);
102     if (token != PpAtomIdentifier) {
103         parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", "");
104         return token;
105     }
106     if (ppToken->loc.string >= 0) {
107         // We are in user code; check for reserved name use:
108         parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define");
109     }
110 
111     // save the macro name
112     const int defAtom = atomStrings.getAddAtom(ppToken->name);
113     TSourceLoc defineLoc = ppToken->loc; // because ppToken might go to the next line before we report errors
114 
115     // gather parameters to the macro, between (...)
116     token = scanToken(ppToken);
117     if (token == '(' && !ppToken->space) {
118         mac.functionLike = 1;
119         do {
120             token = scanToken(ppToken);
121             if (mac.args.size() == 0 && token == ')')
122                 break;
123             if (token != PpAtomIdentifier) {
124                 parseContext.ppError(ppToken->loc, "bad argument", "#define", "");
125 
126                 return token;
127             }
128             const int argAtom = atomStrings.getAddAtom(ppToken->name);
129 
130             // check for duplication of parameter name
131             bool duplicate = false;
132             for (size_t a = 0; a < mac.args.size(); ++a) {
133                 if (mac.args[a] == argAtom) {
134                     parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", "");
135                     duplicate = true;
136                     break;
137                 }
138             }
139             if (! duplicate)
140                 mac.args.push_back(argAtom);
141             token = scanToken(ppToken);
142         } while (token == ',');
143         if (token != ')') {
144             parseContext.ppError(ppToken->loc, "missing parenthesis", "#define", "");
145 
146             return token;
147         }
148 
149         token = scanToken(ppToken);
150     } else if (token != '\n' && token != EndOfInput && !ppToken->space) {
151         parseContext.ppWarn(ppToken->loc, "missing space after macro name", "#define", "");
152 
153         return token;
154     }
155 
156     // record the definition of the macro
157     while (token != '\n' && token != EndOfInput) {
158         mac.body.putToken(token, ppToken);
159         token = scanToken(ppToken);
160         if (token != '\n' && ppToken->space)
161             mac.body.putToken(' ', ppToken);
162     }
163 
164     // check for duplicate definition
165     MacroSymbol* existing = lookupMacroDef(defAtom);
166     if (existing != nullptr) {
167         if (! existing->undef) {
168             // Already defined -- need to make sure they are identical:
169             // "Two replacement lists are identical if and only if the
170             // preprocessing tokens in both have the same number,
171             // ordering, spelling, and white-space separation, where all
172             // white-space separations are considered identical."
173             if (existing->functionLike != mac.functionLike) {
174                 parseContext.ppError(defineLoc, "Macro redefined; function-like versus object-like:", "#define",
175                     atomStrings.getString(defAtom));
176             } else if (existing->args.size() != mac.args.size()) {
177                 parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define",
178                     atomStrings.getString(defAtom));
179             } else {
180                 if (existing->args != mac.args) {
181                     parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define",
182                        atomStrings.getString(defAtom));
183                 }
184                 // set up to compare the two
185                 existing->body.reset();
186                 mac.body.reset();
187                 int newToken;
188                 bool firstToken = true;
189                 do {
190                     int oldToken;
191                     TPpToken oldPpToken;
192                     TPpToken newPpToken;
193                     oldToken = existing->body.getToken(parseContext, &oldPpToken);
194                     newToken = mac.body.getToken(parseContext, &newPpToken);
195                     // for the first token, preceding spaces don't matter
196                     if (firstToken) {
197                         newPpToken.space = oldPpToken.space;
198                         firstToken = false;
199                     }
200                     if (oldToken != newToken || oldPpToken != newPpToken) {
201                         parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define",
202                             atomStrings.getString(defAtom));
203                         break;
204                     }
205                 } while (newToken != EndOfInput);
206             }
207         }
208         *existing = mac;
209     } else
210         addMacroDef(defAtom, mac);
211 
212     return '\n';
213 }
214 
215 // Handle #undef
CPPundef(TPpToken* ppToken)216 int TPpContext::CPPundef(TPpToken* ppToken)
217 {
218     int token = scanToken(ppToken);
219     if (token != PpAtomIdentifier) {
220         parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", "");
221 
222         return token;
223     }
224 
225     parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef");
226 
227     MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
228     if (macro != nullptr)
229         macro->undef = 1;
230     token = scanToken(ppToken);
231     if (token != '\n')
232         parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", "");
233 
234     return token;
235 }
236 
237 // Handle #else
238 /* Skip forward to appropriate spot.  This is used both
239 ** to skip to a #endif after seeing an #else, AND to skip to a #else,
240 ** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false.
241 */
CPPelse(int matchelse, TPpToken* ppToken)242 int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
243 {
244     int depth = 0;
245     int token = scanToken(ppToken);
246 
247     while (token != EndOfInput) {
248         if (token != '#') {
249             while (token != '\n' && token != EndOfInput)
250                 token = scanToken(ppToken);
251 
252             if (token == EndOfInput)
253                 return token;
254 
255             token = scanToken(ppToken);
256             continue;
257         }
258 
259         if ((token = scanToken(ppToken)) != PpAtomIdentifier)
260             continue;
261 
262         int nextAtom = atomStrings.getAtom(ppToken->name);
263         if (nextAtom == PpAtomIf || nextAtom == PpAtomIfdef || nextAtom == PpAtomIfndef) {
264             depth++;
265             if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) {
266                 parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if/#ifdef/#ifndef", "");
267                 return EndOfInput;
268             } else {
269                 ifdepth++;
270                 elsetracker++;
271             }
272         } else if (nextAtom == PpAtomEndif) {
273             token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
274             elseSeen[elsetracker] = false;
275             --elsetracker;
276             if (depth == 0) {
277                 // found the #endif we are looking for
278                 if (ifdepth > 0)
279                     --ifdepth;
280                 break;
281             }
282             --depth;
283             --ifdepth;
284         } else if (matchelse && depth == 0) {
285             if (nextAtom == PpAtomElse) {
286                 elseSeen[elsetracker] = true;
287                 token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
288                 // found the #else we are looking for
289                 break;
290             } else if (nextAtom == PpAtomElif) {
291                 if (elseSeen[elsetracker])
292                     parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
293                 /* we decrement ifdepth here, because CPPif will increment
294                 * it and we really want to leave it alone */
295                 if (ifdepth > 0) {
296                     --ifdepth;
297                     elseSeen[elsetracker] = false;
298                     --elsetracker;
299                 }
300 
301                 return CPPif(ppToken);
302             }
303         } else if (nextAtom == PpAtomElse) {
304             if (elseSeen[elsetracker])
305                 parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
306             else
307                 elseSeen[elsetracker] = true;
308             token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
309         } else if (nextAtom == PpAtomElif) {
310             if (elseSeen[elsetracker])
311                 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
312         }
313     }
314 
315     return token;
316 }
317 
318 // Call when there should be no more tokens left on a line.
extraTokenCheck(int contextAtom, TPpToken* ppToken, int token)319 int TPpContext::extraTokenCheck(int contextAtom, TPpToken* ppToken, int token)
320 {
321     if (token != '\n' && token != EndOfInput) {
322         static const char* message = "unexpected tokens following directive";
323 
324         const char* label;
325         if (contextAtom == PpAtomElse)
326             label = "#else";
327         else if (contextAtom == PpAtomElif)
328             label = "#elif";
329         else if (contextAtom == PpAtomEndif)
330             label = "#endif";
331         else if (contextAtom == PpAtomIf)
332             label = "#if";
333         else if (contextAtom == PpAtomLine)
334             label = "#line";
335         else
336             label = "";
337 
338         if (parseContext.relaxedErrors())
339             parseContext.ppWarn(ppToken->loc, message, label, "");
340         else
341             parseContext.ppError(ppToken->loc, message, label, "");
342 
343         while (token != '\n' && token != EndOfInput)
344             token = scanToken(ppToken);
345     }
346 
347     return token;
348 }
349 
350 enum eval_prec {
351     MIN_PRECEDENCE,
352     COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
353     MAX_PRECEDENCE
354 };
355 
356 namespace {
357 
op_logor(int a, int b)358     int op_logor(int a, int b) { return a || b; }
op_logand(int a, int b)359     int op_logand(int a, int b) { return a && b; }
op_or(int a, int b)360     int op_or(int a, int b) { return a | b; }
op_xor(int a, int b)361     int op_xor(int a, int b) { return a ^ b; }
op_and(int a, int b)362     int op_and(int a, int b) { return a & b; }
op_eq(int a, int b)363     int op_eq(int a, int b) { return a == b; }
op_ne(int a, int b)364     int op_ne(int a, int b) { return a != b; }
op_ge(int a, int b)365     int op_ge(int a, int b) { return a >= b; }
op_le(int a, int b)366     int op_le(int a, int b) { return a <= b; }
op_gt(int a, int b)367     int op_gt(int a, int b) { return a > b; }
op_lt(int a, int b)368     int op_lt(int a, int b) { return a < b; }
op_shl(int a, int b)369     int op_shl(int a, int b) { return a << b; }
op_shr(int a, int b)370     int op_shr(int a, int b) { return a >> b; }
op_add(int a, int b)371     int op_add(int a, int b) { return a + b; }
op_sub(int a, int b)372     int op_sub(int a, int b) { return a - b; }
op_mul(int a, int b)373     int op_mul(int a, int b) { return a * b; }
op_div(int a, int b)374     int op_div(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a / b; }
op_mod(int a, int b)375     int op_mod(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a % b; }
op_pos(int a)376     int op_pos(int a) { return a; }
op_neg(int a)377     int op_neg(int a) { return -a; }
op_cmpl(int a)378     int op_cmpl(int a) { return ~a; }
op_not(int a)379     int op_not(int a) { return !a; }
380 
381 struct TBinop {
382     int token, precedence, (*op)(int, int);
383 } binop[] = {
384     { PpAtomOr, LOGOR, op_logor },
385     { PpAtomAnd, LOGAND, op_logand },
386     { '|', OR, op_or },
387     { '^', XOR, op_xor },
388     { '&', AND, op_and },
389     { PpAtomEQ, EQUAL, op_eq },
390     { PpAtomNE, EQUAL, op_ne },
391     { '>', RELATION, op_gt },
392     { PpAtomGE, RELATION, op_ge },
393     { '<', RELATION, op_lt },
394     { PpAtomLE, RELATION, op_le },
395     { PpAtomLeft, SHIFT, op_shl },
396     { PpAtomRight, SHIFT, op_shr },
397     { '+', ADD, op_add },
398     { '-', ADD, op_sub },
399     { '*', MUL, op_mul },
400     { '/', MUL, op_div },
401     { '%', MUL, op_mod },
402 };
403 
404 struct TUnop {
405     int token, (*op)(int);
406 } unop[] = {
407     { '+', op_pos },
408     { '-', op_neg },
409     { '~', op_cmpl },
410     { '!', op_not },
411 };
412 
413 } // anonymous namespace
414 
415 #define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0]))
416 
eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)417 int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
418 {
419     TSourceLoc loc = ppToken->loc;  // because we sometimes read the newline before reporting the error
420     if (token == PpAtomIdentifier) {
421         if (strcmp("defined", ppToken->name) == 0) {
422             if (! parseContext.isReadingHLSL() && isMacroInput()) {
423                 if (parseContext.relaxedErrors())
424                     parseContext.ppWarn(ppToken->loc, "nonportable when expanded from macros for preprocessor expression",
425                         "defined", "");
426                 else
427                     parseContext.ppError(ppToken->loc, "cannot use in preprocessor expression when expanded from macros",
428                         "defined", "");
429             }
430             bool needclose = 0;
431             token = scanToken(ppToken);
432             if (token == '(') {
433                 needclose = true;
434                 token = scanToken(ppToken);
435             }
436             if (token != PpAtomIdentifier) {
437                 parseContext.ppError(loc, "incorrect directive, expected identifier", "preprocessor evaluation", "");
438                 err = true;
439                 res = 0;
440 
441                 return token;
442             }
443 
444             MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
445             res = macro != nullptr ? !macro->undef : 0;
446             token = scanToken(ppToken);
447             if (needclose) {
448                 if (token != ')') {
449                     parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
450                     err = true;
451                     res = 0;
452 
453                     return token;
454                 }
455                 token = scanToken(ppToken);
456             }
457         } else {
458             token = tokenPaste(token, *ppToken);
459             token = evalToToken(token, shortCircuit, res, err, ppToken);
460             return eval(token, precedence, shortCircuit, res, err, ppToken);
461         }
462     } else if (token == PpAtomConstInt) {
463         res = ppToken->ival;
464         token = scanToken(ppToken);
465     } else if (token == '(') {
466         token = scanToken(ppToken);
467         token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
468         if (! err) {
469             if (token != ')') {
470                 parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
471                 err = true;
472                 res = 0;
473 
474                 return token;
475             }
476             token = scanToken(ppToken);
477         }
478     } else {
479         int op = NUM_ELEMENTS(unop) - 1;
480         for (; op >= 0; op--) {
481             if (unop[op].token == token)
482                 break;
483         }
484         if (op >= 0) {
485             token = scanToken(ppToken);
486             token = eval(token, UNARY, shortCircuit, res, err, ppToken);
487             res = unop[op].op(res);
488         } else {
489             parseContext.ppError(loc, "bad expression", "preprocessor evaluation", "");
490             err = true;
491             res = 0;
492 
493             return token;
494         }
495     }
496 
497     token = evalToToken(token, shortCircuit, res, err, ppToken);
498 
499     // Perform evaluation of binary operation, if there is one, otherwise we are done.
500     while (! err) {
501         if (token == ')' || token == '\n')
502             break;
503         int op;
504         for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
505             if (binop[op].token == token)
506                 break;
507         }
508         if (op < 0 || binop[op].precedence <= precedence)
509             break;
510         int leftSide = res;
511 
512         // Setup short-circuiting, needed for ES, unless already in a short circuit.
513         // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
514         if (! shortCircuit) {
515             if ((token == PpAtomOr  && leftSide == 1) ||
516                 (token == PpAtomAnd && leftSide == 0))
517                 shortCircuit = true;
518         }
519 
520         token = scanToken(ppToken);
521         token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);
522 
523         if (binop[op].op == op_div || binop[op].op == op_mod) {
524             if (res == 0) {
525                 parseContext.ppError(loc, "division by 0", "preprocessor evaluation", "");
526                 res = 1;
527             }
528         }
529         res = binop[op].op(leftSide, res);
530     }
531 
532     return token;
533 }
534 
535 // Expand macros, skipping empty expansions, to get to the first real token in those expansions.
evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)536 int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
537 {
538     while (token == PpAtomIdentifier && strcmp("defined", ppToken->name) != 0) {
539         switch (MacroExpand(ppToken, true, false)) {
540         case MacroExpandNotStarted:
541         case MacroExpandError:
542             parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", "");
543             err = true;
544             res = 0;
545             break;
546         case MacroExpandStarted:
547             break;
548         case MacroExpandUndef:
549             if (! shortCircuit && parseContext.isEsProfile()) {
550                 const char* message = "undefined macro in expression not allowed in es profile";
551                 if (parseContext.relaxedErrors())
552                     parseContext.ppWarn(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
553                 else
554                     parseContext.ppError(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
555             }
556             break;
557         }
558         token = scanToken(ppToken);
559         if (err)
560             break;
561     }
562 
563     return token;
564 }
565 
566 // Handle #if
CPPif(TPpToken* ppToken)567 int TPpContext::CPPif(TPpToken* ppToken)
568 {
569     int token = scanToken(ppToken);
570     if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) {
571         parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
572         return EndOfInput;
573     } else {
574         elsetracker++;
575         ifdepth++;
576     }
577     int res = 0;
578     bool err = false;
579     token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken);
580     token = extraTokenCheck(PpAtomIf, ppToken, token);
581     if (!res && !err)
582         token = CPPelse(1, ppToken);
583 
584     return token;
585 }
586 
587 // Handle #ifdef
CPPifdef(int defined, TPpToken* ppToken)588 int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
589 {
590     int token = scanToken(ppToken);
591     if (ifdepth > maxIfNesting || elsetracker > maxIfNesting) {
592         parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
593         return EndOfInput;
594     } else {
595         elsetracker++;
596         ifdepth++;
597     }
598 
599     if (token != PpAtomIdentifier) {
600         if (defined)
601             parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", "");
602         else
603             parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
604     } else {
605         MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
606         token = scanToken(ppToken);
607         if (token != '\n') {
608             parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
609             while (token != '\n' && token != EndOfInput)
610                 token = scanToken(ppToken);
611         }
612         if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined)
613             token = CPPelse(1, ppToken);
614     }
615 
616     return token;
617 }
618 
619 // Handle #include ...
620 // TODO: Handle macro expansions for the header name
CPPinclude(TPpToken* ppToken)621 int TPpContext::CPPinclude(TPpToken* ppToken)
622 {
623     const TSourceLoc directiveLoc = ppToken->loc;
624     bool startWithLocalSearch = true; // to additionally include the extra "" paths
625     int token;
626 
627     // Find the first non-whitespace char after #include
628     int ch = getChar();
629     while (ch == ' ' || ch == '\t') {
630         ch = getChar();
631     }
632     if (ch == '<') {
633         // <header-name> style
634         startWithLocalSearch = false;
635         token = scanHeaderName(ppToken, '>');
636     } else if (ch == '"') {
637         // "header-name" style
638         token = scanHeaderName(ppToken, '"');
639     } else {
640         // unexpected, get the full token to generate the error
641         ungetChar();
642         token = scanToken(ppToken);
643     }
644 
645     if (token != PpAtomConstString) {
646         parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", "");
647         return token;
648     }
649 
650     // Make a copy of the name because it will be overwritten by the next token scan.
651     const std::string filename = ppToken->name;
652 
653     // See if the directive was well formed
654     token = scanToken(ppToken);
655     if (token != '\n') {
656         if (token == EndOfInput)
657             parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str());
658         else
659             parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str());
660         return token;
661     }
662 
663     // Process well-formed directive
664 
665     // Find the inclusion, first look in "Local" ("") paths, if requested,
666     // otherwise, only search the "System" (<>) paths.
667     TShader::Includer::IncludeResult* res = nullptr;
668     if (startWithLocalSearch)
669         res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
670     if (res == nullptr || res->headerName.empty()) {
671         includer.releaseInclude(res);
672         res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
673     }
674 
675     // Process the results
676     if (res != nullptr && !res->headerName.empty()) {
677         if (res->headerData != nullptr && res->headerLength > 0) {
678             // path for processing one or more tokens from an included header, hand off 'res'
679             const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
680             std::ostringstream prologue;
681             std::ostringstream epilogue;
682             prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n";
683             epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
684                 "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
685             pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
686             parseContext.intermediate.addIncludeText(res->headerName.c_str(), res->headerData, res->headerLength);
687             // There's no "current" location anymore.
688             parseContext.setCurrentColumn(0);
689         } else {
690             // things are okay, but there is nothing to process
691             includer.releaseInclude(res);
692         }
693     } else {
694         // error path, clean up
695         std::string message =
696             res != nullptr ? std::string(res->headerData, res->headerLength)
697                            : std::string("Could not process include directive");
698         parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str());
699         includer.releaseInclude(res);
700     }
701 
702     return token;
703 }
704 
705 // Handle #line
CPPline(TPpToken* ppToken)706 int TPpContext::CPPline(TPpToken* ppToken)
707 {
708     // "#line must have, after macro substitution, one of the following forms:
709     // "#line line
710     // "#line line source-string-number"
711 
712     int token = scanToken(ppToken);
713     const TSourceLoc directiveLoc = ppToken->loc;
714     if (token == '\n') {
715         parseContext.ppError(ppToken->loc, "must by followed by an integral literal", "#line", "");
716         return token;
717     }
718 
719     int lineRes = 0; // Line number after macro expansion.
720     int lineToken = 0;
721     bool hasFile = false;
722     int fileRes = 0; // Source file number after macro expansion.
723     const char* sourceName = nullptr; // Optional source file name.
724     bool lineErr = false;
725     bool fileErr = false;
726     disableEscapeSequences = true;
727     token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken);
728     disableEscapeSequences = false;
729     if (! lineErr) {
730         lineToken = lineRes;
731         if (token == '\n')
732             ++lineRes;
733 
734         if (parseContext.lineDirectiveShouldSetNextLine())
735             --lineRes;
736         parseContext.setCurrentLine(lineRes);
737 
738         if (token != '\n') {
739             if (token == PpAtomConstString) {
740                 parseContext.ppRequireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line");
741                 // We need to save a copy of the string instead of pointing
742                 // to the name field of the token since the name field
743                 // will likely be overwritten by the next token scan.
744                 sourceName = atomStrings.getString(atomStrings.getAddAtom(ppToken->name));
745                 parseContext.setCurrentSourceName(sourceName);
746                 hasFile = true;
747                 token = scanToken(ppToken);
748             } else {
749                 token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
750                 if (! fileErr) {
751                     parseContext.setCurrentString(fileRes);
752                     hasFile = true;
753                 }
754             }
755         }
756     }
757     if (!fileErr && !lineErr) {
758         parseContext.notifyLineDirective(directiveLoc.line, lineToken, hasFile, fileRes, sourceName);
759     }
760     token = extraTokenCheck(PpAtomLine, ppToken, token);
761 
762     return token;
763 }
764 
765 // Handle #error
CPPerror(TPpToken* ppToken)766 int TPpContext::CPPerror(TPpToken* ppToken)
767 {
768     disableEscapeSequences = true;
769     int token = scanToken(ppToken);
770     disableEscapeSequences = false;
771     std::string message;
772     TSourceLoc loc = ppToken->loc;
773 
774     while (token != '\n' && token != EndOfInput) {
775         if (token == PpAtomConstInt16 || token == PpAtomConstUint16 ||
776             token == PpAtomConstInt   || token == PpAtomConstUint   ||
777             token == PpAtomConstInt64 || token == PpAtomConstUint64 ||
778             token == PpAtomConstFloat16 ||
779             token == PpAtomConstFloat || token == PpAtomConstDouble) {
780                 message.append(ppToken->name);
781         } else if (token == PpAtomIdentifier || token == PpAtomConstString) {
782             message.append(ppToken->name);
783         } else {
784             message.append(atomStrings.getString(token));
785         }
786         message.append(" ");
787         token = scanToken(ppToken);
788     }
789     parseContext.notifyErrorDirective(loc.line, message.c_str());
790     // store this msg into the shader's information log..set the Compile Error flag!!!!
791     parseContext.ppError(loc, message.c_str(), "#error", "");
792 
793     return '\n';
794 }
795 
796 // Handle #pragma
CPPpragma(TPpToken* ppToken)797 int TPpContext::CPPpragma(TPpToken* ppToken)
798 {
799     char SrcStrName[2];
800     TVector<TString> tokens;
801 
802     TSourceLoc loc = ppToken->loc;  // because we go to the next line before processing
803     int token = scanToken(ppToken);
804     while (token != '\n' && token != EndOfInput) {
805         switch (token) {
806         case PpAtomIdentifier:
807         case PpAtomConstInt:
808         case PpAtomConstUint:
809         case PpAtomConstInt64:
810         case PpAtomConstUint64:
811         case PpAtomConstInt16:
812         case PpAtomConstUint16:
813         case PpAtomConstFloat:
814         case PpAtomConstDouble:
815         case PpAtomConstFloat16:
816             tokens.push_back(ppToken->name);
817             break;
818         default:
819             SrcStrName[0] = (char)token;
820             SrcStrName[1] = '\0';
821             tokens.push_back(SrcStrName);
822         }
823         token = scanToken(ppToken);
824     }
825 
826     if (token == EndOfInput)
827         parseContext.ppError(loc, "directive must end with a newline", "#pragma", "");
828     else
829         parseContext.handlePragma(loc, tokens);
830 
831     return token;
832 }
833 
834 // #version: This is just for error checking: the version and profile are decided before preprocessing starts
CPPversion(TPpToken* ppToken)835 int TPpContext::CPPversion(TPpToken* ppToken)
836 {
837     int token = scanToken(ppToken);
838 
839     if (errorOnVersion || versionSeen) {
840         if (parseContext.isReadingHLSL())
841             parseContext.ppError(ppToken->loc, "invalid preprocessor command", "#version", "");
842         else
843             parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", "");
844     }
845     versionSeen = true;
846 
847     if (token == '\n') {
848         parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
849 
850         return token;
851     }
852 
853     if (token != PpAtomConstInt)
854         parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
855 
856     ppToken->ival = atoi(ppToken->name);
857     int versionNumber = ppToken->ival;
858     int line = ppToken->loc.line;
859     token = scanToken(ppToken);
860 
861     if (token == '\n') {
862         parseContext.notifyVersion(line, versionNumber, nullptr);
863         return token;
864     } else {
865         int profileAtom = atomStrings.getAtom(ppToken->name);
866         if (profileAtom != PpAtomCore &&
867             profileAtom != PpAtomCompatibility &&
868             profileAtom != PpAtomEs)
869             parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
870         parseContext.notifyVersion(line, versionNumber, ppToken->name);
871         token = scanToken(ppToken);
872 
873         if (token == '\n')
874             return token;
875         else
876             parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
877     }
878 
879     return token;
880 }
881 
882 // Handle #extension
CPPextension(TPpToken* ppToken)883 int TPpContext::CPPextension(TPpToken* ppToken)
884 {
885     int line = ppToken->loc.line;
886     int token = scanToken(ppToken);
887     char extensionName[MaxTokenLength + 1];
888 
889     if (token=='\n') {
890         parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", "");
891         return token;
892     }
893 
894     if (token != PpAtomIdentifier)
895         parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
896 
897     snprintf(extensionName, sizeof(extensionName), "%s", ppToken->name);
898 
899     token = scanToken(ppToken);
900     if (token != ':') {
901         parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", "");
902         return token;
903     }
904 
905     token = scanToken(ppToken);
906     if (token != PpAtomIdentifier) {
907         parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", "");
908         return token;
909     }
910 
911     parseContext.updateExtensionBehavior(line, extensionName, ppToken->name);
912     parseContext.notifyExtensionDirective(line, extensionName, ppToken->name);
913 
914     token = scanToken(ppToken);
915     if (token == '\n')
916         return token;
917     else
918         parseContext.ppError(ppToken->loc,  "extra tokens -- expected newline", "#extension","");
919 
920     return token;
921 }
922 
readCPPline(TPpToken* ppToken)923 int TPpContext::readCPPline(TPpToken* ppToken)
924 {
925     int token = scanToken(ppToken);
926 
927     if (token == PpAtomIdentifier) {
928         switch (atomStrings.getAtom(ppToken->name)) {
929         case PpAtomDefine:
930             token = CPPdefine(ppToken);
931             break;
932         case PpAtomElse:
933             if (elseSeen[elsetracker])
934                 parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
935             elseSeen[elsetracker] = true;
936             if (ifdepth == 0)
937                 parseContext.ppError(ppToken->loc, "mismatched statements", "#else", "");
938             token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken));
939             token = CPPelse(0, ppToken);
940             break;
941         case PpAtomElif:
942             if (ifdepth == 0)
943                 parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", "");
944             if (elseSeen[elsetracker])
945                 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
946             // this token is really a dont care, but we still need to eat the tokens
947             token = scanToken(ppToken);
948             while (token != '\n' && token != EndOfInput)
949                 token = scanToken(ppToken);
950             token = CPPelse(0, ppToken);
951             break;
952         case PpAtomEndif:
953             if (ifdepth == 0)
954                 parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
955             else {
956                 elseSeen[elsetracker] = false;
957                 --elsetracker;
958                 --ifdepth;
959             }
960             token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
961             break;
962         case PpAtomIf:
963             token = CPPif(ppToken);
964             break;
965         case PpAtomIfdef:
966             token = CPPifdef(1, ppToken);
967             break;
968         case PpAtomIfndef:
969             token = CPPifdef(0, ppToken);
970             break;
971         case PpAtomLine:
972             token = CPPline(ppToken);
973             break;
974         case PpAtomInclude:
975             if(!parseContext.isReadingHLSL()) {
976                 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include");
977             }
978             token = CPPinclude(ppToken);
979             break;
980         case PpAtomPragma:
981             token = CPPpragma(ppToken);
982             break;
983         case PpAtomUndef:
984             token = CPPundef(ppToken);
985             break;
986         case PpAtomError:
987             token = CPPerror(ppToken);
988             break;
989         case PpAtomVersion:
990             token = CPPversion(ppToken);
991             break;
992         case PpAtomExtension:
993             token = CPPextension(ppToken);
994             break;
995         default:
996             parseContext.ppError(ppToken->loc, "invalid directive:", "#", ppToken->name);
997             break;
998         }
999     } else if (token != '\n' && token != EndOfInput)
1000         parseContext.ppError(ppToken->loc, "invalid directive", "#", "");
1001 
1002     while (token != '\n' && token != EndOfInput)
1003         token = scanToken(ppToken);
1004 
1005     return token;
1006 }
1007 
1008 // Context-dependent parsing of a #include <header-name>.
1009 // Assumes no macro expansions etc. are being done; the name is just on the current input.
1010 // Always creates a name and returns PpAtomicConstString, unless we run out of input.
scanHeaderName(TPpToken* ppToken, char delimit)1011 int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit)
1012 {
1013     bool tooLong = false;
1014 
1015     if (inputStack.empty())
1016         return EndOfInput;
1017 
1018     int len = 0;
1019     ppToken->name[0] = '\0';
1020     do {
1021         int ch = inputStack.back()->getch();
1022 
1023         // done yet?
1024         if (ch == delimit) {
1025             ppToken->name[len] = '\0';
1026             if (tooLong)
1027                 parseContext.ppError(ppToken->loc, "header name too long", "", "");
1028             return PpAtomConstString;
1029         } else if (ch == EndOfInput)
1030             return EndOfInput;
1031 
1032         // found a character to expand the name with
1033         if (len < MaxTokenLength)
1034             ppToken->name[len++] = (char)ch;
1035         else
1036             tooLong = true;
1037     } while (true);
1038 }
1039 
1040 // Macro-expand a macro argument 'arg' to create 'expandedArg'.
1041 // Does not replace 'arg'.
1042 // Returns nullptr if no expanded argument is created.
PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)1043 TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
1044 {
1045     // expand the argument
1046     TokenStream* expandedArg = new TokenStream;
1047     pushInput(new tMarkerInput(this));
1048     pushTokenStreamInput(arg);
1049     int token;
1050     while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) {
1051         token = tokenPaste(token, *ppToken);
1052         if (token == PpAtomIdentifier) {
1053             switch (MacroExpand(ppToken, false, newLineOkay)) {
1054             case MacroExpandNotStarted:
1055                 break;
1056             case MacroExpandError:
1057                 // toss the rest of the pushed-input argument by scanning until tMarkerInput
1058                 while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput)
1059                     ;
1060                 break;
1061             case MacroExpandStarted:
1062             case MacroExpandUndef:
1063                 continue;
1064             }
1065         }
1066         if (token == tMarkerInput::marker || token == EndOfInput)
1067             break;
1068         expandedArg->putToken(token, ppToken);
1069     }
1070 
1071     if (token != tMarkerInput::marker) {
1072         // Error, or MacroExpand ate the marker, so had bad input, recover
1073         delete expandedArg;
1074         expandedArg = nullptr;
1075     }
1076 
1077     return expandedArg;
1078 }
1079 
1080 //
1081 // Return the next token for a macro expansion, handling macro arguments,
1082 // whose semantics are dependent on being adjacent to ##.
1083 //
scan(TPpToken* ppToken)1084 int TPpContext::tMacroInput::scan(TPpToken* ppToken)
1085 {
1086     int token;
1087     do {
1088         token = mac->body.getToken(pp->parseContext, ppToken);
1089     } while (token == ' ');  // handle white space in macro
1090 
1091     // Hash operators basically turn off a round of macro substitution
1092     // (the round done on the argument before the round done on the RHS of the
1093     // macro definition):
1094     //
1095     // "A parameter in the replacement list, unless preceded by a # or ##
1096     // preprocessing token or followed by a ## preprocessing token (see below),
1097     // is replaced by the corresponding argument after all macros contained
1098     // therein have been expanded."
1099     //
1100     // "If, in the replacement list, a parameter is immediately preceded or
1101     // followed by a ## preprocessing token, the parameter is replaced by the
1102     // corresponding argument's preprocessing token sequence."
1103 
1104     bool pasting = false;
1105     if (postpaste) {
1106         // don't expand next token
1107         pasting = true;
1108         postpaste = false;
1109     }
1110 
1111     if (prepaste) {
1112         // already know we should be on a ##, verify
1113         assert(token == PpAtomPaste);
1114         prepaste = false;
1115         postpaste = true;
1116     }
1117 
1118     // see if are preceding a ##
1119     if (mac->body.peekUntokenizedPasting()) {
1120         prepaste = true;
1121         pasting = true;
1122     }
1123 
1124 
1125     // TODO: preprocessor:  properly handle whitespace (or lack of it) between tokens when expanding
1126     if (token == PpAtomIdentifier) {
1127         int i;
1128         for (i = (int)mac->args.size() - 1; i >= 0; i--)
1129             if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0)
1130                 break;
1131         if (i >= 0) {
1132             TokenStream* arg = expandedArgs[i];
1133             bool expanded = !!arg && !pasting;
1134             // HLSL does expand macros before concatenation
1135             if (arg == nullptr || (pasting && !pp->parseContext.isReadingHLSL()) ) {
1136                 arg = args[i];
1137             }
1138             pp->pushTokenStreamInput(*arg, prepaste, expanded);
1139 
1140             return pp->scanToken(ppToken);
1141         }
1142     }
1143 
1144     if (token == EndOfInput)
1145         mac->busy = 0;
1146 
1147     return token;
1148 }
1149 
1150 // return a textual zero, for scanning a macro that was never defined
scan(TPpToken* ppToken)1151 int TPpContext::tZeroInput::scan(TPpToken* ppToken)
1152 {
1153     if (done)
1154         return EndOfInput;
1155 
1156     ppToken->name[0] = '0';
1157     ppToken->name[1] = 0;
1158     ppToken->ival = 0;
1159     ppToken->space = false;
1160     done = true;
1161 
1162     return PpAtomConstInt;
1163 }
1164 
1165 //
1166 // Check a token to see if it is a macro that should be expanded:
1167 // - If it is, and defined, push a tInput that will produce the appropriate
1168 //   expansion and return MacroExpandStarted.
1169 // - If it is, but undefined, and expandUndef is requested, push a tInput
1170 //   that will expand to 0 and return MacroExpandUndef.
1171 // - Otherwise, there is no expansion, and there are two cases:
1172 //   * It might be okay there is no expansion, and no specific error was
1173 //     detected. Returns MacroExpandNotStarted.
1174 //   * The expansion was started, but could not be completed, due to an error
1175 //     that cannot be recovered from. Returns MacroExpandError.
1176 //
MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)1177 MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)
1178 {
1179     ppToken->space = false;
1180     int macroAtom = atomStrings.getAtom(ppToken->name);
1181     if (ppToken->fullyExpanded)
1182         return MacroExpandNotStarted;
1183 
1184     switch (macroAtom) {
1185     case PpAtomLineMacro:
1186         // Arguments which are macro have been replaced in the first stage.
1187         if (ppToken->ival == 0)
1188             ppToken->ival = parseContext.getCurrentLoc().line;
1189         snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1190         UngetToken(PpAtomConstInt, ppToken);
1191         return MacroExpandStarted;
1192 
1193     case PpAtomFileMacro: {
1194         if (parseContext.getCurrentLoc().name)
1195             parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
1196         ppToken->ival = parseContext.getCurrentLoc().string;
1197         snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str());
1198         UngetToken(PpAtomConstInt, ppToken);
1199         return MacroExpandStarted;
1200     }
1201 
1202     case PpAtomVersionMacro:
1203         ppToken->ival = parseContext.version;
1204         snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1205         UngetToken(PpAtomConstInt, ppToken);
1206         return MacroExpandStarted;
1207 
1208     default:
1209         break;
1210     }
1211 
1212     MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
1213 
1214     // no recursive expansions
1215     if (macro != nullptr && macro->busy) {
1216         ppToken->fullyExpanded = true;
1217         return MacroExpandNotStarted;
1218     }
1219 
1220     // not expanding undefined macros
1221     if ((macro == nullptr || macro->undef) && ! expandUndef)
1222         return MacroExpandNotStarted;
1223 
1224     // 0 is the value of an undefined macro
1225     if ((macro == nullptr || macro->undef) && expandUndef) {
1226         pushInput(new tZeroInput(this));
1227         return MacroExpandUndef;
1228     }
1229 
1230     tMacroInput *in = new tMacroInput(this);
1231 
1232     TSourceLoc loc = ppToken->loc;  // in case we go to the next line before discovering the error
1233     in->mac = macro;
1234     if (macro->functionLike) {
1235         // We don't know yet if this will be a successful call of a
1236         // function-like macro; need to look for a '(', but without trashing
1237         // the passed in ppToken, until we know we are no longer speculative.
1238         TPpToken parenToken;
1239         int token = scanToken(&parenToken);
1240         if (newLineOkay) {
1241             while (token == '\n')
1242                 token = scanToken(&parenToken);
1243         }
1244         if (token != '(') {
1245             // Function-like macro called with object-like syntax: okay, don't expand.
1246             // (We ate exactly one token that might not be white space; put it back.
1247             UngetToken(token, &parenToken);
1248             delete in;
1249             return MacroExpandNotStarted;
1250         }
1251         in->args.resize(in->mac->args.size());
1252         for (size_t i = 0; i < in->mac->args.size(); i++)
1253             in->args[i] = new TokenStream;
1254         in->expandedArgs.resize(in->mac->args.size());
1255         for (size_t i = 0; i < in->mac->args.size(); i++)
1256             in->expandedArgs[i] = nullptr;
1257         size_t arg = 0;
1258         bool tokenRecorded = false;
1259         do {
1260             TVector<char> nestStack;
1261             while (true) {
1262                 token = scanToken(ppToken);
1263                 if (token == EndOfInput || token == tMarkerInput::marker) {
1264                     parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
1265                     delete in;
1266                     return MacroExpandError;
1267                 }
1268                 if (token == '\n') {
1269                     if (! newLineOkay) {
1270                         parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom));
1271                         delete in;
1272                         return MacroExpandError;
1273                     }
1274                     continue;
1275                 }
1276                 if (token == '#') {
1277                     parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom));
1278                     delete in;
1279                     return MacroExpandError;
1280                 }
1281                 if (in->mac->args.size() == 0 && token != ')')
1282                     break;
1283                 if (nestStack.size() == 0 && (token == ',' || token == ')'))
1284                     break;
1285                 if (token == '(')
1286                     nestStack.push_back(')');
1287                 else if (token == '{' && parseContext.isReadingHLSL())
1288                     nestStack.push_back('}');
1289                 else if (nestStack.size() > 0 && token == nestStack.back())
1290                     nestStack.pop_back();
1291 
1292                 //Macro replacement list is expanded in the last stage.
1293                 if (atomStrings.getAtom(ppToken->name) == PpAtomLineMacro)
1294                     ppToken->ival = parseContext.getCurrentLoc().line;
1295 
1296                 in->args[arg]->putToken(token, ppToken);
1297                 tokenRecorded = true;
1298             }
1299             // end of single argument scan
1300 
1301             if (token == ')') {
1302                 // closing paren of call
1303                 if (in->mac->args.size() == 1 && !tokenRecorded)
1304                     break;
1305                 arg++;
1306                 break;
1307             }
1308             arg++;
1309         } while (arg < in->mac->args.size());
1310         // end of all arguments scan
1311 
1312         if (arg < in->mac->args.size())
1313             parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom));
1314         else if (token != ')') {
1315             // Error recover code; find end of call, if possible
1316             int depth = 0;
1317             while (token != EndOfInput && (depth > 0 || token != ')')) {
1318                 if (token == ')' || token == '}')
1319                     depth--;
1320                 token = scanToken(ppToken);
1321                 if (token == '(' || token == '{')
1322                     depth++;
1323             }
1324 
1325             if (token == EndOfInput) {
1326                 parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
1327                 delete in;
1328                 return MacroExpandError;
1329             }
1330             parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom));
1331         }
1332 
1333         // We need both expanded and non-expanded forms of the argument, for whether or
1334         // not token pasting will be applied later when the argument is consumed next to ##.
1335         for (size_t i = 0; i < in->mac->args.size(); i++)
1336             in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay);
1337     }
1338 
1339     pushInput(in);
1340     macro->busy = 1;
1341     macro->body.reset();
1342 
1343     return MacroExpandStarted;
1344 }
1345 
1346 } // end namespace glslang
1347