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