glslang: Fix over 100 warnings from MSVC warning level 4.
[platform/upstream/glslang.git] / 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 // cpp.c
80 //
81
82 #define _CRT_SECURE_NO_WARNINGS
83
84 #include <stdarg.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <ctype.h>
89
90 #include "PpContext.h"
91 #include "PpTokens.h"
92
93 namespace glslang {
94
95 int TPpContext::InitCPP()
96 {
97     // Add various atoms needed by the CPP line scanner:
98     bindAtom = LookUpAddString("bind");
99     constAtom = LookUpAddString("const");
100     defaultAtom = LookUpAddString("default");
101     defineAtom = LookUpAddString("define");
102     definedAtom = LookUpAddString("defined");
103     elifAtom = LookUpAddString("elif");
104     elseAtom = LookUpAddString("else");
105     endifAtom = LookUpAddString("endif");
106     ifAtom = LookUpAddString("if");
107     ifdefAtom = LookUpAddString("ifdef");
108     ifndefAtom = LookUpAddString("ifndef");
109     includeAtom = LookUpAddString("include");
110     lineAtom = LookUpAddString("line");
111     pragmaAtom = LookUpAddString("pragma");
112     texunitAtom = LookUpAddString("texunit");
113     undefAtom = LookUpAddString("undef");
114     errorAtom = LookUpAddString("error");
115     __LINE__Atom = LookUpAddString("__LINE__");
116     __FILE__Atom = LookUpAddString("__FILE__");
117     __VERSION__Atom = LookUpAddString("__VERSION__");
118     versionAtom = LookUpAddString("version");
119     coreAtom = LookUpAddString("core");
120     compatibilityAtom = LookUpAddString("compatibility");
121     esAtom = LookUpAddString("es");
122     extensionAtom = LookUpAddString("extension");
123     pool = mem_CreatePool(0, 0);
124
125     return 1;
126 }
127
128 // Handle #define
129 int TPpContext::CPPdefine(TPpToken* ppToken)
130 {
131     MacroSymbol mac;
132     Symbol *symb;
133
134     // get macro name
135     int token = scanToken(ppToken);
136     if (token != CPP_IDENTIFIER) {
137         parseContext.error(ppToken->loc, "must be followed by macro name", "#define", "");
138         return token;
139     }
140     int atom = ppToken->atom;
141     const char* definedName = GetAtomString(atom);
142     if (ppToken->loc.string >= 0) {
143         // We are in user code; check for reserved name use:
144         parseContext.reservedPpErrorCheck(ppToken->loc, definedName, "#define");
145     }
146
147     // gather parameters to the macro, between (...)
148     token = scanToken(ppToken);
149     if (token == '(' && ! ppToken->space) {
150         int argc = 0;
151         int args[maxMacroArgs];
152         do {
153             token = scanToken(ppToken);
154             if (argc == 0 && token == ')') 
155                 break;
156             if (token != CPP_IDENTIFIER) {
157                 parseContext.error(ppToken->loc, "bad argument", "#define", "");
158
159                 return token;
160             }
161             // check for duplication of parameter name
162             bool duplicate = false;
163             for (int a = 0; a < argc; ++a) {
164                 if (args[a] == ppToken->atom) {
165                     parseContext.error(ppToken->loc, "duplicate macro parameter", "#define", "");
166                     duplicate = true;
167                     break;
168                 }
169             }
170             if (! duplicate) {
171                 if (argc < maxMacroArgs)
172                     args[argc++] = ppToken->atom;
173                 else
174                     parseContext.error(ppToken->loc, "too many macro parameters", "#define", "");                    
175             }
176             token = scanToken(ppToken);
177         } while (token == ',');
178         if (token != ')') {            
179             parseContext.error(ppToken->loc, "missing parenthesis", "#define", "");
180
181             return token;
182         }
183         mac.argc = argc;
184         mac.args = (int*)mem_Alloc(pool, argc * sizeof(int));
185         memcpy(mac.args, args, argc * sizeof(int));
186         token = scanToken(ppToken);
187     }
188
189     // record the definition of the macro
190     TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
191     mac.body = new TokenStream;
192     while (token != '\n') {
193         RecordToken(mac.body, token, ppToken);
194         token = scanToken(ppToken);
195         if (token != '\n' && ppToken->space)
196             RecordToken(mac.body, ' ', ppToken);
197     }
198
199     // check for duplicate definition
200     symb = LookUpSymbol(atom);
201     if (symb) {
202         if (! symb->mac.undef) {
203             // Already defined -- need to make sure they are identical:
204             // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
205             // ordering, spelling, and white-space separation, where all white-space separations are considered identical."
206             if (symb->mac.argc != mac.argc)
207                 parseContext.error(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(atom));
208             else {
209                 for (int argc = 0; argc < mac.argc; argc++) {
210                     if (symb->mac.args[argc] != mac.args[argc])
211                         parseContext.error(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(atom));
212                 }
213                 RewindTokenStream(symb->mac.body);
214                 RewindTokenStream(mac.body);
215                 int newToken;
216                 do {
217                     int oldToken;
218                     TPpToken oldPpToken;
219                     TPpToken newPpToken;                    
220                     oldToken = ReadToken(symb->mac.body, &oldPpToken);
221                     newToken = ReadToken(mac.body, &newPpToken);
222                     if (oldToken != newToken || oldPpToken != newPpToken) {
223                         parseContext.error(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(atom));
224                         break; 
225                     }
226                 } while (newToken > 0);
227             }
228         }
229     } else
230         symb = AddSymbol(atom);
231
232     delete symb->mac.body;
233     symb->mac = mac;
234
235     return '\n';
236 }
237
238 // Handle #undef
239 int TPpContext::CPPundef(TPpToken* ppToken)
240 {
241     int token = scanToken(ppToken);
242     Symbol *symb;
243     if (token != CPP_IDENTIFIER) {
244         parseContext.error(ppToken->loc, "must be followed by macro name", "#undef", "");
245
246         return token;
247     }
248
249     const char* name = GetAtomString(ppToken->atom); // TODO preprocessor simplification: the token text should have been built into the ppToken during scanToken()
250     parseContext.reservedPpErrorCheck(ppToken->loc, name, "#undef");
251
252     symb = LookUpSymbol(ppToken->atom);
253     if (symb) {
254         symb->mac.undef = 1;
255     }
256     token = scanToken(ppToken);
257     if (token != '\n')
258         parseContext.error(ppToken->loc, "can only be followed by a single macro name", "#undef", "");
259
260     return token;
261 }
262
263 // Handle #else
264 /* Skip forward to appropriate spot.  This is used both
265 ** to skip to a #endif after seeing an #else, AND to skip to a #else,
266 ** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false.
267 */
268 int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
269 {
270     int atom;
271     int depth = 0;
272     int token = scanToken(ppToken);
273
274     while (token != EOF) {
275         if (token != '#') {
276             while (token != '\n' && token != EOF)
277                 token = scanToken(ppToken);
278             
279             if (token == EOF)
280                 return EOF;
281
282             token = scanToken(ppToken);
283             continue;
284         }
285
286         if ((token = scanToken(ppToken)) != CPP_IDENTIFIER)
287             continue;
288
289         atom = ppToken->atom;
290         if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom) {
291             depth++; 
292             ifdepth++; 
293             elsetracker++;
294         } else if (atom == endifAtom) {
295             token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
296             elseSeen[elsetracker] = false;
297             --elsetracker;
298             if (depth == 0) {
299                 // found the #endif we are looking for
300                 if (ifdepth) 
301                     --ifdepth;
302                 break;
303             }
304             --depth;
305             --ifdepth;
306         } else if (matchelse && depth == 0) {
307             if (atom == elseAtom) {
308                 elseSeen[elsetracker] = true;
309                 token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
310                 // found the #else we are looking for
311                 break;
312             } else if (atom == elifAtom) {
313                 if (elseSeen[elsetracker])
314                     parseContext.error(ppToken->loc, "#elif after #else", "#elif", "");
315                 /* we decrement ifdepth here, because CPPif will increment
316                 * it and we really want to leave it alone */
317                 if (ifdepth) {
318                     --ifdepth;
319                     elseSeen[elsetracker] = false;
320                     --elsetracker;
321                 }
322
323                 return CPPif(ppToken);
324             }
325         } else if (atom == elseAtom) {
326             if (elseSeen[elsetracker])
327                 parseContext.error(ppToken->loc, "#else after #else", "#else", "");
328             else
329                 elseSeen[elsetracker] = true;
330             token = extraTokenCheck(atom, ppToken, scanToken(ppToken));
331         } else if (atom == elifAtom) {
332             if (elseSeen[elsetracker])
333                 parseContext.error(ppToken->loc, "#elif after #else", "#elif", "");
334         }
335     }
336
337     return token;
338 }
339
340 // Call when there should be no more tokens left on a line.
341 int TPpContext::extraTokenCheck(int atom, TPpToken* ppToken, int token)
342 {
343     if (token != '\n') {
344         static const char* message = "unexpected tokens following directive";
345
346         const char* label;
347         if (atom == elseAtom)
348             label = "#else";
349         else if (atom == elifAtom)
350             label = "#elif";
351         else if (atom == endifAtom)
352             label = "#endif";
353         else if (atom == ifAtom)
354             label = "#if";
355         else if (atom == lineAtom)
356             label = "#line";
357         else
358             label = "";
359
360         if (parseContext.messages & EShMsgRelaxedErrors)
361             parseContext.warn(ppToken->loc, message, label, "");
362         else
363             parseContext.error(ppToken->loc, message, label, "");
364
365         while (token != '\n')
366             token = scanToken(ppToken);
367     }
368
369     return token;
370 }
371
372 enum eval_prec {
373     MIN_PRECEDENCE,
374     COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
375     MAX_PRECEDENCE
376 };
377
378 namespace {
379
380     int op_logor(int a, int b) { return a || b; }
381     int op_logand(int a, int b) { return a && b; }
382     int op_or(int a, int b) { return a | b; }
383     int op_xor(int a, int b) { return a ^ b; }
384     int op_and(int a, int b) { return a & b; }
385     int op_eq(int a, int b) { return a == b; }
386     int op_ne(int a, int b) { return a != b; }
387     int op_ge(int a, int b) { return a >= b; }
388     int op_le(int a, int b) { return a <= b; }
389     int op_gt(int a, int b) { return a > b; }
390     int op_lt(int a, int b) { return a < b; }
391     int op_shl(int a, int b) { return a << b; }
392     int op_shr(int a, int b) { return a >> b; }
393     int op_add(int a, int b) { return a + b; }
394     int op_sub(int a, int b) { return a - b; }
395     int op_mul(int a, int b) { return a * b; }
396     int op_div(int a, int b) { return a / b; }
397     int op_mod(int a, int b) { return a % b; }
398     int op_pos(int a) { return a; }
399     int op_neg(int a) { return -a; }
400     int op_cmpl(int a) { return ~a; }
401     int op_not(int a) { return !a; }
402
403 };
404
405 struct TBinop {
406     int token, precedence, (*op)(int, int);
407 } binop[] = {
408     { CPP_OR_OP, LOGOR, op_logor },
409     { CPP_AND_OP, LOGAND, op_logand },
410     { '|', OR, op_or },
411     { '^', XOR, op_xor },
412     { '&', AND, op_and },
413     { CPP_EQ_OP, EQUAL, op_eq },
414     { CPP_NE_OP, EQUAL, op_ne },
415     { '>', RELATION, op_gt },
416     { CPP_GE_OP, RELATION, op_ge },
417     { '<', RELATION, op_lt },
418     { CPP_LE_OP, RELATION, op_le },
419     { CPP_LEFT_OP, SHIFT, op_shl },
420     { CPP_RIGHT_OP, SHIFT, op_shr },
421     { '+', ADD, op_add },
422     { '-', ADD, op_sub },
423     { '*', MUL, op_mul },
424     { '/', MUL, op_div },
425     { '%', MUL, op_mod },
426 };
427
428 struct TUnop {
429     int token, (*op)(int);
430 } unop[] = {
431     { '+', op_pos },
432     { '-', op_neg },
433     { '~', op_cmpl },
434     { '!', op_not },
435 };
436
437 #define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0]))
438
439 int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
440 {
441     TSourceLoc loc = ppToken->loc;  // because we sometimes read the newline before reporting the error
442     if (token == CPP_IDENTIFIER) {
443         if (ppToken->atom == definedAtom) {
444             bool needclose = 0;
445             token = scanToken(ppToken);
446             if (token == '(') {
447                 needclose = true;
448                 token = scanToken(ppToken);
449             }
450             if (token != CPP_IDENTIFIER) {
451                 parseContext.error(loc, "incorrect directive, expected identifier", "preprocessor evaluation", "");
452                 err = true;
453                 res = 0;
454
455                 return token;
456             }
457             Symbol* s = LookUpSymbol(ppToken->atom);
458             res = s ? ! s->mac.undef : 0;
459             token = scanToken(ppToken);
460             if (needclose) {
461                 if (token != ')') {
462                     parseContext.error(loc, "expected ')'", "preprocessor evaluation", "");
463                     err = true;
464                     res = 0;
465
466                     return token;
467                 }
468                 token = scanToken(ppToken);
469             }
470         } else {
471             token = evalToToken(token, shortCircuit, res, err, ppToken);
472             return eval(token, precedence, shortCircuit, res, err, ppToken);
473         }
474     } else if (token == CPP_INTCONSTANT) {
475         res = ppToken->ival;
476         token = scanToken(ppToken);
477     } else if (token == '(') {
478         token = scanToken(ppToken);
479         token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken);
480         if (! err) {
481             if (token != ')') {
482                 parseContext.error(loc, "expected ')'", "preprocessor evaluation", "");
483                 err = true;
484                 res = 0;
485
486                 return token;
487             }
488             token = scanToken(ppToken);
489         }
490     } else {
491         int op;
492         for (op = NUM_ELEMENTS(unop) - 1; op >= 0; op--) {
493             if (unop[op].token == token)
494                 break;
495         }
496         if (op >= 0) {
497             token = scanToken(ppToken);
498             token = eval(token, UNARY, shortCircuit, res, err, ppToken);
499             res = unop[op].op(res);
500         } else {
501             parseContext.error(loc, "bad expression", "preprocessor evaluation", "");
502             err = true;
503             res = 0;
504
505             return token;
506         }
507     }
508
509     token = evalToToken(token, shortCircuit, res, err, ppToken);
510
511     // Perform evaluation of binary operation, if there is one, otherwise we are done.
512     while (! err) {
513         if (token == ')' || token == '\n') 
514             break;
515         int op;
516         for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) {
517             if (binop[op].token == token)
518                 break;
519         }
520         if (op < 0 || binop[op].precedence <= precedence)
521             break;
522         int leftSide = res;
523         
524         // Setup short-circuiting, needed for ES, unless already in a short circuit.
525         // (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
526         if (! shortCircuit) {
527             if ((token == CPP_OR_OP  && leftSide == 1) ||
528                 (token == CPP_AND_OP && leftSide == 0))
529                 shortCircuit = true;
530         }
531
532         token = scanToken(ppToken);
533         token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken);
534         res = binop[op].op(leftSide, res);
535     }
536
537     return token;
538 }
539
540 // Expand macros, skipping empty expansions, to get to the first real token in those expansions.
541 int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken* ppToken)
542 {
543     while (token == CPP_IDENTIFIER && ppToken->atom != definedAtom) {
544         int macroReturn = MacroExpand(ppToken->atom, ppToken, true, false);
545         if (macroReturn == 0) {
546             parseContext.error(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", "");
547             err = true;
548             res = 0;
549             token = scanToken(ppToken);
550             break;
551         }
552         if (macroReturn == -1) {
553             if (! shortCircuit && parseContext.profile == EEsProfile) {
554                 const char* message = "undefined macro in expression not allowed in es profile";
555                 const char* name = GetAtomString(ppToken->atom);
556                 if (parseContext.messages & EShMsgRelaxedErrors)
557                     parseContext.warn(ppToken->loc, message, "preprocessor evaluation", name);
558                 else
559                     parseContext.error(ppToken->loc, message, "preprocessor evaluation", name);
560             }
561         }
562         token = scanToken(ppToken);
563     }
564
565     return token;
566 }
567
568 // Handle #if
569 int TPpContext::CPPif(TPpToken* ppToken) 
570 {
571     int token = scanToken(ppToken);
572     elsetracker++;
573     if (! ifdepth++)
574         ifloc = ppToken->loc;
575     if (ifdepth > maxIfNesting) {
576         parseContext.error(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
577         return 0;
578     }
579     int res = 0;
580     bool err = false;
581     token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken);
582     token = extraTokenCheck(ifAtom, ppToken, token);
583     if (!res && !err)
584         token = CPPelse(1, ppToken);
585
586     return token;
587 }
588
589 // Handle #ifdef
590 int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
591 {
592     int token = scanToken(ppToken);
593     int name = ppToken->atom;
594     if (++ifdepth > maxIfNesting) {
595         parseContext.error(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
596         return 0;
597     }
598     elsetracker++;
599     if (token != CPP_IDENTIFIER) {
600         if (defined)
601             parseContext.error(ppToken->loc, "must be followed by macro name", "#ifdef", "");
602         else 
603             parseContext.error(ppToken->loc, "must be followed by macro name", "#ifndef", "");
604     } else {
605         Symbol *s = LookUpSymbol(name);
606         token = scanToken(ppToken);
607         if (token != '\n') {
608             parseContext.error(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
609             while (token != '\n')
610                 token = scanToken(ppToken);
611         }
612         if (((s && !s->mac.undef) ? 1 : 0) != defined)
613             token = CPPelse(1, ppToken);
614     }
615
616     return token;
617 }
618
619 // Handle #line
620 int TPpContext::CPPline(TPpToken* ppToken) 
621 {
622     // "#line must have, after macro substitution, one of the following forms:
623     // "#line line
624     // "#line line source-string-number"
625
626     int token = scanToken(ppToken);
627     if (token == '\n') {
628         parseContext.error(ppToken->loc, "must by followed by an integral literal", "#line", "");
629         return token;
630     }
631
632     int lineRes = 0;
633     bool lineErr = false;
634     token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken);
635     if (! lineErr) {
636         if (token == '\n')
637             ++lineRes;
638
639         // Desktop, pre-version 3.30:  "After processing this directive
640         // (including its new-line), the implementation will behave as if it is compiling at line number line+1 and
641         // source string number source-string-number."
642         //
643         // Desktop, version 3.30 and later, and ES:  "After processing this directive
644         // (including its new-line), the implementation will behave as if it is compiling at line number line and
645         // source string number source-string-number.
646         if (parseContext.profile == EEsProfile || parseContext.version >= 330)
647             --lineRes;
648         parseContext.setCurrentLine(lineRes);
649
650         if (token != '\n') {
651             int fileRes = 0;
652             bool fileErr = false;
653             token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken);
654             if (! fileErr)
655                 parseContext.setCurrentString(fileRes);
656         }
657     }
658
659     token = extraTokenCheck(lineAtom, ppToken, token);
660
661     return token;
662 }
663
664 // Handle #error
665 int TPpContext::CPPerror(TPpToken* ppToken) 
666 {
667     int token = scanToken(ppToken);
668     std::string message;
669     TSourceLoc loc = ppToken->loc;
670
671     while (token != '\n') {
672         if (token == CPP_INTCONSTANT || token == CPP_UINTCONSTANT ||
673             token == CPP_FLOATCONSTANT || token == CPP_DOUBLECONSTANT) {
674                 message.append(ppToken->name);
675         } else if (token == CPP_IDENTIFIER || token == CPP_STRCONSTANT) {
676             message.append(GetAtomString(ppToken->atom));
677         } else {
678             message.append(GetAtomString(token));
679         }
680         message.append(" ");
681         token = scanToken(ppToken);
682     }
683     //store this msg into the shader's information log..set the Compile Error flag!!!!
684     parseContext.error(loc, message.c_str(), "#error", "");
685
686     return '\n';
687 }
688
689 // Handle #pragma
690 int TPpContext::CPPpragma(TPpToken* ppToken)
691 {
692     char SrcStrName[2];
693     const char* SrcStr;
694     TVector<TString> tokens;
695
696     TSourceLoc loc = ppToken->loc;  // because we go to the next line before processing
697     int token = scanToken(ppToken);
698     while (token != '\n' && token != EOF) {
699         switch (token) {
700         case CPP_IDENTIFIER:
701             SrcStr = GetAtomString(ppToken->atom);
702             tokens.push_back(SrcStr);
703             break;
704         case CPP_INTCONSTANT:
705         case CPP_UINTCONSTANT:
706         case CPP_FLOATCONSTANT:
707         case CPP_DOUBLECONSTANT:
708             SrcStr = ppToken->name;
709             tokens.push_back(SrcStr);
710             break;
711         default:
712             SrcStrName[0] = (char)token;
713             SrcStrName[1] = '\0';
714             tokens.push_back(SrcStrName);
715         }
716         token = scanToken(ppToken);
717     }
718
719     if (token == EOF)
720         parseContext.error(loc, "directive must end with a newline", "#pragma", "");
721     else
722         parseContext.handlePragma(loc, tokens);
723
724     return token;    
725 }
726
727 // #version: This is just for error checking: the version and profile are decided before preprocessing starts
728 int TPpContext::CPPversion(TPpToken* ppToken)
729 {
730     int token = scanToken(ppToken);
731
732     if (errorOnVersion || versionSeen)
733         parseContext.error(ppToken->loc, "must occur first in shader", "#version", "");
734     versionSeen = true;
735
736     if (token == '\n') {
737         parseContext.error(ppToken->loc, "must be followed by version number", "#version", "");
738
739         return token;
740     }
741
742     if (token != CPP_INTCONSTANT)
743         parseContext.error(ppToken->loc, "must be followed by version number", "#version", "");
744
745     ppToken->ival = atoi(ppToken->name);
746
747     token = scanToken(ppToken);
748
749     if (token == '\n')
750         return token;
751     else {
752         if (ppToken->atom != coreAtom &&
753             ppToken->atom != compatibilityAtom &&
754             ppToken->atom != esAtom)
755             parseContext.error(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", "");
756
757         token = scanToken(ppToken);
758
759         if (token == '\n')
760             return token;
761         else
762             parseContext.error(ppToken->loc, "bad tokens following profile -- expected newline", "#version", "");
763     }
764
765     return token;
766 }
767
768 // Handle #extension
769 int TPpContext::CPPextension(TPpToken* ppToken)
770 {
771     int token = scanToken(ppToken);
772     char extensionName[80];
773
774     if (token=='\n') {
775         parseContext.error(ppToken->loc, "extension name not specified", "#extension", "");
776         return token;
777     }
778
779     if (token != CPP_IDENTIFIER)
780         parseContext.error(ppToken->loc, "extension name expected", "#extension", "");
781
782     strcpy(extensionName, GetAtomString(ppToken->atom));
783
784     token = scanToken(ppToken);
785     if (token != ':') {
786         parseContext.error(ppToken->loc, "':' missing after extension name", "#extension", "");
787         return token;
788     }
789
790     token = scanToken(ppToken);
791     if (token != CPP_IDENTIFIER) {
792         parseContext.error(ppToken->loc, "behavior for extension not specified", "#extension", "");
793         return token;
794     }
795
796     parseContext.updateExtensionBehavior(extensionName, GetAtomString(ppToken->atom));
797
798     token = scanToken(ppToken);
799     if (token == '\n')
800         return token;
801     else
802         parseContext.error(ppToken->loc,  "extra tokens -- expected newline", "#extension","");
803
804     return token;
805 }
806
807 int TPpContext::readCPPline(TPpToken* ppToken)
808 {
809     int token = scanToken(ppToken);
810     bool isVersion = false;
811
812     if (token == CPP_IDENTIFIER) {
813         if (ppToken->atom == defineAtom) {
814             token = CPPdefine(ppToken);
815         } else if (ppToken->atom == elseAtom) {
816             if (elsetracker[elseSeen])
817                 parseContext.error(ppToken->loc, "#else after #else", "#else", "");
818             elsetracker[elseSeen] = true;
819             if (! ifdepth)
820                 parseContext.error(ppToken->loc, "mismatched statements", "#else", "");
821             token = extraTokenCheck(elseAtom, ppToken, scanToken(ppToken));
822             token = CPPelse(0, ppToken);
823         } else if (ppToken->atom == elifAtom) {
824             if (! ifdepth)
825                 parseContext.error(ppToken->loc, "mismatched statements", "#elif", "");
826             if (elseSeen[elsetracker])
827                 parseContext.error(ppToken->loc, "#elif after #else", "#elif", "");
828             // this token is really a dont care, but we still need to eat the tokens
829             token = scanToken(ppToken); 
830             while (token != '\n')
831                 token = scanToken(ppToken);
832             token = CPPelse(0, ppToken);
833         } else if (ppToken->atom == endifAtom) {
834             elseSeen[elsetracker] = false;
835             --elsetracker;
836             if (! ifdepth)
837                 parseContext.error(ppToken->loc, "mismatched statements", "#endif", "");
838             else
839                 --ifdepth;
840             token = extraTokenCheck(endifAtom, ppToken, scanToken(ppToken));
841         } else if (ppToken->atom == ifAtom) {
842             token = CPPif (ppToken);
843         } else if (ppToken->atom == ifdefAtom) {
844             token = CPPifdef(1, ppToken);
845         } else if (ppToken->atom == ifndefAtom) {
846             token = CPPifdef(0, ppToken);
847         } else if (ppToken->atom == lineAtom) {
848             token = CPPline(ppToken);
849         } else if (ppToken->atom == pragmaAtom) {
850             token = CPPpragma(ppToken);
851         } else if (ppToken->atom == undefAtom) {
852             token = CPPundef(ppToken);
853         } else if (ppToken->atom == errorAtom) {
854             token = CPPerror(ppToken);
855         } else if (ppToken->atom == versionAtom) {
856             token = CPPversion(ppToken);
857             isVersion = true;
858         } else if (ppToken->atom == extensionAtom) {
859             token = CPPextension(ppToken);
860         } else {
861             parseContext.error(ppToken->loc, "invalid directive:", "#", GetAtomString(ppToken->atom));
862         }
863     } else if (token != '\n' && token != EOF)
864         parseContext.error(ppToken->loc, "invalid directive", "#", "");
865
866     while (token != '\n' && token != 0 && token != EOF)
867         token = scanToken(ppToken);
868
869     return token;
870 }
871
872 TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream* a, TPpToken* ppToken, bool newLineOkay)
873 {
874     int token;
875     TokenStream *n;
876     RewindTokenStream(a);
877     do {
878         token = ReadToken(a, ppToken);
879         if (token == CPP_IDENTIFIER && LookUpSymbol(ppToken->atom))
880             break;
881     } while (token != tInput::endOfInput);
882
883     if (token == tInput::endOfInput)
884         return a;
885
886     n = new TokenStream;
887     pushInput(new tMarkerInput(this));
888     pushTokenStreamInput(a);
889     while ((token = scanToken(ppToken)) != tMarkerInput::marker) {
890         if (token == CPP_IDENTIFIER && MacroExpand(ppToken->atom, ppToken, false, newLineOkay) != 0)
891             continue;
892         RecordToken(n, token, ppToken);
893     }
894     popInput();
895     delete a;
896
897     return n;
898 }
899
900 // 
901 // Return the next token for a macro expansion, handling macro args.
902 //
903 int TPpContext::tMacroInput::scan(TPpToken* ppToken)
904 {
905     int token;
906     do {
907         token = pp->ReadToken(mac->body, ppToken);
908     } while (token == ' ');  // handle white space in macro
909
910     // TODO: preprocessor:  properly handle whitespace (or lack of it) between tokens when expanding
911     if (token == CPP_IDENTIFIER) {
912         int i;
913         for (i = mac->argc - 1; i >= 0; i--)
914             if (mac->args[i] == ppToken->atom) 
915                 break;
916         if (i >= 0) {
917             pp->pushTokenStreamInput(args[i]);
918
919             return pp->scanToken(ppToken);
920         }
921     }
922
923     if (token == endOfInput)
924         mac->busy = 0;
925         
926     return token;
927 }
928
929 // return a zero, for scanning a macro that was never defined
930 int TPpContext::tZeroInput::scan(TPpToken* ppToken)
931 {
932     if (done)
933         return endOfInput;
934
935     strcpy(ppToken->name, "0");
936     ppToken->ival = 0;
937     ppToken->space = false;
938     done = true;
939
940     return CPP_INTCONSTANT;
941 }
942
943 //
944 // Check an identifier (atom) to see if it is a macro that should be expanded.
945 // If it is, and defined, push a tInput that will produce the appropriate expansion
946 // and return 1.
947 // If it is, but undefined, and expandUndef is requested, push a tInput that will 
948 // expand to 0 and return -1.
949 // Otherwise, return 0 to indicate no expansion, which is not necessarily an error.
950 //
951 int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay)
952 {
953     Symbol *sym = LookUpSymbol(atom);
954     int token;
955     int depth = 0;
956
957     ppToken->space = false;
958     if (atom == __LINE__Atom) {
959         ppToken->ival = parseContext.getCurrentLoc().line;
960         sprintf(ppToken->name, "%d", ppToken->ival);
961         UngetToken(CPP_INTCONSTANT, ppToken);
962
963         return 1;
964     }
965
966     if (atom == __FILE__Atom) {
967         ppToken->ival = parseContext.getCurrentLoc().string;
968         sprintf(ppToken->name, "%d", ppToken->ival);
969         UngetToken(CPP_INTCONSTANT, ppToken);
970
971         return 1;
972     }
973
974     if (atom == __VERSION__Atom) {
975         ppToken->ival = parseContext.version;
976         sprintf(ppToken->name, "%d", ppToken->ival);
977         UngetToken(CPP_INTCONSTANT, ppToken);
978
979         return 1;
980     }
981
982     // no recursive expansions
983     if (sym && sym->mac.busy)
984         return 0;
985
986     // not expanding undefined macros
987     if ((! sym || sym->mac.undef) && ! expandUndef)
988         return 0;
989
990     // 0 is the value of an undefined macro
991     if ((! sym || sym->mac.undef) && expandUndef) {
992         pushInput(new tZeroInput(this));
993         return -1;
994     }
995
996     tMacroInput *in = new tMacroInput(this);
997
998     TSourceLoc loc = ppToken->loc;  // in case we go to the next line before discovering the error
999     in->mac = &sym->mac;
1000     if (sym->mac.args) {
1001         token = scanToken(ppToken);
1002         if (newLineOkay) {
1003             while (token == '\n')                
1004                 token = scanToken(ppToken);
1005         }
1006         if (token != '(') {
1007             parseContext.error(loc, "expected '(' following", "macro expansion", GetAtomString(atom));
1008             UngetToken(token, ppToken);
1009             ppToken->atom = atom;
1010
1011             delete in;
1012             return 0;
1013         }
1014         in->args.resize(in->mac->argc);
1015         for (int i = 0; i < in->mac->argc; i++)
1016             in->args[i] = new TokenStream;
1017         int arg = 0;
1018         bool tokenRecorded = false;
1019         do {
1020             depth = 0;
1021             while (1) {
1022                 token = scanToken(ppToken);
1023                 if (token == EOF) {
1024                     parseContext.error(loc, "EOF in macro", "macro expansion", GetAtomString(atom));
1025                     delete in;
1026                     return 0;
1027                 }
1028                 if (token == '\n') {
1029                     if (! newLineOkay) {
1030                         parseContext.error(loc, "end of line in macro substitution:", "macro expansion", GetAtomString(atom));
1031                         delete in;
1032                         return 0;
1033                     }
1034                     continue;
1035                 }
1036                 if (token == '#') {
1037                     parseContext.error(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom));
1038                     delete in;
1039                     return 0;
1040                 }
1041                 if (in->mac->argc == 0 && token != ')')
1042                     break;
1043                 if (depth == 0 && (token == ',' || token == ')'))
1044                     break;
1045                 if (token == '(')
1046                     depth++;
1047                 if (token == ')')
1048                     depth--;
1049                 RecordToken(in->args[arg], token, ppToken);
1050                 tokenRecorded = true;
1051             }
1052             if (token == ')') {
1053                 if (in->mac->argc == 1 && tokenRecorded == 0)
1054                     break;
1055                 arg++;
1056                 break;
1057             }
1058             arg++;
1059         } while (arg < in->mac->argc);
1060
1061         if (arg < in->mac->argc)
1062             parseContext.error(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom));
1063         else if (token != ')') {
1064             depth=0;
1065             while (token != EOF && (depth > 0 || token != ')')) {
1066                 if (token == ')')
1067                     depth--;
1068                 token = scanToken(ppToken);
1069                 if (token == '(')
1070                     depth++;
1071             }
1072
1073             if (token == EOF) {
1074                 parseContext.error(loc, "EOF in macro", "macro expansion", GetAtomString(atom));
1075                 delete in;
1076                 return 0;
1077             }
1078             parseContext.error(loc, "Too many args in macro", "macro expansion", GetAtomString(atom));
1079         }
1080         for (int i = 0; i < in->mac->argc; i++)
1081             in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay);
1082     }
1083
1084     pushInput(in);
1085     sym->mac.busy = 1;
1086     RewindTokenStream(sym->mac.body);
1087
1088     return 1;
1089 }
1090
1091 } // end namespace glslang