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 */
void PredefineIntMacro(const char *name, int value) { SourceLoc location = {0, 0}; Symbol *symbol = NULL; MacroSymbol macro = {0, NULL, NULL, 0, 0}; yystypepp val = {0, 0.0, 0, {0}}; int atom = 0; macro.body = NewTokenStream(name, macros->pool); val.sc_int = value; snprintf(val.symbol_name, MAX_SYMBOL_NAME_LEN+1, "%d", value); RecordToken(macro.body, CPP_INTCONSTANT, &val); atom = LookUpAddString(atable, name); symbol = AddSymbol(&location, macros, atom, MACRO_S); symbol->details.mac = macro; }
TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream *a, TPpToken * yylvalpp) { int token; TokenStream *n; RewindTokenStream(a); do { token = ReadToken(a, yylvalpp); if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->atom)) break; } while (token > 0); if (token <= 0) return a; n = NewTokenStream("macro arg", 0); PushEofSrc(); ReadFromTokenStream(a, 0, 0); while ((token = currentInput->scan(this, currentInput, yylvalpp)) > 0) { if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->atom, yylvalpp, 0) == 1) continue; RecordToken(n, token, yylvalpp); } PopEofSrc(); DeleteTokenStream(a); return n; } // PrescanMacroArg
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(); snprintf(yylvalpp->symbol_name, MAX_SYMBOL_NAME_LEN+1, "%d", yylvalpp->sc_int); UngetToken(CPP_INTCONSTANT, yylvalpp); return 1; } if (atom == __FILE__Atom) { yylvalpp->sc_int = GetStringNumber(); snprintf(yylvalpp->symbol_name, MAX_SYMBOL_NAME_LEN+1, "%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
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; } else if (token <= 0) { // EOF or error CPPErrorToInfoLog("unexpected end of input in #define preprocessor directive - expected a newline"); return 0; } 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
/* MacroExpand ** Check an identifier (atom) to see if it is a macro that should be expanded. ** If it is, push an InputSrc that will produce the appropriate expansion ** and return 1. ** If it is, but undefined, it should expand to 0, push an InputSrc that will ** expand to 0 and return -1. ** Otherwise, return 0. */ int TPpContext::MacroExpand(int atom, TPpToken* yylvalpp, int expandUndef) { Symbol *sym = LookUpSymbol(macros, atom); MacroInputSrc *in; int i, j, token; int depth = 0; if (atom == __LINE__Atom) { yylvalpp->ival = parseContext.currentLoc.line; sprintf(yylvalpp->name, "%d", yylvalpp->ival); UngetToken(CPP_INTCONSTANT, yylvalpp); return 1; } if (atom == __FILE__Atom) { yylvalpp->ival = parseContext.currentLoc.string; sprintf(yylvalpp->name, "%d", yylvalpp->ival); UngetToken(CPP_INTCONSTANT, yylvalpp); return 1; } if (atom == __VERSION__Atom) { yylvalpp->ival = parseContext.version; sprintf(yylvalpp->name, "%d", yylvalpp->ival); UngetToken(CPP_INTCONSTANT, yylvalpp); return 1; } // no recursive expansions if (sym && sym->details.mac.busy) return 0; // not expanding of undefined symbols if ((! sym || sym->details.mac.undef) && ! expandUndef) return 0; in = (MacroInputSrc*)malloc(sizeof(*in)); memset(in, 0, sizeof(*in)); in->base.line = currentInput->line; in->base.name = currentInput->name; if ((! sym || sym->details.mac.undef) && expandUndef) { // push input in->base.scan = zero_scan; in->base.prev = currentInput; currentInput = &in->base; return -1; } in->base.scan = macro_scan; in->mac = &sym->details.mac; if (sym->details.mac.args) { token = currentInput->scan(this, currentInput, yylvalpp); if (token != '(') { UngetToken(token, yylvalpp); yylvalpp->atom = atom; return 0; } in->args = (TokenStream**)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 = currentInput->scan(this, currentInput, yylvalpp); if (token <= 0) { parseContext.error(yylvalpp->loc, "EOF in macro", "preprocessor", GetStringOfAtom(&atomTable, atom)); 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) parseContext.error(yylvalpp->loc, "Too few args in Macro", "preprocessor", GetStringOfAtom(&atomTable, atom)); else if (token != ')') { depth=0; while (token >= 0 && (depth > 0 || token != ')')) { if (token == ')') depth--; token = currentInput->scan(this, currentInput, yylvalpp); if (token == '(') depth++; } if (token <= 0) { parseContext.error(yylvalpp->loc, "EOF in macro", "preprocessor", GetStringOfAtom(&atomTable, atom)); return 1; } parseContext.error(yylvalpp->loc, "Too many args in Macro", "preprocessor", GetStringOfAtom(&atomTable, atom)); } 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 = currentInput; sym->details.mac.busy = 1; RewindTokenStream(sym->details.mac.body); currentInput = &in->base; return 1; } // MacroExpand
int TPpContext::CPPdefine(TPpToken * yylvalpp) { int token, name, args[maxMacroArgs], argc; MacroSymbol mac; Symbol *symb; memset(&mac, 0, sizeof(mac)); token = currentInput->scan(this, currentInput, yylvalpp); if (token != CPP_IDENTIFIER) { parseContext.error(yylvalpp->loc, "must be followed by macro name", "#define", ""); return token; } name = yylvalpp->atom; token = currentInput->scan(this, currentInput, yylvalpp); if (token == '(' && !yylvalpp->ival) { // gather arguments argc = 0; do { token = currentInput->scan(this, currentInput, yylvalpp); if (argc == 0 && token == ')') break; if (token != CPP_IDENTIFIER) { parseContext.error(yylvalpp->loc, "bad argument", "#define", ""); return token; } if (argc < maxMacroArgs) args[argc++] = yylvalpp->atom; token = currentInput->scan(this, currentInput, yylvalpp); } while (token == ','); if (token != ')') { parseContext.error(yylvalpp->loc, "missing parenthesis", "#define", ""); return token; } mac.argc = argc; mac.args = (int*)mem_Alloc(macros->pool, argc * sizeof(int)); memcpy(mac.args, args, argc * sizeof(int)); token = currentInput->scan(this, currentInput, yylvalpp); } mac.body = NewTokenStream(GetAtomString(&atomTable, name), macros->pool); while (token != '\n') { while (token == '\\') { token = currentInput->scan(this, currentInput, yylvalpp); if (token == '\n') token = currentInput->scan(this, currentInput, yylvalpp); else RecordToken(mac.body, '\\', yylvalpp); } RecordToken(mac.body, token, yylvalpp); token = currentInput->scan(this, 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->ival; token = ReadToken(mac.body, yylvalpp); if (token != old_token || yylvalpp->ival != old_lval) { error: parseContext.error(yylvalpp->loc, "Macro Redefined", "#define", GetStringOfAtom(&atomTable, name)); break; } } while (token > 0); } //FreeMacro(&symb->details.mac); } else { symb = AddSymbol(&yylvalpp->loc, macros, name, MACRO_S); } symb->details.mac = mac; return '\n'; } // CPPdefine