PrintPreprocessedOutput.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. //===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file was developed by Chris Lattner and is distributed under
  6. // the University of Illinois Open Source License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This code simply runs the preprocessor on the input file and prints out the
  11. // result. This is the traditional behavior of the -E option.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "clang.h"
  15. #include "clang/Lex/PPCallbacks.h"
  16. #include "clang/Lex/Preprocessor.h"
  17. #include "clang/Lex/Pragma.h"
  18. #include "clang/Basic/SourceManager.h"
  19. #include "llvm/Support/CommandLine.h"
  20. #include "llvm/ADT/StringExtras.h"
  21. #include "llvm/Config/config.h"
  22. #include <cstdio>
  23. using namespace clang;
  24. //===----------------------------------------------------------------------===//
  25. // Simple buffered I/O
  26. //===----------------------------------------------------------------------===//
  27. //
  28. // Empirically, iostream is over 30% slower than stdio for this workload, and
  29. // stdio itself isn't very well suited. The problem with stdio is use of
  30. // putchar_unlocked. We have many newline characters that need to be emitted,
  31. // but stdio needs to do extra checks to handle line buffering mode. These
  32. // extra checks make putchar_unlocked fall off its inlined code path, hitting
  33. // slow system code. In practice, using 'write' directly makes 'clang -E -P'
  34. // about 10% faster than using the stdio path on darwin.
  35. #ifdef HAVE_UNISTD_H
  36. #include <unistd.h>
  37. #else
  38. #define USE_STDIO 1
  39. #endif
  40. static char *OutBufStart = 0, *OutBufEnd, *OutBufCur;
  41. /// InitOutputBuffer - Initialize our output buffer.
  42. ///
  43. static void InitOutputBuffer() {
  44. #ifndef USE_STDIO
  45. OutBufStart = new char[64*1024];
  46. OutBufEnd = OutBufStart+64*1024;
  47. OutBufCur = OutBufStart;
  48. #endif
  49. }
  50. /// FlushBuffer - Write the accumulated bytes to the output stream.
  51. ///
  52. static void FlushBuffer() {
  53. #ifndef USE_STDIO
  54. write(STDOUT_FILENO, OutBufStart, OutBufCur-OutBufStart);
  55. OutBufCur = OutBufStart;
  56. #endif
  57. }
  58. /// CleanupOutputBuffer - Finish up output.
  59. ///
  60. static void CleanupOutputBuffer() {
  61. #ifndef USE_STDIO
  62. FlushBuffer();
  63. delete [] OutBufStart;
  64. #endif
  65. }
  66. static void OutputChar(char c) {
  67. #ifdef USE_STDIO
  68. putchar_unlocked(c);
  69. #else
  70. if (OutBufCur >= OutBufEnd)
  71. FlushBuffer();
  72. *OutBufCur++ = c;
  73. #endif
  74. }
  75. static void OutputString(const char *Ptr, unsigned Size) {
  76. #ifdef USE_STDIO
  77. fwrite(Ptr, Size, 1, stdout);
  78. #else
  79. if (OutBufCur+Size >= OutBufEnd)
  80. FlushBuffer();
  81. memcpy(OutBufCur, Ptr, Size);
  82. OutBufCur += Size;
  83. #endif
  84. }
  85. //===----------------------------------------------------------------------===//
  86. // Preprocessed token printer
  87. //===----------------------------------------------------------------------===//
  88. static llvm::cl::opt<bool>
  89. DisableLineMarkers("P", llvm::cl::desc("Disable linemarker output in -E mode"));
  90. static llvm::cl::opt<bool>
  91. EnableCommentOutput("C", llvm::cl::desc("Enable comment output in -E mode"));
  92. static llvm::cl::opt<bool>
  93. EnableMacroCommentOutput("CC",
  94. llvm::cl::desc("Enable comment output in -E mode, "
  95. "even from macro expansions"));
  96. namespace {
  97. class PrintPPOutputPPCallbacks : public PPCallbacks {
  98. Preprocessor &PP;
  99. unsigned CurLine;
  100. std::string CurFilename;
  101. bool EmittedTokensOnThisLine;
  102. DirectoryLookup::DirType FileType;
  103. public:
  104. PrintPPOutputPPCallbacks(Preprocessor &pp) : PP(pp) {
  105. CurLine = 0;
  106. CurFilename = "\"<uninit>\"";
  107. EmittedTokensOnThisLine = false;
  108. FileType = DirectoryLookup::NormalHeaderDir;
  109. }
  110. void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
  111. virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
  112. DirectoryLookup::DirType FileType);
  113. virtual void Ident(SourceLocation Loc, const std::string &str);
  114. void HandleFirstTokOnLine(LexerToken &Tok);
  115. void MoveToLine(SourceLocation Loc);
  116. bool AvoidConcat(const LexerToken &PrevTok, const LexerToken &Tok);
  117. };
  118. }
  119. /// MoveToLine - Move the output to the source line specified by the location
  120. /// object. We can do this by emitting some number of \n's, or be emitting a
  121. /// #line directive.
  122. void PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
  123. if (DisableLineMarkers) {
  124. if (EmittedTokensOnThisLine) {
  125. OutputChar('\n');
  126. EmittedTokensOnThisLine = false;
  127. }
  128. return;
  129. }
  130. unsigned LineNo = PP.getSourceManager().getLineNumber(Loc);
  131. // If this line is "close enough" to the original line, just print newlines,
  132. // otherwise print a #line directive.
  133. if (LineNo-CurLine < 8) {
  134. unsigned Line = CurLine;
  135. for (; Line != LineNo; ++Line)
  136. OutputChar('\n');
  137. CurLine = Line;
  138. } else {
  139. if (EmittedTokensOnThisLine) {
  140. OutputChar('\n');
  141. EmittedTokensOnThisLine = false;
  142. }
  143. CurLine = LineNo;
  144. OutputChar('#');
  145. OutputChar(' ');
  146. std::string Num = llvm::utostr_32(LineNo);
  147. OutputString(&Num[0], Num.size());
  148. OutputChar(' ');
  149. OutputString(&CurFilename[0], CurFilename.size());
  150. if (FileType == DirectoryLookup::SystemHeaderDir)
  151. OutputString(" 3", 2);
  152. else if (FileType == DirectoryLookup::ExternCSystemHeaderDir)
  153. OutputString(" 3 4", 4);
  154. OutputChar('\n');
  155. }
  156. }
  157. /// FileChanged - Whenever the preprocessor enters or exits a #include file
  158. /// it invokes this handler. Update our conception of the current source
  159. /// position.
  160. void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
  161. FileChangeReason Reason,
  162. DirectoryLookup::DirType FileType) {
  163. if (DisableLineMarkers) return;
  164. // Unless we are exiting a #include, make sure to skip ahead to the line the
  165. // #include directive was at.
  166. SourceManager &SourceMgr = PP.getSourceManager();
  167. if (Reason == PPCallbacks::EnterFile) {
  168. MoveToLine(SourceMgr.getIncludeLoc(Loc.getFileID()));
  169. } else if (Reason == PPCallbacks::SystemHeaderPragma) {
  170. MoveToLine(Loc);
  171. // TODO GCC emits the # directive for this directive on the line AFTER the
  172. // directive and emits a bunch of spaces that aren't needed. Emulate this
  173. // strange behavior.
  174. }
  175. CurLine = SourceMgr.getLineNumber(Loc);
  176. CurFilename = '"' + Lexer::Stringify(SourceMgr.getSourceName(Loc)) + '"';
  177. FileType = FileType;
  178. if (EmittedTokensOnThisLine) {
  179. OutputChar('\n');
  180. EmittedTokensOnThisLine = false;
  181. }
  182. if (DisableLineMarkers) return;
  183. OutputChar('#');
  184. OutputChar(' ');
  185. std::string Num = llvm::utostr_32(CurLine);
  186. OutputString(&Num[0], Num.size());
  187. OutputChar(' ');
  188. OutputString(&CurFilename[0], CurFilename.size());
  189. switch (Reason) {
  190. case PPCallbacks::EnterFile:
  191. OutputString(" 1", 2);
  192. break;
  193. case PPCallbacks::ExitFile:
  194. OutputString(" 2", 2);
  195. break;
  196. case PPCallbacks::SystemHeaderPragma: break;
  197. case PPCallbacks::RenameFile: break;
  198. }
  199. if (FileType == DirectoryLookup::SystemHeaderDir)
  200. OutputString(" 3", 2);
  201. else if (FileType == DirectoryLookup::ExternCSystemHeaderDir)
  202. OutputString(" 3 4", 4);
  203. OutputChar('\n');
  204. }
  205. /// HandleIdent - Handle #ident directives when read by the preprocessor.
  206. ///
  207. void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
  208. MoveToLine(Loc);
  209. OutputString("#ident ", strlen("#ident "));
  210. OutputString(&S[0], S.size());
  211. EmittedTokensOnThisLine = true;
  212. }
  213. /// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
  214. /// is called for the first token on each new line.
  215. void PrintPPOutputPPCallbacks::HandleFirstTokOnLine(LexerToken &Tok) {
  216. // Figure out what line we went to and insert the appropriate number of
  217. // newline characters.
  218. MoveToLine(Tok.getLocation());
  219. // Print out space characters so that the first token on a line is
  220. // indented for easy reading.
  221. unsigned ColNo =
  222. PP.getSourceManager().getColumnNumber(Tok.getLocation());
  223. // This hack prevents stuff like:
  224. // #define HASH #
  225. // HASH define foo bar
  226. // From having the # character end up at column 1, which makes it so it
  227. // is not handled as a #define next time through the preprocessor if in
  228. // -fpreprocessed mode.
  229. if (ColNo <= 1 && Tok.getKind() == tok::hash)
  230. OutputChar(' ');
  231. // Otherwise, indent the appropriate number of spaces.
  232. for (; ColNo > 1; --ColNo)
  233. OutputChar(' ');
  234. }
  235. namespace {
  236. struct UnknownPragmaHandler : public PragmaHandler {
  237. const char *Prefix;
  238. PrintPPOutputPPCallbacks *Callbacks;
  239. UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
  240. : PragmaHandler(0), Prefix(prefix), Callbacks(callbacks) {}
  241. virtual void HandlePragma(Preprocessor &PP, LexerToken &PragmaTok) {
  242. // Figure out what line we went to and insert the appropriate number of
  243. // newline characters.
  244. Callbacks->MoveToLine(PragmaTok.getLocation());
  245. OutputString(Prefix, strlen(Prefix));
  246. // Read and print all of the pragma tokens.
  247. while (PragmaTok.getKind() != tok::eom) {
  248. if (PragmaTok.hasLeadingSpace())
  249. OutputChar(' ');
  250. std::string TokSpell = PP.getSpelling(PragmaTok);
  251. OutputString(&TokSpell[0], TokSpell.size());
  252. PP.LexUnexpandedToken(PragmaTok);
  253. }
  254. OutputChar('\n');
  255. }
  256. };
  257. } // end anonymous namespace
  258. /// AvoidConcat - If printing PrevTok immediately followed by Tok would cause
  259. /// the two individual tokens to be lexed as a single token, return true (which
  260. /// causes a space to be printed between them). This allows the output of -E
  261. /// mode to be lexed to the same token stream as lexing the input directly
  262. /// would.
  263. ///
  264. /// This code must conservatively return true if it doesn't want to be 100%
  265. /// accurate. This will cause the output to include extra space characters, but
  266. /// the resulting output won't have incorrect concatenations going on. Examples
  267. /// include "..", which we print with a space between, because we don't want to
  268. /// track enough to tell "x.." from "...".
  269. bool PrintPPOutputPPCallbacks::AvoidConcat(const LexerToken &PrevTok,
  270. const LexerToken &Tok) {
  271. char Buffer[256];
  272. // If we haven't emitted a token on this line yet, PrevTok isn't useful to
  273. // look at and no concatenation could happen anyway.
  274. if (!EmittedTokensOnThisLine)
  275. return false;
  276. // Basic algorithm: we look at the first character of the second token, and
  277. // determine whether it, if appended to the first token, would form (or would
  278. // contribute) to a larger token if concatenated.
  279. char FirstChar;
  280. if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
  281. // Avoid spelling identifiers, the most common form of token.
  282. FirstChar = II->getName()[0];
  283. } else if (Tok.getLength() < 256) {
  284. const char *TokPtr = Buffer;
  285. PP.getSpelling(Tok, TokPtr);
  286. FirstChar = TokPtr[0];
  287. } else {
  288. FirstChar = PP.getSpelling(Tok)[0];
  289. }
  290. tok::TokenKind PrevKind = PrevTok.getKind();
  291. if (PrevTok.getIdentifierInfo()) // Language keyword or named operator.
  292. PrevKind = tok::identifier;
  293. switch (PrevKind) {
  294. default: return false;
  295. case tok::identifier: // id+id or id+number or id+L"foo".
  296. return isalnum(FirstChar) || FirstChar == '_';
  297. case tok::numeric_constant:
  298. return isalnum(FirstChar) || Tok.getKind() == tok::numeric_constant ||
  299. FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
  300. case tok::period: // ..., .*, .1234
  301. return FirstChar == '.' || FirstChar == '*' || isdigit(FirstChar);
  302. case tok::amp: // &&, &=
  303. return FirstChar == '&' || FirstChar == '=';
  304. case tok::plus: // ++, +=
  305. return FirstChar == '+' || FirstChar == '=';
  306. case tok::minus: // --, ->, -=, ->*
  307. return FirstChar == '-' || FirstChar == '>' || FirstChar == '=';
  308. case tok::slash: // /=, /*, //
  309. return FirstChar == '=' || FirstChar == '*' || FirstChar == '/';
  310. case tok::less: // <<, <<=, <=, <?=, <?, <:, <%
  311. return FirstChar == '<' || FirstChar == '?' || FirstChar == '=' ||
  312. FirstChar == ':' || FirstChar == '%';
  313. case tok::greater: // >>, >=, >>=, >?=, >?, ->*
  314. return FirstChar == '>' || FirstChar == '?' || FirstChar == '=' ||
  315. FirstChar == '*';
  316. case tok::pipe: // ||, |=
  317. return FirstChar == '|' || FirstChar == '=';
  318. case tok::percent: // %=, %>, %:
  319. return FirstChar == '=' || FirstChar == '>' || FirstChar == ':';
  320. case tok::colon: // ::, :>
  321. return FirstChar == ':' || FirstChar == '>';
  322. case tok::hash: // ##, #@, %:%:
  323. return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
  324. case tok::arrow: // ->*
  325. return FirstChar == '*';
  326. case tok::star: // *=
  327. case tok::exclaim: // !=
  328. case tok::lessless: // <<=
  329. case tok::greaterequal: // >>=
  330. case tok::caret: // ^=
  331. case tok::equal: // ==
  332. // Cases that concatenate only if the next char is =.
  333. return FirstChar == '=';
  334. }
  335. }
  336. /// DoPrintPreprocessedInput - This implements -E mode.
  337. ///
  338. void clang::DoPrintPreprocessedInput(unsigned MainFileID, Preprocessor &PP,
  339. const LangOptions &Options) {
  340. // Inform the preprocessor whether we want it to retain comments or not, due
  341. // to -C or -CC.
  342. PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
  343. InitOutputBuffer();
  344. LexerToken Tok, PrevTok;
  345. char Buffer[256];
  346. PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(PP);
  347. PP.setPPCallbacks(Callbacks);
  348. PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
  349. PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",Callbacks));
  350. // After we have configured the preprocessor, enter the main file.
  351. // Start parsing the specified input file.
  352. PP.EnterSourceFile(MainFileID, 0, true);
  353. do {
  354. PrevTok = Tok;
  355. PP.Lex(Tok);
  356. // If this token is at the start of a line, emit newlines if needed.
  357. if (Tok.isAtStartOfLine()) {
  358. Callbacks->HandleFirstTokOnLine(Tok);
  359. } else if (Tok.hasLeadingSpace() ||
  360. // Don't print "-" next to "-", it would form "--".
  361. Callbacks->AvoidConcat(PrevTok, Tok)) {
  362. OutputChar(' ');
  363. }
  364. if (Tok.getLength() < 256) {
  365. const char *TokPtr = Buffer;
  366. unsigned Len = PP.getSpelling(Tok, TokPtr);
  367. OutputString(TokPtr, Len);
  368. } else {
  369. std::string S = PP.getSpelling(Tok);
  370. OutputString(&S[0], S.size());
  371. }
  372. Callbacks->SetEmittedTokensOnThisLine();
  373. } while (Tok.getKind() != tok::eof);
  374. OutputChar('\n');
  375. CleanupOutputBuffer();
  376. }