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