• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 };
382 
383 struct TBinop {
384     int token, precedence, (*op)(int, int);
385 } binop[] = {
386     { PpAtomOr, LOGOR, op_logor },
387     { PpAtomAnd, LOGAND, op_logand },
388     { '|', OR, op_or },
389     { '^', XOR, op_xor },
390     { '&', AND, op_and },
391     { PpAtomEQ, EQUAL, op_eq },
392     { PpAtomNE, EQUAL, op_ne },
393     { '>', RELATION, op_gt },
394     { PpAtomGE, RELATION, op_ge },
395     { '<', RELATION, op_lt },
396     { PpAtomLE, RELATION, op_le },
397     { PpAtomLeft, SHIFT, op_shl },
398     { PpAtomRight, SHIFT, op_shr },
399     { '+', ADD, op_add },
400     { '-', ADD, op_sub },
401     { '*', MUL, op_mul },
402     { '/', MUL, op_div },
403     { '%', MUL, op_mod },
404 };
405 
406 struct TUnop {
407     int token, (*op)(int);
408 } unop[] = {
409     { '+', op_pos },
410     { '-', op_neg },
411     { '~', op_cmpl },
412     { '!', op_not },
413 };
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 = evalToToken(token, shortCircuit, res, err, ppToken);
459             return eval(token, precedence, shortCircuit, res, err, ppToken);
460         }
461     } else if (token == PpAtomConstInt) {
462         res = ppToken->ival;
463         token = scanToken(ppToken);
464     } else if (token == '(') {
465         token = scanToken(ppToken);
466         token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
467         if (! err) {
468             if (token != ')') {
469                 parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
470                 err = true;
471                 res = 0;
472 
473                 return token;
474             }
475             token = scanToken(ppToken);
476         }
477     } else {
478         int op = NUM_ELEMENTS(unop) - 1;
479         for (; op >= 0; op--) {
480             if (unop[op].token == token)
481                 break;
482         }
483         if (op >= 0) {
484             token = scanToken(ppToken);
485             token = eval(token, UNARY, shortCircuit, res, err, ppToken);
486             res = unop[op].op(res);
487         } else {
488             parseContext.ppError(loc, "bad expression", "preprocessor evaluation", "");
489             err = true;
490             res = 0;
491 
492             return token;
493         }
494     }
495 
496     token = evalToToken(token, shortCircuit, res, err, ppToken);
497 
498     // Perform evaluation of binary operation, if there is one, otherwise we are done.
499     while (! err) {
500         if (token == ')' || token == '\n')
501             break;
502         int op;
503         for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
504             if (binop[op].token == token)
505                 break;
506         }
507         if (op < 0 || binop[op].precedence <= precedence)
508             break;
509         int leftSide = res;
510 
511         // Setup short-circuiting, needed for ES, unless already in a short circuit.
512         // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
513         if (! shortCircuit) {
514             if ((token == PpAtomOr  && leftSide == 1) ||
515                 (token == PpAtomAnd && leftSide == 0))
516                 shortCircuit = true;
517         }
518 
519         token = scanToken(ppToken);
520         token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);
521 
522         if (binop[op].op == op_div || binop[op].op == op_mod) {
523             if (res == 0) {
524                 parseContext.ppError(loc, "division by 0", "preprocessor evaluation", "");
525                 res = 1;
526             }
527         }
528         res = binop[op].op(leftSide, res);
529     }
530 
531     return token;
532 }
533 
534 // 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)535 int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
536 {
537     while (token == PpAtomIdentifier && strcmp("defined", ppToken->name) != 0) {
538         switch (MacroExpand(ppToken, true, false)) {
539         case MacroExpandNotStarted:
540         case MacroExpandError:
541             parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", "");
542             err = true;
543             res = 0;
544             break;
545         case MacroExpandStarted:
546             break;
547         case MacroExpandUndef:
548             if (! shortCircuit && parseContext.isEsProfile()) {
549                 const char* message = "undefined macro in expression not allowed in es profile";
550                 if (parseContext.relaxedErrors())
551                     parseContext.ppWarn(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
552                 else
553                     parseContext.ppError(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
554             }
555             break;
556         }
557         token = scanToken(ppToken);
558         if (err)
559             break;
560     }
561 
562     return token;
563 }
564 
565 // Handle #if
CPPif(TPpToken * ppToken)566 int TPpContext::CPPif(TPpToken* ppToken)
567 {
568     int token = scanToken(ppToken);
569     if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) {
570         parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
571         return EndOfInput;
572     } else {
573         elsetracker++;
574         ifdepth++;
575     }
576     int res = 0;
577     bool err = false;
578     token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken);
579     token = extraTokenCheck(PpAtomIf, ppToken, token);
580     if (!res && !err)
581         token = CPPelse(1, ppToken);
582 
583     return token;
584 }
585 
586 // Handle #ifdef
CPPifdef(int defined,TPpToken * ppToken)587 int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
588 {
589     int token = scanToken(ppToken);
590     if (ifdepth > maxIfNesting || elsetracker > maxIfNesting) {
591         parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
592         return EndOfInput;
593     } else {
594         elsetracker++;
595         ifdepth++;
596     }
597 
598     if (token != PpAtomIdentifier) {
599         if (defined)
600             parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", "");
601         else
602             parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
603     } else {
604         MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
605         token = scanToken(ppToken);
606         if (token != '\n') {
607             parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
608             while (token != '\n' && token != EndOfInput)
609                 token = scanToken(ppToken);
610         }
611         if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined)
612             token = CPPelse(1, ppToken);
613     }
614 
615     return token;
616 }
617 
618 // Handle #include ...
619 // TODO: Handle macro expansions for the header name
CPPinclude(TPpToken * ppToken)620 int TPpContext::CPPinclude(TPpToken* ppToken)
621 {
622     const TSourceLoc directiveLoc = ppToken->loc;
623     bool startWithLocalSearch = true; // to additionally include the extra "" paths
624     int token;
625 
626     // Find the first non-whitespace char after #include
627     int ch = getChar();
628     while (ch == ' ' || ch == '\t') {
629         ch = getChar();
630     }
631     if (ch == '<') {
632         // <header-name> style
633         startWithLocalSearch = false;
634         token = scanHeaderName(ppToken, '>');
635     } else if (ch == '"') {
636         // "header-name" style
637         token = scanHeaderName(ppToken, '"');
638     } else {
639         // unexpected, get the full token to generate the error
640         ungetChar();
641         token = scanToken(ppToken);
642     }
643 
644     if (token != PpAtomConstString) {
645         parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", "");
646         return token;
647     }
648 
649     // Make a copy of the name because it will be overwritten by the next token scan.
650     const std::string filename = ppToken->name;
651 
652     // See if the directive was well formed
653     token = scanToken(ppToken);
654     if (token != '\n') {
655         if (token == EndOfInput)
656             parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str());
657         else
658             parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str());
659         return token;
660     }
661 
662     // Process well-formed directive
663 
664     // Find the inclusion, first look in "Local" ("") paths, if requested,
665     // otherwise, only search the "System" (<>) paths.
666     TShader::Includer::IncludeResult* res = nullptr;
667     if (startWithLocalSearch)
668         res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
669     if (res == nullptr || res->headerName.empty()) {
670         includer.releaseInclude(res);
671         res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
672     }
673 
674     // Process the results
675     if (res != nullptr && !res->headerName.empty()) {
676         if (res->headerData != nullptr && res->headerLength > 0) {
677             // path for processing one or more tokens from an included header, hand off 'res'
678             const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
679             std::ostringstream prologue;
680             std::ostringstream epilogue;
681             prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n";
682             epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
683                 "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
684             pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
685             parseContext.intermediate.addIncludeText(res->headerName.c_str(), res->headerData, res->headerLength);
686             // There's no "current" location anymore.
687             parseContext.setCurrentColumn(0);
688         } else {
689             // things are okay, but there is nothing to process
690             includer.releaseInclude(res);
691         }
692     } else {
693         // error path, clean up
694         std::string message =
695             res != nullptr ? std::string(res->headerData, res->headerLength)
696                            : std::string("Could not process include directive");
697         parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str());
698         includer.releaseInclude(res);
699     }
700 
701     return token;
702 }
703 
704 // Handle #line
CPPline(TPpToken * ppToken)705 int TPpContext::CPPline(TPpToken* ppToken)
706 {
707     // "#line must have, after macro substitution, one of the following forms:
708     // "#line line
709     // "#line line source-string-number"
710 
711     int token = scanToken(ppToken);
712     const TSourceLoc directiveLoc = ppToken->loc;
713     if (token == '\n') {
714         parseContext.ppError(ppToken->loc, "must by followed by an integral literal", "#line", "");
715         return token;
716     }
717 
718     int lineRes = 0; // Line number after macro expansion.
719     int lineToken = 0;
720     bool hasFile = false;
721     int fileRes = 0; // Source file number after macro expansion.
722     const char* sourceName = nullptr; // Optional source file name.
723     bool lineErr = false;
724     bool fileErr = false;
725     disableEscapeSequences = true;
726     token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken);
727     disableEscapeSequences = false;
728     if (! lineErr) {
729         lineToken = lineRes;
730         if (token == '\n')
731             ++lineRes;
732 
733         if (parseContext.lineDirectiveShouldSetNextLine())
734             --lineRes;
735         parseContext.setCurrentLine(lineRes);
736 
737         if (token != '\n') {
738 #ifndef GLSLANG_WEB
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 #endif
750             {
751                 token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
752                 if (! fileErr) {
753                     parseContext.setCurrentString(fileRes);
754                     hasFile = true;
755                 }
756             }
757         }
758     }
759     if (!fileErr && !lineErr) {
760         parseContext.notifyLineDirective(directiveLoc.line, lineToken, hasFile, fileRes, sourceName);
761     }
762     token = extraTokenCheck(PpAtomLine, ppToken, token);
763 
764     return token;
765 }
766 
767 // Handle #error
CPPerror(TPpToken * ppToken)768 int TPpContext::CPPerror(TPpToken* ppToken)
769 {
770     disableEscapeSequences = true;
771     int token = scanToken(ppToken);
772     disableEscapeSequences = false;
773     std::string message;
774     TSourceLoc loc = ppToken->loc;
775 
776     while (token != '\n' && token != EndOfInput) {
777         if (token == PpAtomConstInt16 || token == PpAtomConstUint16 ||
778             token == PpAtomConstInt   || token == PpAtomConstUint   ||
779             token == PpAtomConstInt64 || token == PpAtomConstUint64 ||
780             token == PpAtomConstFloat16 ||
781             token == PpAtomConstFloat || token == PpAtomConstDouble) {
782                 message.append(ppToken->name);
783         } else if (token == PpAtomIdentifier || token == PpAtomConstString) {
784             message.append(ppToken->name);
785         } else {
786             message.append(atomStrings.getString(token));
787         }
788         message.append(" ");
789         token = scanToken(ppToken);
790     }
791     parseContext.notifyErrorDirective(loc.line, message.c_str());
792     // store this msg into the shader's information log..set the Compile Error flag!!!!
793     parseContext.ppError(loc, message.c_str(), "#error", "");
794 
795     return '\n';
796 }
797 
798 // Handle #pragma
CPPpragma(TPpToken * ppToken)799 int TPpContext::CPPpragma(TPpToken* ppToken)
800 {
801     char SrcStrName[2];
802     TVector<TString> tokens;
803 
804     TSourceLoc loc = ppToken->loc;  // because we go to the next line before processing
805     int token = scanToken(ppToken);
806     while (token != '\n' && token != EndOfInput) {
807         switch (token) {
808         case PpAtomIdentifier:
809         case PpAtomConstInt:
810         case PpAtomConstUint:
811         case PpAtomConstInt64:
812         case PpAtomConstUint64:
813         case PpAtomConstInt16:
814         case PpAtomConstUint16:
815         case PpAtomConstFloat:
816         case PpAtomConstDouble:
817         case PpAtomConstFloat16:
818             tokens.push_back(ppToken->name);
819             break;
820         default:
821             SrcStrName[0] = (char)token;
822             SrcStrName[1] = '\0';
823             tokens.push_back(SrcStrName);
824         }
825         token = scanToken(ppToken);
826     }
827 
828     if (token == EndOfInput)
829         parseContext.ppError(loc, "directive must end with a newline", "#pragma", "");
830     else
831         parseContext.handlePragma(loc, tokens);
832 
833     return token;
834 }
835 
836 // #version: This is just for error checking: the version and profile are decided before preprocessing starts
CPPversion(TPpToken * ppToken)837 int TPpContext::CPPversion(TPpToken* ppToken)
838 {
839     int token = scanToken(ppToken);
840 
841     if (errorOnVersion || versionSeen) {
842         if (parseContext.isReadingHLSL())
843             parseContext.ppError(ppToken->loc, "invalid preprocessor command", "#version", "");
844         else
845             parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", "");
846     }
847     versionSeen = true;
848 
849     if (token == '\n') {
850         parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
851 
852         return token;
853     }
854 
855     if (token != PpAtomConstInt)
856         parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
857 
858     ppToken->ival = atoi(ppToken->name);
859     int versionNumber = ppToken->ival;
860     int line = ppToken->loc.line;
861     token = scanToken(ppToken);
862 
863     if (token == '\n') {
864         parseContext.notifyVersion(line, versionNumber, nullptr);
865         return token;
866     } else {
867         int profileAtom = atomStrings.getAtom(ppToken->name);
868         if (profileAtom != PpAtomCore &&
869             profileAtom != PpAtomCompatibility &&
870             profileAtom != PpAtomEs)
871             parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
872         parseContext.notifyVersion(line, versionNumber, ppToken->name);
873         token = scanToken(ppToken);
874 
875         if (token == '\n')
876             return token;
877         else
878             parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
879     }
880 
881     return token;
882 }
883 
884 // Handle #extension
CPPextension(TPpToken * ppToken)885 int TPpContext::CPPextension(TPpToken* ppToken)
886 {
887     int line = ppToken->loc.line;
888     int token = scanToken(ppToken);
889     char extensionName[MaxTokenLength + 1];
890 
891     if (token=='\n') {
892         parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", "");
893         return token;
894     }
895 
896     if (token != PpAtomIdentifier)
897         parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
898 
899     snprintf(extensionName, sizeof(extensionName), "%s", ppToken->name);
900 
901     token = scanToken(ppToken);
902     if (token != ':') {
903         parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", "");
904         return token;
905     }
906 
907     token = scanToken(ppToken);
908     if (token != PpAtomIdentifier) {
909         parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", "");
910         return token;
911     }
912 
913     parseContext.updateExtensionBehavior(line, extensionName, ppToken->name);
914     parseContext.notifyExtensionDirective(line, extensionName, ppToken->name);
915 
916     token = scanToken(ppToken);
917     if (token == '\n')
918         return token;
919     else
920         parseContext.ppError(ppToken->loc,  "extra tokens -- expected newline", "#extension","");
921 
922     return token;
923 }
924 
readCPPline(TPpToken * ppToken)925 int TPpContext::readCPPline(TPpToken* ppToken)
926 {
927     int token = scanToken(ppToken);
928 
929     if (token == PpAtomIdentifier) {
930         switch (atomStrings.getAtom(ppToken->name)) {
931         case PpAtomDefine:
932             token = CPPdefine(ppToken);
933             break;
934         case PpAtomElse:
935             if (elseSeen[elsetracker])
936                 parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
937             elseSeen[elsetracker] = true;
938             if (ifdepth == 0)
939                 parseContext.ppError(ppToken->loc, "mismatched statements", "#else", "");
940             token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken));
941             token = CPPelse(0, ppToken);
942             break;
943         case PpAtomElif:
944             if (ifdepth == 0)
945                 parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", "");
946             if (elseSeen[elsetracker])
947                 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
948             // this token is really a dont care, but we still need to eat the tokens
949             token = scanToken(ppToken);
950             while (token != '\n' && token != EndOfInput)
951                 token = scanToken(ppToken);
952             token = CPPelse(0, ppToken);
953             break;
954         case PpAtomEndif:
955             if (ifdepth == 0)
956                 parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
957             else {
958                 elseSeen[elsetracker] = false;
959                 --elsetracker;
960                 --ifdepth;
961             }
962             token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
963             break;
964         case PpAtomIf:
965             token = CPPif(ppToken);
966             break;
967         case PpAtomIfdef:
968             token = CPPifdef(1, ppToken);
969             break;
970         case PpAtomIfndef:
971             token = CPPifdef(0, ppToken);
972             break;
973         case PpAtomLine:
974             token = CPPline(ppToken);
975             break;
976 #ifndef GLSLANG_WEB
977         case PpAtomInclude:
978             if(!parseContext.isReadingHLSL()) {
979                 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include");
980             }
981             token = CPPinclude(ppToken);
982             break;
983         case PpAtomPragma:
984             token = CPPpragma(ppToken);
985             break;
986 #endif
987         case PpAtomUndef:
988             token = CPPundef(ppToken);
989             break;
990         case PpAtomError:
991             token = CPPerror(ppToken);
992             break;
993         case PpAtomVersion:
994             token = CPPversion(ppToken);
995             break;
996         case PpAtomExtension:
997             token = CPPextension(ppToken);
998             break;
999         default:
1000             parseContext.ppError(ppToken->loc, "invalid directive:", "#", ppToken->name);
1001             break;
1002         }
1003     } else if (token != '\n' && token != EndOfInput)
1004         parseContext.ppError(ppToken->loc, "invalid directive", "#", "");
1005 
1006     while (token != '\n' && token != EndOfInput)
1007         token = scanToken(ppToken);
1008 
1009     return token;
1010 }
1011 
1012 // Context-dependent parsing of a #include <header-name>.
1013 // Assumes no macro expansions etc. are being done; the name is just on the current input.
1014 // Always creates a name and returns PpAtomicConstString, unless we run out of input.
scanHeaderName(TPpToken * ppToken,char delimit)1015 int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit)
1016 {
1017     bool tooLong = false;
1018 
1019     if (inputStack.empty())
1020         return EndOfInput;
1021 
1022     int len = 0;
1023     ppToken->name[0] = '\0';
1024     do {
1025         int ch = inputStack.back()->getch();
1026 
1027         // done yet?
1028         if (ch == delimit) {
1029             ppToken->name[len] = '\0';
1030             if (tooLong)
1031                 parseContext.ppError(ppToken->loc, "header name too long", "", "");
1032             return PpAtomConstString;
1033         } else if (ch == EndOfInput)
1034             return EndOfInput;
1035 
1036         // found a character to expand the name with
1037         if (len < MaxTokenLength)
1038             ppToken->name[len++] = (char)ch;
1039         else
1040             tooLong = true;
1041     } while (true);
1042 }
1043 
1044 // Macro-expand a macro argument 'arg' to create 'expandedArg'.
1045 // Does not replace 'arg'.
1046 // Returns nullptr if no expanded argument is created.
PrescanMacroArg(TokenStream & arg,TPpToken * ppToken,bool newLineOkay)1047 TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
1048 {
1049     // expand the argument
1050     TokenStream* expandedArg = new TokenStream;
1051     pushInput(new tMarkerInput(this));
1052     pushTokenStreamInput(arg);
1053     int token;
1054     while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) {
1055         token = tokenPaste(token, *ppToken);
1056         if (token == PpAtomIdentifier) {
1057             switch (MacroExpand(ppToken, false, newLineOkay)) {
1058             case MacroExpandNotStarted:
1059                 break;
1060             case MacroExpandError:
1061                 // toss the rest of the pushed-input argument by scanning until tMarkerInput
1062                 while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput)
1063                     ;
1064                 break;
1065             case MacroExpandStarted:
1066             case MacroExpandUndef:
1067                 continue;
1068             }
1069         }
1070         if (token == tMarkerInput::marker || token == EndOfInput)
1071             break;
1072         expandedArg->putToken(token, ppToken);
1073     }
1074 
1075     if (token != tMarkerInput::marker) {
1076         // Error, or MacroExpand ate the marker, so had bad input, recover
1077         delete expandedArg;
1078         expandedArg = nullptr;
1079     }
1080 
1081     return expandedArg;
1082 }
1083 
1084 //
1085 // Return the next token for a macro expansion, handling macro arguments,
1086 // whose semantics are dependent on being adjacent to ##.
1087 //
scan(TPpToken * ppToken)1088 int TPpContext::tMacroInput::scan(TPpToken* ppToken)
1089 {
1090     int token;
1091     do {
1092         token = mac->body.getToken(pp->parseContext, ppToken);
1093     } while (token == ' ');  // handle white space in macro
1094 
1095     // Hash operators basically turn off a round of macro substitution
1096     // (the round done on the argument before the round done on the RHS of the
1097     // macro definition):
1098     //
1099     // "A parameter in the replacement list, unless preceded by a # or ##
1100     // preprocessing token or followed by a ## preprocessing token (see below),
1101     // is replaced by the corresponding argument after all macros contained
1102     // therein have been expanded."
1103     //
1104     // "If, in the replacement list, a parameter is immediately preceded or
1105     // followed by a ## preprocessing token, the parameter is replaced by the
1106     // corresponding argument's preprocessing token sequence."
1107 
1108     bool pasting = false;
1109     if (postpaste) {
1110         // don't expand next token
1111         pasting = true;
1112         postpaste = false;
1113     }
1114 
1115     if (prepaste) {
1116         // already know we should be on a ##, verify
1117         assert(token == PpAtomPaste);
1118         prepaste = false;
1119         postpaste = true;
1120     }
1121 
1122     // see if are preceding a ##
1123     if (mac->body.peekUntokenizedPasting()) {
1124         prepaste = true;
1125         pasting = true;
1126     }
1127 
1128     // HLSL does expand macros before concatenation
1129     if (pasting && pp->parseContext.isReadingHLSL())
1130         pasting = false;
1131 
1132     // TODO: preprocessor:  properly handle whitespace (or lack of it) between tokens when expanding
1133     if (token == PpAtomIdentifier) {
1134         int i;
1135         for (i = (int)mac->args.size() - 1; i >= 0; i--)
1136             if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0)
1137                 break;
1138         if (i >= 0) {
1139             TokenStream* arg = expandedArgs[i];
1140             if (arg == nullptr || pasting)
1141                 arg = args[i];
1142             pp->pushTokenStreamInput(*arg, prepaste);
1143 
1144             return pp->scanToken(ppToken);
1145         }
1146     }
1147 
1148     if (token == EndOfInput)
1149         mac->busy = 0;
1150 
1151     return token;
1152 }
1153 
1154 // return a textual zero, for scanning a macro that was never defined
scan(TPpToken * ppToken)1155 int TPpContext::tZeroInput::scan(TPpToken* ppToken)
1156 {
1157     if (done)
1158         return EndOfInput;
1159 
1160     ppToken->name[0] = '0';
1161     ppToken->name[1] = 0;
1162     ppToken->ival = 0;
1163     ppToken->space = false;
1164     done = true;
1165 
1166     return PpAtomConstInt;
1167 }
1168 
1169 //
1170 // Check a token to see if it is a macro that should be expanded:
1171 // - If it is, and defined, push a tInput that will produce the appropriate
1172 //   expansion and return MacroExpandStarted.
1173 // - If it is, but undefined, and expandUndef is requested, push a tInput
1174 //   that will expand to 0 and return MacroExpandUndef.
1175 // - Otherwise, there is no expansion, and there are two cases:
1176 //   * It might be okay there is no expansion, and no specific error was
1177 //     detected. Returns MacroExpandNotStarted.
1178 //   * The expansion was started, but could not be completed, due to an error
1179 //     that cannot be recovered from. Returns MacroExpandError.
1180 //
MacroExpand(TPpToken * ppToken,bool expandUndef,bool newLineOkay)1181 MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)
1182 {
1183     ppToken->space = false;
1184     int macroAtom = atomStrings.getAtom(ppToken->name);
1185     switch (macroAtom) {
1186     case PpAtomLineMacro:
1187         // Arguments which are macro have been replaced in the first stage.
1188         if (ppToken->ival == 0)
1189             ppToken->ival = parseContext.getCurrentLoc().line;
1190         snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1191         UngetToken(PpAtomConstInt, ppToken);
1192         return MacroExpandStarted;
1193 
1194     case PpAtomFileMacro: {
1195         if (parseContext.getCurrentLoc().name)
1196             parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
1197         ppToken->ival = parseContext.getCurrentLoc().string;
1198         snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str());
1199         UngetToken(PpAtomConstInt, ppToken);
1200         return MacroExpandStarted;
1201     }
1202 
1203     case PpAtomVersionMacro:
1204         ppToken->ival = parseContext.version;
1205         snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1206         UngetToken(PpAtomConstInt, ppToken);
1207         return MacroExpandStarted;
1208 
1209     default:
1210         break;
1211     }
1212 
1213     MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
1214 
1215     // no recursive expansions
1216     if (macro != nullptr && macro->busy)
1217         return MacroExpandNotStarted;
1218 
1219     // not expanding undefined macros
1220     if ((macro == nullptr || macro->undef) && ! expandUndef)
1221         return MacroExpandNotStarted;
1222 
1223     // 0 is the value of an undefined macro
1224     if ((macro == nullptr || macro->undef) && expandUndef) {
1225         pushInput(new tZeroInput(this));
1226         return MacroExpandUndef;
1227     }
1228 
1229     tMacroInput *in = new tMacroInput(this);
1230 
1231     TSourceLoc loc = ppToken->loc;  // in case we go to the next line before discovering the error
1232     in->mac = macro;
1233     if (macro->functionLike) {
1234         // We don't know yet if this will be a successful call of a
1235         // function-like macro; need to look for a '(', but without trashing
1236         // the passed in ppToken, until we know we are no longer speculative.
1237         TPpToken parenToken;
1238         int token = scanToken(&parenToken);
1239         if (newLineOkay) {
1240             while (token == '\n')
1241                 token = scanToken(&parenToken);
1242         }
1243         if (token != '(') {
1244             // Function-like macro called with object-like syntax: okay, don't expand.
1245             // (We ate exactly one token that might not be white space; put it back.
1246             UngetToken(token, &parenToken);
1247             delete in;
1248             return MacroExpandNotStarted;
1249         }
1250         in->args.resize(in->mac->args.size());
1251         for (size_t i = 0; i < in->mac->args.size(); i++)
1252             in->args[i] = new TokenStream;
1253         in->expandedArgs.resize(in->mac->args.size());
1254         for (size_t i = 0; i < in->mac->args.size(); i++)
1255             in->expandedArgs[i] = nullptr;
1256         size_t arg = 0;
1257         bool tokenRecorded = false;
1258         do {
1259             TVector<char> nestStack;
1260             while (true) {
1261                 token = scanToken(ppToken);
1262                 if (token == EndOfInput || token == tMarkerInput::marker) {
1263                     parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
1264                     delete in;
1265                     return MacroExpandError;
1266                 }
1267                 if (token == '\n') {
1268                     if (! newLineOkay) {
1269                         parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom));
1270                         delete in;
1271                         return MacroExpandError;
1272                     }
1273                     continue;
1274                 }
1275                 if (token == '#') {
1276                     parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom));
1277                     delete in;
1278                     return MacroExpandError;
1279                 }
1280                 if (in->mac->args.size() == 0 && token != ')')
1281                     break;
1282                 if (nestStack.size() == 0 && (token == ',' || token == ')'))
1283                     break;
1284                 if (token == '(')
1285                     nestStack.push_back(')');
1286                 else if (token == '{' && parseContext.isReadingHLSL())
1287                     nestStack.push_back('}');
1288                 else if (nestStack.size() > 0 && token == nestStack.back())
1289                     nestStack.pop_back();
1290 
1291                 //Macro replacement list is expanded in the last stage.
1292                 if (atomStrings.getAtom(ppToken->name) == PpAtomLineMacro)
1293                     ppToken->ival = parseContext.getCurrentLoc().line;
1294 
1295                 in->args[arg]->putToken(token, ppToken);
1296                 tokenRecorded = true;
1297             }
1298             // end of single argument scan
1299 
1300             if (token == ')') {
1301                 // closing paren of call
1302                 if (in->mac->args.size() == 1 && !tokenRecorded)
1303                     break;
1304                 arg++;
1305                 break;
1306             }
1307             arg++;
1308         } while (arg < in->mac->args.size());
1309         // end of all arguments scan
1310 
1311         if (arg < in->mac->args.size())
1312             parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom));
1313         else if (token != ')') {
1314             // Error recover code; find end of call, if possible
1315             int depth = 0;
1316             while (token != EndOfInput && (depth > 0 || token != ')')) {
1317                 if (token == ')' || token == '}')
1318                     depth--;
1319                 token = scanToken(ppToken);
1320                 if (token == '(' || token == '{')
1321                     depth++;
1322             }
1323 
1324             if (token == EndOfInput) {
1325                 parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
1326                 delete in;
1327                 return MacroExpandError;
1328             }
1329             parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom));
1330         }
1331 
1332         // We need both expanded and non-expanded forms of the argument, for whether or
1333         // not token pasting will be applied later when the argument is consumed next to ##.
1334         for (size_t i = 0; i < in->mac->args.size(); i++)
1335             in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay);
1336     }
1337 
1338     pushInput(in);
1339     macro->busy = 1;
1340     macro->body.reset();
1341 
1342     return MacroExpandStarted;
1343 }
1344 
1345 } // end namespace glslang
1346