123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- //===--- HLSLMacroExpander.cpp - Standalone Macro expansion -----*- C++ -*-===//
- // //
- // HLSLMacroExpander.cpp //
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- // This file is distributed under the University of Illinois Open Source //
- // License. See LICENSE.TXT for details. //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the MacroExpander class.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Lex/HLSLMacroExpander.h"
- #include "clang/Basic/SourceLocation.h"
- #include "clang/Lex/Lexer.h"
- #include "clang/Lex/MacroInfo.h"
- #include "clang/Lex/ModuleMap.h"
- #include "clang/Lex/PPCallbacks.h"
- #include "clang/Lex/Preprocessor.h"
- #include "clang/Lex/PTHLexer.h"
- #include "clang/Lex/PTHManager.h"
- #include "clang/Lex/Token.h"
- #include "clang/Lex/TokenLexer.h"
- #include "llvm/ADT/StringRef.h"
- #include "dxc/Support/Global.h"
- using namespace clang;
- using namespace llvm;
- using namespace hlsl;
- MacroExpander::MacroExpander(Preprocessor &PP_, unsigned options)
- : PP(PP_)
- , m_expansionFileId()
- , m_stripQuotes(false)
- {
- if (options & STRIP_QUOTES)
- m_stripQuotes = true;
- // The preprocess requires a file to be on the lexing stack when we
- // call ExpandMacro. We add an empty in-memory buffer that we use
- // just for expanding macros.
- std::unique_ptr<llvm::MemoryBuffer> SB = llvm::MemoryBuffer::getMemBuffer("", "<hlsl-semantic-defines>");
- if (!SB) {
- DXASSERT(false, "Cannot create macro expansion source buffer");
- throw hlsl::Exception(DXC_E_MACRO_EXPANSION_FAILURE);
- }
- // Unfortunately, there is no api in the SourceManager to lookup a
- // previously added file, so we have to add the empty file every time
- // we expand macros. We could modify source manager to get/set the
- // macro file id similar to the one we have for getPreambleFileID.
- // Macros should only be expanded once (if needed for a root signature)
- // or twice (for semantic defines) so adding an empty file every time
- // is probably not a big deal.
- m_expansionFileId = PP.getSourceManager().createFileID(std::move(SB));
- if (m_expansionFileId.isInvalid()) {
- DXASSERT(false, "Could not create FileID for macro expnasion?");
- throw hlsl::Exception(DXC_E_MACRO_EXPANSION_FAILURE);
- }
- }
- // Simple struct to hold a data/length pair.
- struct LiteralData {
- const char *Data;
- unsigned Length;
- };
- // Get the literal data from a literal token.
- // If stripQuotes flag is true the quotes (and string literal type) will
- // be removed from the data and only the raw string literal value will be
- // returned.
- static LiteralData GetLiteralData(const Token &Tok, bool stripQuotes) {
- if (!tok::isStringLiteral(Tok.getKind()))
- return LiteralData{ Tok.getLiteralData(), Tok.getLength() };
- unsigned start_offset = 0;
- unsigned end_offset = 0;
- switch (Tok.getKind()) {
- case tok::string_literal: start_offset = 1; end_offset = 1; break; // "foo"
- case tok::wide_string_literal: start_offset = 2; end_offset = 1; break; // L"foo"
- case tok::utf8_string_literal: start_offset = 3; end_offset = 1; break; // u8"foo"
- case tok::utf16_string_literal: start_offset = 2; end_offset = 1; break; // u"foo"
- case tok::utf32_string_literal: start_offset = 2; end_offset = 1; break; // U"foo"
- default: break;
- }
- unsigned length = Tok.getLength() - (start_offset + end_offset);
- if (length > Tok.getLength()) { // Check for unsigned underflow.
- DXASSERT(false, "string literal quote count is wrong?");
- start_offset = 0;
- length = Tok.getLength();
- }
- return LiteralData {Tok.getLiteralData() + start_offset, length};
- }
- // Print leading spaces if needed by the token.
- // Take care when stripping string literal quoates that we do not add extra
- // spaces to the output.
- static bool ShouldPrintLeadingSpace(const Token &Tok, const Token &PrevTok, bool stripQuotes) {
- if (!Tok.hasLeadingSpace())
- return false;
- // Token has leading spaces, but the previous token was a sting literal
- // and we are stripping quotes to paste the strings together so do not
- // add a space between the string literal values.
- if (tok::isStringLiteral(PrevTok.getKind()) && stripQuotes)
- return false;
- return true;
- }
- // Macro expansion implementation.
- // We re-lex the macro using the preprocessors lexer.
- bool MacroExpander::ExpandMacro(MacroInfo *pMacro, std::string *out) {
- if (!pMacro || !out)
- return false;
- MacroInfo ¯o = *pMacro;
- // Initialize the token from the macro definition location.
- Token Tok;
- bool failed = PP.getRawToken(macro.getDefinitionLoc(), Tok);
- if (failed)
- return false;
- // Start the lexing process. Use an outer file to make the preprocessor happy.
- PP.EnterSourceFile(m_expansionFileId, nullptr, PP.getSourceManager().getLocForStartOfFile(m_expansionFileId));
- PP.EnterMacro(Tok, macro.getDefinitionEndLoc(), ¯o, nullptr);
- PP.Lex(Tok);
- llvm::raw_string_ostream OS(*out);
- // Keep track of previous token to print spaces correctly.
- Token PrevTok;
- PrevTok.startToken();
- // Lex all the tokens from the macro and add them to the output.
- while (!Tok.is(tok::eof)) {
- if (ShouldPrintLeadingSpace(Tok, PrevTok, m_stripQuotes)) {
- OS << ' ';
- }
- if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
- OS << II->getName();
- }
- else if (Tok.isLiteral() && !Tok.needsCleaning() &&
- Tok.getLiteralData()) {
- LiteralData literalData = GetLiteralData(Tok, m_stripQuotes);
- OS.write(literalData.Data, literalData.Length);
- }
- else {
- std::string S = PP.getSpelling(Tok);
- OS.write(&S[0], S.size());
- }
- PrevTok = Tok;
- PP.Lex(Tok);
- }
- return true;
- }
- // Search for the macro info by the given name.
- MacroInfo *MacroExpander::FindMacroInfo(clang::Preprocessor &PP, StringRef macroName) {
- // Lookup macro identifier.
- IdentifierInfo *ii = PP.getIdentifierInfo(macroName);
- if (!ii)
- return nullptr;
- // Lookup macro info.
- return PP.getMacroInfo(ii);
- }
|