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