Implement stringification.
llvm-svn: 38709
diff --git a/clang/Lex/MacroExpander.cpp b/clang/Lex/MacroExpander.cpp
index f003f46..35e4f8e 100644
--- a/clang/Lex/MacroExpander.cpp
+++ b/clang/Lex/MacroExpander.cpp
@@ -15,6 +15,7 @@
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Diagnostic.h"
using namespace llvm;
using namespace clang;
@@ -33,16 +34,54 @@
ArgTokens.reserve(NumArgs);
}
-/// StringifyArgument - Implement C99 6.10.3.2p2.
+/// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of
+/// tokens into the literal string token that should be produced by the C #
+/// preprocessor operator.
+///
static LexerToken StringifyArgument(const std::vector<LexerToken> &Toks,
Preprocessor &PP) {
LexerToken Tok;
Tok.StartToken();
Tok.SetKind(tok::string_literal);
+
+ // Stringify all the tokens.
+ std::string Result = "\"";
+ for (unsigned i = 0, e = Toks.size(); i != e; ++i) {
+ const LexerToken &Tok = Toks[i];
+ // FIXME: Optimize this.
+ if (i != 0 && Tok.hasLeadingSpace())
+ Result += ' ';
+
+ // If this is a string or character constant, escape the token as specified
+ // by 6.10.3.2p2.
+ if (Tok.getKind() == tok::string_literal || // "foo" and L"foo".
+ Tok.getKind() == tok::char_constant) { // 'x' and L'x'.
+ Result += Lexer::Stringify(PP.getSpelling(Tok));
+ } else {
+ // Otherwise, just append the token.
+ Result += PP.getSpelling(Tok);
+ }
+ }
- std::string Val = "\"XXYZLAKSDFJAS\"";
- Tok.SetLength(Val.size());
- Tok.SetLocation(PP.CreateString(&Val[0], Val.size()));
+ // If the last character of the string is a \, and if it isn't escaped, this
+ // is an invalid string literal, diagnose it as specified in C99.
+ if (Result[Result.size()-1] == '\\') {
+ // Count the number of consequtive \ characters. If even, then they are
+ // just escaped backslashes, otherwise it's an error.
+ unsigned FirstNonSlash = Result.size()-2;
+ // Guaranteed to find the starting " if nothing else.
+ while (Result[FirstNonSlash] == '\\')
+ --FirstNonSlash;
+ if ((Result.size()-1-FirstNonSlash) & 1) {
+ PP.Diag(Toks.back(), diag::pp_invalid_string_literal);
+ Result.erase(Result.end()-1); // remove one of the \'s.
+ }
+ }
+
+ Result += '"';
+
+ Tok.SetLength(Result.size());
+ Tok.SetLocation(PP.CreateString(&Result[0], Result.size()));
return Tok;
}