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