1*5188c4b9SDmitri Gribenko #include "clang/AST/CommentLexer.h"
2*5188c4b9SDmitri Gribenko #include "llvm/ADT/StringSwitch.h"
3*5188c4b9SDmitri Gribenko #include "llvm/Support/ErrorHandling.h"
4*5188c4b9SDmitri Gribenko 
5*5188c4b9SDmitri Gribenko namespace clang {
6*5188c4b9SDmitri Gribenko namespace comments {
7*5188c4b9SDmitri Gribenko 
8*5188c4b9SDmitri Gribenko void Token::dump(const Lexer &L, const SourceManager &SM) const {
9*5188c4b9SDmitri Gribenko   llvm::errs() << "comments::Token Kind=" << Kind << " ";
10*5188c4b9SDmitri Gribenko   Loc.dump(SM);
11*5188c4b9SDmitri Gribenko   llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n";
12*5188c4b9SDmitri Gribenko }
13*5188c4b9SDmitri Gribenko 
14*5188c4b9SDmitri Gribenko bool Lexer::isVerbatimBlockCommand(StringRef BeginName,
15*5188c4b9SDmitri Gribenko                                   StringRef &EndName) const {
16*5188c4b9SDmitri Gribenko   const char *Result = llvm::StringSwitch<const char *>(BeginName)
17*5188c4b9SDmitri Gribenko     .Case("code", "endcode")
18*5188c4b9SDmitri Gribenko     .Case("verbatim", "endverbatim")
19*5188c4b9SDmitri Gribenko     .Case("htmlonly", "endhtmlonly")
20*5188c4b9SDmitri Gribenko     .Case("latexonly", "endlatexonly")
21*5188c4b9SDmitri Gribenko     .Case("xmlonly", "endxmlonly")
22*5188c4b9SDmitri Gribenko     .Case("manonly", "endmanonly")
23*5188c4b9SDmitri Gribenko     .Case("rtfonly", "endrtfonly")
24*5188c4b9SDmitri Gribenko 
25*5188c4b9SDmitri Gribenko     .Case("dot", "enddot")
26*5188c4b9SDmitri Gribenko     .Case("msc", "endmsc")
27*5188c4b9SDmitri Gribenko 
28*5188c4b9SDmitri Gribenko     .Case("f$", "f$") // Inline LaTeX formula
29*5188c4b9SDmitri Gribenko     .Case("f[", "f]") // Displayed LaTeX formula
30*5188c4b9SDmitri Gribenko     .Case("f{", "f}") // LaTeX environment
31*5188c4b9SDmitri Gribenko 
32*5188c4b9SDmitri Gribenko     .Default(NULL);
33*5188c4b9SDmitri Gribenko 
34*5188c4b9SDmitri Gribenko   if (Result) {
35*5188c4b9SDmitri Gribenko     EndName = Result;
36*5188c4b9SDmitri Gribenko     return true;
37*5188c4b9SDmitri Gribenko   }
38*5188c4b9SDmitri Gribenko 
39*5188c4b9SDmitri Gribenko   for (VerbatimBlockCommandVector::const_iterator
40*5188c4b9SDmitri Gribenko            I = VerbatimBlockCommands.begin(),
41*5188c4b9SDmitri Gribenko            E = VerbatimBlockCommands.end();
42*5188c4b9SDmitri Gribenko        I != E; ++I)
43*5188c4b9SDmitri Gribenko     if (I->BeginName == BeginName) {
44*5188c4b9SDmitri Gribenko       EndName = I->EndName;
45*5188c4b9SDmitri Gribenko       return true;
46*5188c4b9SDmitri Gribenko     }
47*5188c4b9SDmitri Gribenko 
48*5188c4b9SDmitri Gribenko   return false;
49*5188c4b9SDmitri Gribenko }
50*5188c4b9SDmitri Gribenko 
51*5188c4b9SDmitri Gribenko bool Lexer::isVerbatimLineCommand(StringRef Name) const {
52*5188c4b9SDmitri Gribenko   bool Result = llvm::StringSwitch<bool>(Name)
53*5188c4b9SDmitri Gribenko   .Case("fn", true)
54*5188c4b9SDmitri Gribenko   .Case("var", true)
55*5188c4b9SDmitri Gribenko   .Case("property", true)
56*5188c4b9SDmitri Gribenko   .Case("typedef", true)
57*5188c4b9SDmitri Gribenko 
58*5188c4b9SDmitri Gribenko   .Case("overload", true)
59*5188c4b9SDmitri Gribenko 
60*5188c4b9SDmitri Gribenko   .Case("defgroup", true)
61*5188c4b9SDmitri Gribenko   .Case("ingroup", true)
62*5188c4b9SDmitri Gribenko   .Case("addtogroup", true)
63*5188c4b9SDmitri Gribenko   .Case("weakgroup", true)
64*5188c4b9SDmitri Gribenko   .Case("name", true)
65*5188c4b9SDmitri Gribenko 
66*5188c4b9SDmitri Gribenko   .Case("section", true)
67*5188c4b9SDmitri Gribenko   .Case("subsection", true)
68*5188c4b9SDmitri Gribenko   .Case("subsubsection", true)
69*5188c4b9SDmitri Gribenko   .Case("paragraph", true)
70*5188c4b9SDmitri Gribenko 
71*5188c4b9SDmitri Gribenko   .Case("mainpage", true)
72*5188c4b9SDmitri Gribenko   .Case("subpage", true)
73*5188c4b9SDmitri Gribenko   .Case("ref", true)
74*5188c4b9SDmitri Gribenko 
75*5188c4b9SDmitri Gribenko   .Default(false);
76*5188c4b9SDmitri Gribenko 
77*5188c4b9SDmitri Gribenko   if (Result)
78*5188c4b9SDmitri Gribenko     return true;
79*5188c4b9SDmitri Gribenko 
80*5188c4b9SDmitri Gribenko   for (VerbatimLineCommandVector::const_iterator
81*5188c4b9SDmitri Gribenko            I = VerbatimLineCommands.begin(),
82*5188c4b9SDmitri Gribenko            E = VerbatimLineCommands.end();
83*5188c4b9SDmitri Gribenko        I != E; ++I)
84*5188c4b9SDmitri Gribenko     if (I->Name == Name)
85*5188c4b9SDmitri Gribenko       return true;
86*5188c4b9SDmitri Gribenko 
87*5188c4b9SDmitri Gribenko   return false;
88*5188c4b9SDmitri Gribenko }
89*5188c4b9SDmitri Gribenko 
90*5188c4b9SDmitri Gribenko void Lexer::skipLineStartingDecorations() {
91*5188c4b9SDmitri Gribenko   // This function should be called only for C comments
92*5188c4b9SDmitri Gribenko   assert(CommentState == LCS_InsideCComment);
93*5188c4b9SDmitri Gribenko 
94*5188c4b9SDmitri Gribenko   if (BufferPtr == CommentEnd)
95*5188c4b9SDmitri Gribenko     return;
96*5188c4b9SDmitri Gribenko 
97*5188c4b9SDmitri Gribenko   switch (*BufferPtr) {
98*5188c4b9SDmitri Gribenko   case ' ':
99*5188c4b9SDmitri Gribenko   case '\t':
100*5188c4b9SDmitri Gribenko   case '\f':
101*5188c4b9SDmitri Gribenko   case '\v': {
102*5188c4b9SDmitri Gribenko     const char *NewBufferPtr = BufferPtr;
103*5188c4b9SDmitri Gribenko     NewBufferPtr++;
104*5188c4b9SDmitri Gribenko     if (NewBufferPtr == CommentEnd)
105*5188c4b9SDmitri Gribenko       return;
106*5188c4b9SDmitri Gribenko 
107*5188c4b9SDmitri Gribenko     char C = *NewBufferPtr;
108*5188c4b9SDmitri Gribenko     while (C == ' ' || C == '\t' || C == '\f' || C == '\v') {
109*5188c4b9SDmitri Gribenko       NewBufferPtr++;
110*5188c4b9SDmitri Gribenko       if (NewBufferPtr == CommentEnd)
111*5188c4b9SDmitri Gribenko         return;
112*5188c4b9SDmitri Gribenko       C = *NewBufferPtr;
113*5188c4b9SDmitri Gribenko     }
114*5188c4b9SDmitri Gribenko     if (C == '*')
115*5188c4b9SDmitri Gribenko       BufferPtr = NewBufferPtr + 1;
116*5188c4b9SDmitri Gribenko     break;
117*5188c4b9SDmitri Gribenko   }
118*5188c4b9SDmitri Gribenko   case '*':
119*5188c4b9SDmitri Gribenko     BufferPtr++;
120*5188c4b9SDmitri Gribenko     break;
121*5188c4b9SDmitri Gribenko   }
122*5188c4b9SDmitri Gribenko }
123*5188c4b9SDmitri Gribenko 
124*5188c4b9SDmitri Gribenko namespace {
125*5188c4b9SDmitri Gribenko const char *findNewline(const char *BufferPtr, const char *BufferEnd) {
126*5188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
127*5188c4b9SDmitri Gribenko     const char C = *BufferPtr;
128*5188c4b9SDmitri Gribenko     if (C == '\n' || C == '\r')
129*5188c4b9SDmitri Gribenko       return BufferPtr;
130*5188c4b9SDmitri Gribenko   }
131*5188c4b9SDmitri Gribenko   return BufferEnd;
132*5188c4b9SDmitri Gribenko }
133*5188c4b9SDmitri Gribenko 
134*5188c4b9SDmitri Gribenko const char *skipNewline(const char *BufferPtr, const char *BufferEnd) {
135*5188c4b9SDmitri Gribenko   if (BufferPtr == BufferEnd)
136*5188c4b9SDmitri Gribenko     return BufferPtr;
137*5188c4b9SDmitri Gribenko 
138*5188c4b9SDmitri Gribenko   if (*BufferPtr == '\n')
139*5188c4b9SDmitri Gribenko     BufferPtr++;
140*5188c4b9SDmitri Gribenko   else {
141*5188c4b9SDmitri Gribenko     assert(*BufferPtr == '\r');
142*5188c4b9SDmitri Gribenko     BufferPtr++;
143*5188c4b9SDmitri Gribenko     if (BufferPtr != BufferEnd && *BufferPtr == '\n')
144*5188c4b9SDmitri Gribenko       BufferPtr++;
145*5188c4b9SDmitri Gribenko   }
146*5188c4b9SDmitri Gribenko   return BufferPtr;
147*5188c4b9SDmitri Gribenko }
148*5188c4b9SDmitri Gribenko 
149*5188c4b9SDmitri Gribenko bool isHTMLIdentifierCharacter(char C) {
150*5188c4b9SDmitri Gribenko   return (C >= 'a' && C <= 'z') ||
151*5188c4b9SDmitri Gribenko          (C >= 'A' && C <= 'Z') ||
152*5188c4b9SDmitri Gribenko          (C >= '0' && C <= '9');
153*5188c4b9SDmitri Gribenko }
154*5188c4b9SDmitri Gribenko 
155*5188c4b9SDmitri Gribenko const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) {
156*5188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
157*5188c4b9SDmitri Gribenko     if (!isHTMLIdentifierCharacter(*BufferPtr))
158*5188c4b9SDmitri Gribenko       return BufferPtr;
159*5188c4b9SDmitri Gribenko   }
160*5188c4b9SDmitri Gribenko   return BufferEnd;
161*5188c4b9SDmitri Gribenko }
162*5188c4b9SDmitri Gribenko 
163*5188c4b9SDmitri Gribenko /// Skip HTML string quoted in single or double quotes.  Escaping quotes inside
164*5188c4b9SDmitri Gribenko /// string allowed.
165*5188c4b9SDmitri Gribenko ///
166*5188c4b9SDmitri Gribenko /// Returns pointer to closing quote.
167*5188c4b9SDmitri Gribenko const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd)
168*5188c4b9SDmitri Gribenko {
169*5188c4b9SDmitri Gribenko   const char Quote = *BufferPtr;
170*5188c4b9SDmitri Gribenko   assert(Quote == '\"' || Quote == '\'');
171*5188c4b9SDmitri Gribenko 
172*5188c4b9SDmitri Gribenko   BufferPtr++;
173*5188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
174*5188c4b9SDmitri Gribenko     const char C = *BufferPtr;
175*5188c4b9SDmitri Gribenko     if (C == Quote && BufferPtr[-1] != '\\')
176*5188c4b9SDmitri Gribenko       return BufferPtr;
177*5188c4b9SDmitri Gribenko   }
178*5188c4b9SDmitri Gribenko   return BufferEnd;
179*5188c4b9SDmitri Gribenko }
180*5188c4b9SDmitri Gribenko 
181*5188c4b9SDmitri Gribenko bool isHorizontalWhitespace(char C) {
182*5188c4b9SDmitri Gribenko   return C == ' ' || C == '\t' || C == '\f' || C == '\v';
183*5188c4b9SDmitri Gribenko }
184*5188c4b9SDmitri Gribenko 
185*5188c4b9SDmitri Gribenko bool isWhitespace(char C) {
186*5188c4b9SDmitri Gribenko   return C == ' ' || C == '\n' || C == '\r' ||
187*5188c4b9SDmitri Gribenko          C == '\t' || C == '\f' || C == '\v';
188*5188c4b9SDmitri Gribenko }
189*5188c4b9SDmitri Gribenko 
190*5188c4b9SDmitri Gribenko const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) {
191*5188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
192*5188c4b9SDmitri Gribenko     if (!isWhitespace(*BufferPtr))
193*5188c4b9SDmitri Gribenko       return BufferPtr;
194*5188c4b9SDmitri Gribenko   }
195*5188c4b9SDmitri Gribenko   return BufferEnd;
196*5188c4b9SDmitri Gribenko }
197*5188c4b9SDmitri Gribenko 
198*5188c4b9SDmitri Gribenko bool isCommandNameCharacter(char C) {
199*5188c4b9SDmitri Gribenko   return (C >= 'a' && C <= 'z') ||
200*5188c4b9SDmitri Gribenko          (C >= 'A' && C <= 'Z') ||
201*5188c4b9SDmitri Gribenko          (C >= '0' && C <= '9');
202*5188c4b9SDmitri Gribenko }
203*5188c4b9SDmitri Gribenko 
204*5188c4b9SDmitri Gribenko const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
205*5188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
206*5188c4b9SDmitri Gribenko     if (!isCommandNameCharacter(*BufferPtr))
207*5188c4b9SDmitri Gribenko       return BufferPtr;
208*5188c4b9SDmitri Gribenko   }
209*5188c4b9SDmitri Gribenko   return BufferEnd;
210*5188c4b9SDmitri Gribenko }
211*5188c4b9SDmitri Gribenko 
212*5188c4b9SDmitri Gribenko /// Return the one past end pointer for BCPL comments.
213*5188c4b9SDmitri Gribenko /// Handles newlines escaped with backslash or trigraph for backslahs.
214*5188c4b9SDmitri Gribenko const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) {
215*5188c4b9SDmitri Gribenko   const char *CurPtr = BufferPtr;
216*5188c4b9SDmitri Gribenko   while (CurPtr != BufferEnd) {
217*5188c4b9SDmitri Gribenko     char C = *CurPtr;
218*5188c4b9SDmitri Gribenko     while (C != '\n' && C != '\r') {
219*5188c4b9SDmitri Gribenko       CurPtr++;
220*5188c4b9SDmitri Gribenko       if (CurPtr == BufferEnd)
221*5188c4b9SDmitri Gribenko         return BufferEnd;
222*5188c4b9SDmitri Gribenko       C = *CurPtr;
223*5188c4b9SDmitri Gribenko     }
224*5188c4b9SDmitri Gribenko     // We found a newline, check if it is escaped.
225*5188c4b9SDmitri Gribenko     const char *EscapePtr = CurPtr - 1;
226*5188c4b9SDmitri Gribenko     while(isHorizontalWhitespace(*EscapePtr))
227*5188c4b9SDmitri Gribenko       EscapePtr--;
228*5188c4b9SDmitri Gribenko 
229*5188c4b9SDmitri Gribenko     if (*EscapePtr == '\\' ||
230*5188c4b9SDmitri Gribenko         (EscapePtr - 2 >= BufferPtr && EscapePtr[0] == '/' &&
231*5188c4b9SDmitri Gribenko          EscapePtr[-1] == '?' && EscapePtr[-2] == '?')) {
232*5188c4b9SDmitri Gribenko       // We found an escaped newline.
233*5188c4b9SDmitri Gribenko       CurPtr = skipNewline(CurPtr, BufferEnd);
234*5188c4b9SDmitri Gribenko     } else
235*5188c4b9SDmitri Gribenko       return CurPtr; // Not an escaped newline.
236*5188c4b9SDmitri Gribenko   }
237*5188c4b9SDmitri Gribenko   return BufferEnd;
238*5188c4b9SDmitri Gribenko }
239*5188c4b9SDmitri Gribenko 
240*5188c4b9SDmitri Gribenko /// Return the one past end pointer for C comments.
241*5188c4b9SDmitri Gribenko /// Very dumb, does not handle escaped newlines or trigraphs.
242*5188c4b9SDmitri Gribenko const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) {
243*5188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
244*5188c4b9SDmitri Gribenko     if (*BufferPtr == '*') {
245*5188c4b9SDmitri Gribenko       assert(BufferPtr + 1 != BufferEnd);
246*5188c4b9SDmitri Gribenko       if (*(BufferPtr + 1) == '/')
247*5188c4b9SDmitri Gribenko         return BufferPtr;
248*5188c4b9SDmitri Gribenko     }
249*5188c4b9SDmitri Gribenko   }
250*5188c4b9SDmitri Gribenko   llvm_unreachable("buffer end hit before '*/' was seen");
251*5188c4b9SDmitri Gribenko }
252*5188c4b9SDmitri Gribenko } // unnamed namespace
253*5188c4b9SDmitri Gribenko 
254*5188c4b9SDmitri Gribenko void Lexer::lexCommentText(Token &T) {
255*5188c4b9SDmitri Gribenko   assert(CommentState == LCS_InsideBCPLComment ||
256*5188c4b9SDmitri Gribenko          CommentState == LCS_InsideCComment);
257*5188c4b9SDmitri Gribenko 
258*5188c4b9SDmitri Gribenko   switch (State) {
259*5188c4b9SDmitri Gribenko   case LS_Normal:
260*5188c4b9SDmitri Gribenko     break;
261*5188c4b9SDmitri Gribenko   case LS_VerbatimBlockFirstLine:
262*5188c4b9SDmitri Gribenko     lexVerbatimBlockFirstLine(T);
263*5188c4b9SDmitri Gribenko     return;
264*5188c4b9SDmitri Gribenko   case LS_VerbatimBlockBody:
265*5188c4b9SDmitri Gribenko     lexVerbatimBlockBody(T);
266*5188c4b9SDmitri Gribenko     return;
267*5188c4b9SDmitri Gribenko   case LS_HTMLOpenTag:
268*5188c4b9SDmitri Gribenko     lexHTMLOpenTag(T);
269*5188c4b9SDmitri Gribenko     return;
270*5188c4b9SDmitri Gribenko   }
271*5188c4b9SDmitri Gribenko 
272*5188c4b9SDmitri Gribenko   assert(State == LS_Normal);
273*5188c4b9SDmitri Gribenko 
274*5188c4b9SDmitri Gribenko   const char *TokenPtr = BufferPtr;
275*5188c4b9SDmitri Gribenko   assert(TokenPtr < CommentEnd);
276*5188c4b9SDmitri Gribenko   while (TokenPtr != CommentEnd) {
277*5188c4b9SDmitri Gribenko     switch(*TokenPtr) {
278*5188c4b9SDmitri Gribenko       case '\\':
279*5188c4b9SDmitri Gribenko       case '@': {
280*5188c4b9SDmitri Gribenko         TokenPtr++;
281*5188c4b9SDmitri Gribenko         if (TokenPtr == CommentEnd) {
282*5188c4b9SDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
283*5188c4b9SDmitri Gribenko           T.setText(StringRef(BufferPtr - T.getLength(), T.getLength()));
284*5188c4b9SDmitri Gribenko           return;
285*5188c4b9SDmitri Gribenko         }
286*5188c4b9SDmitri Gribenko         char C = *TokenPtr;
287*5188c4b9SDmitri Gribenko         switch (C) {
288*5188c4b9SDmitri Gribenko         default:
289*5188c4b9SDmitri Gribenko           break;
290*5188c4b9SDmitri Gribenko 
291*5188c4b9SDmitri Gribenko         case '\\': case '@': case '&': case '$':
292*5188c4b9SDmitri Gribenko         case '#':  case '<': case '>': case '%':
293*5188c4b9SDmitri Gribenko         case '\"': case '.': case ':':
294*5188c4b9SDmitri Gribenko           // This is one of \\ \@ \& \$ etc escape sequences.
295*5188c4b9SDmitri Gribenko           TokenPtr++;
296*5188c4b9SDmitri Gribenko           if (C == ':' && TokenPtr != CommentEnd && *TokenPtr == ':') {
297*5188c4b9SDmitri Gribenko             // This is the \:: escape sequence.
298*5188c4b9SDmitri Gribenko             TokenPtr++;
299*5188c4b9SDmitri Gribenko           }
300*5188c4b9SDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
301*5188c4b9SDmitri Gribenko           T.setText(StringRef(BufferPtr - (T.getLength() - 1),
302*5188c4b9SDmitri Gribenko                               T.getLength() - 1));
303*5188c4b9SDmitri Gribenko           return;
304*5188c4b9SDmitri Gribenko         }
305*5188c4b9SDmitri Gribenko 
306*5188c4b9SDmitri Gribenko         // Don't make zero-length commands.
307*5188c4b9SDmitri Gribenko         if (!isCommandNameCharacter(*TokenPtr)) {
308*5188c4b9SDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
309*5188c4b9SDmitri Gribenko           T.setText(StringRef(BufferPtr - T.getLength(), T.getLength()));
310*5188c4b9SDmitri Gribenko           return;
311*5188c4b9SDmitri Gribenko         }
312*5188c4b9SDmitri Gribenko 
313*5188c4b9SDmitri Gribenko         TokenPtr = skipCommandName(TokenPtr, CommentEnd);
314*5188c4b9SDmitri Gribenko         unsigned Length = TokenPtr - (BufferPtr + 1);
315*5188c4b9SDmitri Gribenko 
316*5188c4b9SDmitri Gribenko         // Hardcoded support for lexing LaTeX formula commands
317*5188c4b9SDmitri Gribenko         // \f$ \f[ \f] \f{ \f} as a single command.
318*5188c4b9SDmitri Gribenko         if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) {
319*5188c4b9SDmitri Gribenko           C = *TokenPtr;
320*5188c4b9SDmitri Gribenko           if (C == '$' || C == '[' || C == ']' || C == '{' || C == '}') {
321*5188c4b9SDmitri Gribenko             TokenPtr++;
322*5188c4b9SDmitri Gribenko             Length++;
323*5188c4b9SDmitri Gribenko           }
324*5188c4b9SDmitri Gribenko         }
325*5188c4b9SDmitri Gribenko 
326*5188c4b9SDmitri Gribenko         const StringRef CommandName(BufferPtr + 1, Length);
327*5188c4b9SDmitri Gribenko         StringRef EndName;
328*5188c4b9SDmitri Gribenko 
329*5188c4b9SDmitri Gribenko         if (isVerbatimBlockCommand(CommandName, EndName)) {
330*5188c4b9SDmitri Gribenko           setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, EndName);
331*5188c4b9SDmitri Gribenko           return;
332*5188c4b9SDmitri Gribenko         }
333*5188c4b9SDmitri Gribenko         if (isVerbatimLineCommand(CommandName)) {
334*5188c4b9SDmitri Gribenko           lexVerbatimLine(T, TokenPtr);
335*5188c4b9SDmitri Gribenko           return;
336*5188c4b9SDmitri Gribenko         }
337*5188c4b9SDmitri Gribenko         formTokenWithChars(T, TokenPtr, tok::command);
338*5188c4b9SDmitri Gribenko         T.setCommandName(CommandName);
339*5188c4b9SDmitri Gribenko         return;
340*5188c4b9SDmitri Gribenko       }
341*5188c4b9SDmitri Gribenko 
342*5188c4b9SDmitri Gribenko       case '<': {
343*5188c4b9SDmitri Gribenko         TokenPtr++;
344*5188c4b9SDmitri Gribenko         if (TokenPtr == CommentEnd) {
345*5188c4b9SDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
346*5188c4b9SDmitri Gribenko           T.setText(StringRef(BufferPtr - T.getLength(), T.getLength()));
347*5188c4b9SDmitri Gribenko           return;
348*5188c4b9SDmitri Gribenko         }
349*5188c4b9SDmitri Gribenko         const char C = *TokenPtr;
350*5188c4b9SDmitri Gribenko         if (isHTMLIdentifierCharacter(C))
351*5188c4b9SDmitri Gribenko           setupAndLexHTMLOpenTag(T);
352*5188c4b9SDmitri Gribenko         else if (C == '/')
353*5188c4b9SDmitri Gribenko           lexHTMLCloseTag(T);
354*5188c4b9SDmitri Gribenko         return;
355*5188c4b9SDmitri Gribenko       }
356*5188c4b9SDmitri Gribenko 
357*5188c4b9SDmitri Gribenko       case '\n':
358*5188c4b9SDmitri Gribenko       case '\r':
359*5188c4b9SDmitri Gribenko         TokenPtr = skipNewline(TokenPtr, CommentEnd);
360*5188c4b9SDmitri Gribenko         formTokenWithChars(T, TokenPtr, tok::newline);
361*5188c4b9SDmitri Gribenko 
362*5188c4b9SDmitri Gribenko         if (CommentState == LCS_InsideCComment)
363*5188c4b9SDmitri Gribenko           skipLineStartingDecorations();
364*5188c4b9SDmitri Gribenko         return;
365*5188c4b9SDmitri Gribenko 
366*5188c4b9SDmitri Gribenko       default: {
367*5188c4b9SDmitri Gribenko         while (true) {
368*5188c4b9SDmitri Gribenko           TokenPtr++;
369*5188c4b9SDmitri Gribenko           if (TokenPtr == CommentEnd)
370*5188c4b9SDmitri Gribenko             break;
371*5188c4b9SDmitri Gribenko           char C = *TokenPtr;
372*5188c4b9SDmitri Gribenko           if(C == '\n' || C == '\r' ||
373*5188c4b9SDmitri Gribenko              C == '\\' || C == '@' || C == '<')
374*5188c4b9SDmitri Gribenko             break;
375*5188c4b9SDmitri Gribenko         }
376*5188c4b9SDmitri Gribenko         formTokenWithChars(T, TokenPtr, tok::text);
377*5188c4b9SDmitri Gribenko         T.setText(StringRef(BufferPtr - T.getLength(), T.getLength()));
378*5188c4b9SDmitri Gribenko         return;
379*5188c4b9SDmitri Gribenko       }
380*5188c4b9SDmitri Gribenko     }
381*5188c4b9SDmitri Gribenko   }
382*5188c4b9SDmitri Gribenko }
383*5188c4b9SDmitri Gribenko 
384*5188c4b9SDmitri Gribenko void Lexer::setupAndLexVerbatimBlock(Token &T,
385*5188c4b9SDmitri Gribenko                                      const char *TextBegin,
386*5188c4b9SDmitri Gribenko                                      char Marker, StringRef EndName) {
387*5188c4b9SDmitri Gribenko   VerbatimBlockEndCommandName.clear();
388*5188c4b9SDmitri Gribenko   VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@");
389*5188c4b9SDmitri Gribenko   VerbatimBlockEndCommandName.append(EndName);
390*5188c4b9SDmitri Gribenko 
391*5188c4b9SDmitri Gribenko   formTokenWithChars(T, TextBegin, tok::verbatim_block_begin);
392*5188c4b9SDmitri Gribenko   T.setVerbatimBlockName(StringRef(TextBegin - (T.getLength() - 1),
393*5188c4b9SDmitri Gribenko                                    T.getLength() - 1));
394*5188c4b9SDmitri Gribenko 
395*5188c4b9SDmitri Gribenko   State = LS_VerbatimBlockFirstLine;
396*5188c4b9SDmitri Gribenko }
397*5188c4b9SDmitri Gribenko 
398*5188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockFirstLine(Token &T) {
399*5188c4b9SDmitri Gribenko   assert(BufferPtr < CommentEnd);
400*5188c4b9SDmitri Gribenko 
401*5188c4b9SDmitri Gribenko   // FIXME: It would be better to scan the text once, finding either the block
402*5188c4b9SDmitri Gribenko   // end command or newline.
403*5188c4b9SDmitri Gribenko   //
404*5188c4b9SDmitri Gribenko   // Extract current line.
405*5188c4b9SDmitri Gribenko   const char *Newline = findNewline(BufferPtr, CommentEnd);
406*5188c4b9SDmitri Gribenko   StringRef Line(BufferPtr, Newline - BufferPtr);
407*5188c4b9SDmitri Gribenko 
408*5188c4b9SDmitri Gribenko   // Look for end command in current line.
409*5188c4b9SDmitri Gribenko   size_t Pos = Line.find(VerbatimBlockEndCommandName);
410*5188c4b9SDmitri Gribenko   const char *NextLine;
411*5188c4b9SDmitri Gribenko   if (Pos == StringRef::npos) {
412*5188c4b9SDmitri Gribenko     // Current line is completely verbatim.
413*5188c4b9SDmitri Gribenko     NextLine = skipNewline(Newline, CommentEnd);
414*5188c4b9SDmitri Gribenko   } else if (Pos == 0) {
415*5188c4b9SDmitri Gribenko     // Current line contains just an end command.
416*5188c4b9SDmitri Gribenko     const char *End = BufferPtr + VerbatimBlockEndCommandName.size();
417*5188c4b9SDmitri Gribenko     formTokenWithChars(T, End, tok::verbatim_block_end);
418*5188c4b9SDmitri Gribenko     T.setVerbatimBlockName(StringRef(End - (T.getLength() - 1),
419*5188c4b9SDmitri Gribenko                                      T.getLength() - 1));
420*5188c4b9SDmitri Gribenko     State = LS_Normal;
421*5188c4b9SDmitri Gribenko     return;
422*5188c4b9SDmitri Gribenko   } else {
423*5188c4b9SDmitri Gribenko     // There is some text, followed by end command.  Extract text first.
424*5188c4b9SDmitri Gribenko     NextLine = BufferPtr + Pos;
425*5188c4b9SDmitri Gribenko   }
426*5188c4b9SDmitri Gribenko 
427*5188c4b9SDmitri Gribenko   formTokenWithChars(T, NextLine, tok::verbatim_block_line);
428*5188c4b9SDmitri Gribenko   T.setVerbatimBlockText(StringRef(NextLine - T.getLength(), T.getLength()));
429*5188c4b9SDmitri Gribenko 
430*5188c4b9SDmitri Gribenko   State = LS_VerbatimBlockBody;
431*5188c4b9SDmitri Gribenko }
432*5188c4b9SDmitri Gribenko 
433*5188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockBody(Token &T) {
434*5188c4b9SDmitri Gribenko   assert(State == LS_VerbatimBlockBody);
435*5188c4b9SDmitri Gribenko 
436*5188c4b9SDmitri Gribenko   if (CommentState == LCS_InsideCComment)
437*5188c4b9SDmitri Gribenko     skipLineStartingDecorations();
438*5188c4b9SDmitri Gribenko 
439*5188c4b9SDmitri Gribenko   lexVerbatimBlockFirstLine(T);
440*5188c4b9SDmitri Gribenko }
441*5188c4b9SDmitri Gribenko 
442*5188c4b9SDmitri Gribenko void Lexer::lexVerbatimLine(Token &T, const char *TextBegin) {
443*5188c4b9SDmitri Gribenko   // Extract current line.
444*5188c4b9SDmitri Gribenko   const char *Newline = findNewline(BufferPtr, CommentEnd);
445*5188c4b9SDmitri Gribenko 
446*5188c4b9SDmitri Gribenko   const StringRef Name(BufferPtr + 1, TextBegin - BufferPtr - 1);
447*5188c4b9SDmitri Gribenko   const StringRef Text(TextBegin, Newline - TextBegin);
448*5188c4b9SDmitri Gribenko 
449*5188c4b9SDmitri Gribenko   formTokenWithChars(T, Newline, tok::verbatim_line);
450*5188c4b9SDmitri Gribenko   T.setVerbatimLineName(Name);
451*5188c4b9SDmitri Gribenko   T.setVerbatimLineText(Text);
452*5188c4b9SDmitri Gribenko }
453*5188c4b9SDmitri Gribenko 
454*5188c4b9SDmitri Gribenko void Lexer::setupAndLexHTMLOpenTag(Token &T) {
455*5188c4b9SDmitri Gribenko   assert(BufferPtr[0] == '<' && isHTMLIdentifierCharacter(BufferPtr[1]));
456*5188c4b9SDmitri Gribenko   const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd);
457*5188c4b9SDmitri Gribenko 
458*5188c4b9SDmitri Gribenko   formTokenWithChars(T, TagNameEnd, tok::html_tag_open);
459*5188c4b9SDmitri Gribenko   T.setHTMLTagOpenName(StringRef(TagNameEnd - (T.getLength() - 1),
460*5188c4b9SDmitri Gribenko                                  T.getLength() - 1));
461*5188c4b9SDmitri Gribenko 
462*5188c4b9SDmitri Gribenko   BufferPtr = skipWhitespace(BufferPtr, CommentEnd);
463*5188c4b9SDmitri Gribenko 
464*5188c4b9SDmitri Gribenko   if (BufferPtr != CommentEnd && *BufferPtr == '>') {
465*5188c4b9SDmitri Gribenko     BufferPtr++;
466*5188c4b9SDmitri Gribenko     return;
467*5188c4b9SDmitri Gribenko   }
468*5188c4b9SDmitri Gribenko 
469*5188c4b9SDmitri Gribenko   if (BufferPtr != CommentEnd && isHTMLIdentifierCharacter(*BufferPtr))
470*5188c4b9SDmitri Gribenko     State = LS_HTMLOpenTag;
471*5188c4b9SDmitri Gribenko }
472*5188c4b9SDmitri Gribenko 
473*5188c4b9SDmitri Gribenko void Lexer::lexHTMLOpenTag(Token &T) {
474*5188c4b9SDmitri Gribenko   assert(State == LS_HTMLOpenTag);
475*5188c4b9SDmitri Gribenko 
476*5188c4b9SDmitri Gribenko   const char *TokenPtr = BufferPtr;
477*5188c4b9SDmitri Gribenko   char C = *TokenPtr;
478*5188c4b9SDmitri Gribenko   if (isHTMLIdentifierCharacter(C)) {
479*5188c4b9SDmitri Gribenko     TokenPtr = skipHTMLIdentifier(TokenPtr, CommentEnd);
480*5188c4b9SDmitri Gribenko     formTokenWithChars(T, TokenPtr, tok::html_ident);
481*5188c4b9SDmitri Gribenko     T.setHTMLIdent(StringRef(TokenPtr - T.getLength(), T.getLength()));
482*5188c4b9SDmitri Gribenko   } else {
483*5188c4b9SDmitri Gribenko     switch (C) {
484*5188c4b9SDmitri Gribenko     case '=':
485*5188c4b9SDmitri Gribenko       TokenPtr++;
486*5188c4b9SDmitri Gribenko       formTokenWithChars(T, TokenPtr, tok::html_equals);
487*5188c4b9SDmitri Gribenko       break;
488*5188c4b9SDmitri Gribenko     case '\"':
489*5188c4b9SDmitri Gribenko     case '\'': {
490*5188c4b9SDmitri Gribenko       const char *OpenQuote = TokenPtr;
491*5188c4b9SDmitri Gribenko       TokenPtr = skipHTMLQuotedString(TokenPtr, CommentEnd);
492*5188c4b9SDmitri Gribenko       const char *ClosingQuote = TokenPtr;
493*5188c4b9SDmitri Gribenko       if (TokenPtr != CommentEnd) // Skip closing quote.
494*5188c4b9SDmitri Gribenko         TokenPtr++;
495*5188c4b9SDmitri Gribenko       formTokenWithChars(T, TokenPtr, tok::html_quoted_string);
496*5188c4b9SDmitri Gribenko       T.setHTMLQuotedString(StringRef(OpenQuote + 1,
497*5188c4b9SDmitri Gribenko                                       ClosingQuote - (OpenQuote + 1)));
498*5188c4b9SDmitri Gribenko       break;
499*5188c4b9SDmitri Gribenko     }
500*5188c4b9SDmitri Gribenko     case '>':
501*5188c4b9SDmitri Gribenko       TokenPtr++;
502*5188c4b9SDmitri Gribenko       formTokenWithChars(T, TokenPtr, tok::html_greater);
503*5188c4b9SDmitri Gribenko       break;
504*5188c4b9SDmitri Gribenko     }
505*5188c4b9SDmitri Gribenko   }
506*5188c4b9SDmitri Gribenko 
507*5188c4b9SDmitri Gribenko   // Now look ahead and return to normal state if we don't see any HTML tokens
508*5188c4b9SDmitri Gribenko   // ahead.
509*5188c4b9SDmitri Gribenko   BufferPtr = skipWhitespace(BufferPtr, CommentEnd);
510*5188c4b9SDmitri Gribenko   if (BufferPtr == CommentEnd) {
511*5188c4b9SDmitri Gribenko     State = LS_Normal;
512*5188c4b9SDmitri Gribenko     return;
513*5188c4b9SDmitri Gribenko   }
514*5188c4b9SDmitri Gribenko 
515*5188c4b9SDmitri Gribenko   C = *BufferPtr;
516*5188c4b9SDmitri Gribenko   if (!isHTMLIdentifierCharacter(C) &&
517*5188c4b9SDmitri Gribenko       C != '=' && C != '\"' && C != '\'' && C != '>') {
518*5188c4b9SDmitri Gribenko     State = LS_Normal;
519*5188c4b9SDmitri Gribenko     return;
520*5188c4b9SDmitri Gribenko   }
521*5188c4b9SDmitri Gribenko }
522*5188c4b9SDmitri Gribenko 
523*5188c4b9SDmitri Gribenko void Lexer::lexHTMLCloseTag(Token &T) {
524*5188c4b9SDmitri Gribenko   assert(BufferPtr[0] == '<' && BufferPtr[1] == '/');
525*5188c4b9SDmitri Gribenko 
526*5188c4b9SDmitri Gribenko   const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd);
527*5188c4b9SDmitri Gribenko   const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd);
528*5188c4b9SDmitri Gribenko 
529*5188c4b9SDmitri Gribenko   const char *End = skipWhitespace(TagNameEnd, CommentEnd);
530*5188c4b9SDmitri Gribenko   if (End != CommentEnd && *End == '>')
531*5188c4b9SDmitri Gribenko     End++;
532*5188c4b9SDmitri Gribenko 
533*5188c4b9SDmitri Gribenko   formTokenWithChars(T, End, tok::html_tag_close);
534*5188c4b9SDmitri Gribenko   T.setHTMLTagCloseName(StringRef(TagNameBegin, TagNameEnd - TagNameBegin));
535*5188c4b9SDmitri Gribenko }
536*5188c4b9SDmitri Gribenko 
537*5188c4b9SDmitri Gribenko Lexer::Lexer(SourceLocation FileLoc, const CommentOptions &CommOpts,
538*5188c4b9SDmitri Gribenko              const char *BufferStart, const char *BufferEnd):
539*5188c4b9SDmitri Gribenko     BufferStart(BufferStart), BufferEnd(BufferEnd),
540*5188c4b9SDmitri Gribenko     FileLoc(FileLoc), CommOpts(CommOpts), BufferPtr(BufferStart),
541*5188c4b9SDmitri Gribenko     CommentState(LCS_BeforeComment), State(LS_Normal) {
542*5188c4b9SDmitri Gribenko }
543*5188c4b9SDmitri Gribenko 
544*5188c4b9SDmitri Gribenko void Lexer::lex(Token &T) {
545*5188c4b9SDmitri Gribenko again:
546*5188c4b9SDmitri Gribenko   switch (CommentState) {
547*5188c4b9SDmitri Gribenko   case LCS_BeforeComment:
548*5188c4b9SDmitri Gribenko     if (BufferPtr == BufferEnd) {
549*5188c4b9SDmitri Gribenko       formTokenWithChars(T, BufferPtr, tok::eof);
550*5188c4b9SDmitri Gribenko       return;
551*5188c4b9SDmitri Gribenko     }
552*5188c4b9SDmitri Gribenko 
553*5188c4b9SDmitri Gribenko     assert(*BufferPtr == '/');
554*5188c4b9SDmitri Gribenko     BufferPtr++; // Skip first slash.
555*5188c4b9SDmitri Gribenko     switch(*BufferPtr) {
556*5188c4b9SDmitri Gribenko     case '/': { // BCPL comment.
557*5188c4b9SDmitri Gribenko       BufferPtr++; // Skip second slash.
558*5188c4b9SDmitri Gribenko 
559*5188c4b9SDmitri Gribenko       if (BufferPtr != BufferEnd) {
560*5188c4b9SDmitri Gribenko         // Skip Doxygen magic marker, if it is present.
561*5188c4b9SDmitri Gribenko         // It might be missing because of a typo //< or /*<, or because we
562*5188c4b9SDmitri Gribenko         // merged this non-Doxygen comment into a bunch of Doxygen comments
563*5188c4b9SDmitri Gribenko         // around it: /** ... */ /* ... */ /** ... */
564*5188c4b9SDmitri Gribenko         const char C = *BufferPtr;
565*5188c4b9SDmitri Gribenko         if (C == '/' || C == '!')
566*5188c4b9SDmitri Gribenko           BufferPtr++;
567*5188c4b9SDmitri Gribenko       }
568*5188c4b9SDmitri Gribenko 
569*5188c4b9SDmitri Gribenko       // Skip less-than symbol that marks trailing comments.
570*5188c4b9SDmitri Gribenko       // Skip it even if the comment is not a Doxygen one, because //< and /*<
571*5188c4b9SDmitri Gribenko       // are frequent typos.
572*5188c4b9SDmitri Gribenko       if (BufferPtr != BufferEnd && *BufferPtr == '<')
573*5188c4b9SDmitri Gribenko         BufferPtr++;
574*5188c4b9SDmitri Gribenko 
575*5188c4b9SDmitri Gribenko       CommentState = LCS_InsideBCPLComment;
576*5188c4b9SDmitri Gribenko       State = LS_Normal;
577*5188c4b9SDmitri Gribenko       CommentEnd = findBCPLCommentEnd(BufferPtr, BufferEnd);
578*5188c4b9SDmitri Gribenko       goto again;
579*5188c4b9SDmitri Gribenko     }
580*5188c4b9SDmitri Gribenko     case '*': { // C comment.
581*5188c4b9SDmitri Gribenko       BufferPtr++; // Skip star.
582*5188c4b9SDmitri Gribenko 
583*5188c4b9SDmitri Gribenko       // Skip Doxygen magic marker.
584*5188c4b9SDmitri Gribenko       const char C = *BufferPtr;
585*5188c4b9SDmitri Gribenko       if ((C == '*' && *(BufferPtr + 1) != '/') || C == '!')
586*5188c4b9SDmitri Gribenko         BufferPtr++;
587*5188c4b9SDmitri Gribenko 
588*5188c4b9SDmitri Gribenko       // Skip less-than symbol that marks trailing comments.
589*5188c4b9SDmitri Gribenko       if (BufferPtr != BufferEnd && *BufferPtr == '<')
590*5188c4b9SDmitri Gribenko         BufferPtr++;
591*5188c4b9SDmitri Gribenko 
592*5188c4b9SDmitri Gribenko       CommentState = LCS_InsideCComment;
593*5188c4b9SDmitri Gribenko       State = LS_Normal;
594*5188c4b9SDmitri Gribenko       CommentEnd = findCCommentEnd(BufferPtr, BufferEnd);
595*5188c4b9SDmitri Gribenko       goto again;
596*5188c4b9SDmitri Gribenko     }
597*5188c4b9SDmitri Gribenko     default:
598*5188c4b9SDmitri Gribenko       llvm_unreachable("second character of comment should be '/' or '*'");
599*5188c4b9SDmitri Gribenko     }
600*5188c4b9SDmitri Gribenko 
601*5188c4b9SDmitri Gribenko   case LCS_BetweenComments: {
602*5188c4b9SDmitri Gribenko     // Consecutive comments are extracted only if there is only whitespace
603*5188c4b9SDmitri Gribenko     // between them.  So we can search for the start of the next comment.
604*5188c4b9SDmitri Gribenko     const char *EndWhitespace = BufferPtr;
605*5188c4b9SDmitri Gribenko     while(EndWhitespace != BufferEnd && *EndWhitespace != '/')
606*5188c4b9SDmitri Gribenko       EndWhitespace++;
607*5188c4b9SDmitri Gribenko 
608*5188c4b9SDmitri Gribenko     // Turn any whitespace between comments (and there is only whitespace
609*5188c4b9SDmitri Gribenko     // between them) into a newline.  We have two newlines between comments
610*5188c4b9SDmitri Gribenko     // in total (first one was synthesized after a comment).
611*5188c4b9SDmitri Gribenko     formTokenWithChars(T, EndWhitespace, tok::newline);
612*5188c4b9SDmitri Gribenko 
613*5188c4b9SDmitri Gribenko     CommentState = LCS_BeforeComment;
614*5188c4b9SDmitri Gribenko     break;
615*5188c4b9SDmitri Gribenko   }
616*5188c4b9SDmitri Gribenko 
617*5188c4b9SDmitri Gribenko   case LCS_InsideBCPLComment:
618*5188c4b9SDmitri Gribenko   case LCS_InsideCComment:
619*5188c4b9SDmitri Gribenko     if (BufferPtr != CommentEnd) {
620*5188c4b9SDmitri Gribenko       lexCommentText(T);
621*5188c4b9SDmitri Gribenko       break;
622*5188c4b9SDmitri Gribenko     } else {
623*5188c4b9SDmitri Gribenko       // Skip C comment closing sequence.
624*5188c4b9SDmitri Gribenko       if (CommentState == LCS_InsideCComment) {
625*5188c4b9SDmitri Gribenko         assert(BufferPtr[0] == '*' && BufferPtr[1] == '/');
626*5188c4b9SDmitri Gribenko         BufferPtr += 2;
627*5188c4b9SDmitri Gribenko         assert(BufferPtr <= BufferEnd);
628*5188c4b9SDmitri Gribenko 
629*5188c4b9SDmitri Gribenko         // Synthenize newline just after the C comment, regardless if there is
630*5188c4b9SDmitri Gribenko         // actually a newline.
631*5188c4b9SDmitri Gribenko         formTokenWithChars(T, BufferPtr, tok::newline);
632*5188c4b9SDmitri Gribenko 
633*5188c4b9SDmitri Gribenko         CommentState = LCS_BetweenComments;
634*5188c4b9SDmitri Gribenko         break;
635*5188c4b9SDmitri Gribenko       } else {
636*5188c4b9SDmitri Gribenko         // Don't synthesized a newline after BCPL comment.
637*5188c4b9SDmitri Gribenko         CommentState = LCS_BetweenComments;
638*5188c4b9SDmitri Gribenko         goto again;
639*5188c4b9SDmitri Gribenko       }
640*5188c4b9SDmitri Gribenko     }
641*5188c4b9SDmitri Gribenko   }
642*5188c4b9SDmitri Gribenko }
643*5188c4b9SDmitri Gribenko 
644*5188c4b9SDmitri Gribenko StringRef Lexer::getSpelling(const Token &Tok,
645*5188c4b9SDmitri Gribenko                              const SourceManager &SourceMgr,
646*5188c4b9SDmitri Gribenko                              bool *Invalid) const {
647*5188c4b9SDmitri Gribenko   SourceLocation Loc = Tok.getLocation();
648*5188c4b9SDmitri Gribenko   std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(Loc);
649*5188c4b9SDmitri Gribenko 
650*5188c4b9SDmitri Gribenko   bool InvalidTemp = false;
651*5188c4b9SDmitri Gribenko   StringRef File = SourceMgr.getBufferData(LocInfo.first, &InvalidTemp);
652*5188c4b9SDmitri Gribenko   if (InvalidTemp) {
653*5188c4b9SDmitri Gribenko     *Invalid = true;
654*5188c4b9SDmitri Gribenko     return StringRef();
655*5188c4b9SDmitri Gribenko   }
656*5188c4b9SDmitri Gribenko 
657*5188c4b9SDmitri Gribenko   const char *Begin = File.data() + LocInfo.second;
658*5188c4b9SDmitri Gribenko   return StringRef(Begin, Tok.getLength());
659*5188c4b9SDmitri Gribenko }
660*5188c4b9SDmitri Gribenko 
661*5188c4b9SDmitri Gribenko void Lexer::addVerbatimBlockCommand(StringRef BeginName, StringRef EndName) {
662*5188c4b9SDmitri Gribenko   VerbatimBlockCommand VBC;
663*5188c4b9SDmitri Gribenko   VBC.BeginName = BeginName;
664*5188c4b9SDmitri Gribenko   VBC.EndName = EndName;
665*5188c4b9SDmitri Gribenko   VerbatimBlockCommands.push_back(VBC);
666*5188c4b9SDmitri Gribenko }
667*5188c4b9SDmitri Gribenko 
668*5188c4b9SDmitri Gribenko void Lexer::addVerbatimLineCommand(StringRef Name) {
669*5188c4b9SDmitri Gribenko   VerbatimLineCommand VLC;
670*5188c4b9SDmitri Gribenko   VLC.Name = Name;
671*5188c4b9SDmitri Gribenko   VerbatimLineCommands.push_back(VLC);
672*5188c4b9SDmitri Gribenko }
673*5188c4b9SDmitri Gribenko 
674*5188c4b9SDmitri Gribenko } // end namespace comments
675*5188c4b9SDmitri Gribenko } // end namespace clang
676*5188c4b9SDmitri Gribenko 
677