// Handle #include int TPpContext::CPPinclude(TPpToken* ppToken) { const TSourceLoc directiveLoc = ppToken->loc; int token = scanToken(ppToken); if (token != PpAtomConstString) { // TODO: handle angle brackets. parseContext.ppError(directiveLoc, "must be followed by a file designation", "#include", ""); } else { // Make a copy of the name because it will be overwritten by the next token scan. const std::string filename = ppToken->name; token = scanToken(ppToken); if (token != '\n' && token != EndOfInput) { parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", ""); } else { std::string sourceName; std::string replacement; std::tie(sourceName, replacement) = includer.include(filename.c_str()); if (!sourceName.empty()) { if (!replacement.empty()) { const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); std::ostringstream content; content << "#line " << forNextLine << " " << "\"" << sourceName << "\"\n"; content << replacement << (replacement.back() == '\n' ? "" : "\n"); content << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; pushInput(new TokenizableString(directiveLoc, content.str(), this)); } // At EOF, there's no "current" location anymore. if (token != EndOfInput) parseContext.setCurrentColumn(0); // Don't accidentally return EndOfInput, which will end all preprocessing. return '\n'; } else { parseContext.ppError(directiveLoc, replacement.c_str(), "#include", ""); } } } return token; }
// Handle #include int TPpContext::CPPinclude(TPpToken* ppToken) { const TSourceLoc directiveLoc = ppToken->loc; int token = scanToken(ppToken); if (token != PpAtomConstString) { // TODO: handle angle brackets. parseContext.ppError(directiveLoc, "must be followed by a file designation", "#include", ""); } else { // Make a copy of the name because it will be overwritten by the next token scan. const std::string filename = ppToken->name; token = scanToken(ppToken); if (token != '\n' && token != EndOfInput) { parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", ""); } else { TShader::Includer::IncludeResult* res = includer.include(filename.c_str(), TShader::Includer::EIncludeRelative, currentSourceFile.c_str(), includeStack.size() + 1); if (res && !res->file_name.empty()) { if (res->file_data && res->file_length) { const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); std::ostringstream prologue; std::ostringstream epilogue; prologue << "#line " << forNextLine << " " << "\"" << res->file_name << "\"\n"; epilogue << (res->file_data[res->file_length - 1] == '\n'? "" : "\n") << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this)); } // At EOF, there's no "current" location anymore. if (token != EndOfInput) parseContext.setCurrentColumn(0); // Don't accidentally return EndOfInput, which will end all preprocessing. return '\n'; } else { std::string message = res ? std::string(res->file_data, res->file_length) : std::string("Could not process include directive"); parseContext.ppError(directiveLoc, message.c_str(), "#include", ""); if (res) { includer.releaseInclude(res); } } } } return token; }
// Handle #include ... // TODO: Handle macro expansions for the header name int TPpContext::CPPinclude(TPpToken* ppToken) { const TSourceLoc directiveLoc = ppToken->loc; bool startWithLocalSearch = true; // to additionally include the extra "" paths int token = scanToken(ppToken); // handle <header-name>-style #include if (token == '<') { startWithLocalSearch = false; token = scanHeaderName(ppToken, '>'); } // otherwise ppToken already has the header name and it was "header-name" style if (token != PpAtomConstString) { parseContext.ppError(directiveLoc, "must be followed by a header name", "#include", ""); return token; } // Make a copy of the name because it will be overwritten by the next token scan. const std::string filename = ppToken->name; // See if the directive was well formed token = scanToken(ppToken); if (token != '\n') { if (token == EndOfInput) parseContext.ppError(ppToken->loc, "expected newline after header name:", "#include", "%s", filename.c_str()); else parseContext.ppError(ppToken->loc, "extra content after header name:", "#include", "%s", filename.c_str()); return token; } // Process well-formed directive // Find the inclusion, first look in "Local" ("") paths, if requested, // otherwise, only search the "System" (<>) paths. TShader::Includer::IncludeResult* res = nullptr; if (startWithLocalSearch) res = includer.includeLocal(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1); if (res == nullptr || res->headerName.empty()) { includer.releaseInclude(res); res = includer.includeSystem(filename.c_str(), currentSourceFile.c_str(), includeStack.size() + 1); } // Process the results if (res != nullptr && !res->headerName.empty()) { if (res->headerData != nullptr && res->headerLength > 0) { // path for processing one or more tokens from an included header, hand off 'res' const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine(); std::ostringstream prologue; std::ostringstream epilogue; prologue << "#line " << forNextLine << " " << "\"" << res->headerName << "\"\n"; epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") << "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n"; pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this)); // There's no "current" location anymore. parseContext.setCurrentColumn(0); } else { // things are okay, but there is nothing to process includer.releaseInclude(res); } } else { // error path, clean up std::string message = res != nullptr ? std::string(res->headerData, res->headerLength) : std::string("Could not process include directive"); parseContext.ppError(directiveLoc, message.c_str(), "#include", "for header name: %s", filename.c_str()); includer.releaseInclude(res); } return token; }