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