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