15188c4b9SDmitri Gribenko #include "clang/AST/CommentLexer.h" 25188c4b9SDmitri Gribenko #include "llvm/ADT/StringSwitch.h" 35188c4b9SDmitri Gribenko #include "llvm/Support/ErrorHandling.h" 45188c4b9SDmitri Gribenko 55188c4b9SDmitri Gribenko namespace clang { 65188c4b9SDmitri Gribenko namespace comments { 75188c4b9SDmitri Gribenko 85188c4b9SDmitri Gribenko void Token::dump(const Lexer &L, const SourceManager &SM) const { 95188c4b9SDmitri Gribenko llvm::errs() << "comments::Token Kind=" << Kind << " "; 105188c4b9SDmitri Gribenko Loc.dump(SM); 115188c4b9SDmitri Gribenko llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n"; 125188c4b9SDmitri Gribenko } 135188c4b9SDmitri Gribenko 145188c4b9SDmitri Gribenko bool Lexer::isVerbatimBlockCommand(StringRef BeginName, 155188c4b9SDmitri Gribenko StringRef &EndName) const { 165188c4b9SDmitri Gribenko const char *Result = llvm::StringSwitch<const char *>(BeginName) 175188c4b9SDmitri Gribenko .Case("code", "endcode") 185188c4b9SDmitri Gribenko .Case("verbatim", "endverbatim") 195188c4b9SDmitri Gribenko .Case("htmlonly", "endhtmlonly") 205188c4b9SDmitri Gribenko .Case("latexonly", "endlatexonly") 215188c4b9SDmitri Gribenko .Case("xmlonly", "endxmlonly") 225188c4b9SDmitri Gribenko .Case("manonly", "endmanonly") 235188c4b9SDmitri Gribenko .Case("rtfonly", "endrtfonly") 245188c4b9SDmitri Gribenko 255188c4b9SDmitri Gribenko .Case("dot", "enddot") 265188c4b9SDmitri Gribenko .Case("msc", "endmsc") 275188c4b9SDmitri Gribenko 285188c4b9SDmitri Gribenko .Case("f$", "f$") // Inline LaTeX formula 295188c4b9SDmitri Gribenko .Case("f[", "f]") // Displayed LaTeX formula 305188c4b9SDmitri Gribenko .Case("f{", "f}") // LaTeX environment 315188c4b9SDmitri Gribenko 325188c4b9SDmitri Gribenko .Default(NULL); 335188c4b9SDmitri Gribenko 345188c4b9SDmitri Gribenko if (Result) { 355188c4b9SDmitri Gribenko EndName = Result; 365188c4b9SDmitri Gribenko return true; 375188c4b9SDmitri Gribenko } 385188c4b9SDmitri Gribenko 395188c4b9SDmitri Gribenko for (VerbatimBlockCommandVector::const_iterator 405188c4b9SDmitri Gribenko I = VerbatimBlockCommands.begin(), 415188c4b9SDmitri Gribenko E = VerbatimBlockCommands.end(); 425188c4b9SDmitri Gribenko I != E; ++I) 435188c4b9SDmitri Gribenko if (I->BeginName == BeginName) { 445188c4b9SDmitri Gribenko EndName = I->EndName; 455188c4b9SDmitri Gribenko return true; 465188c4b9SDmitri Gribenko } 475188c4b9SDmitri Gribenko 485188c4b9SDmitri Gribenko return false; 495188c4b9SDmitri Gribenko } 505188c4b9SDmitri Gribenko 515188c4b9SDmitri Gribenko bool Lexer::isVerbatimLineCommand(StringRef Name) const { 525188c4b9SDmitri Gribenko bool Result = llvm::StringSwitch<bool>(Name) 535188c4b9SDmitri Gribenko .Case("fn", true) 545188c4b9SDmitri Gribenko .Case("var", true) 555188c4b9SDmitri Gribenko .Case("property", true) 565188c4b9SDmitri Gribenko .Case("typedef", true) 575188c4b9SDmitri Gribenko 585188c4b9SDmitri Gribenko .Case("overload", true) 595188c4b9SDmitri Gribenko 605188c4b9SDmitri Gribenko .Case("defgroup", true) 615188c4b9SDmitri Gribenko .Case("ingroup", true) 625188c4b9SDmitri Gribenko .Case("addtogroup", true) 635188c4b9SDmitri Gribenko .Case("weakgroup", true) 645188c4b9SDmitri Gribenko .Case("name", true) 655188c4b9SDmitri Gribenko 665188c4b9SDmitri Gribenko .Case("section", true) 675188c4b9SDmitri Gribenko .Case("subsection", true) 685188c4b9SDmitri Gribenko .Case("subsubsection", true) 695188c4b9SDmitri Gribenko .Case("paragraph", true) 705188c4b9SDmitri Gribenko 715188c4b9SDmitri Gribenko .Case("mainpage", true) 725188c4b9SDmitri Gribenko .Case("subpage", true) 735188c4b9SDmitri Gribenko .Case("ref", true) 745188c4b9SDmitri Gribenko 755188c4b9SDmitri Gribenko .Default(false); 765188c4b9SDmitri Gribenko 775188c4b9SDmitri Gribenko if (Result) 785188c4b9SDmitri Gribenko return true; 795188c4b9SDmitri Gribenko 805188c4b9SDmitri Gribenko for (VerbatimLineCommandVector::const_iterator 815188c4b9SDmitri Gribenko I = VerbatimLineCommands.begin(), 825188c4b9SDmitri Gribenko E = VerbatimLineCommands.end(); 835188c4b9SDmitri Gribenko I != E; ++I) 845188c4b9SDmitri Gribenko if (I->Name == Name) 855188c4b9SDmitri Gribenko return true; 865188c4b9SDmitri Gribenko 875188c4b9SDmitri Gribenko return false; 885188c4b9SDmitri Gribenko } 895188c4b9SDmitri Gribenko 905188c4b9SDmitri Gribenko void Lexer::skipLineStartingDecorations() { 915188c4b9SDmitri Gribenko // This function should be called only for C comments 925188c4b9SDmitri Gribenko assert(CommentState == LCS_InsideCComment); 935188c4b9SDmitri Gribenko 945188c4b9SDmitri Gribenko if (BufferPtr == CommentEnd) 955188c4b9SDmitri Gribenko return; 965188c4b9SDmitri Gribenko 975188c4b9SDmitri Gribenko switch (*BufferPtr) { 985188c4b9SDmitri Gribenko case ' ': 995188c4b9SDmitri Gribenko case '\t': 1005188c4b9SDmitri Gribenko case '\f': 1015188c4b9SDmitri Gribenko case '\v': { 1025188c4b9SDmitri Gribenko const char *NewBufferPtr = BufferPtr; 1035188c4b9SDmitri Gribenko NewBufferPtr++; 1045188c4b9SDmitri Gribenko if (NewBufferPtr == CommentEnd) 1055188c4b9SDmitri Gribenko return; 1065188c4b9SDmitri Gribenko 1075188c4b9SDmitri Gribenko char C = *NewBufferPtr; 1085188c4b9SDmitri Gribenko while (C == ' ' || C == '\t' || C == '\f' || C == '\v') { 1095188c4b9SDmitri Gribenko NewBufferPtr++; 1105188c4b9SDmitri Gribenko if (NewBufferPtr == CommentEnd) 1115188c4b9SDmitri Gribenko return; 1125188c4b9SDmitri Gribenko C = *NewBufferPtr; 1135188c4b9SDmitri Gribenko } 1145188c4b9SDmitri Gribenko if (C == '*') 1155188c4b9SDmitri Gribenko BufferPtr = NewBufferPtr + 1; 1165188c4b9SDmitri Gribenko break; 1175188c4b9SDmitri Gribenko } 1185188c4b9SDmitri Gribenko case '*': 1195188c4b9SDmitri Gribenko BufferPtr++; 1205188c4b9SDmitri Gribenko break; 1215188c4b9SDmitri Gribenko } 1225188c4b9SDmitri Gribenko } 1235188c4b9SDmitri Gribenko 1245188c4b9SDmitri Gribenko namespace { 125ec92531cSDmitri Gribenko /// Returns pointer to the first newline character in the string. 1265188c4b9SDmitri Gribenko const char *findNewline(const char *BufferPtr, const char *BufferEnd) { 1275188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 1285188c4b9SDmitri Gribenko const char C = *BufferPtr; 1295188c4b9SDmitri Gribenko if (C == '\n' || C == '\r') 1305188c4b9SDmitri Gribenko return BufferPtr; 1315188c4b9SDmitri Gribenko } 1325188c4b9SDmitri Gribenko return BufferEnd; 1335188c4b9SDmitri Gribenko } 1345188c4b9SDmitri Gribenko 1355188c4b9SDmitri Gribenko const char *skipNewline(const char *BufferPtr, const char *BufferEnd) { 1365188c4b9SDmitri Gribenko if (BufferPtr == BufferEnd) 1375188c4b9SDmitri Gribenko return BufferPtr; 1385188c4b9SDmitri Gribenko 1395188c4b9SDmitri Gribenko if (*BufferPtr == '\n') 1405188c4b9SDmitri Gribenko BufferPtr++; 1415188c4b9SDmitri Gribenko else { 1425188c4b9SDmitri Gribenko assert(*BufferPtr == '\r'); 1435188c4b9SDmitri Gribenko BufferPtr++; 1445188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '\n') 1455188c4b9SDmitri Gribenko BufferPtr++; 1465188c4b9SDmitri Gribenko } 1475188c4b9SDmitri Gribenko return BufferPtr; 1485188c4b9SDmitri Gribenko } 1495188c4b9SDmitri Gribenko 15017709ae8SDmitri Gribenko bool isHTMLIdentifierStartingCharacter(char C) { 15117709ae8SDmitri Gribenko return (C >= 'a' && C <= 'z') || 15217709ae8SDmitri Gribenko (C >= 'A' && C <= 'Z'); 15317709ae8SDmitri Gribenko } 15417709ae8SDmitri Gribenko 1555188c4b9SDmitri Gribenko bool isHTMLIdentifierCharacter(char C) { 1565188c4b9SDmitri Gribenko return (C >= 'a' && C <= 'z') || 1575188c4b9SDmitri Gribenko (C >= 'A' && C <= 'Z') || 1585188c4b9SDmitri Gribenko (C >= '0' && C <= '9'); 1595188c4b9SDmitri Gribenko } 1605188c4b9SDmitri Gribenko 1615188c4b9SDmitri Gribenko const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) { 1625188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 1635188c4b9SDmitri Gribenko if (!isHTMLIdentifierCharacter(*BufferPtr)) 1645188c4b9SDmitri Gribenko return BufferPtr; 1655188c4b9SDmitri Gribenko } 1665188c4b9SDmitri Gribenko return BufferEnd; 1675188c4b9SDmitri Gribenko } 1685188c4b9SDmitri Gribenko 1695188c4b9SDmitri Gribenko /// Skip HTML string quoted in single or double quotes. Escaping quotes inside 1705188c4b9SDmitri Gribenko /// string allowed. 1715188c4b9SDmitri Gribenko /// 1725188c4b9SDmitri Gribenko /// Returns pointer to closing quote. 1735188c4b9SDmitri Gribenko const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd) 1745188c4b9SDmitri Gribenko { 1755188c4b9SDmitri Gribenko const char Quote = *BufferPtr; 1765188c4b9SDmitri Gribenko assert(Quote == '\"' || Quote == '\''); 1775188c4b9SDmitri Gribenko 1785188c4b9SDmitri Gribenko BufferPtr++; 1795188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 1805188c4b9SDmitri Gribenko const char C = *BufferPtr; 1815188c4b9SDmitri Gribenko if (C == Quote && BufferPtr[-1] != '\\') 1825188c4b9SDmitri Gribenko return BufferPtr; 1835188c4b9SDmitri Gribenko } 1845188c4b9SDmitri Gribenko return BufferEnd; 1855188c4b9SDmitri Gribenko } 1865188c4b9SDmitri Gribenko 1875188c4b9SDmitri Gribenko bool isHorizontalWhitespace(char C) { 1885188c4b9SDmitri Gribenko return C == ' ' || C == '\t' || C == '\f' || C == '\v'; 1895188c4b9SDmitri Gribenko } 1905188c4b9SDmitri Gribenko 1915188c4b9SDmitri Gribenko bool isWhitespace(char C) { 1925188c4b9SDmitri Gribenko return C == ' ' || C == '\n' || C == '\r' || 1935188c4b9SDmitri Gribenko C == '\t' || C == '\f' || C == '\v'; 1945188c4b9SDmitri Gribenko } 1955188c4b9SDmitri Gribenko 1965188c4b9SDmitri Gribenko const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) { 1975188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 1985188c4b9SDmitri Gribenko if (!isWhitespace(*BufferPtr)) 1995188c4b9SDmitri Gribenko return BufferPtr; 2005188c4b9SDmitri Gribenko } 2015188c4b9SDmitri Gribenko return BufferEnd; 2025188c4b9SDmitri Gribenko } 2035188c4b9SDmitri Gribenko 2045188c4b9SDmitri Gribenko bool isCommandNameCharacter(char C) { 2055188c4b9SDmitri Gribenko return (C >= 'a' && C <= 'z') || 2065188c4b9SDmitri Gribenko (C >= 'A' && C <= 'Z') || 2075188c4b9SDmitri Gribenko (C >= '0' && C <= '9'); 2085188c4b9SDmitri Gribenko } 2095188c4b9SDmitri Gribenko 2105188c4b9SDmitri Gribenko const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) { 2115188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 2125188c4b9SDmitri Gribenko if (!isCommandNameCharacter(*BufferPtr)) 2135188c4b9SDmitri Gribenko return BufferPtr; 2145188c4b9SDmitri Gribenko } 2155188c4b9SDmitri Gribenko return BufferEnd; 2165188c4b9SDmitri Gribenko } 2175188c4b9SDmitri Gribenko 2185188c4b9SDmitri Gribenko /// Return the one past end pointer for BCPL comments. 2195188c4b9SDmitri Gribenko /// Handles newlines escaped with backslash or trigraph for backslahs. 2205188c4b9SDmitri Gribenko const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) { 2215188c4b9SDmitri Gribenko const char *CurPtr = BufferPtr; 2225188c4b9SDmitri Gribenko while (CurPtr != BufferEnd) { 2235188c4b9SDmitri Gribenko char C = *CurPtr; 2245188c4b9SDmitri Gribenko while (C != '\n' && C != '\r') { 2255188c4b9SDmitri Gribenko CurPtr++; 2265188c4b9SDmitri Gribenko if (CurPtr == BufferEnd) 2275188c4b9SDmitri Gribenko return BufferEnd; 2285188c4b9SDmitri Gribenko C = *CurPtr; 2295188c4b9SDmitri Gribenko } 2305188c4b9SDmitri Gribenko // We found a newline, check if it is escaped. 2315188c4b9SDmitri Gribenko const char *EscapePtr = CurPtr - 1; 2325188c4b9SDmitri Gribenko while(isHorizontalWhitespace(*EscapePtr)) 2335188c4b9SDmitri Gribenko EscapePtr--; 2345188c4b9SDmitri Gribenko 2355188c4b9SDmitri Gribenko if (*EscapePtr == '\\' || 2365188c4b9SDmitri Gribenko (EscapePtr - 2 >= BufferPtr && EscapePtr[0] == '/' && 2375188c4b9SDmitri Gribenko EscapePtr[-1] == '?' && EscapePtr[-2] == '?')) { 2385188c4b9SDmitri Gribenko // We found an escaped newline. 2395188c4b9SDmitri Gribenko CurPtr = skipNewline(CurPtr, BufferEnd); 2405188c4b9SDmitri Gribenko } else 2415188c4b9SDmitri Gribenko return CurPtr; // Not an escaped newline. 2425188c4b9SDmitri Gribenko } 2435188c4b9SDmitri Gribenko return BufferEnd; 2445188c4b9SDmitri Gribenko } 2455188c4b9SDmitri Gribenko 2465188c4b9SDmitri Gribenko /// Return the one past end pointer for C comments. 2475188c4b9SDmitri Gribenko /// Very dumb, does not handle escaped newlines or trigraphs. 2485188c4b9SDmitri Gribenko const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) { 2495188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 2505188c4b9SDmitri Gribenko if (*BufferPtr == '*') { 2515188c4b9SDmitri Gribenko assert(BufferPtr + 1 != BufferEnd); 2525188c4b9SDmitri Gribenko if (*(BufferPtr + 1) == '/') 2535188c4b9SDmitri Gribenko return BufferPtr; 2545188c4b9SDmitri Gribenko } 2555188c4b9SDmitri Gribenko } 2565188c4b9SDmitri Gribenko llvm_unreachable("buffer end hit before '*/' was seen"); 2575188c4b9SDmitri Gribenko } 2585188c4b9SDmitri Gribenko } // unnamed namespace 2595188c4b9SDmitri Gribenko 2605188c4b9SDmitri Gribenko void Lexer::lexCommentText(Token &T) { 2615188c4b9SDmitri Gribenko assert(CommentState == LCS_InsideBCPLComment || 2625188c4b9SDmitri Gribenko CommentState == LCS_InsideCComment); 2635188c4b9SDmitri Gribenko 2645188c4b9SDmitri Gribenko switch (State) { 2655188c4b9SDmitri Gribenko case LS_Normal: 2665188c4b9SDmitri Gribenko break; 2675188c4b9SDmitri Gribenko case LS_VerbatimBlockFirstLine: 2685188c4b9SDmitri Gribenko lexVerbatimBlockFirstLine(T); 2695188c4b9SDmitri Gribenko return; 2705188c4b9SDmitri Gribenko case LS_VerbatimBlockBody: 2715188c4b9SDmitri Gribenko lexVerbatimBlockBody(T); 2725188c4b9SDmitri Gribenko return; 2731669f702SDmitri Gribenko case LS_VerbatimLineText: 2741669f702SDmitri Gribenko lexVerbatimLineText(T); 2751669f702SDmitri Gribenko return; 2765188c4b9SDmitri Gribenko case LS_HTMLOpenTag: 2775188c4b9SDmitri Gribenko lexHTMLOpenTag(T); 2785188c4b9SDmitri Gribenko return; 279ec92531cSDmitri Gribenko case LS_HTMLCloseTag: 280ec92531cSDmitri Gribenko lexHTMLCloseTag(T); 281ec92531cSDmitri Gribenko return; 2825188c4b9SDmitri Gribenko } 2835188c4b9SDmitri Gribenko 2845188c4b9SDmitri Gribenko assert(State == LS_Normal); 2855188c4b9SDmitri Gribenko 2865188c4b9SDmitri Gribenko const char *TokenPtr = BufferPtr; 2875188c4b9SDmitri Gribenko assert(TokenPtr < CommentEnd); 2885188c4b9SDmitri Gribenko while (TokenPtr != CommentEnd) { 2895188c4b9SDmitri Gribenko switch(*TokenPtr) { 2905188c4b9SDmitri Gribenko case '\\': 2915188c4b9SDmitri Gribenko case '@': { 2925188c4b9SDmitri Gribenko TokenPtr++; 2935188c4b9SDmitri Gribenko if (TokenPtr == CommentEnd) { 29460ddd8a1SDmitri Gribenko StringRef Text(BufferPtr, TokenPtr - BufferPtr); 2955188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 29660ddd8a1SDmitri Gribenko T.setText(Text); 2975188c4b9SDmitri Gribenko return; 2985188c4b9SDmitri Gribenko } 2995188c4b9SDmitri Gribenko char C = *TokenPtr; 3005188c4b9SDmitri Gribenko switch (C) { 3015188c4b9SDmitri Gribenko default: 3025188c4b9SDmitri Gribenko break; 3035188c4b9SDmitri Gribenko 3045188c4b9SDmitri Gribenko case '\\': case '@': case '&': case '$': 3055188c4b9SDmitri Gribenko case '#': case '<': case '>': case '%': 3065188c4b9SDmitri Gribenko case '\"': case '.': case ':': 3075188c4b9SDmitri Gribenko // This is one of \\ \@ \& \$ etc escape sequences. 3085188c4b9SDmitri Gribenko TokenPtr++; 3095188c4b9SDmitri Gribenko if (C == ':' && TokenPtr != CommentEnd && *TokenPtr == ':') { 3105188c4b9SDmitri Gribenko // This is the \:: escape sequence. 3115188c4b9SDmitri Gribenko TokenPtr++; 3125188c4b9SDmitri Gribenko } 31360ddd8a1SDmitri Gribenko StringRef UnescapedText(BufferPtr + 1, TokenPtr - (BufferPtr + 1)); 3145188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 31560ddd8a1SDmitri Gribenko T.setText(UnescapedText); 3165188c4b9SDmitri Gribenko return; 3175188c4b9SDmitri Gribenko } 3185188c4b9SDmitri Gribenko 3195188c4b9SDmitri Gribenko // Don't make zero-length commands. 3205188c4b9SDmitri Gribenko if (!isCommandNameCharacter(*TokenPtr)) { 32160ddd8a1SDmitri Gribenko StringRef Text(BufferPtr, TokenPtr - BufferPtr); 3225188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 32360ddd8a1SDmitri Gribenko T.setText(Text); 3245188c4b9SDmitri Gribenko return; 3255188c4b9SDmitri Gribenko } 3265188c4b9SDmitri Gribenko 3275188c4b9SDmitri Gribenko TokenPtr = skipCommandName(TokenPtr, CommentEnd); 3285188c4b9SDmitri Gribenko unsigned Length = TokenPtr - (BufferPtr + 1); 3295188c4b9SDmitri Gribenko 3305188c4b9SDmitri Gribenko // Hardcoded support for lexing LaTeX formula commands 3315188c4b9SDmitri Gribenko // \f$ \f[ \f] \f{ \f} as a single command. 3325188c4b9SDmitri Gribenko if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) { 3335188c4b9SDmitri Gribenko C = *TokenPtr; 3345188c4b9SDmitri Gribenko if (C == '$' || C == '[' || C == ']' || C == '{' || C == '}') { 3355188c4b9SDmitri Gribenko TokenPtr++; 3365188c4b9SDmitri Gribenko Length++; 3375188c4b9SDmitri Gribenko } 3385188c4b9SDmitri Gribenko } 3395188c4b9SDmitri Gribenko 3405188c4b9SDmitri Gribenko const StringRef CommandName(BufferPtr + 1, Length); 3415188c4b9SDmitri Gribenko StringRef EndName; 3425188c4b9SDmitri Gribenko 3435188c4b9SDmitri Gribenko if (isVerbatimBlockCommand(CommandName, EndName)) { 3445188c4b9SDmitri Gribenko setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, EndName); 3455188c4b9SDmitri Gribenko return; 3465188c4b9SDmitri Gribenko } 3475188c4b9SDmitri Gribenko if (isVerbatimLineCommand(CommandName)) { 3481669f702SDmitri Gribenko setupAndLexVerbatimLine(T, TokenPtr); 3495188c4b9SDmitri Gribenko return; 3505188c4b9SDmitri Gribenko } 3515188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::command); 3525188c4b9SDmitri Gribenko T.setCommandName(CommandName); 3535188c4b9SDmitri Gribenko return; 3545188c4b9SDmitri Gribenko } 3555188c4b9SDmitri Gribenko 3565188c4b9SDmitri Gribenko case '<': { 3575188c4b9SDmitri Gribenko TokenPtr++; 3585188c4b9SDmitri Gribenko if (TokenPtr == CommentEnd) { 35960ddd8a1SDmitri Gribenko StringRef Text(BufferPtr, TokenPtr - BufferPtr); 3605188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 36160ddd8a1SDmitri Gribenko T.setText(Text); 3625188c4b9SDmitri Gribenko return; 3635188c4b9SDmitri Gribenko } 3645188c4b9SDmitri Gribenko const char C = *TokenPtr; 36517709ae8SDmitri Gribenko if (isHTMLIdentifierStartingCharacter(C)) 3665188c4b9SDmitri Gribenko setupAndLexHTMLOpenTag(T); 3675188c4b9SDmitri Gribenko else if (C == '/') 368ec92531cSDmitri Gribenko setupAndLexHTMLCloseTag(T); 369632d58afSDmitri Gribenko else { 370632d58afSDmitri Gribenko StringRef Text(BufferPtr, TokenPtr - BufferPtr); 371632d58afSDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 372632d58afSDmitri Gribenko T.setText(Text); 373632d58afSDmitri Gribenko } 3745188c4b9SDmitri Gribenko return; 3755188c4b9SDmitri Gribenko } 3765188c4b9SDmitri Gribenko 3775188c4b9SDmitri Gribenko case '\n': 3785188c4b9SDmitri Gribenko case '\r': 3795188c4b9SDmitri Gribenko TokenPtr = skipNewline(TokenPtr, CommentEnd); 3805188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::newline); 3815188c4b9SDmitri Gribenko 3825188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) 3835188c4b9SDmitri Gribenko skipLineStartingDecorations(); 3845188c4b9SDmitri Gribenko return; 3855188c4b9SDmitri Gribenko 3865188c4b9SDmitri Gribenko default: { 3875188c4b9SDmitri Gribenko while (true) { 3885188c4b9SDmitri Gribenko TokenPtr++; 3895188c4b9SDmitri Gribenko if (TokenPtr == CommentEnd) 3905188c4b9SDmitri Gribenko break; 39117709ae8SDmitri Gribenko const char C = *TokenPtr; 3925188c4b9SDmitri Gribenko if(C == '\n' || C == '\r' || 3935188c4b9SDmitri Gribenko C == '\\' || C == '@' || C == '<') 3945188c4b9SDmitri Gribenko break; 3955188c4b9SDmitri Gribenko } 39660ddd8a1SDmitri Gribenko StringRef Text(BufferPtr, TokenPtr - BufferPtr); 3975188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 39860ddd8a1SDmitri Gribenko T.setText(Text); 3995188c4b9SDmitri Gribenko return; 4005188c4b9SDmitri Gribenko } 4015188c4b9SDmitri Gribenko } 4025188c4b9SDmitri Gribenko } 4035188c4b9SDmitri Gribenko } 4045188c4b9SDmitri Gribenko 4055188c4b9SDmitri Gribenko void Lexer::setupAndLexVerbatimBlock(Token &T, 4065188c4b9SDmitri Gribenko const char *TextBegin, 4075188c4b9SDmitri Gribenko char Marker, StringRef EndName) { 4085188c4b9SDmitri Gribenko VerbatimBlockEndCommandName.clear(); 4095188c4b9SDmitri Gribenko VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@"); 4105188c4b9SDmitri Gribenko VerbatimBlockEndCommandName.append(EndName); 4115188c4b9SDmitri Gribenko 41260ddd8a1SDmitri Gribenko StringRef Name(BufferPtr + 1, TextBegin - (BufferPtr + 1)); 4135188c4b9SDmitri Gribenko formTokenWithChars(T, TextBegin, tok::verbatim_block_begin); 41460ddd8a1SDmitri Gribenko T.setVerbatimBlockName(Name); 4155188c4b9SDmitri Gribenko 416ec92531cSDmitri Gribenko // If there is a newline following the verbatim opening command, skip the 417ec92531cSDmitri Gribenko // newline so that we don't create an tok::verbatim_block_line with empty 418ec92531cSDmitri Gribenko // text content. 419ec92531cSDmitri Gribenko if (BufferPtr != CommentEnd) { 420ec92531cSDmitri Gribenko const char C = *BufferPtr; 421ec92531cSDmitri Gribenko if (C == '\n' || C == '\r') { 422ec92531cSDmitri Gribenko BufferPtr = skipNewline(BufferPtr, CommentEnd); 423ec92531cSDmitri Gribenko State = LS_VerbatimBlockBody; 424ec92531cSDmitri Gribenko return; 425ec92531cSDmitri Gribenko } 426ec92531cSDmitri Gribenko } 427ec92531cSDmitri Gribenko 4285188c4b9SDmitri Gribenko State = LS_VerbatimBlockFirstLine; 4295188c4b9SDmitri Gribenko } 4305188c4b9SDmitri Gribenko 4315188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockFirstLine(Token &T) { 4325188c4b9SDmitri Gribenko assert(BufferPtr < CommentEnd); 4335188c4b9SDmitri Gribenko 4345188c4b9SDmitri Gribenko // FIXME: It would be better to scan the text once, finding either the block 4355188c4b9SDmitri Gribenko // end command or newline. 4365188c4b9SDmitri Gribenko // 4375188c4b9SDmitri Gribenko // Extract current line. 4385188c4b9SDmitri Gribenko const char *Newline = findNewline(BufferPtr, CommentEnd); 4395188c4b9SDmitri Gribenko StringRef Line(BufferPtr, Newline - BufferPtr); 4405188c4b9SDmitri Gribenko 4415188c4b9SDmitri Gribenko // Look for end command in current line. 4425188c4b9SDmitri Gribenko size_t Pos = Line.find(VerbatimBlockEndCommandName); 443ec92531cSDmitri Gribenko const char *TextEnd; 4445188c4b9SDmitri Gribenko const char *NextLine; 4455188c4b9SDmitri Gribenko if (Pos == StringRef::npos) { 4465188c4b9SDmitri Gribenko // Current line is completely verbatim. 447ec92531cSDmitri Gribenko TextEnd = Newline; 4485188c4b9SDmitri Gribenko NextLine = skipNewline(Newline, CommentEnd); 4495188c4b9SDmitri Gribenko } else if (Pos == 0) { 4505188c4b9SDmitri Gribenko // Current line contains just an end command. 4515188c4b9SDmitri Gribenko const char *End = BufferPtr + VerbatimBlockEndCommandName.size(); 45260ddd8a1SDmitri Gribenko StringRef Name(BufferPtr + 1, End - (BufferPtr + 1)); 4535188c4b9SDmitri Gribenko formTokenWithChars(T, End, tok::verbatim_block_end); 45460ddd8a1SDmitri Gribenko T.setVerbatimBlockName(Name); 4555188c4b9SDmitri Gribenko State = LS_Normal; 4565188c4b9SDmitri Gribenko return; 4575188c4b9SDmitri Gribenko } else { 4585188c4b9SDmitri Gribenko // There is some text, followed by end command. Extract text first. 459ec92531cSDmitri Gribenko TextEnd = BufferPtr + Pos; 460ec92531cSDmitri Gribenko NextLine = TextEnd; 4615188c4b9SDmitri Gribenko } 4625188c4b9SDmitri Gribenko 463ec92531cSDmitri Gribenko StringRef Text(BufferPtr, TextEnd - BufferPtr); 4645188c4b9SDmitri Gribenko formTokenWithChars(T, NextLine, tok::verbatim_block_line); 46560ddd8a1SDmitri Gribenko T.setVerbatimBlockText(Text); 4665188c4b9SDmitri Gribenko 4675188c4b9SDmitri Gribenko State = LS_VerbatimBlockBody; 4685188c4b9SDmitri Gribenko } 4695188c4b9SDmitri Gribenko 4705188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockBody(Token &T) { 4715188c4b9SDmitri Gribenko assert(State == LS_VerbatimBlockBody); 4725188c4b9SDmitri Gribenko 4735188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) 4745188c4b9SDmitri Gribenko skipLineStartingDecorations(); 4755188c4b9SDmitri Gribenko 4765188c4b9SDmitri Gribenko lexVerbatimBlockFirstLine(T); 4775188c4b9SDmitri Gribenko } 4785188c4b9SDmitri Gribenko 4791669f702SDmitri Gribenko void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin) { 4801669f702SDmitri Gribenko const StringRef Name(BufferPtr + 1, TextBegin - BufferPtr - 1); 4811669f702SDmitri Gribenko formTokenWithChars(T, TextBegin, tok::verbatim_line_name); 4821669f702SDmitri Gribenko T.setVerbatimLineName(Name); 4831669f702SDmitri Gribenko 4841669f702SDmitri Gribenko State = LS_VerbatimLineText; 4851669f702SDmitri Gribenko } 4861669f702SDmitri Gribenko 4871669f702SDmitri Gribenko void Lexer::lexVerbatimLineText(Token &T) { 4881669f702SDmitri Gribenko assert(State == LS_VerbatimLineText); 4891669f702SDmitri Gribenko 4905188c4b9SDmitri Gribenko // Extract current line. 4915188c4b9SDmitri Gribenko const char *Newline = findNewline(BufferPtr, CommentEnd); 4921669f702SDmitri Gribenko const StringRef Text(BufferPtr, Newline - BufferPtr); 4931669f702SDmitri Gribenko formTokenWithChars(T, Newline, tok::verbatim_line_text); 4945188c4b9SDmitri Gribenko T.setVerbatimLineText(Text); 4951669f702SDmitri Gribenko 4961669f702SDmitri Gribenko State = LS_Normal; 4975188c4b9SDmitri Gribenko } 4985188c4b9SDmitri Gribenko 4995188c4b9SDmitri Gribenko void Lexer::setupAndLexHTMLOpenTag(Token &T) { 50017709ae8SDmitri Gribenko assert(BufferPtr[0] == '<' && 50117709ae8SDmitri Gribenko isHTMLIdentifierStartingCharacter(BufferPtr[1])); 5025188c4b9SDmitri Gribenko const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd); 5035188c4b9SDmitri Gribenko 50460ddd8a1SDmitri Gribenko StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1)); 5055188c4b9SDmitri Gribenko formTokenWithChars(T, TagNameEnd, tok::html_tag_open); 50660ddd8a1SDmitri Gribenko T.setHTMLTagOpenName(Name); 5075188c4b9SDmitri Gribenko 5085188c4b9SDmitri Gribenko BufferPtr = skipWhitespace(BufferPtr, CommentEnd); 5095188c4b9SDmitri Gribenko 51017709ae8SDmitri Gribenko const char C = *BufferPtr; 51117709ae8SDmitri Gribenko if (BufferPtr != CommentEnd && 512*f26054f0SDmitri Gribenko (C == '>' || C == '/' || isHTMLIdentifierStartingCharacter(C))) 5135188c4b9SDmitri Gribenko State = LS_HTMLOpenTag; 5145188c4b9SDmitri Gribenko } 5155188c4b9SDmitri Gribenko 5165188c4b9SDmitri Gribenko void Lexer::lexHTMLOpenTag(Token &T) { 5175188c4b9SDmitri Gribenko assert(State == LS_HTMLOpenTag); 5185188c4b9SDmitri Gribenko 5195188c4b9SDmitri Gribenko const char *TokenPtr = BufferPtr; 5205188c4b9SDmitri Gribenko char C = *TokenPtr; 5215188c4b9SDmitri Gribenko if (isHTMLIdentifierCharacter(C)) { 5225188c4b9SDmitri Gribenko TokenPtr = skipHTMLIdentifier(TokenPtr, CommentEnd); 52360ddd8a1SDmitri Gribenko StringRef Ident(BufferPtr, TokenPtr - BufferPtr); 5245188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_ident); 52560ddd8a1SDmitri Gribenko T.setHTMLIdent(Ident); 5265188c4b9SDmitri Gribenko } else { 5275188c4b9SDmitri Gribenko switch (C) { 5285188c4b9SDmitri Gribenko case '=': 5295188c4b9SDmitri Gribenko TokenPtr++; 5305188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_equals); 5315188c4b9SDmitri Gribenko break; 5325188c4b9SDmitri Gribenko case '\"': 5335188c4b9SDmitri Gribenko case '\'': { 5345188c4b9SDmitri Gribenko const char *OpenQuote = TokenPtr; 5355188c4b9SDmitri Gribenko TokenPtr = skipHTMLQuotedString(TokenPtr, CommentEnd); 5365188c4b9SDmitri Gribenko const char *ClosingQuote = TokenPtr; 5375188c4b9SDmitri Gribenko if (TokenPtr != CommentEnd) // Skip closing quote. 5385188c4b9SDmitri Gribenko TokenPtr++; 5395188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_quoted_string); 5405188c4b9SDmitri Gribenko T.setHTMLQuotedString(StringRef(OpenQuote + 1, 5415188c4b9SDmitri Gribenko ClosingQuote - (OpenQuote + 1))); 5425188c4b9SDmitri Gribenko break; 5435188c4b9SDmitri Gribenko } 5445188c4b9SDmitri Gribenko case '>': 5455188c4b9SDmitri Gribenko TokenPtr++; 5465188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_greater); 54717709ae8SDmitri Gribenko State = LS_Normal; 54817709ae8SDmitri Gribenko return; 549*f26054f0SDmitri Gribenko case '/': 550*f26054f0SDmitri Gribenko TokenPtr++; 551*f26054f0SDmitri Gribenko if (TokenPtr != CommentEnd && *TokenPtr == '>') { 552*f26054f0SDmitri Gribenko TokenPtr++; 553*f26054f0SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_slash_greater); 554*f26054f0SDmitri Gribenko } else { 555*f26054f0SDmitri Gribenko StringRef Text(BufferPtr, TokenPtr - BufferPtr); 556*f26054f0SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 557*f26054f0SDmitri Gribenko T.setText(Text); 558*f26054f0SDmitri Gribenko } 559*f26054f0SDmitri Gribenko State = LS_Normal; 560*f26054f0SDmitri Gribenko return; 5615188c4b9SDmitri Gribenko } 5625188c4b9SDmitri Gribenko } 5635188c4b9SDmitri Gribenko 5645188c4b9SDmitri Gribenko // Now look ahead and return to normal state if we don't see any HTML tokens 5655188c4b9SDmitri Gribenko // ahead. 5665188c4b9SDmitri Gribenko BufferPtr = skipWhitespace(BufferPtr, CommentEnd); 5675188c4b9SDmitri Gribenko if (BufferPtr == CommentEnd) { 5685188c4b9SDmitri Gribenko State = LS_Normal; 5695188c4b9SDmitri Gribenko return; 5705188c4b9SDmitri Gribenko } 5715188c4b9SDmitri Gribenko 5725188c4b9SDmitri Gribenko C = *BufferPtr; 57317709ae8SDmitri Gribenko if (!isHTMLIdentifierStartingCharacter(C) && 5745188c4b9SDmitri Gribenko C != '=' && C != '\"' && C != '\'' && C != '>') { 5755188c4b9SDmitri Gribenko State = LS_Normal; 5765188c4b9SDmitri Gribenko return; 5775188c4b9SDmitri Gribenko } 5785188c4b9SDmitri Gribenko } 5795188c4b9SDmitri Gribenko 580ec92531cSDmitri Gribenko void Lexer::setupAndLexHTMLCloseTag(Token &T) { 5815188c4b9SDmitri Gribenko assert(BufferPtr[0] == '<' && BufferPtr[1] == '/'); 5825188c4b9SDmitri Gribenko 5835188c4b9SDmitri Gribenko const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd); 5845188c4b9SDmitri Gribenko const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd); 5855188c4b9SDmitri Gribenko 5865188c4b9SDmitri Gribenko const char *End = skipWhitespace(TagNameEnd, CommentEnd); 5875188c4b9SDmitri Gribenko 5885188c4b9SDmitri Gribenko formTokenWithChars(T, End, tok::html_tag_close); 5895188c4b9SDmitri Gribenko T.setHTMLTagCloseName(StringRef(TagNameBegin, TagNameEnd - TagNameBegin)); 590ec92531cSDmitri Gribenko 591ec92531cSDmitri Gribenko if (BufferPtr != CommentEnd && *BufferPtr == '>') 592ec92531cSDmitri Gribenko State = LS_HTMLCloseTag; 593ec92531cSDmitri Gribenko } 594ec92531cSDmitri Gribenko 595ec92531cSDmitri Gribenko void Lexer::lexHTMLCloseTag(Token &T) { 596ec92531cSDmitri Gribenko assert(BufferPtr != CommentEnd && *BufferPtr == '>'); 597ec92531cSDmitri Gribenko 598ec92531cSDmitri Gribenko formTokenWithChars(T, BufferPtr + 1, tok::html_greater); 599ec92531cSDmitri Gribenko State = LS_Normal; 6005188c4b9SDmitri Gribenko } 6015188c4b9SDmitri Gribenko 6025188c4b9SDmitri Gribenko Lexer::Lexer(SourceLocation FileLoc, const CommentOptions &CommOpts, 6035188c4b9SDmitri Gribenko const char *BufferStart, const char *BufferEnd): 6045188c4b9SDmitri Gribenko BufferStart(BufferStart), BufferEnd(BufferEnd), 6055188c4b9SDmitri Gribenko FileLoc(FileLoc), CommOpts(CommOpts), BufferPtr(BufferStart), 6065188c4b9SDmitri Gribenko CommentState(LCS_BeforeComment), State(LS_Normal) { 6075188c4b9SDmitri Gribenko } 6085188c4b9SDmitri Gribenko 6095188c4b9SDmitri Gribenko void Lexer::lex(Token &T) { 6105188c4b9SDmitri Gribenko again: 6115188c4b9SDmitri Gribenko switch (CommentState) { 6125188c4b9SDmitri Gribenko case LCS_BeforeComment: 6135188c4b9SDmitri Gribenko if (BufferPtr == BufferEnd) { 6145188c4b9SDmitri Gribenko formTokenWithChars(T, BufferPtr, tok::eof); 6155188c4b9SDmitri Gribenko return; 6165188c4b9SDmitri Gribenko } 6175188c4b9SDmitri Gribenko 6185188c4b9SDmitri Gribenko assert(*BufferPtr == '/'); 6195188c4b9SDmitri Gribenko BufferPtr++; // Skip first slash. 6205188c4b9SDmitri Gribenko switch(*BufferPtr) { 6215188c4b9SDmitri Gribenko case '/': { // BCPL comment. 6225188c4b9SDmitri Gribenko BufferPtr++; // Skip second slash. 6235188c4b9SDmitri Gribenko 6245188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd) { 6255188c4b9SDmitri Gribenko // Skip Doxygen magic marker, if it is present. 6265188c4b9SDmitri Gribenko // It might be missing because of a typo //< or /*<, or because we 6275188c4b9SDmitri Gribenko // merged this non-Doxygen comment into a bunch of Doxygen comments 6285188c4b9SDmitri Gribenko // around it: /** ... */ /* ... */ /** ... */ 6295188c4b9SDmitri Gribenko const char C = *BufferPtr; 6305188c4b9SDmitri Gribenko if (C == '/' || C == '!') 6315188c4b9SDmitri Gribenko BufferPtr++; 6325188c4b9SDmitri Gribenko } 6335188c4b9SDmitri Gribenko 6345188c4b9SDmitri Gribenko // Skip less-than symbol that marks trailing comments. 6355188c4b9SDmitri Gribenko // Skip it even if the comment is not a Doxygen one, because //< and /*< 6365188c4b9SDmitri Gribenko // are frequent typos. 6375188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '<') 6385188c4b9SDmitri Gribenko BufferPtr++; 6395188c4b9SDmitri Gribenko 6405188c4b9SDmitri Gribenko CommentState = LCS_InsideBCPLComment; 641ec92531cSDmitri Gribenko if (State != LS_VerbatimBlockBody && State != LS_VerbatimBlockFirstLine) 6425188c4b9SDmitri Gribenko State = LS_Normal; 6435188c4b9SDmitri Gribenko CommentEnd = findBCPLCommentEnd(BufferPtr, BufferEnd); 6445188c4b9SDmitri Gribenko goto again; 6455188c4b9SDmitri Gribenko } 6465188c4b9SDmitri Gribenko case '*': { // C comment. 6475188c4b9SDmitri Gribenko BufferPtr++; // Skip star. 6485188c4b9SDmitri Gribenko 6495188c4b9SDmitri Gribenko // Skip Doxygen magic marker. 6505188c4b9SDmitri Gribenko const char C = *BufferPtr; 6515188c4b9SDmitri Gribenko if ((C == '*' && *(BufferPtr + 1) != '/') || C == '!') 6525188c4b9SDmitri Gribenko BufferPtr++; 6535188c4b9SDmitri Gribenko 6545188c4b9SDmitri Gribenko // Skip less-than symbol that marks trailing comments. 6555188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '<') 6565188c4b9SDmitri Gribenko BufferPtr++; 6575188c4b9SDmitri Gribenko 6585188c4b9SDmitri Gribenko CommentState = LCS_InsideCComment; 6595188c4b9SDmitri Gribenko State = LS_Normal; 6605188c4b9SDmitri Gribenko CommentEnd = findCCommentEnd(BufferPtr, BufferEnd); 6615188c4b9SDmitri Gribenko goto again; 6625188c4b9SDmitri Gribenko } 6635188c4b9SDmitri Gribenko default: 6645188c4b9SDmitri Gribenko llvm_unreachable("second character of comment should be '/' or '*'"); 6655188c4b9SDmitri Gribenko } 6665188c4b9SDmitri Gribenko 6675188c4b9SDmitri Gribenko case LCS_BetweenComments: { 6685188c4b9SDmitri Gribenko // Consecutive comments are extracted only if there is only whitespace 6695188c4b9SDmitri Gribenko // between them. So we can search for the start of the next comment. 6705188c4b9SDmitri Gribenko const char *EndWhitespace = BufferPtr; 6715188c4b9SDmitri Gribenko while(EndWhitespace != BufferEnd && *EndWhitespace != '/') 6725188c4b9SDmitri Gribenko EndWhitespace++; 6735188c4b9SDmitri Gribenko 6745188c4b9SDmitri Gribenko // Turn any whitespace between comments (and there is only whitespace 67517709ae8SDmitri Gribenko // between them -- guaranteed by comment extraction) into a newline. We 67617709ae8SDmitri Gribenko // have two newlines between C comments in total (first one was synthesized 67717709ae8SDmitri Gribenko // after a comment). 6785188c4b9SDmitri Gribenko formTokenWithChars(T, EndWhitespace, tok::newline); 6795188c4b9SDmitri Gribenko 6805188c4b9SDmitri Gribenko CommentState = LCS_BeforeComment; 6815188c4b9SDmitri Gribenko break; 6825188c4b9SDmitri Gribenko } 6835188c4b9SDmitri Gribenko 6845188c4b9SDmitri Gribenko case LCS_InsideBCPLComment: 6855188c4b9SDmitri Gribenko case LCS_InsideCComment: 6865188c4b9SDmitri Gribenko if (BufferPtr != CommentEnd) { 6875188c4b9SDmitri Gribenko lexCommentText(T); 6885188c4b9SDmitri Gribenko break; 6895188c4b9SDmitri Gribenko } else { 6905188c4b9SDmitri Gribenko // Skip C comment closing sequence. 6915188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) { 6925188c4b9SDmitri Gribenko assert(BufferPtr[0] == '*' && BufferPtr[1] == '/'); 6935188c4b9SDmitri Gribenko BufferPtr += 2; 6945188c4b9SDmitri Gribenko assert(BufferPtr <= BufferEnd); 6955188c4b9SDmitri Gribenko 6965188c4b9SDmitri Gribenko // Synthenize newline just after the C comment, regardless if there is 6975188c4b9SDmitri Gribenko // actually a newline. 6985188c4b9SDmitri Gribenko formTokenWithChars(T, BufferPtr, tok::newline); 6995188c4b9SDmitri Gribenko 7005188c4b9SDmitri Gribenko CommentState = LCS_BetweenComments; 7015188c4b9SDmitri Gribenko break; 7025188c4b9SDmitri Gribenko } else { 7035188c4b9SDmitri Gribenko // Don't synthesized a newline after BCPL comment. 7045188c4b9SDmitri Gribenko CommentState = LCS_BetweenComments; 7055188c4b9SDmitri Gribenko goto again; 7065188c4b9SDmitri Gribenko } 7075188c4b9SDmitri Gribenko } 7085188c4b9SDmitri Gribenko } 7095188c4b9SDmitri Gribenko } 7105188c4b9SDmitri Gribenko 7115188c4b9SDmitri Gribenko StringRef Lexer::getSpelling(const Token &Tok, 7125188c4b9SDmitri Gribenko const SourceManager &SourceMgr, 7135188c4b9SDmitri Gribenko bool *Invalid) const { 7145188c4b9SDmitri Gribenko SourceLocation Loc = Tok.getLocation(); 7155188c4b9SDmitri Gribenko std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(Loc); 7165188c4b9SDmitri Gribenko 7175188c4b9SDmitri Gribenko bool InvalidTemp = false; 7185188c4b9SDmitri Gribenko StringRef File = SourceMgr.getBufferData(LocInfo.first, &InvalidTemp); 7195188c4b9SDmitri Gribenko if (InvalidTemp) { 7205188c4b9SDmitri Gribenko *Invalid = true; 7215188c4b9SDmitri Gribenko return StringRef(); 7225188c4b9SDmitri Gribenko } 7235188c4b9SDmitri Gribenko 7245188c4b9SDmitri Gribenko const char *Begin = File.data() + LocInfo.second; 7255188c4b9SDmitri Gribenko return StringRef(Begin, Tok.getLength()); 7265188c4b9SDmitri Gribenko } 7275188c4b9SDmitri Gribenko 7285188c4b9SDmitri Gribenko void Lexer::addVerbatimBlockCommand(StringRef BeginName, StringRef EndName) { 7295188c4b9SDmitri Gribenko VerbatimBlockCommand VBC; 7305188c4b9SDmitri Gribenko VBC.BeginName = BeginName; 7315188c4b9SDmitri Gribenko VBC.EndName = EndName; 7325188c4b9SDmitri Gribenko VerbatimBlockCommands.push_back(VBC); 7335188c4b9SDmitri Gribenko } 7345188c4b9SDmitri Gribenko 7355188c4b9SDmitri Gribenko void Lexer::addVerbatimLineCommand(StringRef Name) { 7365188c4b9SDmitri Gribenko VerbatimLineCommand VLC; 7375188c4b9SDmitri Gribenko VLC.Name = Name; 7385188c4b9SDmitri Gribenko VerbatimLineCommands.push_back(VLC); 7395188c4b9SDmitri Gribenko } 7405188c4b9SDmitri Gribenko 7415188c4b9SDmitri Gribenko } // end namespace comments 7425188c4b9SDmitri Gribenko } // end namespace clang 7435188c4b9SDmitri Gribenko 744