| /****************************************************************************\ |
| Copyright (c) 2002, NVIDIA Corporation. |
| |
| NVIDIA Corporation("NVIDIA") supplies this software to you in |
| consideration of your agreement to the following terms, and your use, |
| installation, modification or redistribution of this NVIDIA software |
| constitutes acceptance of these terms. If you do not agree with these |
| terms, please do not use, install, modify or redistribute this NVIDIA |
| software. |
| |
| In consideration of your agreement to abide by the following terms, and |
| subject to these terms, NVIDIA grants you a personal, non-exclusive |
| license, under NVIDIA's copyrights in this original NVIDIA software (the |
| "NVIDIA Software"), to use, reproduce, modify and redistribute the |
| NVIDIA Software, with or without modifications, in source and/or binary |
| forms; provided that if you redistribute the NVIDIA Software, you must |
| retain the copyright notice of NVIDIA, this notice and the following |
| text and disclaimers in all such redistributions of the NVIDIA Software. |
| Neither the name, trademarks, service marks nor logos of NVIDIA |
| Corporation may be used to endorse or promote products derived from the |
| NVIDIA Software without specific prior written permission from NVIDIA. |
| Except as expressly stated in this notice, no other rights or licenses |
| express or implied, are granted by NVIDIA herein, including but not |
| limited to any patent rights that may be infringed by your derivative |
| works or by other works in which the NVIDIA Software may be |
| incorporated. No hardware is licensed hereunder. |
| |
| THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT |
| WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, |
| NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR |
| ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER |
| PRODUCTS. |
| |
| IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, |
| INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
| TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY |
| OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE |
| NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, |
| TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF |
| NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| \****************************************************************************/ |
| // |
| // cpp.c |
| // |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| |
| #include "compiler/preprocessor/slglobals.h" |
| |
| static int CPPif(yystypepp * yylvalpp); |
| |
| /* Don't use memory.c's replacements, as we clean up properly here */ |
| #undef malloc |
| #undef free |
| |
| static int bindAtom = 0; |
| static int constAtom = 0; |
| static int defaultAtom = 0; |
| static int defineAtom = 0; |
| static int definedAtom = 0; |
| static int elseAtom = 0; |
| static int elifAtom = 0; |
| static int endifAtom = 0; |
| static int ifAtom = 0; |
| static int ifdefAtom = 0; |
| static int ifndefAtom = 0; |
| static int includeAtom = 0; |
| static int lineAtom = 0; |
| static int pragmaAtom = 0; |
| static int texunitAtom = 0; |
| static int undefAtom = 0; |
| static int errorAtom = 0; |
| static int __LINE__Atom = 0; |
| static int __FILE__Atom = 0; |
| static int __VERSION__Atom = 0; |
| static int versionAtom = 0; |
| static int extensionAtom = 0; |
| |
| static Scope *macros = 0; |
| #define MAX_MACRO_ARGS 64 |
| #define MAX_IF_NESTING 64 |
| |
| static SourceLoc ifloc; /* outermost #if */ |
| |
| int InitCPP(void) |
| { |
| char buffer[64], *t; |
| const char *f; |
| |
| // Add various atoms needed by the CPP line scanner: |
| bindAtom = LookUpAddString(atable, "bind"); |
| constAtom = LookUpAddString(atable, "const"); |
| defaultAtom = LookUpAddString(atable, "default"); |
| defineAtom = LookUpAddString(atable, "define"); |
| definedAtom = LookUpAddString(atable, "defined"); |
| elifAtom = LookUpAddString(atable, "elif"); |
| elseAtom = LookUpAddString(atable, "else"); |
| endifAtom = LookUpAddString(atable, "endif"); |
| ifAtom = LookUpAddString(atable, "if"); |
| ifdefAtom = LookUpAddString(atable, "ifdef"); |
| ifndefAtom = LookUpAddString(atable, "ifndef"); |
| includeAtom = LookUpAddString(atable, "include"); |
| lineAtom = LookUpAddString(atable, "line"); |
| pragmaAtom = LookUpAddString(atable, "pragma"); |
| texunitAtom = LookUpAddString(atable, "texunit"); |
| undefAtom = LookUpAddString(atable, "undef"); |
| errorAtom = LookUpAddString(atable, "error"); |
| __LINE__Atom = LookUpAddString(atable, "__LINE__"); |
| __FILE__Atom = LookUpAddString(atable, "__FILE__"); |
| __VERSION__Atom = LookUpAddString(atable, "__VERSION__"); |
| versionAtom = LookUpAddString(atable, "version"); |
| extensionAtom = LookUpAddString(atable, "extension"); |
| macros = NewScopeInPool(mem_CreatePool(0, 0)); |
| strcpy(buffer, "PROFILE_"); |
| t = buffer + strlen(buffer); |
| f = cpp->options.profileString; |
| while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1) |
| *t++ = toupper(*f++); |
| *t = 0; |
| |
| PredefineIntMacro("GL_ES", 1); |
| PredefineIntMacro("GL_FRAGMENT_PRECISION_HIGH", 1); |
| |
| return 1; |
| } // InitCPP |
| |
| int FreeCPP(void) |
| { |
| if (macros) |
| { |
| mem_FreePool(macros->pool); |
| macros = 0; |
| } |
| |
| return 1; |
| } |
| |
| int FinalCPP(void) |
| { |
| if (cpp->ifdepth) |
| CPPErrorToInfoLog("#if mismatch"); |
| return 1; |
| } |
| |
| static int CPPdefine(yystypepp * yylvalpp) |
| { |
| int token, name, args[MAX_MACRO_ARGS], argc; |
| const char *message; |
| MacroSymbol mac; |
| Symbol *symb; |
| SourceLoc dummyLoc; |
| memset(&mac, 0, sizeof(mac)); |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token != CPP_IDENTIFIER) { |
| CPPErrorToInfoLog("#define"); |
| return token; |
| } |
| name = yylvalpp->sc_ident; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token == '(' && !yylvalpp->sc_int) { |
| // gather arguments |
| argc = 0; |
| do { |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (argc == 0 && token == ')') break; |
| if (token != CPP_IDENTIFIER) { |
| CPPErrorToInfoLog("#define"); |
| return token; |
| } |
| if (argc < MAX_MACRO_ARGS) |
| args[argc++] = yylvalpp->sc_ident; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } while (token == ','); |
| if (token != ')') { |
| CPPErrorToInfoLog("#define"); |
| return token; |
| } |
| mac.argc = argc; |
| mac.args = mem_Alloc(macros->pool, argc * sizeof(int)); |
| memcpy(mac.args, args, argc * sizeof(int)); |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool); |
| while (token != '\n') { |
| if (token == '\\') { |
| CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language"); |
| return token; |
| } |
| RecordToken(mac.body, token, yylvalpp); |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| }; |
| |
| symb = LookUpSymbol(macros, name); |
| if (symb) { |
| if (!symb->details.mac.undef) { |
| // already defined -- need to make sure they are identical |
| if (symb->details.mac.argc != mac.argc) goto error; |
| for (argc=0; argc < mac.argc; argc++) |
| if (symb->details.mac.args[argc] != mac.args[argc]) |
| goto error; |
| RewindTokenStream(symb->details.mac.body); |
| RewindTokenStream(mac.body); |
| do { |
| int old_lval, old_token; |
| old_token = ReadToken(symb->details.mac.body, yylvalpp); |
| old_lval = yylvalpp->sc_int; |
| token = ReadToken(mac.body, yylvalpp); |
| if (token != old_token || yylvalpp->sc_int != old_lval) { |
| error: |
| StoreStr("Macro Redefined"); |
| StoreStr(GetStringOfAtom(atable,name)); |
| message=GetStrfromTStr(); |
| DecLineNumber(); |
| CPPShInfoLogMsg(message); |
| IncLineNumber(); |
| ResetTString(); |
| break; } |
| } while (token > 0); |
| } |
| //FreeMacro(&symb->details.mac); |
| } else { |
| dummyLoc.file = 0; |
| dummyLoc.line = 0; |
| symb = AddSymbol(&dummyLoc, macros, name, MACRO_S); |
| } |
| symb->details.mac = mac; |
| return '\n'; |
| } // CPPdefine |
| |
| static int CPPundef(yystypepp * yylvalpp) |
| { |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| Symbol *symb; |
| if(token == '\n'){ |
| CPPErrorToInfoLog("#undef"); |
| return token; |
| } |
| if (token != CPP_IDENTIFIER) |
| goto error; |
| symb = LookUpSymbol(macros, yylvalpp->sc_ident); |
| if (symb) { |
| symb->details.mac.undef = 1; |
| } |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token != '\n') { |
| error: |
| CPPErrorToInfoLog("#undef"); |
| } |
| return token; |
| } // CPPundef |
| |
| /* CPPelse -- skip forward to appropriate spot. This is actually used |
| ** to skip to and #endif after seeing an #else, AND to skip to a #else, |
| ** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false |
| */ |
| |
| static int CPPelse(int matchelse, yystypepp * yylvalpp) |
| { |
| int atom,depth=0; |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| |
| while (token > 0) { |
| if (token != '#') { |
| while (token != '\n') |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| continue; |
| } |
| if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER) |
| continue; |
| atom = yylvalpp->sc_ident; |
| if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){ |
| depth++; cpp->ifdepth++; cpp->elsetracker++; |
| cpp->elsedepth[cpp->elsetracker] = 0; |
| } |
| else if (atom == endifAtom) { |
| if(--depth<0){ |
| --cpp->elsetracker; |
| if (cpp->ifdepth) |
| --cpp->ifdepth; |
| break; |
| } |
| --cpp->elsetracker; |
| --cpp->ifdepth; |
| } |
| else if (((int)(matchelse) != 0)&& depth==0) { |
| if (atom == elseAtom ) { |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token != '\n') { |
| CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline"); |
| while (token != '\n') |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| break; |
| } |
| else if (atom == elifAtom) { |
| /* we decrement cpp->ifdepth here, because CPPif will increment |
| * it and we really want to leave it alone */ |
| if (cpp->ifdepth){ |
| --cpp->ifdepth; |
| --cpp->elsetracker; |
| } |
| return CPPif(yylvalpp); |
| } |
| } |
| else if((atom==elseAtom) && (!ChkCorrectElseNesting())){ |
| CPPErrorToInfoLog("#else after a #else"); |
| cpp->CompileError=1; |
| } |
| }; |
| return token; |
| } |
| |
| enum eval_prec { |
| MIN_PREC, |
| COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY, |
| MAX_PREC |
| }; |
| |
| static int op_logor(int a, int b) { return a || b; } |
| static int op_logand(int a, int b) { return a && b; } |
| static int op_or(int a, int b) { return a | b; } |
| static int op_xor(int a, int b) { return a ^ b; } |
| static int op_and(int a, int b) { return a & b; } |
| static int op_eq(int a, int b) { return a == b; } |
| static int op_ne(int a, int b) { return a != b; } |
| static int op_ge(int a, int b) { return a >= b; } |
| static int op_le(int a, int b) { return a <= b; } |
| static int op_gt(int a, int b) { return a > b; } |
| static int op_lt(int a, int b) { return a < b; } |
| static int op_shl(int a, int b) { return a << b; } |
| static int op_shr(int a, int b) { return a >> b; } |
| static int op_add(int a, int b) { return a + b; } |
| static int op_sub(int a, int b) { return a - b; } |
| static int op_mul(int a, int b) { return a * b; } |
| static int op_div(int a, int b) { return a / b; } |
| static int op_mod(int a, int b) { return a % b; } |
| static int op_pos(int a) { return a; } |
| static int op_neg(int a) { return -a; } |
| static int op_cmpl(int a) { return ~a; } |
| static int op_not(int a) { return !a; } |
| |
| struct { |
| int token, prec, (*op)(int, int); |
| } binop[] = { |
| { CPP_OR_OP, LOGOR, op_logor }, |
| { CPP_AND_OP, LOGAND, op_logand }, |
| { '|', OR, op_or }, |
| { '^', XOR, op_xor }, |
| { '&', AND, op_and }, |
| { CPP_EQ_OP, EQUAL, op_eq }, |
| { CPP_NE_OP, EQUAL, op_ne }, |
| { '>', RELATION, op_gt }, |
| { CPP_GE_OP, RELATION, op_ge }, |
| { '<', RELATION, op_lt }, |
| { CPP_LE_OP, RELATION, op_le }, |
| { CPP_LEFT_OP, SHIFT, op_shl }, |
| { CPP_RIGHT_OP, SHIFT, op_shr }, |
| { '+', ADD, op_add }, |
| { '-', ADD, op_sub }, |
| { '*', MUL, op_mul }, |
| { '/', MUL, op_div }, |
| { '%', MUL, op_mod }, |
| }; |
| |
| struct { |
| int token, (*op)(int); |
| } unop[] = { |
| { '+', op_pos }, |
| { '-', op_neg }, |
| { '~', op_cmpl }, |
| { '!', op_not }, |
| }; |
| |
| #define ALEN(A) (sizeof(A)/sizeof(A[0])) |
| |
| static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp) |
| { |
| int i, val; |
| Symbol *s; |
| if (token == CPP_IDENTIFIER) { |
| if (yylvalpp->sc_ident == definedAtom) { |
| int needclose = 0; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token == '(') { |
| needclose = 1; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| if (token != CPP_IDENTIFIER) |
| goto error; |
| *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident)) |
| ? !s->details.mac.undef : 0; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (needclose) { |
| if (token != ')') |
| goto error; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) { |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| return eval(token, prec, res, err, yylvalpp); |
| } else { |
| goto error; |
| } |
| } else if (token == CPP_INTCONSTANT) { |
| *res = yylvalpp->sc_int; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } else if (token == '(') { |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| token = eval(token, MIN_PREC, res, err, yylvalpp); |
| if (!*err) { |
| if (token != ')') |
| goto error; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| } else { |
| for (i = ALEN(unop) - 1; i >= 0; i--) { |
| if (unop[i].token == token) |
| break; |
| } |
| if (i >= 0) { |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| token = eval(token, UNARY, res, err, yylvalpp); |
| *res = unop[i].op(*res); |
| } else { |
| goto error; |
| } |
| } |
| while (!*err) { |
| if (token == ')' || token == '\n') break; |
| for (i = ALEN(binop) - 1; i >= 0; i--) { |
| if (binop[i].token == token) |
| break; |
| } |
| if (i < 0 || binop[i].prec <= prec) |
| break; |
| val = *res; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| token = eval(token, binop[i].prec, res, err, yylvalpp); |
| *res = binop[i].op(val, *res); |
| } |
| return token; |
| error: |
| CPPErrorToInfoLog("incorrect preprocessor directive"); |
| *err = 1; |
| *res = 0; |
| return token; |
| } // eval |
| |
| static int CPPif(yystypepp * yylvalpp) { |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| int res = 0, err = 0; |
| cpp->elsetracker++; |
| cpp->elsedepth[cpp->elsetracker] = 0; |
| if (!cpp->ifdepth++) |
| ifloc = *cpp->tokenLoc; |
| if(cpp->ifdepth >MAX_IF_NESTING){ |
| CPPErrorToInfoLog("max #if nesting depth exceeded"); |
| return 0; |
| } |
| token = eval(token, MIN_PREC, &res, &err, yylvalpp); |
| if (token != '\n') { |
| CPPWarningToInfoLog("unexpected tokens following the preprocessor directive - expected a newline"); |
| while (token != '\n') |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| if (!res && !err) { |
| token = CPPelse(1, yylvalpp); |
| } |
| |
| return token; |
| } // CPPif |
| |
| static int CPPifdef(int defined, yystypepp * yylvalpp) |
| { |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| int name = yylvalpp->sc_ident; |
| if(++cpp->ifdepth >MAX_IF_NESTING){ |
| CPPErrorToInfoLog("max #if nesting depth exceeded"); |
| return 0; |
| } |
| cpp->elsetracker++; |
| cpp->elsedepth[cpp->elsetracker] = 0; |
| if (token != CPP_IDENTIFIER) { |
| defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef"); |
| } else { |
| Symbol *s = LookUpSymbol(macros, name); |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token != '\n') { |
| CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline"); |
| while (token != '\n') |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| if (((s && !s->details.mac.undef) ? 1 : 0) != defined) |
| token = CPPelse(1, yylvalpp); |
| } |
| return token; |
| } // CPPifdef |
| |
| static int CPPline(yystypepp * yylvalpp) |
| { |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if(token=='\n'){ |
| DecLineNumber(); |
| CPPErrorToInfoLog("#line"); |
| IncLineNumber(); |
| return token; |
| } |
| else if (token == CPP_INTCONSTANT) { |
| yylvalpp->sc_int=atoi(yylvalpp->symbol_name); |
| SetLineNumber(yylvalpp->sc_int); |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| |
| if (token == CPP_INTCONSTANT) { |
| yylvalpp->sc_int=atoi(yylvalpp->symbol_name); |
| SetStringNumber(yylvalpp->sc_int); |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if(token!='\n') |
| CPPErrorToInfoLog("#line"); |
| } |
| else if (token == '\n'){ |
| return token; |
| } |
| else{ |
| CPPErrorToInfoLog("#line"); |
| } |
| } |
| else{ |
| CPPErrorToInfoLog("#line"); |
| } |
| return token; |
| } |
| |
| static int CPPerror(yystypepp * yylvalpp) { |
| |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| const char *message; |
| |
| while (token != '\n') { |
| if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){ |
| StoreStr(yylvalpp->symbol_name); |
| }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){ |
| StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident)); |
| }else { |
| StoreStr(GetStringOfAtom(atable,token)); |
| } |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| DecLineNumber(); |
| //store this msg into the shader's information log..set the Compile Error flag!!!! |
| message=GetStrfromTStr(); |
| CPPShInfoLogMsg(message); |
| ResetTString(); |
| cpp->CompileError=1; |
| IncLineNumber(); |
| return '\n'; |
| }//CPPerror |
| |
| static int CPPpragma(yystypepp * yylvalpp) |
| { |
| char SrcStrName[2]; |
| char** allTokens; |
| int tokenCount = 0; |
| int maxTokenCount = 10; |
| const char* SrcStr; |
| int i; |
| |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| |
| if (token=='\n') { |
| DecLineNumber(); |
| CPPErrorToInfoLog("#pragma"); |
| IncLineNumber(); |
| return token; |
| } |
| |
| allTokens = (char**)malloc(sizeof(char*) * maxTokenCount); |
| |
| while (token != '\n') { |
| if (tokenCount >= maxTokenCount) { |
| maxTokenCount *= 2; |
| allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount); |
| } |
| switch (token) { |
| case CPP_IDENTIFIER: |
| SrcStr = GetAtomString(atable, yylvalpp->sc_ident); |
| allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); |
| strcpy(allTokens[tokenCount++], SrcStr); |
| break; |
| case CPP_INTCONSTANT: |
| SrcStr = yylvalpp->symbol_name; |
| allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); |
| strcpy(allTokens[tokenCount++], SrcStr); |
| break; |
| case CPP_FLOATCONSTANT: |
| SrcStr = yylvalpp->symbol_name; |
| allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); |
| strcpy(allTokens[tokenCount++], SrcStr); |
| break; |
| case -1: |
| // EOF |
| CPPShInfoLogMsg("#pragma directive must end with a newline"); |
| return token; |
| default: |
| SrcStrName[0] = token; |
| SrcStrName[1] = '\0'; |
| allTokens[tokenCount] = (char*)malloc(2); |
| strcpy(allTokens[tokenCount++], SrcStrName); |
| } |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| |
| cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp); |
| HandlePragma((const char**)allTokens, tokenCount); |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| |
| for (i = 0; i < tokenCount; ++i) { |
| free (allTokens[i]); |
| } |
| free (allTokens); |
| |
| return token; |
| } // CPPpragma |
| |
| #define ESSL_VERSION_NUMBER 100 |
| #define ESSL_VERSION_STRING "100" |
| |
| static int CPPversion(yystypepp * yylvalpp) |
| { |
| |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| |
| if (cpp->pastFirstStatement == 1) |
| CPPShInfoLogMsg("#version must occur before any other statement in the program"); |
| |
| if(token=='\n'){ |
| DecLineNumber(); |
| CPPErrorToInfoLog("#version"); |
| IncLineNumber(); |
| return token; |
| } |
| if (token != CPP_INTCONSTANT) |
| CPPErrorToInfoLog("#version"); |
| |
| yylvalpp->sc_int=atoi(yylvalpp->symbol_name); |
| //SetVersionNumber(yylvalpp->sc_int); |
| |
| if (yylvalpp->sc_int != ESSL_VERSION_NUMBER) |
| CPPShInfoLogMsg("Version number not supported by ESSL"); |
| |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| |
| if (token == '\n'){ |
| return token; |
| } |
| else{ |
| CPPErrorToInfoLog("#version"); |
| } |
| return token; |
| } // CPPversion |
| |
| static int CPPextension(yystypepp * yylvalpp) |
| { |
| |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| char extensionName[80]; |
| |
| if(token=='\n'){ |
| DecLineNumber(); |
| CPPShInfoLogMsg("extension name not specified"); |
| IncLineNumber(); |
| return token; |
| } |
| |
| if (token != CPP_IDENTIFIER) |
| CPPErrorToInfoLog("#extension"); |
| |
| strcpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident)); |
| |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token != ':') { |
| CPPShInfoLogMsg("':' missing after extension name"); |
| return token; |
| } |
| |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token != CPP_IDENTIFIER) { |
| CPPShInfoLogMsg("behavior for extension not specified"); |
| return token; |
| } |
| |
| updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident)); |
| |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token == '\n'){ |
| return token; |
| } |
| else{ |
| CPPErrorToInfoLog("#extension"); |
| } |
| return token; |
| } // CPPextension |
| |
| int readCPPline(yystypepp * yylvalpp) |
| { |
| int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| const char *message; |
| int isVersion = 0; |
| |
| if (token == CPP_IDENTIFIER) { |
| if (yylvalpp->sc_ident == defineAtom) { |
| token = CPPdefine(yylvalpp); |
| } else if (yylvalpp->sc_ident == elseAtom) { |
| if(ChkCorrectElseNesting()){ |
| if (!cpp->ifdepth ){ |
| CPPErrorToInfoLog("#else mismatch"); |
| cpp->CompileError=1; |
| } |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token != '\n') { |
| CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline"); |
| while (token != '\n') |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| token = CPPelse(0, yylvalpp); |
| }else{ |
| CPPErrorToInfoLog("#else after a #else"); |
| cpp->ifdepth=0; |
| cpp->pastFirstStatement = 1; |
| return 0; |
| } |
| } else if (yylvalpp->sc_ident == elifAtom) { |
| if (!cpp->ifdepth){ |
| CPPErrorToInfoLog("#elif mismatch"); |
| cpp->CompileError=1; |
| } |
| // this token is really a dont care, but we still need to eat the tokens |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| while (token != '\n') |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| token = CPPelse(0, yylvalpp); |
| } else if (yylvalpp->sc_ident == endifAtom) { |
| --cpp->elsetracker; |
| if (!cpp->ifdepth){ |
| CPPErrorToInfoLog("#endif mismatch"); |
| cpp->CompileError=1; |
| } |
| else |
| --cpp->ifdepth; |
| } else if (yylvalpp->sc_ident == ifAtom) { |
| token = CPPif(yylvalpp); |
| } else if (yylvalpp->sc_ident == ifdefAtom) { |
| token = CPPifdef(1, yylvalpp); |
| } else if (yylvalpp->sc_ident == ifndefAtom) { |
| token = CPPifdef(0, yylvalpp); |
| } else if (yylvalpp->sc_ident == lineAtom) { |
| token = CPPline(yylvalpp); |
| } else if (yylvalpp->sc_ident == pragmaAtom) { |
| token = CPPpragma(yylvalpp); |
| } else if (yylvalpp->sc_ident == undefAtom) { |
| token = CPPundef(yylvalpp); |
| } else if (yylvalpp->sc_ident == errorAtom) { |
| token = CPPerror(yylvalpp); |
| } else if (yylvalpp->sc_ident == versionAtom) { |
| token = CPPversion(yylvalpp); |
| isVersion = 1; |
| } else if (yylvalpp->sc_ident == extensionAtom) { |
| token = CPPextension(yylvalpp); |
| } else { |
| StoreStr("Invalid Directive"); |
| StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident)); |
| message=GetStrfromTStr(); |
| CPPShInfoLogMsg(message); |
| ResetTString(); |
| } |
| } |
| while (token != '\n' && token != 0 && token != EOF) { |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| |
| cpp->pastFirstStatement = 1; |
| |
| return token; |
| } // readCPPline |
| |
| void FreeMacro(MacroSymbol *s) { |
| DeleteTokenStream(s->body); |
| } |
| |
| void PredefineIntMacro(const char *name, int value) { |
| SourceLoc location = {0}; |
| Symbol *symbol = NULL; |
| MacroSymbol macro = {0}; |
| yystypepp val = {0}; |
| int atom = 0; |
| |
| macro.body = NewTokenStream(name, macros->pool); |
| val.sc_int = value; |
| sprintf(val.symbol_name, "%d", value); |
| RecordToken(macro.body, CPP_INTCONSTANT, &val); |
| atom = LookUpAddString(atable, name); |
| symbol = AddSymbol(&location, macros, atom, MACRO_S); |
| symbol->details.mac = macro; |
| } |
| |
| static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; } |
| static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { } |
| |
| static void PushEofSrc() { |
| InputSrc *in = malloc(sizeof(InputSrc)); |
| memset(in, 0, sizeof(InputSrc)); |
| in->scan = eof_scan; |
| in->getch = eof_scan; |
| in->ungetch = noop; |
| in->prev = cpp->currentInput; |
| cpp->currentInput = in; |
| } |
| |
| static void PopEofSrc() { |
| if (cpp->currentInput->scan == eof_scan) { |
| InputSrc *in = cpp->currentInput; |
| cpp->currentInput = in->prev; |
| free(in); |
| } |
| } |
| |
| static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) { |
| int token; |
| TokenStream *n; |
| RewindTokenStream(a); |
| do { |
| token = ReadToken(a, yylvalpp); |
| if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident)) |
| break; |
| } while (token > 0); |
| if (token <= 0) return a; |
| n = NewTokenStream("macro arg", 0); |
| PushEofSrc(); |
| ReadFromTokenStream(a, 0, 0); |
| while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) { |
| if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp)) |
| continue; |
| RecordToken(n, token, yylvalpp); |
| } |
| PopEofSrc(); |
| DeleteTokenStream(a); |
| return n; |
| } // PrescanMacroArg |
| |
| typedef struct MacroInputSrc { |
| InputSrc base; |
| MacroSymbol *mac; |
| TokenStream **args; |
| } MacroInputSrc; |
| |
| /* macro_scan --- |
| ** return the next token for a macro expanion, handling macro args |
| */ |
| static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) { |
| int i; |
| int token = ReadToken(in->mac->body, yylvalpp); |
| if (token == CPP_IDENTIFIER) { |
| for (i = in->mac->argc-1; i>=0; i--) |
| if (in->mac->args[i] == yylvalpp->sc_ident) break; |
| if (i >= 0) { |
| ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0); |
| return cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } |
| } |
| if (token > 0) return token; |
| in->mac->busy = 0; |
| cpp->currentInput = in->base.prev; |
| if (in->args) { |
| for (i=in->mac->argc-1; i>=0; i--) |
| DeleteTokenStream(in->args[i]); |
| free(in->args); |
| } |
| free(in); |
| return cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| } // macro_scan |
| |
| /* MacroExpand |
| ** check an identifier (atom) to see if it a macro that should be expanded. |
| ** If it is, push an InputSrc that will produce the appropriate expansion |
| ** and return TRUE. If not, return FALSE. |
| */ |
| |
| int MacroExpand(int atom, yystypepp * yylvalpp) |
| { |
| Symbol *sym = LookUpSymbol(macros, atom); |
| MacroInputSrc *in; |
| int i,j, token, depth=0; |
| const char *message; |
| if (atom == __LINE__Atom) { |
| yylvalpp->sc_int = GetLineNumber(); |
| sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int); |
| UngetToken(CPP_INTCONSTANT, yylvalpp); |
| return 1; |
| } |
| if (atom == __FILE__Atom) { |
| yylvalpp->sc_int = GetStringNumber(); |
| sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int); |
| UngetToken(CPP_INTCONSTANT, yylvalpp); |
| return 1; |
| } |
| if (atom == __VERSION__Atom) { |
| strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING); |
| yylvalpp->sc_int = atoi(yylvalpp->symbol_name); |
| UngetToken(CPP_INTCONSTANT, yylvalpp); |
| return 1; |
| } |
| if (!sym || sym->details.mac.undef) return 0; |
| if (sym->details.mac.busy) return 0; // no recursive expansions |
| in = malloc(sizeof(*in)); |
| memset(in, 0, sizeof(*in)); |
| in->base.scan = (void *)macro_scan; |
| in->base.line = cpp->currentInput->line; |
| in->base.name = cpp->currentInput->name; |
| in->mac = &sym->details.mac; |
| if (sym->details.mac.args) { |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token != '(') { |
| UngetToken(token, yylvalpp); |
| yylvalpp->sc_ident = atom; |
| return 0; |
| } |
| in->args = malloc(in->mac->argc * sizeof(TokenStream *)); |
| for (i=0; i<in->mac->argc; i++) |
| in->args[i] = NewTokenStream("macro arg", 0); |
| i=0;j=0; |
| do{ |
| depth = 0; |
| while(1) { |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token <= 0) { |
| StoreStr("EOF in Macro "); |
| StoreStr(GetStringOfAtom(atable,atom)); |
| message=GetStrfromTStr(); |
| CPPShInfoLogMsg(message); |
| ResetTString(); |
| return 1; |
| } |
| if((in->mac->argc==0) && (token!=')')) break; |
| if (depth == 0 && (token == ',' || token == ')')) break; |
| if (token == '(') depth++; |
| if (token == ')') depth--; |
| RecordToken(in->args[i], token, yylvalpp); |
| j=1; |
| } |
| if (token == ')') { |
| if((in->mac->argc==1) &&j==0) |
| break; |
| i++; |
| break; |
| } |
| i++; |
| }while(i < in->mac->argc); |
| |
| if (i < in->mac->argc) { |
| StoreStr("Too few args in Macro "); |
| StoreStr(GetStringOfAtom(atable,atom)); |
| message=GetStrfromTStr(); |
| CPPShInfoLogMsg(message); |
| ResetTString(); |
| } else if (token != ')') { |
| depth=0; |
| while (token >= 0 && (depth > 0 || token != ')')) { |
| if (token == ')') depth--; |
| token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); |
| if (token == '(') depth++; |
| } |
| |
| if (token <= 0) { |
| StoreStr("EOF in Macro "); |
| StoreStr(GetStringOfAtom(atable,atom)); |
| message=GetStrfromTStr(); |
| CPPShInfoLogMsg(message); |
| ResetTString(); |
| return 1; |
| } |
| StoreStr("Too many args in Macro "); |
| StoreStr(GetStringOfAtom(atable,atom)); |
| message=GetStrfromTStr(); |
| CPPShInfoLogMsg(message); |
| ResetTString(); |
| } |
| for (i=0; i<in->mac->argc; i++) { |
| in->args[i] = PrescanMacroArg(in->args[i], yylvalpp); |
| } |
| } |
| #if 0 |
| printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file), |
| loc.line, GetAtomString(atable, atom)); |
| for (i=0; i<in->mac->argc; i++) { |
| printf("\targ %s = '", GetAtomString(atable, in->mac->args[i])); |
| DumpTokenStream(stdout, in->args[i]); |
| printf("'\n"); |
| } |
| #endif |
| /*retain the input source*/ |
| in->base.prev = cpp->currentInput; |
| sym->details.mac.busy = 1; |
| RewindTokenStream(sym->details.mac.body); |
| cpp->currentInput = &in->base; |
| return 1; |
| } // MacroExpand |
| |
| int ChkCorrectElseNesting(void) |
| { |
| if(cpp->elsedepth[cpp->elsetracker]==0){ |
| cpp->elsedepth[cpp->elsetracker]=1; |
| return 1; |
| } |
| return 0; |
| } |
| |
| |