// Handle #ifdef int TPpContext::CPPifdef(int defined, TPpToken* ppToken) { int token = scanToken(ppToken); if (++ifdepth > maxIfNesting) { parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", ""); return 0; } elsetracker++; if (token != PpAtomIdentifier) { if (defined) parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", ""); else parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", ""); } else { MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name)); token = scanToken(ppToken); if (token != '\n') { parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", ""); while (token != '\n' && token != EndOfInput) token = scanToken(ppToken); } if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined) token = CPPelse(1, ppToken); } return token; }
// Handle #undef int TPpContext::CPPundef(TPpToken* ppToken) { int token = scanToken(ppToken); if (token != PpAtomIdentifier) { parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", ""); return token; } parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef"); MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name)); if (macro != nullptr) macro->undef = 1; token = scanToken(ppToken); if (token != '\n') parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", ""); return token; }
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 (strcmp("defined", ppToken->name) == 0) { if (! parseContext.isReadingHLSL() && isMacroInput()) { if (parseContext.relaxedErrors()) parseContext.ppWarn(ppToken->loc, "nonportable when expanded from macros for preprocessor expression", "defined", ""); else parseContext.ppError(ppToken->loc, "cannot use in preprocessor expression when expanded from macros", "defined", ""); } 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; } MacroSymbol* macro = lookupMacroDef(atomStrings.getAtom(ppToken->name)); res = macro != nullptr ? !macro->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; }
// // Check a token 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(TPpToken* ppToken, bool expandUndef, bool newLineOkay) { ppToken->space = false; int macroAtom = atomStrings.getAtom(ppToken->name); switch (macroAtom) { 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; } MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom); int token; int depth = 0; // no recursive expansions if (macro != nullptr && macro->busy) return 0; // not expanding undefined macros if ((macro == nullptr || macro->undef) && ! expandUndef) return 0; // 0 is the value of an undefined macro if ((macro == nullptr || macro->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 = macro; if (macro->args.size() > 0 || macro->emptyArgs) { token = scanToken(ppToken); if (newLineOkay) { while (token == '\n') token = scanToken(ppToken); } if (token != '(') { parseContext.ppError(loc, "expected '(' following", "macro expansion", atomStrings.getString(macroAtom)); UngetToken(token, ppToken); delete in; return 0; } in->args.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->args[i] = new TokenStream; in->expandedArgs.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = nullptr; size_t arg = 0; bool tokenRecorded = false; do { depth = 0; while (1) { token = scanToken(ppToken); if (token == EndOfInput || token == tMarkerInput::marker) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } if (token == '\n') { if (! newLineOkay) { parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } continue; } if (token == '#') { parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom)); delete in; return 0; } if (in->mac->args.size() == 0 && token != ')') break; if (depth == 0 && (token == ',' || token == ')')) break; if (token == '(') depth++; if (token == ')') depth--; in->args[arg]->putToken(token, ppToken); tokenRecorded = true; } if (token == ')') { if (in->mac->args.size() == 1 && tokenRecorded == 0) break; arg++; break; } arg++; } while (arg < in->mac->args.size()); if (arg < in->mac->args.size()) parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom)); 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", atomStrings.getString(macroAtom)); delete in; return 0; } parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom)); } // We need both expanded and non-expanded forms of the argument, for whether or // not token pasting will be applied later when the argument is consumed next to ##. for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay); } pushInput(in); macro->busy = 1; macro->body.reset(); return 1; }
// // Check a token 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 MacroExpandStarted. // - If it is, but undefined, and expandUndef is requested, push a tInput // that will expand to 0 and return MacroExpandUndef. // - Otherwise, there is no expansion, and there are two cases: // * It might be okay there is no expansion, and no specific error was // detected. Returns MacroExpandNotStarted. // * The expansion was started, but could not be completed, due to an error // that cannot be recovered from. Returns MacroExpandError. // MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOkay) { ppToken->space = false; int macroAtom = atomStrings.getAtom(ppToken->name); switch (macroAtom) { case PpAtomLineMacro: ppToken->ival = parseContext.getCurrentLoc().line; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; 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 MacroExpandStarted; } case PpAtomVersionMacro: ppToken->ival = parseContext.version; snprintf(ppToken->name, sizeof(ppToken->name), "%d", ppToken->ival); UngetToken(PpAtomConstInt, ppToken); return MacroExpandStarted; default: break; } MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom); // no recursive expansions if (macro != nullptr && macro->busy) return MacroExpandNotStarted; // not expanding undefined macros if ((macro == nullptr || macro->undef) && ! expandUndef) return MacroExpandNotStarted; // 0 is the value of an undefined macro if ((macro == nullptr || macro->undef) && expandUndef) { pushInput(new tZeroInput(this)); return MacroExpandUndef; } tMacroInput *in = new tMacroInput(this); TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error in->mac = macro; if (macro->functionLike) { // We don't know yet if this will be a successful call of a // function-like macro; need to look for a '(', but without trashing // the passed in ppToken, until we know we are no longer speculative. TPpToken parenToken; int token = scanToken(&parenToken); if (newLineOkay) { while (token == '\n') token = scanToken(&parenToken); } if (token != '(') { // Function-like macro called with object-like syntax: okay, don't expand. // (We ate exactly one token that might not be white space; put it back. UngetToken(token, &parenToken); delete in; return MacroExpandNotStarted; } in->args.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->args[i] = new TokenStream; in->expandedArgs.resize(in->mac->args.size()); for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = nullptr; size_t arg = 0; bool tokenRecorded = false; do { TVector<char> nestStack; while (true) { token = scanToken(ppToken); if (token == EndOfInput || token == tMarkerInput::marker) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } if (token == '\n') { if (! newLineOkay) { parseContext.ppError(loc, "End of line in macro substitution:", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } continue; } if (token == '#') { parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } if (in->mac->args.size() == 0 && token != ')') break; if (nestStack.size() == 0 && (token == ',' || token == ')')) break; if (token == '(') nestStack.push_back(')'); else if (token == '{' && parseContext.isReadingHLSL()) nestStack.push_back('}'); else if (nestStack.size() > 0 && token == nestStack.back()) nestStack.pop_back(); in->args[arg]->putToken(token, ppToken); tokenRecorded = true; } // end of single argument scan if (token == ')') { // closing paren of call if (in->mac->args.size() == 1 && !tokenRecorded) break; arg++; break; } arg++; } while (arg < in->mac->args.size()); // end of all arguments scan if (arg < in->mac->args.size()) parseContext.ppError(loc, "Too few args in Macro", "macro expansion", atomStrings.getString(macroAtom)); else if (token != ')') { // Error recover code; find end of call, if possible int depth = 0; while (token != EndOfInput && (depth > 0 || token != ')')) { if (token == ')' || token == '}') depth--; token = scanToken(ppToken); if (token == '(' || token == '{') depth++; } if (token == EndOfInput) { parseContext.ppError(loc, "End of input in macro", "macro expansion", atomStrings.getString(macroAtom)); delete in; return MacroExpandError; } parseContext.ppError(loc, "Too many args in macro", "macro expansion", atomStrings.getString(macroAtom)); } // We need both expanded and non-expanded forms of the argument, for whether or // not token pasting will be applied later when the argument is consumed next to ##. for (size_t i = 0; i < in->mac->args.size(); i++) in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay); } pushInput(in); macro->busy = 1; macro->body.reset(); return MacroExpandStarted; }