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
int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken) { TSourceLoc loc = ppToken->loc; // because we sometimes read the newline before reporting the error if (token == PpAtomIdentifier) { if (ppToken->atom == PpAtomDefined) { bool needclose = 0; token = scanToken(ppToken); if (token == '(') { needclose = true; token = scanToken(ppToken); } if (token != PpAtomIdentifier) { parseContext.ppError(loc, "incorrect directive, expected identifier", "preprocessor evaluation", ""); err = true; res = 0; return token; } Symbol* s = LookUpSymbol(ppToken->atom); res = s ? ! s->mac.undef : 0; token = scanToken(ppToken); if (needclose) { if (token != ')') { parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", ""); err = true; res = 0; return token; } token = scanToken(ppToken); } } else { token = evalToToken(token, shortCircuit, res, err, ppToken); return eval(token, precedence, shortCircuit, res, err, ppToken); } } else if (token == PpAtomConstInt) { res = ppToken->ival; token = scanToken(ppToken); } else if (token == '(') { token = scanToken(ppToken); token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken); if (! err) { if (token != ')') { parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", ""); err = true; res = 0; return token; } token = scanToken(ppToken); } } else { int op = NUM_ELEMENTS(unop) - 1; for (; op >= 0; op--) { if (unop[op].token == token) break; } if (op >= 0) { token = scanToken(ppToken); token = eval(token, UNARY, shortCircuit, res, err, ppToken); res = unop[op].op(res); } else { parseContext.ppError(loc, "bad expression", "preprocessor evaluation", ""); err = true; res = 0; return token; } } token = evalToToken(token, shortCircuit, res, err, ppToken); // Perform evaluation of binary operation, if there is one, otherwise we are done. while (! err) { if (token == ')' || token == '\n') break; int op; for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) { if (binop[op].token == token) break; } if (op < 0 || binop[op].precedence <= precedence) break; int leftSide = res; // Setup short-circuiting, needed for ES, unless already in a short circuit. // (Once in a short-circuit, can't turn off again, until that whole subexpression is done. if (! shortCircuit) { if ((token == PpAtomOr && leftSide == 1) || (token == PpAtomAnd && leftSide == 0)) shortCircuit = true; } token = scanToken(ppToken); token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken); if (binop[op].op == op_div || binop[op].op == op_mod) { if (res == 0) { parseContext.ppError(loc, "division by 0", "preprocessor evaluation", ""); res = 1; } } res = binop[op].op(leftSide, res); } return token; }
// Handle #define int TPpContext::CPPdefine(TPpToken* ppToken) { MacroSymbol mac; Symbol *symb; // get macro name int token = scanToken(ppToken); if (token != PpAtomIdentifier) { parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", ""); return token; } if (ppToken->loc.string >= 0) { // We are in user code; check for reserved name use: parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#define"); } // save the original atom const int defAtom = ppToken->atom; // gather parameters to the macro, between (...) token = scanToken(ppToken); if (token == '(' && ! ppToken->space) { int argc = 0; int args[maxMacroArgs]; do { token = scanToken(ppToken); if (argc == 0 && token == ')') break; if (token != PpAtomIdentifier) { parseContext.ppError(ppToken->loc, "bad argument", "#define", ""); return token; } // check for duplication of parameter name bool duplicate = false; for (int a = 0; a < argc; ++a) { if (args[a] == ppToken->atom) { parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", ""); duplicate = true; break; } } if (! duplicate) { if (argc < maxMacroArgs) args[argc++] = ppToken->atom; else parseContext.ppError(ppToken->loc, "too many macro parameters", "#define", ""); } token = scanToken(ppToken); } while (token == ','); if (token != ')') { parseContext.ppError(ppToken->loc, "missing parenthesis", "#define", ""); return token; } mac.argc = argc; mac.args = (int*)mem_Alloc(pool, argc * sizeof(int)); memcpy(mac.args, args, argc * sizeof(int)); token = scanToken(ppToken); } // record the definition of the macro TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors mac.body = new TokenStream; while (token != '\n' && token != EndOfInput) { RecordToken(mac.body, token, ppToken); token = scanToken(ppToken); if (token != '\n' && ppToken->space) RecordToken(mac.body, ' ', ppToken); } // check for duplicate definition symb = LookUpSymbol(defAtom); if (symb) { if (! symb->mac.undef) { // Already defined -- need to make sure they are identical: // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number, // ordering, spelling, and white-space separation, where all white-space separations are considered identical." if (symb->mac.argc != mac.argc) parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(defAtom)); else { for (int argc = 0; argc < mac.argc; argc++) { if (symb->mac.args[argc] != mac.args[argc]) parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(defAtom)); } RewindTokenStream(symb->mac.body); RewindTokenStream(mac.body); int newToken; do { int oldToken; TPpToken oldPpToken; TPpToken newPpToken; oldToken = ReadToken(symb->mac.body, &oldPpToken); newToken = ReadToken(mac.body, &newPpToken); if (oldToken != newToken || oldPpToken != newPpToken) { parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(defAtom)); break; } } while (newToken > 0); } } } else symb = AddSymbol(defAtom); delete symb->mac.body; symb->mac = mac; return '\n'; }
// // Check an identifier (atom) to see if it is a macro that should be expanded. // If it is, and defined, push a tInput that will produce the appropriate expansion // and return 1. // If it is, but undefined, and expandUndef is requested, push a tInput that will // expand to 0 and return -1. // Otherwise, return 0 to indicate no expansion, which is not necessarily an error. // int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay) { ppToken->space = false; switch (atom) { case PpAtomLineMacro: ppToken->ival = parseContext.getCurrentLoc().line; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return 1; case PpAtomFileMacro: { if (parseContext.getCurrentLoc().name) parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__"); ppToken->ival = parseContext.getCurrentLoc().string; snprintf(ppToken->name, sizeof(ppToken->name), "%s", ppToken->loc.getStringNameOrNum().c_str()); UngetToken(PpAtomConstInt, ppToken); return 1; } case PpAtomVersionMacro: ppToken->ival = parseContext.version; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return 1; default: break; } Symbol *sym = LookUpSymbol(atom); int token; int depth = 0; // no recursive expansions if (sym && sym->mac.busy) return 0; // not expanding undefined macros if ((! sym || sym->mac.undef) && ! expandUndef) return 0; // 0 is the value of an undefined macro if ((! sym || sym->mac.undef) && expandUndef) { pushInput(new tZeroInput(this)); return -1; } tMacroInput *in = new tMacroInput(this); TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error in->mac = &sym->mac; if (sym->mac.args) { token = scanToken(ppToken); if (newLineOkay) { while (token == '\n') token = scanToken(ppToken); } if (token != '(') { parseContext.ppError(loc, "expected '(' following", "macro expansion", GetAtomString(atom)); UngetToken(token, ppToken); ppToken->atom = atom; delete in; return 0; } in->args.resize(in->mac->argc); for (int i = 0; i < in->mac->argc; i++) in->args[i] = new TokenStream; int arg = 0; bool tokenRecorded = false; do { depth = 0; while (1) { token = scanToken(ppToken); if (token == EndOfInput) { parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom)); delete in; return 0; } if (token == '\n') { if (! newLineOkay) { parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", GetAtomString(atom)); delete in; return 0; } continue; } if (token == '#') { parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom)); delete in; return 0; } if (in->mac->argc == 0 && token != ')') break; if (depth == 0 && (token == ',' || token == ')')) break; if (token == '(') depth++; if (token == ')') depth--; RecordToken(in->args[arg], token, ppToken); tokenRecorded = true; } if (token == ')') { if (in->mac->argc == 1 && tokenRecorded == 0) break; arg++; break; } arg++; } while (arg < in->mac->argc); if (arg < in->mac->argc) parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom)); else if (token != ')') { depth=0; while (token != EndOfInput && (depth > 0 || token != ')')) { if (token == ')') depth--; token = scanToken(ppToken); if (token == '(') depth++; } if (token == EndOfInput) { parseContext.ppError(loc, "End of input in macro", "macro expansion", GetAtomString(atom)); delete in; return 0; } parseContext.ppError(loc, "Too many args in macro", "macro expansion", GetAtomString(atom)); } for (int i = 0; i < in->mac->argc; i++) in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay); } pushInput(in); sym->mac.busy = 1; RewindTokenStream(sym->mac.body); return 1; }
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
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); if (binop[i].op == op_div || binop[i].op == op_mod) { if (*res == 0) { CPPErrorToInfoLog("preprocessor divide or modulo by zero"); *err = 1; return token; } } *res = binop[i].op(val, *res); } return token; error: CPPErrorToInfoLog("incorrect preprocessor directive"); *err = 1; *res = 0; return token; } // eval