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 = 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 #ifndef GLSLANG_WEB
740             if (token == PpAtomConstString) {
741                 parseContext.ppRequireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line");
742                 // We need to save a copy of the string instead of pointing
743                 // to the name field of the token since the name field
744                 // will likely be overwritten by the next token scan.
745                 sourceName = atomStrings.getString(atomStrings.getAddAtom(ppToken->name));
746                 parseContext.setCurrentSourceName(sourceName);
747                 hasFile = true;
748                 token = scanToken(ppToken);
749             } else
750 #endif
751             {
752                 token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
753                 if (! fileErr) {
754                     parseContext.setCurrentString(fileRes);
755                     hasFile = true;
756                 }
757             }
758         }
759     }
760     if (!fileErr && !lineErr) {
761         parseContext.notifyLineDirective(directiveLoc.line, lineToken, hasFile, fileRes, sourceName);
762     }
763     token = extraTokenCheck(PpAtomLine, ppToken, token);
764 
765     return token;
766 }
767 
768 // Handle #error
CPPerror(TPpToken * ppToken)769 int TPpContext::CPPerror(TPpToken* ppToken)
770 {
771     disableEscapeSequences = true;
772     int token = scanToken(ppToken);
773     disableEscapeSequences = false;
774     std::string message;
775     TSourceLoc loc = ppToken->loc;
776 
777     while (token != '\n' && token != EndOfInput) {
778         if (token == PpAtomConstInt16 || token == PpAtomConstUint16 ||
779             token == PpAtomConstInt   || token == PpAtomConstUint   ||
780             token == PpAtomConstInt64 || token == PpAtomConstUint64 ||
781             token == PpAtomConstFloat16 ||
782             token == PpAtomConstFloat || token == PpAtomConstDouble) {
783                 message.append(ppToken->name);
784         } else if (token == PpAtomIdentifier || token == PpAtomConstString) {
785             message.append(ppToken->name);
786         } else {
787             message.append(atomStrings.getString(token));
788         }
789         message.append(" ");
790         token = scanToken(ppToken);
791     }
792     parseContext.notifyErrorDirective(loc.line, message.c_str());
793     // store this msg into the shader's information log..set the Compile Error flag!!!!
794     parseContext.ppError(loc, message.c_str(), "#error", "");
795 
796     return '\n';
797 }
798 
799 // Handle #pragma
CPPpragma(TPpToken * ppToken)800 int TPpContext::CPPpragma(TPpToken* ppToken)
801 {
802     char SrcStrName[2];
803     TVector<TString> tokens;
804 
805     TSourceLoc loc = ppToken->loc;  // because we go to the next line before processing
806     int token = scanToken(ppToken);
807     while (token != '\n' && token != EndOfInput) {
808         switch (token) {
809         case PpAtomIdentifier:
810         case PpAtomConstInt:
811         case PpAtomConstUint:
812         case PpAtomConstInt64:
813         case PpAtomConstUint64:
814         case PpAtomConstInt16:
815         case PpAtomConstUint16:
816         case PpAtomConstFloat:
817         case PpAtomConstDouble:
818         case PpAtomConstFloat16:
819             tokens.push_back(ppToken->name);
820             break;
821         default:
822             SrcStrName[0] = (char)token;
823             SrcStrName[1] = '\0';
824             tokens.push_back(SrcStrName);
825         }
826         token = scanToken(ppToken);
827     }
828 
829     if (token == EndOfInput)
830         parseContext.ppError(loc, "directive must end with a newline", "#pragma", "");
831     else
832         parseContext.handlePragma(loc, tokens);
833 
834     return token;
835 }
836 
837 // #version: This is just for error checking: the version and profile are decided before preprocessing starts
CPPversion(TPpToken * ppToken)838 int TPpContext::CPPversion(TPpToken* ppToken)
839 {
840     int token = scanToken(ppToken);
841 
842     if (errorOnVersion || versionSeen) {
843         if (parseContext.isReadingHLSL())
844             parseContext.ppError(ppToken->loc, "invalid preprocessor command", "#version", "");
845         else
846             parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", "");
847     }
848     versionSeen = true;
849 
850     if (token == '\n') {
851         parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
852 
853         return token;
854     }
855 
856     if (token != PpAtomConstInt)
857         parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
858 
859     ppToken->ival = atoi(ppToken->name);
860     int versionNumber = ppToken->ival;
861     int line = ppToken->loc.line;
862     token = scanToken(ppToken);
863 
864     if (token == '\n') {
865         parseContext.notifyVersion(line, versionNumber, nullptr);
866         return token;
867     } else {
868         int profileAtom = atomStrings.getAtom(ppToken->name);
869         if (profileAtom != PpAtomCore &&
870             profileAtom != PpAtomCompatibility &&
871             profileAtom != PpAtomEs)
872             parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
873         parseContext.notifyVersion(line, versionNumber, ppToken->name);
874         token = scanToken(ppToken);
875 
876         if (token == '\n')
877             return token;
878         else
879             parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
880     }
881 
882     return token;
883 }
884 
885 // Handle #extension
CPPextension(TPpToken * ppToken)886 int TPpContext::CPPextension(TPpToken* ppToken)
887 {
888     int line = ppToken->loc.line;
889     int token = scanToken(ppToken);
890     char extensionName[MaxTokenLength + 1];
891 
892     if (token=='\n') {
893         parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", "");
894         return token;
895     }
896 
897     if (token != PpAtomIdentifier)
898         parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
899 
900     snprintf(extensionName, sizeof(extensionName), "%s", ppToken->name);
901 
902     token = scanToken(ppToken);
903     if (token != ':') {
904         parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", "");
905         return token;
906     }
907 
908     token = scanToken(ppToken);
909     if (token != PpAtomIdentifier) {
910         parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", "");
911         return token;
912     }
913 
914     parseContext.updateExtensionBehavior(line, extensionName, ppToken->name);
915     parseContext.notifyExtensionDirective(line, extensionName, ppToken->name);
916 
917     token = scanToken(ppToken);
918     if (token == '\n')
919         return token;
920     else
921         parseContext.ppError(ppToken->loc,  "extra tokens -- expected newline", "#extension","");
922 
923     return token;
924 }
925 
readCPPline(TPpToken * ppToken)926 int TPpContext::readCPPline(TPpToken* ppToken)
927 {
928     int token = scanToken(ppToken);
929 
930     if (token == PpAtomIdentifier) {
931         switch (atomStrings.getAtom(ppToken->name)) {
932         case PpAtomDefine:
933             token = CPPdefine(ppToken);
934             break;
935         case PpAtomElse:
936             if (elseSeen[elsetracker])
937                 parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
938             elseSeen[elsetracker] = true;
939             if (ifdepth == 0)
940                 parseContext.ppError(ppToken->loc, "mismatched statements", "#else", "");
941             token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken));
942             token = CPPelse(0, ppToken);
943             break;
944         case PpAtomElif:
945             if (ifdepth == 0)
946                 parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", "");
947             if (elseSeen[elsetracker])
948                 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
949             // this token is really a dont care, but we still need to eat the tokens
950             token = scanToken(ppToken);
951             while (token != '\n' && token != EndOfInput)
952                 token = scanToken(ppToken);
953             token = CPPelse(0, ppToken);
954             break;
955         case PpAtomEndif:
956             if (ifdepth == 0)
957                 parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
958             else {
959                 elseSeen[elsetracker] = false;
960                 --elsetracker;
961                 --ifdepth;
962             }
963             token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
964             break;
965         case PpAtomIf:
966             token = CPPif(ppToken);
967             break;
968         case PpAtomIfdef:
969             token = CPPifdef(1, ppToken);
970             break;
971         case PpAtomIfndef:
972             token = CPPifdef(0, ppToken);
973             break;
974         case PpAtomLine:
975             token = CPPline(ppToken);
976             break;
977 #ifndef GLSLANG_WEB
978         case PpAtomInclude:
979             if(!parseContext.isReadingHLSL()) {
980                 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include");
981             }
982             token = CPPinclude(ppToken);
983             break;
984         case PpAtomPragma:
985             token = CPPpragma(ppToken);
986             break;
987 #endif
988         case PpAtomUndef:
989             token = CPPundef(ppToken);
990             break;
991         case PpAtomError:
992             token = CPPerror(ppToken);
993             break;
994         case PpAtomVersion:
995             token = CPPversion(ppToken);
996             break;
997         case PpAtomExtension:
998             token = CPPextension(ppToken);
999             break;
1000         default:
1001             parseContext.ppError(ppToken->loc, "invalid directive:", "#", ppToken->name);
1002             break;
1003         }
1004     } else if (token != '\n' && token != EndOfInput)
1005         parseContext.ppError(ppToken->loc, "invalid directive", "#", "");
1006 
1007     while (token != '\n' && token != EndOfInput)
1008         token = scanToken(ppToken);
1009 
1010     return token;
1011 }
1012 
1013 // Context-dependent parsing of a #include <header-name>.
1014 // Assumes no macro expansions etc. are being done; the name is just on the current input.
1015 // Always creates a name and returns PpAtomicConstString, unless we run out of input.
scanHeaderName(TPpToken * ppToken,char delimit)1016 int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit)
1017 {
1018     bool tooLong = false;
1019 
1020     if (inputStack.empty())
1021         return EndOfInput;
1022 
1023     int len = 0;
1024     ppToken->name[0] = '\0';
1025     do {
1026         int ch = inputStack.back()->getch();
1027 
1028         // done yet?
1029         if (ch == delimit) {
1030             ppToken->name[len] = '\0';
1031             if (tooLong)
1032                 parseContext.ppError(ppToken->loc, "header name too long", "", "");
1033             return PpAtomConstString;
1034         } else if (ch == EndOfInput)
1035             return EndOfInput;
1036 
1037         // found a character to expand the name with
1038         if (len < MaxTokenLength)
1039             ppToken->name[len++] = (char)ch;
1040         else
1041             tooLong = true;
1042     } while (true);
1043 }
1044 
1045 // Macro-expand a macro argument 'arg' to create 'expandedArg'.
1046 // Does not replace 'arg'.
1047 // Returns nullptr if no expanded argument is created.
PrescanMacroArg(TokenStream & arg,TPpToken * ppToken,bool newLineOkay)1048 TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
1049 {
1050     // expand the argument
1051     TokenStream* expandedArg = new TokenStream;
1052     pushInput(new tMarkerInput(this));
1053     pushTokenStreamInput(arg);
1054     int token;
1055     while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) {
1056         token = tokenPaste(token, *ppToken);
1057         if (token == PpAtomIdentifier) {
1058             switch (MacroExpand(ppToken, false, newLineOkay)) {
1059             case MacroExpandNotStarted:
1060                 break;
1061             case MacroExpandError:
1062                 // toss the rest of the pushed-input argument by scanning until tMarkerInput
1063                 while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput)
1064                     ;
1065                 break;
1066             case MacroExpandStarted:
1067             case MacroExpandUndef:
1068                 continue;
1069             }
1070         }
1071         if (token == tMarkerInput::marker || token == EndOfInput)
1072             break;
1073         expandedArg->putToken(token, ppToken);
1074     }
1075 
1076     if (token != tMarkerInput::marker) {
1077         // Error, or MacroExpand ate the marker, so had bad input, recover
1078         delete expandedArg;
1079         expandedArg = nullptr;
1080     }
1081 
1082     return expandedArg;
1083 }
1084 
1085 //
1086 // Return the next token for a macro expansion, handling macro arguments,
1087 // whose semantics are dependent on being adjacent to ##.
1088 //
scan(TPpToken * ppToken)1089 int TPpContext::tMacroInput::scan(TPpToken* ppToken)
1090 {
1091     int token;
1092     do {
1093         token = mac->body.getToken(pp->parseContext, ppToken);
1094     } while (token == ' ');  // handle white space in macro
1095 
1096     // Hash operators basically turn off a round of macro substitution
1097     // (the round done on the argument before the round done on the RHS of the
1098     // macro definition):
1099     //
1100     // "A parameter in the replacement list, unless preceded by a # or ##
1101     // preprocessing token or followed by a ## preprocessing token (see below),
1102     // is replaced by the corresponding argument after all macros contained
1103     // therein have been expanded."
1104     //
1105     // "If, in the replacement list, a parameter is immediately preceded or
1106     // followed by a ## preprocessing token, the parameter is replaced by the
1107     // corresponding argument's preprocessing token sequence."
1108 
1109     bool pasting = false;
1110     if (postpaste) {
1111         // don't expand next token
1112         pasting = true;
1113         postpaste = false;
1114     }
1115 
1116     if (prepaste) {
1117         // already know we should be on a ##, verify
1118         assert(token == PpAtomPaste);
1119         prepaste = false;
1120         postpaste = true;
1121     }
1122 
1123     // see if are preceding a ##
1124     if (mac->body.peekUntokenizedPasting()) {
1125         prepaste = true;
1126         pasting = true;
1127     }
1128 
1129     // HLSL does expand macros before concatenation
1130     if (pasting && pp->parseContext.isReadingHLSL())
1131         pasting = false;
1132 
1133     // TODO: preprocessor:  properly handle whitespace (or lack of it) between tokens when expanding
1134     if (token == PpAtomIdentifier) {
1135         int i;
1136         for (i = (int)mac->args.size() - 1; i >= 0; i--)
1137             if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0)
1138                 break;
1139         if (i >= 0) {
1140             TokenStream* arg = expandedArgs[i];
1141             if (arg == nullptr || pasting)
1142                 arg = args[i];
1143             pp->pushTokenStreamInput(*arg, prepaste);
1144 
1145             return pp->scanToken(ppToken);
1146         }
1147     }
1148 
1149     if (token == EndOfInput)
1150         mac->busy = 0;
1151 
1152     return token;
1153 }
1154 
1155 // return a textual zero, for scanning a macro that was never defined
scan(TPpToken * ppToken)1156 int TPpContext::tZeroInput::scan(TPpToken* ppToken)
1157 {
1158     if (done)
1159         return EndOfInput;
1160 
1161     ppToken->name[0] = '0';
1162     ppToken->name[1] = 0;
1163     ppToken->ival = 0;
1164     ppToken->space = false;
1165     done = true;
1166 
1167     return PpAtomConstInt;
1168 }
1169 
1170 //
1171 // Check a token to see if it is a macro that should be expanded:
1172 // - If it is, and defined, push a tInput that will produce the appropriate
1173 //   expansion and return MacroExpandStarted.
1174 // - If it is, but undefined, and expandUndef is requested, push a tInput
1175 //   that will expand to 0 and return MacroExpandUndef.
1176 // - Otherwise, there is no expansion, and there are two cases:
1177 //   * It might be okay there is no expansion, and no specific error was
1178 //     detected. Returns MacroExpandNotStarted.
1179 //   * The expansion was started, but could not be completed, due to an error
1180 //     that cannot be recovered from. Returns MacroExpandError.
1181 //
MacroExpand(TPpToken * ppToken,bool expandUndef,bool newLineOkay)1182 MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)
1183 {
1184     ppToken->space = false;
1185     int macroAtom = atomStrings.getAtom(ppToken->name);
1186     switch (macroAtom) {
1187     case PpAtomLineMacro:
1188         // Arguments which are macro have been replaced in the first stage.
1189         if (ppToken->ival == 0)
1190             ppToken->ival = parseContext.getCurrentLoc().line;
1191         snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1192         UngetToken(PpAtomConstInt, ppToken);
1193         return MacroExpandStarted;
1194 
1195     case PpAtomFileMacro: {
1196         if (parseContext.getCurrentLoc().name)
1197             parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
1198         ppToken->ival = parseContext.getCurrentLoc().string;
1199         snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str());
1200         UngetToken(PpAtomConstInt, ppToken);
1201         return MacroExpandStarted;
1202     }
1203 
1204     case PpAtomVersionMacro:
1205         ppToken->ival = parseContext.version;
1206         snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1207         UngetToken(PpAtomConstInt, ppToken);
1208         return MacroExpandStarted;
1209 
1210     default:
1211         break;
1212     }
1213 
1214     MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
1215 
1216     // no recursive expansions
1217     if (macro != nullptr && macro->busy)
1218         return MacroExpandNotStarted;
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