15188c4b9SDmitri Gribenko #include "clang/AST/CommentLexer.h" 2ca7f80adSDmitri Gribenko #include "clang/AST/CommentCommandTraits.h" 3b2e5482bSDmitri Gribenko #include "llvm/ADT/StringExtras.h" 45188c4b9SDmitri Gribenko #include "llvm/ADT/StringSwitch.h" 5*9feeef40SDmitri Gribenko #include "llvm/Support/ConvertUTF.h" 65188c4b9SDmitri Gribenko #include "llvm/Support/ErrorHandling.h" 75188c4b9SDmitri Gribenko 85188c4b9SDmitri Gribenko namespace clang { 95188c4b9SDmitri Gribenko namespace comments { 105188c4b9SDmitri Gribenko 115188c4b9SDmitri Gribenko void Token::dump(const Lexer &L, const SourceManager &SM) const { 125188c4b9SDmitri Gribenko llvm::errs() << "comments::Token Kind=" << Kind << " "; 135188c4b9SDmitri Gribenko Loc.dump(SM); 145188c4b9SDmitri Gribenko llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n"; 155188c4b9SDmitri Gribenko } 165188c4b9SDmitri Gribenko 174586df76SDmitri Gribenko namespace { 184586df76SDmitri Gribenko bool isHTMLNamedCharacterReferenceCharacter(char C) { 194586df76SDmitri Gribenko return (C >= 'a' && C <= 'z') || 204586df76SDmitri Gribenko (C >= 'A' && C <= 'Z'); 214586df76SDmitri Gribenko } 224586df76SDmitri Gribenko 234586df76SDmitri Gribenko bool isHTMLDecimalCharacterReferenceCharacter(char C) { 244586df76SDmitri Gribenko return C >= '0' && C <= '9'; 254586df76SDmitri Gribenko } 264586df76SDmitri Gribenko 274586df76SDmitri Gribenko bool isHTMLHexCharacterReferenceCharacter(char C) { 284586df76SDmitri Gribenko return (C >= '0' && C <= '9') || 294586df76SDmitri Gribenko (C >= 'a' && C <= 'f') || 304586df76SDmitri Gribenko (C >= 'A' && C <= 'F'); 314586df76SDmitri Gribenko } 32107618a6SDmitri Gribenko 333ca956f7SDmitri Gribenko #include "clang/AST/CommentHTMLTags.inc" 343ca956f7SDmitri Gribenko 354586df76SDmitri Gribenko } // unnamed namespace 364586df76SDmitri Gribenko 377b3ae190SFariborz Jahanian static unsigned getCodePoint(StringRef Name) { 384586df76SDmitri Gribenko unsigned CodePoint = 0; 394586df76SDmitri Gribenko for (unsigned i = 0, e = Name.size(); i != e; ++i) { 407b3ae190SFariborz Jahanian CodePoint *= 16; 417b3ae190SFariborz Jahanian const char C = Name[i]; 427b3ae190SFariborz Jahanian assert(isHTMLHexCharacterReferenceCharacter(C)); 437b3ae190SFariborz Jahanian CodePoint += llvm::hexDigitValue(C); 447b3ae190SFariborz Jahanian } 457b3ae190SFariborz Jahanian return CodePoint; 464586df76SDmitri Gribenko } 474586df76SDmitri Gribenko 487b3ae190SFariborz Jahanian StringRef Lexer::helperResolveHTMLHexCharacterReference(unsigned CodePoint) const { 494586df76SDmitri Gribenko char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT); 504586df76SDmitri Gribenko char *ResolvedPtr = Resolved; 51*9feeef40SDmitri Gribenko if (llvm::ConvertCodePointToUTF8(CodePoint, ResolvedPtr)) 524586df76SDmitri Gribenko return StringRef(Resolved, ResolvedPtr - Resolved); 534586df76SDmitri Gribenko else 544586df76SDmitri Gribenko return StringRef(); 554586df76SDmitri Gribenko } 564586df76SDmitri Gribenko 574586df76SDmitri Gribenko StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const { 587b3ae190SFariborz Jahanian unsigned CodePoint = getCodePoint(Name); 597b3ae190SFariborz Jahanian return helperResolveHTMLHexCharacterReference(CodePoint); 607b3ae190SFariborz Jahanian } 617b3ae190SFariborz Jahanian 627b3ae190SFariborz Jahanian StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const { 637b3ae190SFariborz Jahanian return llvm::StringSwitch<StringRef>(Name) 647b3ae190SFariborz Jahanian .Case("amp", "&") 657b3ae190SFariborz Jahanian .Case("lt", "<") 667b3ae190SFariborz Jahanian .Case("gt", ">") 677b3ae190SFariborz Jahanian .Case("quot", "\"") 687b3ae190SFariborz Jahanian .Case("apos", "\'") 697b3ae190SFariborz Jahanian .Default(""); 707b3ae190SFariborz Jahanian } 717b3ae190SFariborz Jahanian 727b3ae190SFariborz Jahanian StringRef Lexer::HTMLDoxygenCharacterReference(StringRef Name) const { 737b3ae190SFariborz Jahanian return llvm::StringSwitch<StringRef>(Name) 747b3ae190SFariborz Jahanian .Case("copy", helperResolveHTMLHexCharacterReference(0x000A9)) 757b3ae190SFariborz Jahanian .Case("trade", helperResolveHTMLHexCharacterReference(0x02122)) 767b3ae190SFariborz Jahanian .Case("reg", helperResolveHTMLHexCharacterReference(0x000AE)) 777b3ae190SFariborz Jahanian .Case("lt", helperResolveHTMLHexCharacterReference(0x0003C)) 787b3ae190SFariborz Jahanian .Case("gt", helperResolveHTMLHexCharacterReference(0x0003C)) 797b3ae190SFariborz Jahanian .Case("amp", helperResolveHTMLHexCharacterReference(0x00026)) 807b3ae190SFariborz Jahanian .Case("apos", helperResolveHTMLHexCharacterReference(0x00027)) 817b3ae190SFariborz Jahanian .Case("quot", helperResolveHTMLHexCharacterReference(0x00022)) 827b3ae190SFariborz Jahanian .Case("lsquo", helperResolveHTMLHexCharacterReference(0x02018)) 837b3ae190SFariborz Jahanian .Case("rsquo", helperResolveHTMLHexCharacterReference(0x02019)) 847b3ae190SFariborz Jahanian .Case("ldquo", helperResolveHTMLHexCharacterReference(0x0201C)) 857b3ae190SFariborz Jahanian .Case("rdquo", helperResolveHTMLHexCharacterReference(0x0201D)) 867b3ae190SFariborz Jahanian .Case("ndash", helperResolveHTMLHexCharacterReference(0x02013)) 877b3ae190SFariborz Jahanian .Case("mdash", helperResolveHTMLHexCharacterReference(0x02014)) 887b3ae190SFariborz Jahanian .Case("Auml", helperResolveHTMLHexCharacterReference(0x000C4)) 897b3ae190SFariborz Jahanian .Case("Euml", helperResolveHTMLHexCharacterReference(0x000CB)) 907b3ae190SFariborz Jahanian .Case("Iuml", helperResolveHTMLHexCharacterReference(0x000CF)) 917b3ae190SFariborz Jahanian .Case("Ouml", helperResolveHTMLHexCharacterReference(0x000D6)) 927b3ae190SFariborz Jahanian .Case("Uuml", helperResolveHTMLHexCharacterReference(0x000DC)) 937b3ae190SFariborz Jahanian .Case("Yuml", helperResolveHTMLHexCharacterReference(0x00178)) 947b3ae190SFariborz Jahanian .Case("auml", helperResolveHTMLHexCharacterReference(0x000E4)) 957b3ae190SFariborz Jahanian .Case("euml", helperResolveHTMLHexCharacterReference(0x000EB)) 967b3ae190SFariborz Jahanian .Case("iuml", helperResolveHTMLHexCharacterReference(0x000EF)) 977b3ae190SFariborz Jahanian .Case("ouml", helperResolveHTMLHexCharacterReference(0x000F6)) 987b3ae190SFariborz Jahanian .Case("uuml", helperResolveHTMLHexCharacterReference(0x000FC)) 997b3ae190SFariborz Jahanian .Case("yuml", helperResolveHTMLHexCharacterReference(0x000FF)) 1007b3ae190SFariborz Jahanian .Case("Aacute", helperResolveHTMLHexCharacterReference(0x000C1)) 1017b3ae190SFariborz Jahanian .Case("Eacute", helperResolveHTMLHexCharacterReference(0x000C9)) 1027b3ae190SFariborz Jahanian .Case("Iacute", helperResolveHTMLHexCharacterReference(0x000CD)) 1037b3ae190SFariborz Jahanian .Case("Oacute", helperResolveHTMLHexCharacterReference(0x000D3)) 1047b3ae190SFariborz Jahanian .Case("Uacute", helperResolveHTMLHexCharacterReference(0x000DA)) 1057b3ae190SFariborz Jahanian .Case("Yacute", helperResolveHTMLHexCharacterReference(0x000DD)) 1067b3ae190SFariborz Jahanian .Case("aacute", helperResolveHTMLHexCharacterReference(0x000E1)) 1077b3ae190SFariborz Jahanian .Case("eacute", helperResolveHTMLHexCharacterReference(0x000E9)) 1087b3ae190SFariborz Jahanian .Case("iacute", helperResolveHTMLHexCharacterReference(0x000ED)) 1097b3ae190SFariborz Jahanian .Case("oacute", helperResolveHTMLHexCharacterReference(0x000F3)) 1107b3ae190SFariborz Jahanian .Case("uacute", helperResolveHTMLHexCharacterReference(0x000FA)) 1117b3ae190SFariborz Jahanian .Case("yacute", helperResolveHTMLHexCharacterReference(0x000FD)) 1127b3ae190SFariborz Jahanian .Case("Agrave", helperResolveHTMLHexCharacterReference(0x000C0)) 1137b3ae190SFariborz Jahanian .Case("Egrave", helperResolveHTMLHexCharacterReference(0x000C8)) 1147b3ae190SFariborz Jahanian .Case("Igrave", helperResolveHTMLHexCharacterReference(0x000CC)) 1157b3ae190SFariborz Jahanian .Case("Ograve", helperResolveHTMLHexCharacterReference(0x000D2)) 1167b3ae190SFariborz Jahanian .Case("Ugrave", helperResolveHTMLHexCharacterReference(0x000D9)) 1177b3ae190SFariborz Jahanian .Case("agrave", helperResolveHTMLHexCharacterReference(0x000E0)) 1187b3ae190SFariborz Jahanian .Case("egrave", helperResolveHTMLHexCharacterReference(0x000E8)) 1197b3ae190SFariborz Jahanian .Case("igrave", helperResolveHTMLHexCharacterReference(0x000EC)) 1207b3ae190SFariborz Jahanian .Case("ograve", helperResolveHTMLHexCharacterReference(0x000F2)) 1217b3ae190SFariborz Jahanian .Case("ugrave", helperResolveHTMLHexCharacterReference(0x000F9)) 1227b3ae190SFariborz Jahanian .Case("ygrave", helperResolveHTMLHexCharacterReference(0x01EF3)) 1237b3ae190SFariborz Jahanian .Case("Acirc", helperResolveHTMLHexCharacterReference(0x000C2)) 1247b3ae190SFariborz Jahanian .Case("Ecirc", helperResolveHTMLHexCharacterReference(0x000CA)) 1257b3ae190SFariborz Jahanian .Case("Icirc", helperResolveHTMLHexCharacterReference(0x000CE)) 1267b3ae190SFariborz Jahanian .Case("Ocirc", helperResolveHTMLHexCharacterReference(0x000D4)) 1277b3ae190SFariborz Jahanian .Case("Ucirc", helperResolveHTMLHexCharacterReference(0x000DB)) 1287b3ae190SFariborz Jahanian .Case("acirc", helperResolveHTMLHexCharacterReference(0x000E2)) 1297b3ae190SFariborz Jahanian .Case("ecirc", helperResolveHTMLHexCharacterReference(0x000EA)) 1307b3ae190SFariborz Jahanian .Case("icirc", helperResolveHTMLHexCharacterReference(0x000EE)) 1317b3ae190SFariborz Jahanian .Case("ocirc", helperResolveHTMLHexCharacterReference(0x000F4)) 1327b3ae190SFariborz Jahanian .Case("ucirc", helperResolveHTMLHexCharacterReference(0x000FB)) 1337b3ae190SFariborz Jahanian .Case("ycirc", helperResolveHTMLHexCharacterReference(0x00177)) 1347b3ae190SFariborz Jahanian .Case("Atilde", helperResolveHTMLHexCharacterReference(0x000C3)) 1357b3ae190SFariborz Jahanian .Case("Ntilde", helperResolveHTMLHexCharacterReference(0x000D1)) 1367b3ae190SFariborz Jahanian .Case("Otilde", helperResolveHTMLHexCharacterReference(0x000D5)) 1377b3ae190SFariborz Jahanian .Case("atilde", helperResolveHTMLHexCharacterReference(0x000E3)) 1387b3ae190SFariborz Jahanian .Case("ntilde", helperResolveHTMLHexCharacterReference(0x000F1)) 1397b3ae190SFariborz Jahanian .Case("otilde", helperResolveHTMLHexCharacterReference(0x000F5)) 1407b3ae190SFariborz Jahanian .Case("szlig", helperResolveHTMLHexCharacterReference(0x000DF)) 1417b3ae190SFariborz Jahanian .Case("ccedil", helperResolveHTMLHexCharacterReference(0x000E7)) 1427b3ae190SFariborz Jahanian .Case("Ccedil", helperResolveHTMLHexCharacterReference(0x000C7)) 1437b3ae190SFariborz Jahanian .Case("aring", helperResolveHTMLHexCharacterReference(0x000E5)) 1447b3ae190SFariborz Jahanian .Case("Aring", helperResolveHTMLHexCharacterReference(0x000C5)) 1457b3ae190SFariborz Jahanian .Case("nbsp", helperResolveHTMLHexCharacterReference(0x000A0)) 1467b3ae190SFariborz Jahanian .Case("Gamma", helperResolveHTMLHexCharacterReference(0x00393)) 1477b3ae190SFariborz Jahanian .Case("Delta", helperResolveHTMLHexCharacterReference(0x00394)) 1487b3ae190SFariborz Jahanian .Case("Theta", helperResolveHTMLHexCharacterReference(0x00398)) 1497b3ae190SFariborz Jahanian .Case("Lambda", helperResolveHTMLHexCharacterReference(0x0039B)) 1507b3ae190SFariborz Jahanian .Case("Xi", helperResolveHTMLHexCharacterReference(0x0039E)) 1517b3ae190SFariborz Jahanian .Case("Pi", helperResolveHTMLHexCharacterReference(0x003A0)) 1527b3ae190SFariborz Jahanian .Case("Sigma", helperResolveHTMLHexCharacterReference(0x003A3)) 1537b3ae190SFariborz Jahanian .Case("Upsilon", helperResolveHTMLHexCharacterReference(0x003A5)) 1547b3ae190SFariborz Jahanian .Case("Phi", helperResolveHTMLHexCharacterReference(0x003A6)) 1557b3ae190SFariborz Jahanian .Case("Psi", helperResolveHTMLHexCharacterReference(0x003A8)) 1567b3ae190SFariborz Jahanian .Case("Omega", helperResolveHTMLHexCharacterReference(0x003A9)) 1577b3ae190SFariborz Jahanian .Case("alpha", helperResolveHTMLHexCharacterReference(0x003B1)) 1587b3ae190SFariborz Jahanian .Case("beta", helperResolveHTMLHexCharacterReference(0x003B2)) 1597b3ae190SFariborz Jahanian .Case("gamma", helperResolveHTMLHexCharacterReference(0x003B3)) 1607b3ae190SFariborz Jahanian .Case("delta", helperResolveHTMLHexCharacterReference(0x003B4)) 1617b3ae190SFariborz Jahanian .Case("epsilon", helperResolveHTMLHexCharacterReference(0x003B5)) 1627b3ae190SFariborz Jahanian .Case("zeta", helperResolveHTMLHexCharacterReference(0x003B6)) 1637b3ae190SFariborz Jahanian .Case("eta", helperResolveHTMLHexCharacterReference(0x003B7)) 1647b3ae190SFariborz Jahanian .Case("theta", helperResolveHTMLHexCharacterReference(0x003B8)) 1657b3ae190SFariborz Jahanian .Case("iota", helperResolveHTMLHexCharacterReference(0x003B9)) 1667b3ae190SFariborz Jahanian .Case("kappa", helperResolveHTMLHexCharacterReference(0x003BA)) 1677b3ae190SFariborz Jahanian .Case("lambda", helperResolveHTMLHexCharacterReference(0x003BB)) 1687b3ae190SFariborz Jahanian .Case("mu", helperResolveHTMLHexCharacterReference(0x003BC)) 1697b3ae190SFariborz Jahanian .Case("nu", helperResolveHTMLHexCharacterReference(0x003BD)) 1707b3ae190SFariborz Jahanian .Case("xi", helperResolveHTMLHexCharacterReference(0x003BE)) 1717b3ae190SFariborz Jahanian .Case("pi", helperResolveHTMLHexCharacterReference(0x003C0)) 1727b3ae190SFariborz Jahanian .Case("rho", helperResolveHTMLHexCharacterReference(0x003C1)) 1737b3ae190SFariborz Jahanian .Case("sigma", helperResolveHTMLHexCharacterReference(0x003C3)) 1747b3ae190SFariborz Jahanian .Case("tau", helperResolveHTMLHexCharacterReference(0x003C4)) 1757b3ae190SFariborz Jahanian .Case("upsilon", helperResolveHTMLHexCharacterReference(0x003C5)) 1767b3ae190SFariborz Jahanian .Case("phi", helperResolveHTMLHexCharacterReference(0x003C6)) 1777b3ae190SFariborz Jahanian .Case("chi", helperResolveHTMLHexCharacterReference(0x003C7)) 1787b3ae190SFariborz Jahanian .Case("psi", helperResolveHTMLHexCharacterReference(0x003C8)) 1797b3ae190SFariborz Jahanian .Case("omega", helperResolveHTMLHexCharacterReference(0x003C9)) 1807b3ae190SFariborz Jahanian .Case("sigmaf", helperResolveHTMLHexCharacterReference(0x003C2)) 1817b3ae190SFariborz Jahanian .Case("sect", helperResolveHTMLHexCharacterReference(0x000A7)) 1827b3ae190SFariborz Jahanian .Case("deg", helperResolveHTMLHexCharacterReference(0x000B0)) 1837b3ae190SFariborz Jahanian .Case("prime", helperResolveHTMLHexCharacterReference(0x02032)) 1847b3ae190SFariborz Jahanian .Case("Prime", helperResolveHTMLHexCharacterReference(0x02033)) 1857b3ae190SFariborz Jahanian .Case("infin", helperResolveHTMLHexCharacterReference(0x0221E)) 1867b3ae190SFariborz Jahanian .Case("empty", helperResolveHTMLHexCharacterReference(0x02205)) 1877b3ae190SFariborz Jahanian .Case("plusmn", helperResolveHTMLHexCharacterReference(0x000B1)) 1887b3ae190SFariborz Jahanian .Case("times", helperResolveHTMLHexCharacterReference(0x000D7)) 1897b3ae190SFariborz Jahanian .Case("minus", helperResolveHTMLHexCharacterReference(0x02212)) 1907b3ae190SFariborz Jahanian .Case("sdot", helperResolveHTMLHexCharacterReference(0x022C5)) 1917b3ae190SFariborz Jahanian .Case("part", helperResolveHTMLHexCharacterReference(0x02202)) 1927b3ae190SFariborz Jahanian .Case("nabla", helperResolveHTMLHexCharacterReference(0x02207)) 1937b3ae190SFariborz Jahanian .Case("radic", helperResolveHTMLHexCharacterReference(0x0221A)) 1947b3ae190SFariborz Jahanian .Case("perp", helperResolveHTMLHexCharacterReference(0x022A5)) 1957b3ae190SFariborz Jahanian .Case("sum", helperResolveHTMLHexCharacterReference(0x02211)) 1967b3ae190SFariborz Jahanian .Case("int", helperResolveHTMLHexCharacterReference(0x0222B)) 1977b3ae190SFariborz Jahanian .Case("prod", helperResolveHTMLHexCharacterReference(0x0220F)) 1987b3ae190SFariborz Jahanian .Case("sim", helperResolveHTMLHexCharacterReference(0x0223C)) 1997b3ae190SFariborz Jahanian .Case("asymp", helperResolveHTMLHexCharacterReference(0x02248)) 2007b3ae190SFariborz Jahanian .Case("ne", helperResolveHTMLHexCharacterReference(0x02260)) 2017b3ae190SFariborz Jahanian .Case("equiv", helperResolveHTMLHexCharacterReference(0x02261)) 2027b3ae190SFariborz Jahanian .Case("prop", helperResolveHTMLHexCharacterReference(0x0221D)) 2037b3ae190SFariborz Jahanian .Case("le", helperResolveHTMLHexCharacterReference(0x02264)) 2047b3ae190SFariborz Jahanian .Case("ge", helperResolveHTMLHexCharacterReference(0x02265)) 2057b3ae190SFariborz Jahanian .Case("larr", helperResolveHTMLHexCharacterReference(0x02190)) 2067b3ae190SFariborz Jahanian .Case("rarr", helperResolveHTMLHexCharacterReference(0x02192)) 2077b3ae190SFariborz Jahanian .Case("isin", helperResolveHTMLHexCharacterReference(0x02208)) 2087b3ae190SFariborz Jahanian .Case("notin", helperResolveHTMLHexCharacterReference(0x02209)) 2097b3ae190SFariborz Jahanian .Case("lceil", helperResolveHTMLHexCharacterReference(0x02308)) 2107b3ae190SFariborz Jahanian .Case("rceil", helperResolveHTMLHexCharacterReference(0x02309)) 2117b3ae190SFariborz Jahanian .Case("lfloor", helperResolveHTMLHexCharacterReference(0x0230A)) 2127b3ae190SFariborz Jahanian .Case("rfloor", helperResolveHTMLHexCharacterReference(0x0230B)) 2137b3ae190SFariborz Jahanian .Default(""); 2147b3ae190SFariborz Jahanian } 2157b3ae190SFariborz Jahanian 2167b3ae190SFariborz Jahanian StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const { 2174586df76SDmitri Gribenko unsigned CodePoint = 0; 2184586df76SDmitri Gribenko for (unsigned i = 0, e = Name.size(); i != e; ++i) { 2197b3ae190SFariborz Jahanian assert(isHTMLDecimalCharacterReferenceCharacter(Name[i])); 2207b3ae190SFariborz Jahanian CodePoint *= 10; 2217b3ae190SFariborz Jahanian CodePoint += Name[i] - '0'; 2224586df76SDmitri Gribenko } 2234586df76SDmitri Gribenko 2244586df76SDmitri Gribenko char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT); 2254586df76SDmitri Gribenko char *ResolvedPtr = Resolved; 226*9feeef40SDmitri Gribenko if (llvm::ConvertCodePointToUTF8(CodePoint, ResolvedPtr)) 2274586df76SDmitri Gribenko return StringRef(Resolved, ResolvedPtr - Resolved); 2284586df76SDmitri Gribenko else 2294586df76SDmitri Gribenko return StringRef(); 2304586df76SDmitri Gribenko } 2314586df76SDmitri Gribenko 2325188c4b9SDmitri Gribenko void Lexer::skipLineStartingDecorations() { 2335188c4b9SDmitri Gribenko // This function should be called only for C comments 2345188c4b9SDmitri Gribenko assert(CommentState == LCS_InsideCComment); 2355188c4b9SDmitri Gribenko 2365188c4b9SDmitri Gribenko if (BufferPtr == CommentEnd) 2375188c4b9SDmitri Gribenko return; 2385188c4b9SDmitri Gribenko 2395188c4b9SDmitri Gribenko switch (*BufferPtr) { 2405188c4b9SDmitri Gribenko case ' ': 2415188c4b9SDmitri Gribenko case '\t': 2425188c4b9SDmitri Gribenko case '\f': 2435188c4b9SDmitri Gribenko case '\v': { 2445188c4b9SDmitri Gribenko const char *NewBufferPtr = BufferPtr; 2455188c4b9SDmitri Gribenko NewBufferPtr++; 2465188c4b9SDmitri Gribenko if (NewBufferPtr == CommentEnd) 2475188c4b9SDmitri Gribenko return; 2485188c4b9SDmitri Gribenko 2495188c4b9SDmitri Gribenko char C = *NewBufferPtr; 2505188c4b9SDmitri Gribenko while (C == ' ' || C == '\t' || C == '\f' || C == '\v') { 2515188c4b9SDmitri Gribenko NewBufferPtr++; 2525188c4b9SDmitri Gribenko if (NewBufferPtr == CommentEnd) 2535188c4b9SDmitri Gribenko return; 2545188c4b9SDmitri Gribenko C = *NewBufferPtr; 2555188c4b9SDmitri Gribenko } 2565188c4b9SDmitri Gribenko if (C == '*') 2575188c4b9SDmitri Gribenko BufferPtr = NewBufferPtr + 1; 2585188c4b9SDmitri Gribenko break; 2595188c4b9SDmitri Gribenko } 2605188c4b9SDmitri Gribenko case '*': 2615188c4b9SDmitri Gribenko BufferPtr++; 2625188c4b9SDmitri Gribenko break; 2635188c4b9SDmitri Gribenko } 2645188c4b9SDmitri Gribenko } 2655188c4b9SDmitri Gribenko 2665188c4b9SDmitri Gribenko namespace { 267ec92531cSDmitri Gribenko /// Returns pointer to the first newline character in the string. 2685188c4b9SDmitri Gribenko const char *findNewline(const char *BufferPtr, const char *BufferEnd) { 2695188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 2705188c4b9SDmitri Gribenko const char C = *BufferPtr; 2715188c4b9SDmitri Gribenko if (C == '\n' || C == '\r') 2725188c4b9SDmitri Gribenko return BufferPtr; 2735188c4b9SDmitri Gribenko } 2745188c4b9SDmitri Gribenko return BufferEnd; 2755188c4b9SDmitri Gribenko } 2765188c4b9SDmitri Gribenko 2775188c4b9SDmitri Gribenko const char *skipNewline(const char *BufferPtr, const char *BufferEnd) { 2785188c4b9SDmitri Gribenko if (BufferPtr == BufferEnd) 2795188c4b9SDmitri Gribenko return BufferPtr; 2805188c4b9SDmitri Gribenko 2815188c4b9SDmitri Gribenko if (*BufferPtr == '\n') 2825188c4b9SDmitri Gribenko BufferPtr++; 2835188c4b9SDmitri Gribenko else { 2845188c4b9SDmitri Gribenko assert(*BufferPtr == '\r'); 2855188c4b9SDmitri Gribenko BufferPtr++; 2865188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '\n') 2875188c4b9SDmitri Gribenko BufferPtr++; 2885188c4b9SDmitri Gribenko } 2895188c4b9SDmitri Gribenko return BufferPtr; 2905188c4b9SDmitri Gribenko } 2915188c4b9SDmitri Gribenko 2924586df76SDmitri Gribenko const char *skipNamedCharacterReference(const char *BufferPtr, 2934586df76SDmitri Gribenko const char *BufferEnd) { 2944586df76SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 2954586df76SDmitri Gribenko if (!isHTMLNamedCharacterReferenceCharacter(*BufferPtr)) 2964586df76SDmitri Gribenko return BufferPtr; 2974586df76SDmitri Gribenko } 2984586df76SDmitri Gribenko return BufferEnd; 2994586df76SDmitri Gribenko } 3004586df76SDmitri Gribenko 3014586df76SDmitri Gribenko const char *skipDecimalCharacterReference(const char *BufferPtr, 3024586df76SDmitri Gribenko const char *BufferEnd) { 3034586df76SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3044586df76SDmitri Gribenko if (!isHTMLDecimalCharacterReferenceCharacter(*BufferPtr)) 3054586df76SDmitri Gribenko return BufferPtr; 3064586df76SDmitri Gribenko } 3074586df76SDmitri Gribenko return BufferEnd; 3084586df76SDmitri Gribenko } 3094586df76SDmitri Gribenko 3104586df76SDmitri Gribenko const char *skipHexCharacterReference(const char *BufferPtr, 3114586df76SDmitri Gribenko const char *BufferEnd) { 3124586df76SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3134586df76SDmitri Gribenko if (!isHTMLHexCharacterReferenceCharacter(*BufferPtr)) 3144586df76SDmitri Gribenko return BufferPtr; 3154586df76SDmitri Gribenko } 3164586df76SDmitri Gribenko return BufferEnd; 3174586df76SDmitri Gribenko } 3184586df76SDmitri Gribenko 31917709ae8SDmitri Gribenko bool isHTMLIdentifierStartingCharacter(char C) { 32017709ae8SDmitri Gribenko return (C >= 'a' && C <= 'z') || 32117709ae8SDmitri Gribenko (C >= 'A' && C <= 'Z'); 32217709ae8SDmitri Gribenko } 32317709ae8SDmitri Gribenko 3245188c4b9SDmitri Gribenko bool isHTMLIdentifierCharacter(char C) { 3255188c4b9SDmitri Gribenko return (C >= 'a' && C <= 'z') || 3265188c4b9SDmitri Gribenko (C >= 'A' && C <= 'Z') || 3275188c4b9SDmitri Gribenko (C >= '0' && C <= '9'); 3285188c4b9SDmitri Gribenko } 3295188c4b9SDmitri Gribenko 3305188c4b9SDmitri Gribenko const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) { 3315188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3325188c4b9SDmitri Gribenko if (!isHTMLIdentifierCharacter(*BufferPtr)) 3335188c4b9SDmitri Gribenko return BufferPtr; 3345188c4b9SDmitri Gribenko } 3355188c4b9SDmitri Gribenko return BufferEnd; 3365188c4b9SDmitri Gribenko } 3375188c4b9SDmitri Gribenko 3385188c4b9SDmitri Gribenko /// Skip HTML string quoted in single or double quotes. Escaping quotes inside 3395188c4b9SDmitri Gribenko /// string allowed. 3405188c4b9SDmitri Gribenko /// 3415188c4b9SDmitri Gribenko /// Returns pointer to closing quote. 3425188c4b9SDmitri Gribenko const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd) 3435188c4b9SDmitri Gribenko { 3445188c4b9SDmitri Gribenko const char Quote = *BufferPtr; 3455188c4b9SDmitri Gribenko assert(Quote == '\"' || Quote == '\''); 3465188c4b9SDmitri Gribenko 3475188c4b9SDmitri Gribenko BufferPtr++; 3485188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3495188c4b9SDmitri Gribenko const char C = *BufferPtr; 3505188c4b9SDmitri Gribenko if (C == Quote && BufferPtr[-1] != '\\') 3515188c4b9SDmitri Gribenko return BufferPtr; 3525188c4b9SDmitri Gribenko } 3535188c4b9SDmitri Gribenko return BufferEnd; 3545188c4b9SDmitri Gribenko } 3555188c4b9SDmitri Gribenko 3565188c4b9SDmitri Gribenko bool isHorizontalWhitespace(char C) { 3575188c4b9SDmitri Gribenko return C == ' ' || C == '\t' || C == '\f' || C == '\v'; 3585188c4b9SDmitri Gribenko } 3595188c4b9SDmitri Gribenko 3605188c4b9SDmitri Gribenko bool isWhitespace(char C) { 3615188c4b9SDmitri Gribenko return C == ' ' || C == '\n' || C == '\r' || 3625188c4b9SDmitri Gribenko C == '\t' || C == '\f' || C == '\v'; 3635188c4b9SDmitri Gribenko } 3645188c4b9SDmitri Gribenko 3655188c4b9SDmitri Gribenko const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) { 3665188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3675188c4b9SDmitri Gribenko if (!isWhitespace(*BufferPtr)) 3685188c4b9SDmitri Gribenko return BufferPtr; 3695188c4b9SDmitri Gribenko } 3705188c4b9SDmitri Gribenko return BufferEnd; 3715188c4b9SDmitri Gribenko } 3725188c4b9SDmitri Gribenko 373e4a3997dSDmitri Gribenko bool isWhitespace(const char *BufferPtr, const char *BufferEnd) { 374e4a3997dSDmitri Gribenko return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd; 375e4a3997dSDmitri Gribenko } 376e4a3997dSDmitri Gribenko 377ad45ad6fSDmitri Gribenko bool isCommandNameStartCharacter(char C) { 378ad45ad6fSDmitri Gribenko return (C >= 'a' && C <= 'z') || 379ad45ad6fSDmitri Gribenko (C >= 'A' && C <= 'Z'); 380ad45ad6fSDmitri Gribenko } 381ad45ad6fSDmitri Gribenko 3825188c4b9SDmitri Gribenko bool isCommandNameCharacter(char C) { 3835188c4b9SDmitri Gribenko return (C >= 'a' && C <= 'z') || 3845188c4b9SDmitri Gribenko (C >= 'A' && C <= 'Z') || 3855188c4b9SDmitri Gribenko (C >= '0' && C <= '9'); 3865188c4b9SDmitri Gribenko } 3875188c4b9SDmitri Gribenko 3885188c4b9SDmitri Gribenko const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) { 3895188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3905188c4b9SDmitri Gribenko if (!isCommandNameCharacter(*BufferPtr)) 3915188c4b9SDmitri Gribenko return BufferPtr; 3925188c4b9SDmitri Gribenko } 3935188c4b9SDmitri Gribenko return BufferEnd; 3945188c4b9SDmitri Gribenko } 3955188c4b9SDmitri Gribenko 3965188c4b9SDmitri Gribenko /// Return the one past end pointer for BCPL comments. 3975188c4b9SDmitri Gribenko /// Handles newlines escaped with backslash or trigraph for backslahs. 3985188c4b9SDmitri Gribenko const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) { 3995188c4b9SDmitri Gribenko const char *CurPtr = BufferPtr; 4005188c4b9SDmitri Gribenko while (CurPtr != BufferEnd) { 4015188c4b9SDmitri Gribenko char C = *CurPtr; 4025188c4b9SDmitri Gribenko while (C != '\n' && C != '\r') { 4035188c4b9SDmitri Gribenko CurPtr++; 4045188c4b9SDmitri Gribenko if (CurPtr == BufferEnd) 4055188c4b9SDmitri Gribenko return BufferEnd; 4065188c4b9SDmitri Gribenko C = *CurPtr; 4075188c4b9SDmitri Gribenko } 4085188c4b9SDmitri Gribenko // We found a newline, check if it is escaped. 4095188c4b9SDmitri Gribenko const char *EscapePtr = CurPtr - 1; 4105188c4b9SDmitri Gribenko while(isHorizontalWhitespace(*EscapePtr)) 4115188c4b9SDmitri Gribenko EscapePtr--; 4125188c4b9SDmitri Gribenko 4135188c4b9SDmitri Gribenko if (*EscapePtr == '\\' || 4145188c4b9SDmitri Gribenko (EscapePtr - 2 >= BufferPtr && EscapePtr[0] == '/' && 4155188c4b9SDmitri Gribenko EscapePtr[-1] == '?' && EscapePtr[-2] == '?')) { 4165188c4b9SDmitri Gribenko // We found an escaped newline. 4175188c4b9SDmitri Gribenko CurPtr = skipNewline(CurPtr, BufferEnd); 4185188c4b9SDmitri Gribenko } else 4195188c4b9SDmitri Gribenko return CurPtr; // Not an escaped newline. 4205188c4b9SDmitri Gribenko } 4215188c4b9SDmitri Gribenko return BufferEnd; 4225188c4b9SDmitri Gribenko } 4235188c4b9SDmitri Gribenko 4245188c4b9SDmitri Gribenko /// Return the one past end pointer for C comments. 4255188c4b9SDmitri Gribenko /// Very dumb, does not handle escaped newlines or trigraphs. 4265188c4b9SDmitri Gribenko const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) { 4275188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 4285188c4b9SDmitri Gribenko if (*BufferPtr == '*') { 4295188c4b9SDmitri Gribenko assert(BufferPtr + 1 != BufferEnd); 4305188c4b9SDmitri Gribenko if (*(BufferPtr + 1) == '/') 4315188c4b9SDmitri Gribenko return BufferPtr; 4325188c4b9SDmitri Gribenko } 4335188c4b9SDmitri Gribenko } 4345188c4b9SDmitri Gribenko llvm_unreachable("buffer end hit before '*/' was seen"); 4355188c4b9SDmitri Gribenko } 4365188c4b9SDmitri Gribenko } // unnamed namespace 4375188c4b9SDmitri Gribenko 4385188c4b9SDmitri Gribenko void Lexer::lexCommentText(Token &T) { 4395188c4b9SDmitri Gribenko assert(CommentState == LCS_InsideBCPLComment || 4405188c4b9SDmitri Gribenko CommentState == LCS_InsideCComment); 4415188c4b9SDmitri Gribenko 4425188c4b9SDmitri Gribenko switch (State) { 4435188c4b9SDmitri Gribenko case LS_Normal: 4445188c4b9SDmitri Gribenko break; 4455188c4b9SDmitri Gribenko case LS_VerbatimBlockFirstLine: 4465188c4b9SDmitri Gribenko lexVerbatimBlockFirstLine(T); 4475188c4b9SDmitri Gribenko return; 4485188c4b9SDmitri Gribenko case LS_VerbatimBlockBody: 4495188c4b9SDmitri Gribenko lexVerbatimBlockBody(T); 4505188c4b9SDmitri Gribenko return; 4511669f702SDmitri Gribenko case LS_VerbatimLineText: 4521669f702SDmitri Gribenko lexVerbatimLineText(T); 4531669f702SDmitri Gribenko return; 454e00ffc7bSDmitri Gribenko case LS_HTMLStartTag: 455e00ffc7bSDmitri Gribenko lexHTMLStartTag(T); 4565188c4b9SDmitri Gribenko return; 457e00ffc7bSDmitri Gribenko case LS_HTMLEndTag: 458e00ffc7bSDmitri Gribenko lexHTMLEndTag(T); 459ec92531cSDmitri Gribenko return; 4605188c4b9SDmitri Gribenko } 4615188c4b9SDmitri Gribenko 4625188c4b9SDmitri Gribenko assert(State == LS_Normal); 4635188c4b9SDmitri Gribenko 4645188c4b9SDmitri Gribenko const char *TokenPtr = BufferPtr; 4655188c4b9SDmitri Gribenko assert(TokenPtr < CommentEnd); 4665188c4b9SDmitri Gribenko while (TokenPtr != CommentEnd) { 4675188c4b9SDmitri Gribenko switch(*TokenPtr) { 4685188c4b9SDmitri Gribenko case '\\': 4695188c4b9SDmitri Gribenko case '@': { 4705188c4b9SDmitri Gribenko TokenPtr++; 4715188c4b9SDmitri Gribenko if (TokenPtr == CommentEnd) { 4724586df76SDmitri Gribenko formTextToken(T, TokenPtr); 4735188c4b9SDmitri Gribenko return; 4745188c4b9SDmitri Gribenko } 4755188c4b9SDmitri Gribenko char C = *TokenPtr; 4765188c4b9SDmitri Gribenko switch (C) { 4775188c4b9SDmitri Gribenko default: 4785188c4b9SDmitri Gribenko break; 4795188c4b9SDmitri Gribenko 4805188c4b9SDmitri Gribenko case '\\': case '@': case '&': case '$': 4815188c4b9SDmitri Gribenko case '#': case '<': case '>': case '%': 4825188c4b9SDmitri Gribenko case '\"': case '.': case ':': 4835188c4b9SDmitri Gribenko // This is one of \\ \@ \& \$ etc escape sequences. 4845188c4b9SDmitri Gribenko TokenPtr++; 4855188c4b9SDmitri Gribenko if (C == ':' && TokenPtr != CommentEnd && *TokenPtr == ':') { 4865188c4b9SDmitri Gribenko // This is the \:: escape sequence. 4875188c4b9SDmitri Gribenko TokenPtr++; 4885188c4b9SDmitri Gribenko } 48960ddd8a1SDmitri Gribenko StringRef UnescapedText(BufferPtr + 1, TokenPtr - (BufferPtr + 1)); 4905188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 49160ddd8a1SDmitri Gribenko T.setText(UnescapedText); 4925188c4b9SDmitri Gribenko return; 4935188c4b9SDmitri Gribenko } 4945188c4b9SDmitri Gribenko 4955188c4b9SDmitri Gribenko // Don't make zero-length commands. 496ad45ad6fSDmitri Gribenko if (!isCommandNameStartCharacter(*TokenPtr)) { 4974586df76SDmitri Gribenko formTextToken(T, TokenPtr); 4985188c4b9SDmitri Gribenko return; 4995188c4b9SDmitri Gribenko } 5005188c4b9SDmitri Gribenko 5015188c4b9SDmitri Gribenko TokenPtr = skipCommandName(TokenPtr, CommentEnd); 5025188c4b9SDmitri Gribenko unsigned Length = TokenPtr - (BufferPtr + 1); 5035188c4b9SDmitri Gribenko 5045188c4b9SDmitri Gribenko // Hardcoded support for lexing LaTeX formula commands 5055188c4b9SDmitri Gribenko // \f$ \f[ \f] \f{ \f} as a single command. 5065188c4b9SDmitri Gribenko if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) { 5075188c4b9SDmitri Gribenko C = *TokenPtr; 5085188c4b9SDmitri Gribenko if (C == '$' || C == '[' || C == ']' || C == '{' || C == '}') { 5095188c4b9SDmitri Gribenko TokenPtr++; 5105188c4b9SDmitri Gribenko Length++; 5115188c4b9SDmitri Gribenko } 5125188c4b9SDmitri Gribenko } 5135188c4b9SDmitri Gribenko 5145188c4b9SDmitri Gribenko const StringRef CommandName(BufferPtr + 1, Length); 5155188c4b9SDmitri Gribenko 5167acbf00fSDmitri Gribenko const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); 5177acbf00fSDmitri Gribenko if (!Info) { 5187acbf00fSDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::unknown_command); 5197acbf00fSDmitri Gribenko T.setUnknownCommandName(CommandName); 5205188c4b9SDmitri Gribenko return; 5215188c4b9SDmitri Gribenko } 5227acbf00fSDmitri Gribenko if (Info->IsVerbatimBlockCommand) { 5237acbf00fSDmitri Gribenko setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info); 5247acbf00fSDmitri Gribenko return; 5257acbf00fSDmitri Gribenko } 5267acbf00fSDmitri Gribenko if (Info->IsVerbatimLineCommand) { 5277acbf00fSDmitri Gribenko setupAndLexVerbatimLine(T, TokenPtr, Info); 5285188c4b9SDmitri Gribenko return; 5295188c4b9SDmitri Gribenko } 5305188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::command); 5317acbf00fSDmitri Gribenko T.setCommandID(Info->getID()); 5325188c4b9SDmitri Gribenko return; 5335188c4b9SDmitri Gribenko } 5345188c4b9SDmitri Gribenko 5354586df76SDmitri Gribenko case '&': 5364586df76SDmitri Gribenko lexHTMLCharacterReference(T); 5374586df76SDmitri Gribenko return; 5384586df76SDmitri Gribenko 5395188c4b9SDmitri Gribenko case '<': { 5405188c4b9SDmitri Gribenko TokenPtr++; 5415188c4b9SDmitri Gribenko if (TokenPtr == CommentEnd) { 5424586df76SDmitri Gribenko formTextToken(T, TokenPtr); 5435188c4b9SDmitri Gribenko return; 5445188c4b9SDmitri Gribenko } 5455188c4b9SDmitri Gribenko const char C = *TokenPtr; 54617709ae8SDmitri Gribenko if (isHTMLIdentifierStartingCharacter(C)) 547e00ffc7bSDmitri Gribenko setupAndLexHTMLStartTag(T); 5485188c4b9SDmitri Gribenko else if (C == '/') 549e00ffc7bSDmitri Gribenko setupAndLexHTMLEndTag(T); 5504586df76SDmitri Gribenko else 5514586df76SDmitri Gribenko formTextToken(T, TokenPtr); 5524586df76SDmitri Gribenko 5535188c4b9SDmitri Gribenko return; 5545188c4b9SDmitri Gribenko } 5555188c4b9SDmitri Gribenko 5565188c4b9SDmitri Gribenko case '\n': 5575188c4b9SDmitri Gribenko case '\r': 5585188c4b9SDmitri Gribenko TokenPtr = skipNewline(TokenPtr, CommentEnd); 5595188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::newline); 5605188c4b9SDmitri Gribenko 5615188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) 5625188c4b9SDmitri Gribenko skipLineStartingDecorations(); 5635188c4b9SDmitri Gribenko return; 5645188c4b9SDmitri Gribenko 5655188c4b9SDmitri Gribenko default: { 56610af67a9SDmitri Gribenko size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr). 56710af67a9SDmitri Gribenko find_first_of("\n\r\\@&<"); 56810af67a9SDmitri Gribenko if (End != StringRef::npos) 56910af67a9SDmitri Gribenko TokenPtr += End; 57010af67a9SDmitri Gribenko else 57110af67a9SDmitri Gribenko TokenPtr = CommentEnd; 5724586df76SDmitri Gribenko formTextToken(T, TokenPtr); 5735188c4b9SDmitri Gribenko return; 5745188c4b9SDmitri Gribenko } 5755188c4b9SDmitri Gribenko } 5765188c4b9SDmitri Gribenko } 5775188c4b9SDmitri Gribenko } 5785188c4b9SDmitri Gribenko 5795188c4b9SDmitri Gribenko void Lexer::setupAndLexVerbatimBlock(Token &T, 5805188c4b9SDmitri Gribenko const char *TextBegin, 5817acbf00fSDmitri Gribenko char Marker, const CommandInfo *Info) { 5827acbf00fSDmitri Gribenko assert(Info->IsVerbatimBlockCommand); 5837acbf00fSDmitri Gribenko 5845188c4b9SDmitri Gribenko VerbatimBlockEndCommandName.clear(); 5855188c4b9SDmitri Gribenko VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@"); 5867acbf00fSDmitri Gribenko VerbatimBlockEndCommandName.append(Info->EndCommandName); 5875188c4b9SDmitri Gribenko 5885188c4b9SDmitri Gribenko formTokenWithChars(T, TextBegin, tok::verbatim_block_begin); 5897acbf00fSDmitri Gribenko T.setVerbatimBlockID(Info->getID()); 5905188c4b9SDmitri Gribenko 591ec92531cSDmitri Gribenko // If there is a newline following the verbatim opening command, skip the 592ec92531cSDmitri Gribenko // newline so that we don't create an tok::verbatim_block_line with empty 593ec92531cSDmitri Gribenko // text content. 594ec92531cSDmitri Gribenko if (BufferPtr != CommentEnd) { 595ec92531cSDmitri Gribenko const char C = *BufferPtr; 596ec92531cSDmitri Gribenko if (C == '\n' || C == '\r') { 597ec92531cSDmitri Gribenko BufferPtr = skipNewline(BufferPtr, CommentEnd); 598ec92531cSDmitri Gribenko State = LS_VerbatimBlockBody; 599ec92531cSDmitri Gribenko return; 600ec92531cSDmitri Gribenko } 601ec92531cSDmitri Gribenko } 602ec92531cSDmitri Gribenko 6035188c4b9SDmitri Gribenko State = LS_VerbatimBlockFirstLine; 6045188c4b9SDmitri Gribenko } 6055188c4b9SDmitri Gribenko 6065188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockFirstLine(Token &T) { 607e4a3997dSDmitri Gribenko again: 6085188c4b9SDmitri Gribenko assert(BufferPtr < CommentEnd); 6095188c4b9SDmitri Gribenko 6105188c4b9SDmitri Gribenko // FIXME: It would be better to scan the text once, finding either the block 6115188c4b9SDmitri Gribenko // end command or newline. 6125188c4b9SDmitri Gribenko // 6135188c4b9SDmitri Gribenko // Extract current line. 6145188c4b9SDmitri Gribenko const char *Newline = findNewline(BufferPtr, CommentEnd); 6155188c4b9SDmitri Gribenko StringRef Line(BufferPtr, Newline - BufferPtr); 6165188c4b9SDmitri Gribenko 6175188c4b9SDmitri Gribenko // Look for end command in current line. 6185188c4b9SDmitri Gribenko size_t Pos = Line.find(VerbatimBlockEndCommandName); 619ec92531cSDmitri Gribenko const char *TextEnd; 6205188c4b9SDmitri Gribenko const char *NextLine; 6215188c4b9SDmitri Gribenko if (Pos == StringRef::npos) { 6225188c4b9SDmitri Gribenko // Current line is completely verbatim. 623ec92531cSDmitri Gribenko TextEnd = Newline; 6245188c4b9SDmitri Gribenko NextLine = skipNewline(Newline, CommentEnd); 6255188c4b9SDmitri Gribenko } else if (Pos == 0) { 6265188c4b9SDmitri Gribenko // Current line contains just an end command. 6275188c4b9SDmitri Gribenko const char *End = BufferPtr + VerbatimBlockEndCommandName.size(); 62860ddd8a1SDmitri Gribenko StringRef Name(BufferPtr + 1, End - (BufferPtr + 1)); 6295188c4b9SDmitri Gribenko formTokenWithChars(T, End, tok::verbatim_block_end); 6307acbf00fSDmitri Gribenko T.setVerbatimBlockID(Traits.getCommandInfo(Name)->getID()); 6315188c4b9SDmitri Gribenko State = LS_Normal; 6325188c4b9SDmitri Gribenko return; 6335188c4b9SDmitri Gribenko } else { 6345188c4b9SDmitri Gribenko // There is some text, followed by end command. Extract text first. 635ec92531cSDmitri Gribenko TextEnd = BufferPtr + Pos; 636ec92531cSDmitri Gribenko NextLine = TextEnd; 637e4a3997dSDmitri Gribenko // If there is only whitespace before end command, skip whitespace. 638e4a3997dSDmitri Gribenko if (isWhitespace(BufferPtr, TextEnd)) { 639e4a3997dSDmitri Gribenko BufferPtr = TextEnd; 640e4a3997dSDmitri Gribenko goto again; 641e4a3997dSDmitri Gribenko } 6425188c4b9SDmitri Gribenko } 6435188c4b9SDmitri Gribenko 644ec92531cSDmitri Gribenko StringRef Text(BufferPtr, TextEnd - BufferPtr); 6455188c4b9SDmitri Gribenko formTokenWithChars(T, NextLine, tok::verbatim_block_line); 64660ddd8a1SDmitri Gribenko T.setVerbatimBlockText(Text); 6475188c4b9SDmitri Gribenko 6485188c4b9SDmitri Gribenko State = LS_VerbatimBlockBody; 6495188c4b9SDmitri Gribenko } 6505188c4b9SDmitri Gribenko 6515188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockBody(Token &T) { 6525188c4b9SDmitri Gribenko assert(State == LS_VerbatimBlockBody); 6535188c4b9SDmitri Gribenko 6545188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) 6555188c4b9SDmitri Gribenko skipLineStartingDecorations(); 6565188c4b9SDmitri Gribenko 6575188c4b9SDmitri Gribenko lexVerbatimBlockFirstLine(T); 6585188c4b9SDmitri Gribenko } 6595188c4b9SDmitri Gribenko 6607acbf00fSDmitri Gribenko void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin, 6617acbf00fSDmitri Gribenko const CommandInfo *Info) { 6627acbf00fSDmitri Gribenko assert(Info->IsVerbatimLineCommand); 6631669f702SDmitri Gribenko formTokenWithChars(T, TextBegin, tok::verbatim_line_name); 6647acbf00fSDmitri Gribenko T.setVerbatimLineID(Info->getID()); 6651669f702SDmitri Gribenko 6661669f702SDmitri Gribenko State = LS_VerbatimLineText; 6671669f702SDmitri Gribenko } 6681669f702SDmitri Gribenko 6691669f702SDmitri Gribenko void Lexer::lexVerbatimLineText(Token &T) { 6701669f702SDmitri Gribenko assert(State == LS_VerbatimLineText); 6711669f702SDmitri Gribenko 6725188c4b9SDmitri Gribenko // Extract current line. 6735188c4b9SDmitri Gribenko const char *Newline = findNewline(BufferPtr, CommentEnd); 6741669f702SDmitri Gribenko const StringRef Text(BufferPtr, Newline - BufferPtr); 6751669f702SDmitri Gribenko formTokenWithChars(T, Newline, tok::verbatim_line_text); 6765188c4b9SDmitri Gribenko T.setVerbatimLineText(Text); 6771669f702SDmitri Gribenko 6781669f702SDmitri Gribenko State = LS_Normal; 6795188c4b9SDmitri Gribenko } 6805188c4b9SDmitri Gribenko 6814586df76SDmitri Gribenko void Lexer::lexHTMLCharacterReference(Token &T) { 6824586df76SDmitri Gribenko const char *TokenPtr = BufferPtr; 6834586df76SDmitri Gribenko assert(*TokenPtr == '&'); 6844586df76SDmitri Gribenko TokenPtr++; 6854586df76SDmitri Gribenko if (TokenPtr == CommentEnd) { 6864586df76SDmitri Gribenko formTextToken(T, TokenPtr); 6874586df76SDmitri Gribenko return; 6884586df76SDmitri Gribenko } 6894586df76SDmitri Gribenko const char *NamePtr; 6904586df76SDmitri Gribenko bool isNamed = false; 6914586df76SDmitri Gribenko bool isDecimal = false; 6924586df76SDmitri Gribenko char C = *TokenPtr; 6934586df76SDmitri Gribenko if (isHTMLNamedCharacterReferenceCharacter(C)) { 6944586df76SDmitri Gribenko NamePtr = TokenPtr; 6954586df76SDmitri Gribenko TokenPtr = skipNamedCharacterReference(TokenPtr, CommentEnd); 6964586df76SDmitri Gribenko isNamed = true; 6974586df76SDmitri Gribenko } else if (C == '#') { 6984586df76SDmitri Gribenko TokenPtr++; 6994586df76SDmitri Gribenko if (TokenPtr == CommentEnd) { 7004586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7014586df76SDmitri Gribenko return; 7024586df76SDmitri Gribenko } 7034586df76SDmitri Gribenko C = *TokenPtr; 7044586df76SDmitri Gribenko if (isHTMLDecimalCharacterReferenceCharacter(C)) { 7054586df76SDmitri Gribenko NamePtr = TokenPtr; 7064586df76SDmitri Gribenko TokenPtr = skipDecimalCharacterReference(TokenPtr, CommentEnd); 7074586df76SDmitri Gribenko isDecimal = true; 7084586df76SDmitri Gribenko } else if (C == 'x' || C == 'X') { 7094586df76SDmitri Gribenko TokenPtr++; 7104586df76SDmitri Gribenko NamePtr = TokenPtr; 7114586df76SDmitri Gribenko TokenPtr = skipHexCharacterReference(TokenPtr, CommentEnd); 7124586df76SDmitri Gribenko } else { 7134586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7144586df76SDmitri Gribenko return; 7154586df76SDmitri Gribenko } 7164586df76SDmitri Gribenko } else { 7174586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7184586df76SDmitri Gribenko return; 7194586df76SDmitri Gribenko } 7204586df76SDmitri Gribenko if (NamePtr == TokenPtr || TokenPtr == CommentEnd || 7214586df76SDmitri Gribenko *TokenPtr != ';') { 7224586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7234586df76SDmitri Gribenko return; 7244586df76SDmitri Gribenko } 7254586df76SDmitri Gribenko StringRef Name(NamePtr, TokenPtr - NamePtr); 7264586df76SDmitri Gribenko TokenPtr++; // Skip semicolon. 7274586df76SDmitri Gribenko StringRef Resolved; 7287b3ae190SFariborz Jahanian if (isNamed) { 7294586df76SDmitri Gribenko Resolved = resolveHTMLNamedCharacterReference(Name); 7307b3ae190SFariborz Jahanian if (Resolved.empty()) { 7317b3ae190SFariborz Jahanian Resolved = HTMLDoxygenCharacterReference(Name); 7327b3ae190SFariborz Jahanian if (!Resolved.empty()) { 7337b3ae190SFariborz Jahanian formTokenWithChars(T, TokenPtr, tok::text); 7347b3ae190SFariborz Jahanian T.setText(Resolved); 7357b3ae190SFariborz Jahanian return; 7367b3ae190SFariborz Jahanian } 7377b3ae190SFariborz Jahanian } 7387b3ae190SFariborz Jahanian } 7394586df76SDmitri Gribenko else if (isDecimal) 7404586df76SDmitri Gribenko Resolved = resolveHTMLDecimalCharacterReference(Name); 7414586df76SDmitri Gribenko else 7424586df76SDmitri Gribenko Resolved = resolveHTMLHexCharacterReference(Name); 7434586df76SDmitri Gribenko 7444586df76SDmitri Gribenko if (Resolved.empty()) { 7454586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7464586df76SDmitri Gribenko return; 7474586df76SDmitri Gribenko } 7484586df76SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 7494586df76SDmitri Gribenko T.setText(Resolved); 7504586df76SDmitri Gribenko return; 7514586df76SDmitri Gribenko } 7524586df76SDmitri Gribenko 753e00ffc7bSDmitri Gribenko void Lexer::setupAndLexHTMLStartTag(Token &T) { 75417709ae8SDmitri Gribenko assert(BufferPtr[0] == '<' && 75517709ae8SDmitri Gribenko isHTMLIdentifierStartingCharacter(BufferPtr[1])); 7565188c4b9SDmitri Gribenko const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd); 75760ddd8a1SDmitri Gribenko StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1)); 758107618a6SDmitri Gribenko if (!isHTMLTagName(Name)) { 759107618a6SDmitri Gribenko formTextToken(T, TagNameEnd); 760107618a6SDmitri Gribenko return; 761107618a6SDmitri Gribenko } 762107618a6SDmitri Gribenko 763e00ffc7bSDmitri Gribenko formTokenWithChars(T, TagNameEnd, tok::html_start_tag); 764e00ffc7bSDmitri Gribenko T.setHTMLTagStartName(Name); 7655188c4b9SDmitri Gribenko 7665188c4b9SDmitri Gribenko BufferPtr = skipWhitespace(BufferPtr, CommentEnd); 7675188c4b9SDmitri Gribenko 76817709ae8SDmitri Gribenko const char C = *BufferPtr; 76917709ae8SDmitri Gribenko if (BufferPtr != CommentEnd && 770f26054f0SDmitri Gribenko (C == '>' || C == '/' || isHTMLIdentifierStartingCharacter(C))) 771e00ffc7bSDmitri Gribenko State = LS_HTMLStartTag; 7725188c4b9SDmitri Gribenko } 7735188c4b9SDmitri Gribenko 774e00ffc7bSDmitri Gribenko void Lexer::lexHTMLStartTag(Token &T) { 775e00ffc7bSDmitri Gribenko assert(State == LS_HTMLStartTag); 7765188c4b9SDmitri Gribenko 7775188c4b9SDmitri Gribenko const char *TokenPtr = BufferPtr; 7785188c4b9SDmitri Gribenko char C = *TokenPtr; 7795188c4b9SDmitri Gribenko if (isHTMLIdentifierCharacter(C)) { 7805188c4b9SDmitri Gribenko TokenPtr = skipHTMLIdentifier(TokenPtr, CommentEnd); 78160ddd8a1SDmitri Gribenko StringRef Ident(BufferPtr, TokenPtr - BufferPtr); 7825188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_ident); 78360ddd8a1SDmitri Gribenko T.setHTMLIdent(Ident); 7845188c4b9SDmitri Gribenko } else { 7855188c4b9SDmitri Gribenko switch (C) { 7865188c4b9SDmitri Gribenko case '=': 7875188c4b9SDmitri Gribenko TokenPtr++; 7885188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_equals); 7895188c4b9SDmitri Gribenko break; 7905188c4b9SDmitri Gribenko case '\"': 7915188c4b9SDmitri Gribenko case '\'': { 7925188c4b9SDmitri Gribenko const char *OpenQuote = TokenPtr; 7935188c4b9SDmitri Gribenko TokenPtr = skipHTMLQuotedString(TokenPtr, CommentEnd); 7945188c4b9SDmitri Gribenko const char *ClosingQuote = TokenPtr; 7955188c4b9SDmitri Gribenko if (TokenPtr != CommentEnd) // Skip closing quote. 7965188c4b9SDmitri Gribenko TokenPtr++; 7975188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_quoted_string); 7985188c4b9SDmitri Gribenko T.setHTMLQuotedString(StringRef(OpenQuote + 1, 7995188c4b9SDmitri Gribenko ClosingQuote - (OpenQuote + 1))); 8005188c4b9SDmitri Gribenko break; 8015188c4b9SDmitri Gribenko } 8025188c4b9SDmitri Gribenko case '>': 8035188c4b9SDmitri Gribenko TokenPtr++; 8045188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_greater); 80517709ae8SDmitri Gribenko State = LS_Normal; 80617709ae8SDmitri Gribenko return; 807f26054f0SDmitri Gribenko case '/': 808f26054f0SDmitri Gribenko TokenPtr++; 809f26054f0SDmitri Gribenko if (TokenPtr != CommentEnd && *TokenPtr == '>') { 810f26054f0SDmitri Gribenko TokenPtr++; 811f26054f0SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_slash_greater); 8124586df76SDmitri Gribenko } else 8134586df76SDmitri Gribenko formTextToken(T, TokenPtr); 8144586df76SDmitri Gribenko 815f26054f0SDmitri Gribenko State = LS_Normal; 816f26054f0SDmitri Gribenko return; 8175188c4b9SDmitri Gribenko } 8185188c4b9SDmitri Gribenko } 8195188c4b9SDmitri Gribenko 8205188c4b9SDmitri Gribenko // Now look ahead and return to normal state if we don't see any HTML tokens 8215188c4b9SDmitri Gribenko // ahead. 8225188c4b9SDmitri Gribenko BufferPtr = skipWhitespace(BufferPtr, CommentEnd); 8235188c4b9SDmitri Gribenko if (BufferPtr == CommentEnd) { 8245188c4b9SDmitri Gribenko State = LS_Normal; 8255188c4b9SDmitri Gribenko return; 8265188c4b9SDmitri Gribenko } 8275188c4b9SDmitri Gribenko 8285188c4b9SDmitri Gribenko C = *BufferPtr; 82917709ae8SDmitri Gribenko if (!isHTMLIdentifierStartingCharacter(C) && 8305188c4b9SDmitri Gribenko C != '=' && C != '\"' && C != '\'' && C != '>') { 8315188c4b9SDmitri Gribenko State = LS_Normal; 8325188c4b9SDmitri Gribenko return; 8335188c4b9SDmitri Gribenko } 8345188c4b9SDmitri Gribenko } 8355188c4b9SDmitri Gribenko 836e00ffc7bSDmitri Gribenko void Lexer::setupAndLexHTMLEndTag(Token &T) { 8375188c4b9SDmitri Gribenko assert(BufferPtr[0] == '<' && BufferPtr[1] == '/'); 8385188c4b9SDmitri Gribenko 8395188c4b9SDmitri Gribenko const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd); 8405188c4b9SDmitri Gribenko const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd); 841107618a6SDmitri Gribenko StringRef Name(TagNameBegin, TagNameEnd - TagNameBegin); 842107618a6SDmitri Gribenko if (!isHTMLTagName(Name)) { 843107618a6SDmitri Gribenko formTextToken(T, TagNameEnd); 844107618a6SDmitri Gribenko return; 845107618a6SDmitri Gribenko } 8465188c4b9SDmitri Gribenko 8475188c4b9SDmitri Gribenko const char *End = skipWhitespace(TagNameEnd, CommentEnd); 8485188c4b9SDmitri Gribenko 849e00ffc7bSDmitri Gribenko formTokenWithChars(T, End, tok::html_end_tag); 850107618a6SDmitri Gribenko T.setHTMLTagEndName(Name); 851ec92531cSDmitri Gribenko 852ec92531cSDmitri Gribenko if (BufferPtr != CommentEnd && *BufferPtr == '>') 853e00ffc7bSDmitri Gribenko State = LS_HTMLEndTag; 854ec92531cSDmitri Gribenko } 855ec92531cSDmitri Gribenko 856e00ffc7bSDmitri Gribenko void Lexer::lexHTMLEndTag(Token &T) { 857ec92531cSDmitri Gribenko assert(BufferPtr != CommentEnd && *BufferPtr == '>'); 858ec92531cSDmitri Gribenko 859ec92531cSDmitri Gribenko formTokenWithChars(T, BufferPtr + 1, tok::html_greater); 860ec92531cSDmitri Gribenko State = LS_Normal; 8615188c4b9SDmitri Gribenko } 8625188c4b9SDmitri Gribenko 863ca7f80adSDmitri Gribenko Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits, 8646bab9113SDmitri Gribenko SourceLocation FileLoc, 8655188c4b9SDmitri Gribenko const char *BufferStart, const char *BufferEnd): 866ca7f80adSDmitri Gribenko Allocator(Allocator), Traits(Traits), 8675188c4b9SDmitri Gribenko BufferStart(BufferStart), BufferEnd(BufferEnd), 8686bab9113SDmitri Gribenko FileLoc(FileLoc), BufferPtr(BufferStart), 8695188c4b9SDmitri Gribenko CommentState(LCS_BeforeComment), State(LS_Normal) { 8705188c4b9SDmitri Gribenko } 8715188c4b9SDmitri Gribenko 8725188c4b9SDmitri Gribenko void Lexer::lex(Token &T) { 8735188c4b9SDmitri Gribenko again: 8745188c4b9SDmitri Gribenko switch (CommentState) { 8755188c4b9SDmitri Gribenko case LCS_BeforeComment: 8765188c4b9SDmitri Gribenko if (BufferPtr == BufferEnd) { 8775188c4b9SDmitri Gribenko formTokenWithChars(T, BufferPtr, tok::eof); 8785188c4b9SDmitri Gribenko return; 8795188c4b9SDmitri Gribenko } 8805188c4b9SDmitri Gribenko 8815188c4b9SDmitri Gribenko assert(*BufferPtr == '/'); 8825188c4b9SDmitri Gribenko BufferPtr++; // Skip first slash. 8835188c4b9SDmitri Gribenko switch(*BufferPtr) { 8845188c4b9SDmitri Gribenko case '/': { // BCPL comment. 8855188c4b9SDmitri Gribenko BufferPtr++; // Skip second slash. 8865188c4b9SDmitri Gribenko 8875188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd) { 8885188c4b9SDmitri Gribenko // Skip Doxygen magic marker, if it is present. 8895188c4b9SDmitri Gribenko // It might be missing because of a typo //< or /*<, or because we 8905188c4b9SDmitri Gribenko // merged this non-Doxygen comment into a bunch of Doxygen comments 8915188c4b9SDmitri Gribenko // around it: /** ... */ /* ... */ /** ... */ 8925188c4b9SDmitri Gribenko const char C = *BufferPtr; 8935188c4b9SDmitri Gribenko if (C == '/' || C == '!') 8945188c4b9SDmitri Gribenko BufferPtr++; 8955188c4b9SDmitri Gribenko } 8965188c4b9SDmitri Gribenko 8975188c4b9SDmitri Gribenko // Skip less-than symbol that marks trailing comments. 8985188c4b9SDmitri Gribenko // Skip it even if the comment is not a Doxygen one, because //< and /*< 8995188c4b9SDmitri Gribenko // are frequent typos. 9005188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '<') 9015188c4b9SDmitri Gribenko BufferPtr++; 9025188c4b9SDmitri Gribenko 9035188c4b9SDmitri Gribenko CommentState = LCS_InsideBCPLComment; 904ec92531cSDmitri Gribenko if (State != LS_VerbatimBlockBody && State != LS_VerbatimBlockFirstLine) 9055188c4b9SDmitri Gribenko State = LS_Normal; 9065188c4b9SDmitri Gribenko CommentEnd = findBCPLCommentEnd(BufferPtr, BufferEnd); 9075188c4b9SDmitri Gribenko goto again; 9085188c4b9SDmitri Gribenko } 9095188c4b9SDmitri Gribenko case '*': { // C comment. 9105188c4b9SDmitri Gribenko BufferPtr++; // Skip star. 9115188c4b9SDmitri Gribenko 9125188c4b9SDmitri Gribenko // Skip Doxygen magic marker. 9135188c4b9SDmitri Gribenko const char C = *BufferPtr; 9145188c4b9SDmitri Gribenko if ((C == '*' && *(BufferPtr + 1) != '/') || C == '!') 9155188c4b9SDmitri Gribenko BufferPtr++; 9165188c4b9SDmitri Gribenko 9175188c4b9SDmitri Gribenko // Skip less-than symbol that marks trailing comments. 9185188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '<') 9195188c4b9SDmitri Gribenko BufferPtr++; 9205188c4b9SDmitri Gribenko 9215188c4b9SDmitri Gribenko CommentState = LCS_InsideCComment; 9225188c4b9SDmitri Gribenko State = LS_Normal; 9235188c4b9SDmitri Gribenko CommentEnd = findCCommentEnd(BufferPtr, BufferEnd); 9245188c4b9SDmitri Gribenko goto again; 9255188c4b9SDmitri Gribenko } 9265188c4b9SDmitri Gribenko default: 9275188c4b9SDmitri Gribenko llvm_unreachable("second character of comment should be '/' or '*'"); 9285188c4b9SDmitri Gribenko } 9295188c4b9SDmitri Gribenko 9305188c4b9SDmitri Gribenko case LCS_BetweenComments: { 9315188c4b9SDmitri Gribenko // Consecutive comments are extracted only if there is only whitespace 9325188c4b9SDmitri Gribenko // between them. So we can search for the start of the next comment. 9335188c4b9SDmitri Gribenko const char *EndWhitespace = BufferPtr; 9345188c4b9SDmitri Gribenko while(EndWhitespace != BufferEnd && *EndWhitespace != '/') 9355188c4b9SDmitri Gribenko EndWhitespace++; 9365188c4b9SDmitri Gribenko 9375188c4b9SDmitri Gribenko // Turn any whitespace between comments (and there is only whitespace 93817709ae8SDmitri Gribenko // between them -- guaranteed by comment extraction) into a newline. We 93917709ae8SDmitri Gribenko // have two newlines between C comments in total (first one was synthesized 94017709ae8SDmitri Gribenko // after a comment). 9415188c4b9SDmitri Gribenko formTokenWithChars(T, EndWhitespace, tok::newline); 9425188c4b9SDmitri Gribenko 9435188c4b9SDmitri Gribenko CommentState = LCS_BeforeComment; 9445188c4b9SDmitri Gribenko break; 9455188c4b9SDmitri Gribenko } 9465188c4b9SDmitri Gribenko 9475188c4b9SDmitri Gribenko case LCS_InsideBCPLComment: 9485188c4b9SDmitri Gribenko case LCS_InsideCComment: 9495188c4b9SDmitri Gribenko if (BufferPtr != CommentEnd) { 9505188c4b9SDmitri Gribenko lexCommentText(T); 9515188c4b9SDmitri Gribenko break; 9525188c4b9SDmitri Gribenko } else { 9535188c4b9SDmitri Gribenko // Skip C comment closing sequence. 9545188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) { 9555188c4b9SDmitri Gribenko assert(BufferPtr[0] == '*' && BufferPtr[1] == '/'); 9565188c4b9SDmitri Gribenko BufferPtr += 2; 9575188c4b9SDmitri Gribenko assert(BufferPtr <= BufferEnd); 9585188c4b9SDmitri Gribenko 9595188c4b9SDmitri Gribenko // Synthenize newline just after the C comment, regardless if there is 9605188c4b9SDmitri Gribenko // actually a newline. 9615188c4b9SDmitri Gribenko formTokenWithChars(T, BufferPtr, tok::newline); 9625188c4b9SDmitri Gribenko 9635188c4b9SDmitri Gribenko CommentState = LCS_BetweenComments; 9645188c4b9SDmitri Gribenko break; 9655188c4b9SDmitri Gribenko } else { 9665188c4b9SDmitri Gribenko // Don't synthesized a newline after BCPL comment. 9675188c4b9SDmitri Gribenko CommentState = LCS_BetweenComments; 9685188c4b9SDmitri Gribenko goto again; 9695188c4b9SDmitri Gribenko } 9705188c4b9SDmitri Gribenko } 9715188c4b9SDmitri Gribenko } 9725188c4b9SDmitri Gribenko } 9735188c4b9SDmitri Gribenko 9745188c4b9SDmitri Gribenko StringRef Lexer::getSpelling(const Token &Tok, 9755188c4b9SDmitri Gribenko const SourceManager &SourceMgr, 9765188c4b9SDmitri Gribenko bool *Invalid) const { 9775188c4b9SDmitri Gribenko SourceLocation Loc = Tok.getLocation(); 9785188c4b9SDmitri Gribenko std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(Loc); 9795188c4b9SDmitri Gribenko 9805188c4b9SDmitri Gribenko bool InvalidTemp = false; 9815188c4b9SDmitri Gribenko StringRef File = SourceMgr.getBufferData(LocInfo.first, &InvalidTemp); 9825188c4b9SDmitri Gribenko if (InvalidTemp) { 9835188c4b9SDmitri Gribenko *Invalid = true; 9845188c4b9SDmitri Gribenko return StringRef(); 9855188c4b9SDmitri Gribenko } 9865188c4b9SDmitri Gribenko 9875188c4b9SDmitri Gribenko const char *Begin = File.data() + LocInfo.second; 9885188c4b9SDmitri Gribenko return StringRef(Begin, Tok.getLength()); 9895188c4b9SDmitri Gribenko } 9905188c4b9SDmitri Gribenko 9915188c4b9SDmitri Gribenko } // end namespace comments 9925188c4b9SDmitri Gribenko } // end namespace clang 9935188c4b9SDmitri Gribenko 994