initial import
[vuplus_webkit] / Source / ThirdParty / ANGLE / src / compiler / preprocessor / cpp.c
1 /****************************************************************************\
2 Copyright (c) 2002, NVIDIA Corporation.
3
4 NVIDIA Corporation("NVIDIA") supplies this software to you in
5 consideration of your agreement to the following terms, and your use,
6 installation, modification or redistribution of this NVIDIA software
7 constitutes acceptance of these terms.  If you do not agree with these
8 terms, please do not use, install, modify or redistribute this NVIDIA
9 software.
10
11 In consideration of your agreement to abide by the following terms, and
12 subject to these terms, NVIDIA grants you a personal, non-exclusive
13 license, under NVIDIA's copyrights in this original NVIDIA software (the
14 "NVIDIA Software"), to use, reproduce, modify and redistribute the
15 NVIDIA Software, with or without modifications, in source and/or binary
16 forms; provided that if you redistribute the NVIDIA Software, you must
17 retain the copyright notice of NVIDIA, this notice and the following
18 text and disclaimers in all such redistributions of the NVIDIA Software.
19 Neither the name, trademarks, service marks nor logos of NVIDIA
20 Corporation may be used to endorse or promote products derived from the
21 NVIDIA Software without specific prior written permission from NVIDIA.
22 Except as expressly stated in this notice, no other rights or licenses
23 express or implied, are granted by NVIDIA herein, including but not
24 limited to any patent rights that may be infringed by your derivative
25 works or by other works in which the NVIDIA Software may be
26 incorporated. No hardware is licensed hereunder. 
27
28 THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
29 WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
30 INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
31 NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
32 ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
33 PRODUCTS.
34
35 IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
36 INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
37 TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
38 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
39 OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
40 NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
41 TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
42 NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 \****************************************************************************/
44 //
45 // cpp.c
46 //
47
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <ctype.h>
53
54 #include "compiler/preprocessor/slglobals.h"
55
56 static int CPPif(yystypepp * yylvalpp);
57
58 /* Don't use memory.c's replacements, as we clean up properly here */
59 #undef malloc
60 #undef free
61
62 static int bindAtom = 0;
63 static int constAtom = 0;
64 static int defaultAtom = 0;
65 static int defineAtom = 0;
66 static int definedAtom = 0;
67 static int elseAtom = 0;
68 static int elifAtom = 0;
69 static int endifAtom = 0;
70 static int ifAtom = 0;
71 static int ifdefAtom = 0;
72 static int ifndefAtom = 0;
73 static int includeAtom = 0;
74 static int lineAtom = 0;
75 static int pragmaAtom = 0;
76 static int texunitAtom = 0;
77 static int undefAtom = 0;
78 static int errorAtom = 0;
79 static int __LINE__Atom = 0;
80 static int __FILE__Atom = 0;
81 static int __VERSION__Atom = 0;
82 static int versionAtom = 0;
83 static int extensionAtom = 0;
84
85 static Scope *macros = 0;
86 #define MAX_MACRO_ARGS  64
87
88 static SourceLoc ifloc; /* outermost #if */
89
90 int InitCPP(void)
91 {
92     char        buffer[64], *t;
93     const char  *f;
94
95     // Add various atoms needed by the CPP line scanner:
96     bindAtom = LookUpAddString(atable, "bind");
97     constAtom = LookUpAddString(atable, "const");
98     defaultAtom = LookUpAddString(atable, "default");
99     defineAtom = LookUpAddString(atable, "define");
100     definedAtom = LookUpAddString(atable, "defined");
101     elifAtom = LookUpAddString(atable, "elif");
102     elseAtom = LookUpAddString(atable, "else");
103     endifAtom = LookUpAddString(atable, "endif");
104     ifAtom = LookUpAddString(atable, "if");
105     ifdefAtom = LookUpAddString(atable, "ifdef");
106     ifndefAtom = LookUpAddString(atable, "ifndef");
107     includeAtom = LookUpAddString(atable, "include");
108     lineAtom = LookUpAddString(atable, "line");
109     pragmaAtom = LookUpAddString(atable, "pragma");
110     texunitAtom = LookUpAddString(atable, "texunit");
111     undefAtom = LookUpAddString(atable, "undef");
112         errorAtom = LookUpAddString(atable, "error");
113     __LINE__Atom = LookUpAddString(atable, "__LINE__");
114     __FILE__Atom = LookUpAddString(atable, "__FILE__");
115         __VERSION__Atom = LookUpAddString(atable, "__VERSION__");
116     versionAtom = LookUpAddString(atable, "version");
117     extensionAtom = LookUpAddString(atable, "extension");
118     macros = NewScopeInPool(mem_CreatePool(0, 0));
119     strcpy(buffer, "PROFILE_");
120     t = buffer + strlen(buffer);
121     f = cpp->options.profileString;
122     while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1)
123         *t++ = toupper(*f++);
124     *t = 0;
125
126     PredefineIntMacro("GL_ES", 1);
127     PredefineIntMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
128
129         return 1;
130 } // InitCPP
131
132 int FreeCPP(void)
133 {
134     if (macros)
135     {
136         mem_FreePool(macros->pool);
137         macros = 0;
138     }
139
140     return 1;
141 }
142
143 int FinalCPP(void)
144 {
145         if (cpp->ifdepth)
146                 CPPErrorToInfoLog("#if mismatch");
147     return 1;
148 }
149
150 static int CPPdefine(yystypepp * yylvalpp)
151 {
152     int token, name, args[MAX_MACRO_ARGS], argc;
153     const char *message;
154     MacroSymbol mac;
155     Symbol *symb;
156     SourceLoc dummyLoc;
157     memset(&mac, 0, sizeof(mac));
158     token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
159     if (token != CPP_IDENTIFIER) {
160         CPPErrorToInfoLog("#define");
161         return token;
162     }
163     name = yylvalpp->sc_ident;
164     token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
165     if (token == '(' && !yylvalpp->sc_int) {
166         // gather arguments
167         argc = 0;
168         do {
169             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
170             if (argc == 0 && token == ')') break;
171             if (token != CPP_IDENTIFIER) {
172                                 CPPErrorToInfoLog("#define");
173                 return token;
174             }
175             if (argc < MAX_MACRO_ARGS)
176                 args[argc++] = yylvalpp->sc_ident;
177             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
178         } while (token == ',');
179         if (token != ')') {
180             CPPErrorToInfoLog("#define");
181             return token;
182         }
183         mac.argc = argc;
184         mac.args = mem_Alloc(macros->pool, argc * sizeof(int));
185         memcpy(mac.args, args, argc * sizeof(int));
186         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
187         }
188     mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool);
189     while (token != '\n') {
190         if (token == '\\') {
191             CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
192             return token;
193         } else if (token <= 0) { // EOF or error
194             CPPErrorToInfoLog("unexpected end of input in #define preprocessor directive - expected a newline");
195             return 0;
196         }
197         RecordToken(mac.body, token, yylvalpp);
198         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
199     };
200
201     symb = LookUpSymbol(macros, name);
202     if (symb) {
203         if (!symb->details.mac.undef) {
204             // already defined -- need to make sure they are identical
205             if (symb->details.mac.argc != mac.argc) goto error;
206             for (argc=0; argc < mac.argc; argc++)
207                 if (symb->details.mac.args[argc] != mac.args[argc])
208                     goto error;
209             RewindTokenStream(symb->details.mac.body);
210             RewindTokenStream(mac.body);
211             do {
212                 int old_lval, old_token;
213                 old_token = ReadToken(symb->details.mac.body, yylvalpp);
214                 old_lval = yylvalpp->sc_int;
215                 token = ReadToken(mac.body, yylvalpp);
216                 if (token != old_token || yylvalpp->sc_int != old_lval) { 
217                 error:
218                     StoreStr("Macro Redefined");
219                     StoreStr(GetStringOfAtom(atable,name));
220                     message=GetStrfromTStr();
221                     DecLineNumber();
222                     CPPShInfoLogMsg(message);
223                     IncLineNumber();
224                     ResetTString();
225                     break; }
226             } while (token > 0);
227         }
228         //FreeMacro(&symb->details.mac);
229     } else {
230         dummyLoc.file = 0;
231         dummyLoc.line = 0;
232         symb = AddSymbol(&dummyLoc, macros, name, MACRO_S);
233     }
234     symb->details.mac = mac;
235     return '\n';
236 } // CPPdefine
237
238 static int CPPundef(yystypepp * yylvalpp)
239 {
240     int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
241     Symbol *symb;
242         if(token == '\n'){
243                 CPPErrorToInfoLog("#undef");
244             return token;
245     }
246     if (token != CPP_IDENTIFIER)
247           goto error;
248     symb = LookUpSymbol(macros, yylvalpp->sc_ident);
249     if (symb) {
250         symb->details.mac.undef = 1;
251     }
252     token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
253     if (token != '\n') {
254     error:
255         CPPErrorToInfoLog("#undef");
256     }
257     return token;
258 } // CPPundef
259
260 /* CPPelse -- skip forward to appropriate spot.  This is actually used
261 ** to skip to and #endif after seeing an #else, AND to skip to a #else,
262 ** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false
263 */
264
265 static int CPPelse(int matchelse, yystypepp * yylvalpp)
266 {
267     int atom,depth=0;
268     int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
269         
270         while (token > 0) {
271         if (token != '#') {
272             while (token != '\n') {
273                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
274                 if (token <= 0) { // EOF or error
275                     CPPErrorToInfoLog("unexpected end of input in #else preprocessor directive - expected a newline");
276                     return 0;
277                 }
278             }
279             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
280             continue;
281         }
282                 if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER)
283                         continue;
284         atom = yylvalpp->sc_ident;
285         if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){
286             depth++; cpp->ifdepth++; cpp->elsetracker++;
287             if (cpp->ifdepth > MAX_IF_NESTING) {
288                 CPPErrorToInfoLog("max #if nesting depth exceeded");
289                 cpp->CompileError = 1;
290                 return 0;
291             }
292             // sanity check elsetracker
293             if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
294                 CPPErrorToInfoLog("mismatched #if/#endif statements");
295                 cpp->CompileError = 1;
296                 return 0;
297             }
298             cpp->elsedepth[cpp->elsetracker] = 0;
299         }
300         else if (atom == endifAtom) {
301             if(--depth<0){
302                 if (cpp->elsetracker)
303                     --cpp->elsetracker;
304                 if (cpp->ifdepth) 
305                     --cpp->ifdepth;
306                 break;
307             }             
308             --cpp->elsetracker;
309             --cpp->ifdepth;
310         }
311         else if (((int)(matchelse) != 0)&& depth==0) {
312                         if (atom == elseAtom ) {
313                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
314                 if (token != '\n') {
315                     CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
316                     while (token != '\n') {
317                         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
318                         if (token <= 0) { // EOF or error
319                             CPPErrorToInfoLog("unexpected end of input following #else preprocessor directive - expected a newline");
320                             return 0;
321                         }
322                     }
323                 } 
324                                 break;
325                         } 
326                         else if (atom == elifAtom) {
327                 /* we decrement cpp->ifdepth here, because CPPif will increment
328                  * it and we really want to leave it alone */
329                                 if (cpp->ifdepth){
330                                         --cpp->ifdepth;
331                                     --cpp->elsetracker;
332                                 }
333                 return CPPif(yylvalpp);
334             }
335                 }
336         else if((atom==elseAtom) && (!ChkCorrectElseNesting())){
337             CPPErrorToInfoLog("#else after a #else");
338             cpp->CompileError=1;
339             return 0;
340         }
341         };
342     return token;
343 }
344
345 enum eval_prec {
346     MIN_PREC,
347     COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
348     MAX_PREC
349 };
350
351 static int op_logor(int a, int b) { return a || b; }
352 static int op_logand(int a, int b) { return a && b; }
353 static int op_or(int a, int b) { return a | b; }
354 static int op_xor(int a, int b) { return a ^ b; }
355 static int op_and(int a, int b) { return a & b; }
356 static int op_eq(int a, int b) { return a == b; }
357 static int op_ne(int a, int b) { return a != b; }
358 static int op_ge(int a, int b) { return a >= b; }
359 static int op_le(int a, int b) { return a <= b; }
360 static int op_gt(int a, int b) { return a > b; }
361 static int op_lt(int a, int b) { return a < b; }
362 static int op_shl(int a, int b) { return a << b; }
363 static int op_shr(int a, int b) { return a >> b; }
364 static int op_add(int a, int b) { return a + b; }
365 static int op_sub(int a, int b) { return a - b; }
366 static int op_mul(int a, int b) { return a * b; }
367 static int op_div(int a, int b) { return a / b; }
368 static int op_mod(int a, int b) { return a % b; }
369 static int op_pos(int a) { return a; }
370 static int op_neg(int a) { return -a; }
371 static int op_cmpl(int a) { return ~a; }
372 static int op_not(int a) { return !a; }
373
374 struct {
375     int token, prec, (*op)(int, int);
376 } binop[] = {
377     { CPP_OR_OP, LOGOR, op_logor },
378     { CPP_AND_OP, LOGAND, op_logand },
379     { '|', OR, op_or },
380     { '^', XOR, op_xor },
381     { '&', AND, op_and },
382     { CPP_EQ_OP, EQUAL, op_eq },
383     { CPP_NE_OP, EQUAL, op_ne },
384     { '>', RELATION, op_gt },
385     { CPP_GE_OP, RELATION, op_ge },
386     { '<', RELATION, op_lt },
387     { CPP_LE_OP, RELATION, op_le },
388     { CPP_LEFT_OP, SHIFT, op_shl },
389     { CPP_RIGHT_OP, SHIFT, op_shr },
390     { '+', ADD, op_add },
391     { '-', ADD, op_sub },
392     { '*', MUL, op_mul },
393     { '/', MUL, op_div },
394     { '%', MUL, op_mod },
395 };
396
397 struct {
398     int token, (*op)(int);
399 } unop[] = {
400     { '+', op_pos },
401     { '-', op_neg },
402     { '~', op_cmpl },
403     { '!', op_not },
404 };
405
406 #define ALEN(A) (sizeof(A)/sizeof(A[0]))
407
408 static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp)
409 {
410     int         i, val;
411     Symbol      *s;
412     if (token == CPP_IDENTIFIER) {
413         if (yylvalpp->sc_ident == definedAtom) {
414             int needclose = 0;
415             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
416             if (token == '(') {
417                 needclose = 1;
418                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
419             }
420             if (token != CPP_IDENTIFIER)
421                 goto error;
422             *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident))
423                         ? !s->details.mac.undef : 0;
424             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
425             if (needclose) {
426                 if (token != ')')
427                     goto error;
428                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
429             }
430                 } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) {
431                         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
432             return eval(token, prec, res, err, yylvalpp);
433         } else {
434             goto error;
435         }
436         } else if (token == CPP_INTCONSTANT) {
437         *res = yylvalpp->sc_int;
438         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
439     } else if (token == '(') {
440         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
441         token = eval(token, MIN_PREC, res, err, yylvalpp);
442         if (!*err) {
443             if (token != ')')
444                 goto error;
445             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
446         }
447     } else {
448         for (i = ALEN(unop) - 1; i >= 0; i--) {
449             if (unop[i].token == token)
450                 break;
451         }
452         if (i >= 0) {
453             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
454             token = eval(token, UNARY, res, err, yylvalpp);
455             *res = unop[i].op(*res);
456         } else {
457             goto error;
458         }
459     }
460     while (!*err) {
461         if (token == ')' || token == '\n') break;
462         for (i = ALEN(binop) - 1; i >= 0; i--) {
463             if (binop[i].token == token)
464                 break;
465         }
466         if (i < 0 || binop[i].prec <= prec)
467             break;
468         val = *res;
469         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
470         token = eval(token, binop[i].prec, res, err, yylvalpp);
471         
472         if (binop[i].op == op_div || binop[i].op == op_mod)
473         {
474             if (*res == 0)
475             {
476                 CPPErrorToInfoLog("preprocessor divide or modulo by zero");
477                 *err = 1;
478                 return token;
479             }
480         }
481
482         *res = binop[i].op(val, *res);
483     }
484     return token;
485 error:
486     CPPErrorToInfoLog("incorrect preprocessor directive");
487     *err = 1;
488     *res = 0;
489     return token;
490 } // eval
491
492 static int CPPif(yystypepp * yylvalpp) {
493     int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
494     int res = 0, err = 0;
495
496     if (!cpp->ifdepth++)
497         ifloc = *cpp->tokenLoc;
498     if(cpp->ifdepth > MAX_IF_NESTING){
499         CPPErrorToInfoLog("max #if nesting depth exceeded");
500         cpp->CompileError = 1;
501         return 0;
502     }
503     cpp->elsetracker++;
504     // sanity check elsetracker
505     if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
506         CPPErrorToInfoLog("mismatched #if/#endif statements");
507         cpp->CompileError = 1;
508         return 0;
509     }
510     cpp->elsedepth[cpp->elsetracker] = 0;
511
512     token = eval(token, MIN_PREC, &res, &err, yylvalpp);
513     if (token != '\n') {
514         CPPWarningToInfoLog("unexpected tokens following #if preprocessor directive - expected a newline");
515         while (token != '\n') {
516             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
517             if (token <= 0) { // EOF or error
518                 CPPErrorToInfoLog("unexpected end of input in #if preprocessor directive - expected a newline");
519                 return 0;
520             }
521         }
522     } 
523     if (!res && !err) {
524         token = CPPelse(1, yylvalpp);
525     }
526
527     return token;
528 } // CPPif
529
530 static int CPPifdef(int defined, yystypepp * yylvalpp)
531 {
532     int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
533     int name = yylvalpp->sc_ident;
534     if(++cpp->ifdepth > MAX_IF_NESTING){
535         CPPErrorToInfoLog("max #if nesting depth exceeded");
536         cpp->CompileError = 1;
537         return 0;
538     }
539     cpp->elsetracker++;
540     // sanity check elsetracker
541     if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
542         CPPErrorToInfoLog("mismatched #if/#endif statements");
543         cpp->CompileError = 1;
544         return 0;
545     }
546     cpp->elsedepth[cpp->elsetracker] = 0;
547
548     if (token != CPP_IDENTIFIER) {
549             defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef");
550     } else {
551         Symbol *s = LookUpSymbol(macros, name);
552         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
553         if (token != '\n') {
554             CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline");
555             while (token != '\n') {
556                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
557                 if (token <= 0) { // EOF or error
558                     CPPErrorToInfoLog("unexpected end of input in #ifdef preprocessor directive - expected a newline");
559                     return 0;
560                 }
561             }
562         }
563         if (((s && !s->details.mac.undef) ? 1 : 0) != defined)
564             token = CPPelse(1, yylvalpp);
565     }
566     return token;
567 } // CPPifdef
568
569 static int CPPline(yystypepp * yylvalpp) 
570 {
571     int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
572         if(token=='\n'){
573                 DecLineNumber();
574         CPPErrorToInfoLog("#line");
575         IncLineNumber();
576                 return token;
577         }
578         else if (token == CPP_INTCONSTANT) {
579                 yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
580                 SetLineNumber(yylvalpp->sc_int);
581         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
582         
583                 if (token == CPP_INTCONSTANT) {
584             yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
585                         SetStringNumber(yylvalpp->sc_int);
586             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
587                         if(token!='\n')
588                                 CPPErrorToInfoLog("#line");
589         }
590                 else if (token == '\n'){
591                         return token;
592                 }
593                 else{
594             CPPErrorToInfoLog("#line");
595                 }
596         }
597         else{
598           CPPErrorToInfoLog("#line");
599         }
600     return token;
601 }
602
603 static int CPPerror(yystypepp * yylvalpp) {
604
605         int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
606     const char *message;
607         
608     while (token != '\n') {
609         if (token <= 0){
610             CPPErrorToInfoLog("unexpected end of input in #error preprocessor directive - expected a newline");
611             return 0;
612         }else if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
613             StoreStr(yylvalpp->symbol_name);
614                 }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){
615                         StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
616                 }else {
617                     StoreStr(GetStringOfAtom(atable,token));
618                 }
619                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
620         }
621         DecLineNumber();
622         //store this msg into the shader's information log..set the Compile Error flag!!!!
623         message=GetStrfromTStr();
624     CPPShInfoLogMsg(message);
625     ResetTString();
626     cpp->CompileError=1;
627     IncLineNumber();
628     return '\n';
629 }//CPPerror
630
631 static int CPPpragma(yystypepp * yylvalpp)
632 {
633         char SrcStrName[2];
634         char** allTokens;
635         int tokenCount = 0;
636         int maxTokenCount = 10;
637         const char* SrcStr;
638         int i;
639
640         int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
641         
642         if (token=='\n') {
643                 DecLineNumber();
644         CPPErrorToInfoLog("#pragma");
645         IncLineNumber();
646             return token;
647         }
648         
649         allTokens = (char**)malloc(sizeof(char*) * maxTokenCount);      
650
651         while (token != '\n') {
652                 if (tokenCount >= maxTokenCount) {
653                         maxTokenCount *= 2;
654                         allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount);
655                 }
656                 switch (token) {
657                 case CPP_IDENTIFIER:
658                         SrcStr = GetAtomString(atable, yylvalpp->sc_ident);
659                         allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
660                         strcpy(allTokens[tokenCount++], SrcStr);
661                         break;
662                 case CPP_INTCONSTANT:
663                         SrcStr = yylvalpp->symbol_name;
664                         allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
665                         strcpy(allTokens[tokenCount++], SrcStr);
666                         break;
667                 case CPP_FLOATCONSTANT:
668                         SrcStr = yylvalpp->symbol_name;
669                         allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
670                         strcpy(allTokens[tokenCount++], SrcStr);
671                         break;
672                 case -1:
673             // EOF
674             CPPShInfoLogMsg("#pragma directive must end with a newline");                       
675                         return token;
676                 default:
677                         SrcStrName[0] = token;
678                         SrcStrName[1] = '\0';
679                         allTokens[tokenCount] = (char*)malloc(2);
680                         strcpy(allTokens[tokenCount++], SrcStrName);
681                 }
682                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
683         }
684
685         cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp);
686         HandlePragma((const char**)allTokens, tokenCount);
687         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
688         
689         for (i = 0; i < tokenCount; ++i) {
690                 free (allTokens[i]);
691         }
692         free (allTokens);       
693
694         return token;    
695 } // CPPpragma
696
697 #define ESSL_VERSION_NUMBER 100
698 #define ESSL_VERSION_STRING "100"
699
700 static int CPPversion(yystypepp * yylvalpp)
701 {
702
703     int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
704
705     if (cpp->pastFirstStatement == 1)
706         CPPShInfoLogMsg("#version must occur before any other statement in the program");
707
708     if(token=='\n'){
709                 DecLineNumber();
710         CPPErrorToInfoLog("#version");
711         IncLineNumber();
712                 return token;
713         }
714     if (token != CPP_INTCONSTANT)
715         CPPErrorToInfoLog("#version");
716         
717     yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
718         //SetVersionNumber(yylvalpp->sc_int);
719     
720     if (yylvalpp->sc_int != ESSL_VERSION_NUMBER)
721         CPPShInfoLogMsg("Version number not supported by ESSL");
722
723     token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
724     
725         if (token == '\n'){
726                 return token;
727         }
728         else{
729         CPPErrorToInfoLog("#version");
730         }
731     return token;
732 } // CPPversion
733
734 static int CPPextension(yystypepp * yylvalpp)
735 {
736
737     int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
738     char extensionName[MAX_SYMBOL_NAME_LEN + 1];
739
740     if(token=='\n'){
741                 DecLineNumber();
742         CPPShInfoLogMsg("extension name not specified");
743         IncLineNumber();
744                 return token;
745         }
746
747     if (token != CPP_IDENTIFIER)
748         CPPErrorToInfoLog("#extension");
749     
750     strncpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident), MAX_SYMBOL_NAME_LEN);
751     extensionName[MAX_SYMBOL_NAME_LEN] = '\0';
752             
753     token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
754     if (token != ':') {
755         CPPShInfoLogMsg("':' missing after extension name");
756         return token;
757     }
758     
759     token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
760     if (token != CPP_IDENTIFIER) {
761         CPPShInfoLogMsg("behavior for extension not specified");
762         return token;
763     }
764
765     updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
766
767     token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
768         if (token == '\n'){
769                 return token;
770         }
771         else{
772         CPPErrorToInfoLog("#extension");
773         }
774     return token;
775 } // CPPextension
776
777 int readCPPline(yystypepp * yylvalpp)
778 {
779     int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
780     const char *message;
781     int isVersion = 0;
782
783     if (token == CPP_IDENTIFIER) {
784         if (yylvalpp->sc_ident == defineAtom) {
785              token = CPPdefine(yylvalpp);
786         } else if (yylvalpp->sc_ident == elseAtom) {
787                          if(ChkCorrectElseNesting()){
788                  if (!cpp->ifdepth ){
789                      CPPErrorToInfoLog("#else mismatch");
790                      cpp->CompileError=1;
791                      return 0;
792                  }
793                  token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
794                  if (token != '\n') {
795                      CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
796                      while (token != '\n') {
797                          token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
798                          if (token <= 0) { // EOF or error
799                              CPPErrorToInfoLog("unexpected end of input in #ifdef preprocessor directive - expected a newline");
800                              return 0;
801                          }
802                      }
803                  }
804                              token = CPPelse(0, yylvalpp);
805              }else{
806                  CPPErrorToInfoLog("#else after a #else");
807                  cpp->ifdepth = 0;
808                  cpp->elsetracker = 0;
809                  cpp->pastFirstStatement = 1;
810                  cpp->CompileError = 1;
811                  return 0;
812              }
813                 } else if (yylvalpp->sc_ident == elifAtom) {
814             if (!cpp->ifdepth){
815                  CPPErrorToInfoLog("#elif mismatch");
816                  cpp->CompileError=1;
817                  return 0;
818             } 
819             // this token is really a dont care, but we still need to eat the tokens
820             token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); 
821             while (token != '\n') {
822                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
823                 if (token <= 0) { // EOF or error
824                     CPPErrorToInfoLog("unexpect tokens following #elif preprocessor directive - expected a newline");
825                     cpp->CompileError = 1;
826                     return 0;
827                 }
828             }
829                     token = CPPelse(0, yylvalpp);
830         } else if (yylvalpp->sc_ident == endifAtom) {
831              if (!cpp->ifdepth){
832                  CPPErrorToInfoLog("#endif mismatch");
833                  cpp->CompileError=1;
834                  return 0;
835              }
836              else
837                  --cpp->ifdepth;
838
839              if (cpp->elsetracker)
840                  --cpp->elsetracker;
841
842             } else if (yylvalpp->sc_ident == ifAtom) {
843              token = CPPif(yylvalpp);
844         } else if (yylvalpp->sc_ident == ifdefAtom) {
845              token = CPPifdef(1, yylvalpp);
846         } else if (yylvalpp->sc_ident == ifndefAtom) {
847              token = CPPifdef(0, yylvalpp);
848         } else if (yylvalpp->sc_ident == lineAtom) {
849              token = CPPline(yylvalpp);
850         } else if (yylvalpp->sc_ident == pragmaAtom) {
851              token = CPPpragma(yylvalpp);
852         } else if (yylvalpp->sc_ident == undefAtom) {
853              token = CPPundef(yylvalpp);
854         } else if (yylvalpp->sc_ident == errorAtom) {
855              token = CPPerror(yylvalpp);
856         } else if (yylvalpp->sc_ident == versionAtom) {
857             token = CPPversion(yylvalpp);
858             isVersion = 1;
859         } else if (yylvalpp->sc_ident == extensionAtom) {
860             token = CPPextension(yylvalpp);
861         } else {
862             StoreStr("Invalid Directive");
863             StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
864             message=GetStrfromTStr();
865             CPPShInfoLogMsg(message);
866             ResetTString();
867         }
868     }
869     while (token != '\n' && token != 0 && token != EOF) {
870                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
871         }
872         
873     cpp->pastFirstStatement = 1;
874
875     return token;
876 } // readCPPline
877
878 void FreeMacro(MacroSymbol *s) {
879     DeleteTokenStream(s->body);
880 }
881
882 void PredefineIntMacro(const char *name, int value) {
883     SourceLoc location = {0};
884     Symbol *symbol = NULL;
885     MacroSymbol macro = {0};
886     yystypepp val = {0};
887     int atom = 0;
888
889     macro.body = NewTokenStream(name, macros->pool);
890     val.sc_int = value;
891     sprintf(val.symbol_name, "%d", value);
892     RecordToken(macro.body, CPP_INTCONSTANT, &val);
893     atom = LookUpAddString(atable, name);
894     symbol = AddSymbol(&location, macros, atom, MACRO_S);
895     symbol->details.mac = macro;
896 }
897
898 static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; }
899 static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { }
900
901 static void PushEofSrc() {
902     InputSrc *in = malloc(sizeof(InputSrc));
903     memset(in, 0, sizeof(InputSrc));
904     in->scan = eof_scan;
905     in->getch = eof_scan;
906     in->ungetch = noop;
907     in->prev = cpp->currentInput;
908     cpp->currentInput = in;
909 }
910
911 static void PopEofSrc() {
912     if (cpp->currentInput->scan == eof_scan) {
913         InputSrc *in = cpp->currentInput;
914         cpp->currentInput = in->prev;
915         free(in);
916     }
917 }
918
919 static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) {
920     int token;
921     TokenStream *n;
922     RewindTokenStream(a);
923     do {
924         token = ReadToken(a, yylvalpp);
925         if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident))
926             break;
927     } while (token > 0);
928     if (token <= 0) return a;
929     n = NewTokenStream("macro arg", 0);
930     PushEofSrc();
931     ReadFromTokenStream(a, 0, 0);
932     while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) {
933         if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp))
934             continue;
935         RecordToken(n, token, yylvalpp);
936     }
937     PopEofSrc();
938     DeleteTokenStream(a);
939     return n;
940 } // PrescanMacroArg
941
942 typedef struct MacroInputSrc {
943     InputSrc    base;
944     MacroSymbol *mac;
945     TokenStream **args;
946 } MacroInputSrc;
947
948 /* macro_scan ---
949 ** return the next token for a macro expanion, handling macro args 
950 */
951 static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) {
952     int i;
953     int token = ReadToken(in->mac->body, yylvalpp);
954     if (token == CPP_IDENTIFIER) {
955         for (i = in->mac->argc-1; i>=0; i--)
956             if (in->mac->args[i] == yylvalpp->sc_ident) break;
957         if (i >= 0) {
958             ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0);
959             return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
960         }
961     }
962     if (token > 0) return token;
963     in->mac->busy = 0;
964     cpp->currentInput = in->base.prev;
965     if (in->args) {
966         for (i=in->mac->argc-1; i>=0; i--)
967             DeleteTokenStream(in->args[i]);
968         free(in->args);
969     }
970     free(in);
971     return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
972 } // macro_scan
973
974 /* MacroExpand
975 ** check an identifier (atom) to see if it a macro that should be expanded.
976 ** If it is, push an InputSrc that will produce the appropriate expansion
977 ** and return TRUE.  If not, return FALSE.
978 */
979
980 int MacroExpand(int atom, yystypepp * yylvalpp)
981 {
982     Symbol              *sym = LookUpSymbol(macros, atom);
983     MacroInputSrc       *in;
984     int i,j, token, depth=0;
985     const char *message;
986         if (atom == __LINE__Atom) {
987         yylvalpp->sc_int = GetLineNumber();
988         sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
989         UngetToken(CPP_INTCONSTANT, yylvalpp);
990         return 1;
991     }
992     if (atom == __FILE__Atom) {
993         yylvalpp->sc_int = GetStringNumber();
994         sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
995         UngetToken(CPP_INTCONSTANT, yylvalpp);
996         return 1;
997     }
998         if (atom == __VERSION__Atom) {
999         strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING);
1000         yylvalpp->sc_int = atoi(yylvalpp->symbol_name);
1001         UngetToken(CPP_INTCONSTANT, yylvalpp);
1002         return 1;
1003     }
1004     if (!sym || sym->details.mac.undef) return 0;
1005     if (sym->details.mac.busy) return 0;        // no recursive expansions
1006     in = malloc(sizeof(*in));
1007     memset(in, 0, sizeof(*in));
1008     in->base.scan = (void *)macro_scan;
1009     in->base.line = cpp->currentInput->line;
1010     in->base.name = cpp->currentInput->name;
1011     in->mac = &sym->details.mac;
1012     if (sym->details.mac.args) {
1013         token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
1014                 if (token != '(') {
1015             UngetToken(token, yylvalpp);
1016             yylvalpp->sc_ident = atom;
1017             return 0;
1018         }
1019         in->args = malloc(in->mac->argc * sizeof(TokenStream *));
1020         for (i=0; i<in->mac->argc; i++)
1021             in->args[i] = NewTokenStream("macro arg", 0);
1022                 i=0;j=0;
1023         do{
1024             depth = 0;
1025                         while(1) {
1026                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
1027                 if (token <= 0) {
1028                     StoreStr("EOF in Macro ");
1029                     StoreStr(GetStringOfAtom(atable,atom));
1030                     message=GetStrfromTStr();
1031                     CPPShInfoLogMsg(message);
1032                     ResetTString();
1033                     return 1;
1034                 }
1035                 if((in->mac->argc==0) && (token!=')')) break;
1036                 if (depth == 0 && (token == ',' || token == ')')) break;
1037                 if (token == '(') depth++;
1038                 if (token == ')') depth--;
1039                 RecordToken(in->args[i], token, yylvalpp);
1040                 j=1;
1041                         }
1042             if (token == ')') {
1043                 if((in->mac->argc==1) &&j==0)
1044                     break;
1045                 i++;
1046                 break;
1047             }
1048             i++;
1049                 }while(i < in->mac->argc);
1050
1051         if (i < in->mac->argc) {
1052             StoreStr("Too few args in Macro ");
1053             StoreStr(GetStringOfAtom(atable,atom));
1054             message=GetStrfromTStr();
1055             CPPShInfoLogMsg(message);
1056             ResetTString();
1057         } else if (token != ')') {
1058             depth=0;
1059                         while (token >= 0 && (depth > 0 || token != ')')) {
1060                 if (token == ')') depth--;
1061                 token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
1062                 if (token == '(') depth++;
1063             }
1064                         
1065             if (token <= 0) {
1066                 StoreStr("EOF in Macro ");
1067                 StoreStr(GetStringOfAtom(atable,atom));
1068                 message=GetStrfromTStr();
1069                 CPPShInfoLogMsg(message);
1070                 ResetTString();
1071                 return 1;
1072             }
1073             StoreStr("Too many args in Macro ");
1074             StoreStr(GetStringOfAtom(atable,atom));
1075             message=GetStrfromTStr();
1076             CPPShInfoLogMsg(message);
1077             ResetTString();
1078                 }
1079                 for (i=0; i<in->mac->argc; i++) {
1080             in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
1081         }
1082     }
1083 #if 0
1084     printf("  <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
1085            loc.line, GetAtomString(atable, atom));
1086     for (i=0; i<in->mac->argc; i++) {
1087         printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
1088         DumpTokenStream(stdout, in->args[i]);
1089         printf("'\n");
1090     }
1091 #endif
1092         /*retain the input source*/
1093     in->base.prev = cpp->currentInput;
1094     sym->details.mac.busy = 1;
1095     RewindTokenStream(sym->details.mac.body);
1096     cpp->currentInput = &in->base;
1097     return 1;
1098 } // MacroExpand
1099
1100 int ChkCorrectElseNesting(void)
1101 {
1102     // sanity check to make sure elsetracker is in a valid range
1103     if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
1104         return 0;
1105     }
1106
1107     if (cpp->elsedepth[cpp->elsetracker] == 0) {
1108         cpp->elsedepth[cpp->elsetracker] = 1;
1109         return 1;
1110     }
1111     return 0;
1112 }
1113
1114