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