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 = evalToToken(token, shortCircuit, res, err, ppToken);
459 return eval(token, precedence, shortCircuit, res, err, ppToken);
460 }
461 } else if (token == PpAtomConstInt) {
462 res = ppToken->ival;
463 token = scanToken(ppToken);
464 } else if (token == '(') {
465 token = scanToken(ppToken);
466 token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
467 if (! err) {
468 if (token != ')') {
469 parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", "");
470 err = true;
471 res = 0;
472
473 return token;
474 }
475 token = scanToken(ppToken);
476 }
477 } else {
478 int op = NUM_ELEMENTS(unop) - 1;
479 for (; op >= 0; op--) {
480 if (unop[op].token == token)
481 break;
482 }
483 if (op >= 0) {
484 token = scanToken(ppToken);
485 token = eval(token, UNARY, shortCircuit, res, err, ppToken);
486 res = unop[op].op(res);
487 } else {
488 parseContext.ppError(loc, "bad expression", "preprocessor evaluation", "");
489 err = true;
490 res = 0;
491
492 return token;
493 }
494 }
495
496 token = evalToToken(token, shortCircuit, res, err, ppToken);
497
498 // Perform evaluation of binary operation, if there is one, otherwise we are done.
499 while (! err) {
500 if (token == ')' || token == '\n')
501 break;
502 int op;
503 for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
504 if (binop[op].token == token)
505 break;
506 }
507 if (op < 0 || binop[op].precedence <= precedence)
508 break;
509 int leftSide = res;
510
511 // Setup short-circuiting, needed for ES, unless already in a short circuit.
512 // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
513 if (! shortCircuit) {
514 if ((token == PpAtomOr && leftSide == 1) ||
515 (token == PpAtomAnd && leftSide == 0))
516 shortCircuit = true;
517 }
518
519 token = scanToken(ppToken);
520 token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);
521
522 if (binop[op].op == op_div || binop[op].op == op_mod) {
523 if (res == 0) {
524 parseContext.ppError(loc, "division by 0", "preprocessor evaluation", "");
525 res = 1;
526 }
527 }
528 res = binop[op].op(leftSide, res);
529 }
530
531 return token;
532 }
533
534 // 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)535 int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
536 {
537 while (token == PpAtomIdentifier && strcmp("defined", ppToken->name) != 0) {
538 switch (MacroExpand(ppToken, true, false)) {
539 case MacroExpandNotStarted:
540 case MacroExpandError:
541 parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", "");
542 err = true;
543 res = 0;
544 break;
545 case MacroExpandStarted:
546 break;
547 case MacroExpandUndef:
548 if (! shortCircuit && parseContext.isEsProfile()) {
549 const char* message = "undefined macro in expression not allowed in es profile";
550 if (parseContext.relaxedErrors())
551 parseContext.ppWarn(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
552 else
553 parseContext.ppError(ppToken->loc, message, "preprocessor evaluation", ppToken->name);
554 }
555 break;
556 }
557 token = scanToken(ppToken);
558 if (err)
559 break;
560 }
561
562 return token;
563 }
564
565 // Handle #if
CPPif(TPpToken * ppToken)566 int TPpContext::CPPif(TPpToken* ppToken)
567 {
568 int token = scanToken(ppToken);
569 if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) {
570 parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
571 return EndOfInput;
572 } else {
573 elsetracker++;
574 ifdepth++;
575 }
576 int res = 0;
577 bool err = false;
578 token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken);
579 token = extraTokenCheck(PpAtomIf, ppToken, token);
580 if (!res && !err)
581 token = CPPelse(1, ppToken);
582
583 return token;
584 }
585
586 // Handle #ifdef
CPPifdef(int defined,TPpToken * ppToken)587 int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
588 {
589 int token = scanToken(ppToken);
590 if (ifdepth > maxIfNesting || elsetracker > maxIfNesting) {
591 parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
592 return EndOfInput;
593 } else {
594 elsetracker++;
595 ifdepth++;
596 }
597
598 if (token != PpAtomIdentifier) {
599 if (defined)
600 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", "");
601 else
602 parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
603 } else {
604 MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name));
605 token = scanToken(ppToken);
606 if (token != '\n') {
607 parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
608 while (token != '\n' && token != EndOfInput)
609 token = scanToken(ppToken);
610 }
611 if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined)
612 token = CPPelse(1, ppToken);
613 }
614
615 return token;
616 }
617
618 // Handle #include ...
619 // TODO: Handle macro expansions for the header name
CPPinclude(TPpToken * ppToken)620 int TPpContext::CPPinclude(TPpToken* ppToken)
621 {
622 const TSourceLoc directiveLoc = ppToken->loc;
623 bool startWithLocalSearch = true; // to additionally include the extra "" paths
624 int token;
625
626 // Find the first non-whitespace char after #include
627 int ch = getChar();
628 while (ch == ' ' || ch == '\t') {
629 ch = getChar();
630 }
631 if (ch == '<') {
632 // <header-name> style
633 startWithLocalSearch = false;
634 token = scanHeaderName(ppToken, '>');
635 } else if (ch == '"') {
636 // "header-name" style
637 token = scanHeaderName(ppToken, '"');
638 } else {
639 // unexpected, get the full token to generate the error
640 ungetChar();
641 token = scanToken(ppToken);
642 }
643
644 if (token != PpAtomConstString) {
645 parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", "");
646 return token;
647 }
648
649 // Make a copy of the name because it will be overwritten by the next token scan.
650 const std::string filename = ppToken->name;
651
652 // See if the directive was well formed
653 token = scanToken(ppToken);
654 if (token != '\n') {
655 if (token == EndOfInput)
656 parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str());
657 else
658 parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str());
659 return token;
660 }
661
662 // Process well-formed directive
663
664 // Find the inclusion, first look in "Local" ("") paths, if requested,
665 // otherwise, only search the "System" (<>) paths.
666 TShader::Includer::IncludeResult* res = nullptr;
667 if (startWithLocalSearch)
668 res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
669 if (res == nullptr || res->headerName.empty()) {
670 includer.releaseInclude(res);
671 res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1);
672 }
673
674 // Process the results
675 if (res != nullptr && !res->headerName.empty()) {
676 if (res->headerData != nullptr && res->headerLength > 0) {
677 // path for processing one or more tokens from an included header, hand off 'res'
678 const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
679 std::ostringstream prologue;
680 std::ostringstream epilogue;
681 prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n";
682 epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
683 "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
684 pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
685 parseContext.intermediate.addIncludeText(res->headerName.c_str(), res->headerData, res->headerLength);
686 // There's no "current" location anymore.
687 parseContext.setCurrentColumn(0);
688 } else {
689 // things are okay, but there is nothing to process
690 includer.releaseInclude(res);
691 }
692 } else {
693 // error path, clean up
694 std::string message =
695 res != nullptr ? std::string(res->headerData, res->headerLength)
696 : std::string("Could not process include directive");
697 parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str());
698 includer.releaseInclude(res);
699 }
700
701 return token;
702 }
703
704 // Handle #line
CPPline(TPpToken * ppToken)705 int TPpContext::CPPline(TPpToken* ppToken)
706 {
707 // "#line must have, after macro substitution, one of the following forms:
708 // "#line line
709 // "#line line source-string-number"
710
711 int token = scanToken(ppToken);
712 const TSourceLoc directiveLoc = ppToken->loc;
713 if (token == '\n') {
714 parseContext.ppError(ppToken->loc, "must by followed by an integral literal", "#line", "");
715 return token;
716 }
717
718 int lineRes = 0; // Line number after macro expansion.
719 int lineToken = 0;
720 bool hasFile = false;
721 int fileRes = 0; // Source file number after macro expansion.
722 const char* sourceName = nullptr; // Optional source file name.
723 bool lineErr = false;
724 bool fileErr = false;
725 disableEscapeSequences = true;
726 token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken);
727 disableEscapeSequences = false;
728 if (! lineErr) {
729 lineToken = lineRes;
730 if (token == '\n')
731 ++lineRes;
732
733 if (parseContext.lineDirectiveShouldSetNextLine())
734 --lineRes;
735 parseContext.setCurrentLine(lineRes);
736
737 if (token != '\n') {
738 #ifndef GLSLANG_WEB
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 #endif
750 {
751 token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
752 if (! fileErr) {
753 parseContext.setCurrentString(fileRes);
754 hasFile = true;
755 }
756 }
757 }
758 }
759 if (!fileErr && !lineErr) {
760 parseContext.notifyLineDirective(directiveLoc.line, lineToken, hasFile, fileRes, sourceName);
761 }
762 token = extraTokenCheck(PpAtomLine, ppToken, token);
763
764 return token;
765 }
766
767 // Handle #error
CPPerror(TPpToken * ppToken)768 int TPpContext::CPPerror(TPpToken* ppToken)
769 {
770 disableEscapeSequences = true;
771 int token = scanToken(ppToken);
772 disableEscapeSequences = false;
773 std::string message;
774 TSourceLoc loc = ppToken->loc;
775
776 while (token != '\n' && token != EndOfInput) {
777 if (token == PpAtomConstInt16 || token == PpAtomConstUint16 ||
778 token == PpAtomConstInt || token == PpAtomConstUint ||
779 token == PpAtomConstInt64 || token == PpAtomConstUint64 ||
780 token == PpAtomConstFloat16 ||
781 token == PpAtomConstFloat || token == PpAtomConstDouble) {
782 message.append(ppToken->name);
783 } else if (token == PpAtomIdentifier || token == PpAtomConstString) {
784 message.append(ppToken->name);
785 } else {
786 message.append(atomStrings.getString(token));
787 }
788 message.append(" ");
789 token = scanToken(ppToken);
790 }
791 parseContext.notifyErrorDirective(loc.line, message.c_str());
792 // store this msg into the shader's information log..set the Compile Error flag!!!!
793 parseContext.ppError(loc, message.c_str(), "#error", "");
794
795 return '\n';
796 }
797
798 // Handle #pragma
CPPpragma(TPpToken * ppToken)799 int TPpContext::CPPpragma(TPpToken* ppToken)
800 {
801 char SrcStrName[2];
802 TVector<TString> tokens;
803
804 TSourceLoc loc = ppToken->loc; // because we go to the next line before processing
805 int token = scanToken(ppToken);
806 while (token != '\n' && token != EndOfInput) {
807 switch (token) {
808 case PpAtomIdentifier:
809 case PpAtomConstInt:
810 case PpAtomConstUint:
811 case PpAtomConstInt64:
812 case PpAtomConstUint64:
813 case PpAtomConstInt16:
814 case PpAtomConstUint16:
815 case PpAtomConstFloat:
816 case PpAtomConstDouble:
817 case PpAtomConstFloat16:
818 tokens.push_back(ppToken->name);
819 break;
820 default:
821 SrcStrName[0] = (char)token;
822 SrcStrName[1] = '\0';
823 tokens.push_back(SrcStrName);
824 }
825 token = scanToken(ppToken);
826 }
827
828 if (token == EndOfInput)
829 parseContext.ppError(loc, "directive must end with a newline", "#pragma", "");
830 else
831 parseContext.handlePragma(loc, tokens);
832
833 return token;
834 }
835
836 // #version: This is just for error checking: the version and profile are decided before preprocessing starts
CPPversion(TPpToken * ppToken)837 int TPpContext::CPPversion(TPpToken* ppToken)
838 {
839 int token = scanToken(ppToken);
840
841 if (errorOnVersion || versionSeen) {
842 if (parseContext.isReadingHLSL())
843 parseContext.ppError(ppToken->loc, "invalid preprocessor command", "#version", "");
844 else
845 parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", "");
846 }
847 versionSeen = true;
848
849 if (token == '\n') {
850 parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
851
852 return token;
853 }
854
855 if (token != PpAtomConstInt)
856 parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", "");
857
858 ppToken->ival = atoi(ppToken->name);
859 int versionNumber = ppToken->ival;
860 int line = ppToken->loc.line;
861 token = scanToken(ppToken);
862
863 if (token == '\n') {
864 parseContext.notifyVersion(line, versionNumber, nullptr);
865 return token;
866 } else {
867 int profileAtom = atomStrings.getAtom(ppToken->name);
868 if (profileAtom != PpAtomCore &&
869 profileAtom != PpAtomCompatibility &&
870 profileAtom != PpAtomEs)
871 parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
872 parseContext.notifyVersion(line, versionNumber, ppToken->name);
873 token = scanToken(ppToken);
874
875 if (token == '\n')
876 return token;
877 else
878 parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
879 }
880
881 return token;
882 }
883
884 // Handle #extension
CPPextension(TPpToken * ppToken)885 int TPpContext::CPPextension(TPpToken* ppToken)
886 {
887 int line = ppToken->loc.line;
888 int token = scanToken(ppToken);
889 char extensionName[MaxTokenLength + 1];
890
891 if (token=='\n') {
892 parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", "");
893 return token;
894 }
895
896 if (token != PpAtomIdentifier)
897 parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
898
899 snprintf(extensionName, sizeof(extensionName), "%s", ppToken->name);
900
901 token = scanToken(ppToken);
902 if (token != ':') {
903 parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", "");
904 return token;
905 }
906
907 token = scanToken(ppToken);
908 if (token != PpAtomIdentifier) {
909 parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", "");
910 return token;
911 }
912
913 parseContext.updateExtensionBehavior(line, extensionName, ppToken->name);
914 parseContext.notifyExtensionDirective(line, extensionName, ppToken->name);
915
916 token = scanToken(ppToken);
917 if (token == '\n')
918 return token;
919 else
920 parseContext.ppError(ppToken->loc, "extra tokens -- expected newline", "#extension","");
921
922 return token;
923 }
924
readCPPline(TPpToken * ppToken)925 int TPpContext::readCPPline(TPpToken* ppToken)
926 {
927 int token = scanToken(ppToken);
928
929 if (token == PpAtomIdentifier) {
930 switch (atomStrings.getAtom(ppToken->name)) {
931 case PpAtomDefine:
932 token = CPPdefine(ppToken);
933 break;
934 case PpAtomElse:
935 if (elseSeen[elsetracker])
936 parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
937 elseSeen[elsetracker] = true;
938 if (ifdepth == 0)
939 parseContext.ppError(ppToken->loc, "mismatched statements", "#else", "");
940 token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken));
941 token = CPPelse(0, ppToken);
942 break;
943 case PpAtomElif:
944 if (ifdepth == 0)
945 parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", "");
946 if (elseSeen[elsetracker])
947 parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
948 // this token is really a dont care, but we still need to eat the tokens
949 token = scanToken(ppToken);
950 while (token != '\n' && token != EndOfInput)
951 token = scanToken(ppToken);
952 token = CPPelse(0, ppToken);
953 break;
954 case PpAtomEndif:
955 if (ifdepth == 0)
956 parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
957 else {
958 elseSeen[elsetracker] = false;
959 --elsetracker;
960 --ifdepth;
961 }
962 token = extraTokenCheck(PpAtomEndif, ppToken, scanToken(ppToken));
963 break;
964 case PpAtomIf:
965 token = CPPif(ppToken);
966 break;
967 case PpAtomIfdef:
968 token = CPPifdef(1, ppToken);
969 break;
970 case PpAtomIfndef:
971 token = CPPifdef(0, ppToken);
972 break;
973 case PpAtomLine:
974 token = CPPline(ppToken);
975 break;
976 #ifndef GLSLANG_WEB
977 case PpAtomInclude:
978 if(!parseContext.isReadingHLSL()) {
979 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include");
980 }
981 token = CPPinclude(ppToken);
982 break;
983 case PpAtomPragma:
984 token = CPPpragma(ppToken);
985 break;
986 #endif
987 case PpAtomUndef:
988 token = CPPundef(ppToken);
989 break;
990 case PpAtomError:
991 token = CPPerror(ppToken);
992 break;
993 case PpAtomVersion:
994 token = CPPversion(ppToken);
995 break;
996 case PpAtomExtension:
997 token = CPPextension(ppToken);
998 break;
999 default:
1000 parseContext.ppError(ppToken->loc, "invalid directive:", "#", ppToken->name);
1001 break;
1002 }
1003 } else if (token != '\n' && token != EndOfInput)
1004 parseContext.ppError(ppToken->loc, "invalid directive", "#", "");
1005
1006 while (token != '\n' && token != EndOfInput)
1007 token = scanToken(ppToken);
1008
1009 return token;
1010 }
1011
1012 // Context-dependent parsing of a #include <header-name>.
1013 // Assumes no macro expansions etc. are being done; the name is just on the current input.
1014 // Always creates a name and returns PpAtomicConstString, unless we run out of input.
scanHeaderName(TPpToken * ppToken,char delimit)1015 int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit)
1016 {
1017 bool tooLong = false;
1018
1019 if (inputStack.empty())
1020 return EndOfInput;
1021
1022 int len = 0;
1023 ppToken->name[0] = '\0';
1024 do {
1025 int ch = inputStack.back()->getch();
1026
1027 // done yet?
1028 if (ch == delimit) {
1029 ppToken->name[len] = '\0';
1030 if (tooLong)
1031 parseContext.ppError(ppToken->loc, "header name too long", "", "");
1032 return PpAtomConstString;
1033 } else if (ch == EndOfInput)
1034 return EndOfInput;
1035
1036 // found a character to expand the name with
1037 if (len < MaxTokenLength)
1038 ppToken->name[len++] = (char)ch;
1039 else
1040 tooLong = true;
1041 } while (true);
1042 }
1043
1044 // Macro-expand a macro argument 'arg' to create 'expandedArg'.
1045 // Does not replace 'arg'.
1046 // Returns nullptr if no expanded argument is created.
PrescanMacroArg(TokenStream & arg,TPpToken * ppToken,bool newLineOkay)1047 TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
1048 {
1049 // expand the argument
1050 TokenStream* expandedArg = new TokenStream;
1051 pushInput(new tMarkerInput(this));
1052 pushTokenStreamInput(arg);
1053 int token;
1054 while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) {
1055 token = tokenPaste(token, *ppToken);
1056 if (token == PpAtomIdentifier) {
1057 switch (MacroExpand(ppToken, false, newLineOkay)) {
1058 case MacroExpandNotStarted:
1059 break;
1060 case MacroExpandError:
1061 // toss the rest of the pushed-input argument by scanning until tMarkerInput
1062 while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput)
1063 ;
1064 break;
1065 case MacroExpandStarted:
1066 case MacroExpandUndef:
1067 continue;
1068 }
1069 }
1070 if (token == tMarkerInput::marker || token == EndOfInput)
1071 break;
1072 expandedArg->putToken(token, ppToken);
1073 }
1074
1075 if (token != tMarkerInput::marker) {
1076 // Error, or MacroExpand ate the marker, so had bad input, recover
1077 delete expandedArg;
1078 expandedArg = nullptr;
1079 }
1080
1081 return expandedArg;
1082 }
1083
1084 //
1085 // Return the next token for a macro expansion, handling macro arguments,
1086 // whose semantics are dependent on being adjacent to ##.
1087 //
scan(TPpToken * ppToken)1088 int TPpContext::tMacroInput::scan(TPpToken* ppToken)
1089 {
1090 int token;
1091 do {
1092 token = mac->body.getToken(pp->parseContext, ppToken);
1093 } while (token == ' '); // handle white space in macro
1094
1095 // Hash operators basically turn off a round of macro substitution
1096 // (the round done on the argument before the round done on the RHS of the
1097 // macro definition):
1098 //
1099 // "A parameter in the replacement list, unless preceded by a # or ##
1100 // preprocessing token or followed by a ## preprocessing token (see below),
1101 // is replaced by the corresponding argument after all macros contained
1102 // therein have been expanded."
1103 //
1104 // "If, in the replacement list, a parameter is immediately preceded or
1105 // followed by a ## preprocessing token, the parameter is replaced by the
1106 // corresponding argument's preprocessing token sequence."
1107
1108 bool pasting = false;
1109 if (postpaste) {
1110 // don't expand next token
1111 pasting = true;
1112 postpaste = false;
1113 }
1114
1115 if (prepaste) {
1116 // already know we should be on a ##, verify
1117 assert(token == PpAtomPaste);
1118 prepaste = false;
1119 postpaste = true;
1120 }
1121
1122 // see if are preceding a ##
1123 if (mac->body.peekUntokenizedPasting()) {
1124 prepaste = true;
1125 pasting = true;
1126 }
1127
1128 // HLSL does expand macros before concatenation
1129 if (pasting && pp->parseContext.isReadingHLSL())
1130 pasting = false;
1131
1132 // TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding
1133 if (token == PpAtomIdentifier) {
1134 int i;
1135 for (i = (int)mac->args.size() - 1; i >= 0; i--)
1136 if (strcmp(pp->atomStrings.getString(mac->args[i]), ppToken->name) == 0)
1137 break;
1138 if (i >= 0) {
1139 TokenStream* arg = expandedArgs[i];
1140 if (arg == nullptr || pasting)
1141 arg = args[i];
1142 pp->pushTokenStreamInput(*arg, prepaste);
1143
1144 return pp->scanToken(ppToken);
1145 }
1146 }
1147
1148 if (token == EndOfInput)
1149 mac->busy = 0;
1150
1151 return token;
1152 }
1153
1154 // return a textual zero, for scanning a macro that was never defined
scan(TPpToken * ppToken)1155 int TPpContext::tZeroInput::scan(TPpToken* ppToken)
1156 {
1157 if (done)
1158 return EndOfInput;
1159
1160 ppToken->name[0] = '0';
1161 ppToken->name[1] = 0;
1162 ppToken->ival = 0;
1163 ppToken->space = false;
1164 done = true;
1165
1166 return PpAtomConstInt;
1167 }
1168
1169 //
1170 // Check a token to see if it is a macro that should be expanded:
1171 // - If it is, and defined, push a tInput that will produce the appropriate
1172 // expansion and return MacroExpandStarted.
1173 // - If it is, but undefined, and expandUndef is requested, push a tInput
1174 // that will expand to 0 and return MacroExpandUndef.
1175 // - Otherwise, there is no expansion, and there are two cases:
1176 // * It might be okay there is no expansion, and no specific error was
1177 // detected. Returns MacroExpandNotStarted.
1178 // * The expansion was started, but could not be completed, due to an error
1179 // that cannot be recovered from. Returns MacroExpandError.
1180 //
MacroExpand(TPpToken * ppToken,bool expandUndef,bool newLineOkay)1181 MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay)
1182 {
1183 ppToken->space = false;
1184 int macroAtom = atomStrings.getAtom(ppToken->name);
1185 switch (macroAtom) {
1186 case PpAtomLineMacro:
1187 // Arguments which are macro have been replaced in the first stage.
1188 if (ppToken->ival == 0)
1189 ppToken->ival = parseContext.getCurrentLoc().line;
1190 snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1191 UngetToken(PpAtomConstInt, ppToken);
1192 return MacroExpandStarted;
1193
1194 case PpAtomFileMacro: {
1195 if (parseContext.getCurrentLoc().name)
1196 parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
1197 ppToken->ival = parseContext.getCurrentLoc().string;
1198 snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str());
1199 UngetToken(PpAtomConstInt, ppToken);
1200 return MacroExpandStarted;
1201 }
1202
1203 case PpAtomVersionMacro:
1204 ppToken->ival = parseContext.version;
1205 snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival);
1206 UngetToken(PpAtomConstInt, ppToken);
1207 return MacroExpandStarted;
1208
1209 default:
1210 break;
1211 }
1212
1213 MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
1214
1215 // no recursive expansions
1216 if (macro != nullptr && macro->busy)
1217 return MacroExpandNotStarted;
1218
1219 // not expanding undefined macros
1220 if ((macro == nullptr || macro->undef) && ! expandUndef)
1221 return MacroExpandNotStarted;
1222
1223 // 0 is the value of an undefined macro
1224 if ((macro == nullptr || macro->undef) && expandUndef) {
1225 pushInput(new tZeroInput(this));
1226 return MacroExpandUndef;
1227 }
1228
1229 tMacroInput *in = new tMacroInput(this);
1230
1231 TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error
1232 in->mac = macro;
1233 if (macro->functionLike) {
1234 // We don't know yet if this will be a successful call of a
1235 // function-like macro; need to look for a '(', but without trashing
1236 // the passed in ppToken, until we know we are no longer speculative.
1237 TPpToken parenToken;
1238 int token = scanToken(&parenToken);
1239 if (newLineOkay) {
1240 while (token == '\n')
1241 token = scanToken(&parenToken);
1242 }
1243 if (token != '(') {
1244 // Function-like macro called with object-like syntax: okay, don't expand.
1245 // (We ate exactly one token that might not be white space; put it back.
1246 UngetToken(token, &parenToken);
1247 delete in;
1248 return MacroExpandNotStarted;
1249 }
1250 in->args.resize(in->mac->args.size());
1251 for (size_t i = 0; i < in->mac->args.size(); i++)
1252 in->args[i] = new TokenStream;
1253 in->expandedArgs.resize(in->mac->args.size());
1254 for (size_t i = 0; i < in->mac->args.size(); i++)
1255 in->expandedArgs[i] = nullptr;
1256 size_t arg = 0;
1257 bool tokenRecorded = false;
1258 do {
1259 TVector<char> nestStack;
1260 while (true) {
1261 token = scanToken(ppToken);
1262 if (token == EndOfInput || token == tMarkerInput::marker) {
1263 parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
1264 delete in;
1265 return MacroExpandError;
1266 }
1267 if (token == '\n') {
1268 if (! newLineOkay) {
1269 parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom));
1270 delete in;
1271 return MacroExpandError;
1272 }
1273 continue;
1274 }
1275 if (token == '#') {
1276 parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom));
1277 delete in;
1278 return MacroExpandError;
1279 }
1280 if (in->mac->args.size() == 0 && token != ')')
1281 break;
1282 if (nestStack.size() == 0 && (token == ',' || token == ')'))
1283 break;
1284 if (token == '(')
1285 nestStack.push_back(')');
1286 else if (token == '{' && parseContext.isReadingHLSL())
1287 nestStack.push_back('}');
1288 else if (nestStack.size() > 0 && token == nestStack.back())
1289 nestStack.pop_back();
1290
1291 //Macro replacement list is expanded in the last stage.
1292 if (atomStrings.getAtom(ppToken->name) == PpAtomLineMacro)
1293 ppToken->ival = parseContext.getCurrentLoc().line;
1294
1295 in->args[arg]->putToken(token, ppToken);
1296 tokenRecorded = true;
1297 }
1298 // end of single argument scan
1299
1300 if (token == ')') {
1301 // closing paren of call
1302 if (in->mac->args.size() == 1 && !tokenRecorded)
1303 break;
1304 arg++;
1305 break;
1306 }
1307 arg++;
1308 } while (arg < in->mac->args.size());
1309 // end of all arguments scan
1310
1311 if (arg < in->mac->args.size())
1312 parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom));
1313 else if (token != ')') {
1314 // Error recover code; find end of call, if possible
1315 int depth = 0;
1316 while (token != EndOfInput && (depth > 0 || token != ')')) {
1317 if (token == ')' || token == '}')
1318 depth--;
1319 token = scanToken(ppToken);
1320 if (token == '(' || token == '{')
1321 depth++;
1322 }
1323
1324 if (token == EndOfInput) {
1325 parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom));
1326 delete in;
1327 return MacroExpandError;
1328 }
1329 parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom));
1330 }
1331
1332 // We need both expanded and non-expanded forms of the argument, for whether or
1333 // not token pasting will be applied later when the argument is consumed next to ##.
1334 for (size_t i = 0; i < in->mac->args.size(); i++)
1335 in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay);
1336 }
1337
1338 pushInput(in);
1339 macro->busy = 1;
1340 macro->body.reset();
1341
1342 return MacroExpandStarted;
1343 }
1344
1345 } // end namespace glslang
1346