15188c4b9SDmitri Gribenko #include "clang/AST/CommentLexer.h" 2ca7f80adSDmitri Gribenko #include "clang/AST/CommentCommandTraits.h" 34586df76SDmitri Gribenko #include "clang/Basic/ConvertUTF.h" 4b2e5482bSDmitri Gribenko #include "llvm/ADT/StringExtras.h" 55188c4b9SDmitri Gribenko #include "llvm/ADT/StringSwitch.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 37*7b3ae190SFariborz Jahanian static unsigned getCodePoint(StringRef Name) { 384586df76SDmitri Gribenko unsigned CodePoint = 0; 394586df76SDmitri Gribenko for (unsigned i = 0, e = Name.size(); i != e; ++i) { 40*7b3ae190SFariborz Jahanian CodePoint *= 16; 41*7b3ae190SFariborz Jahanian const char C = Name[i]; 42*7b3ae190SFariborz Jahanian assert(isHTMLHexCharacterReferenceCharacter(C)); 43*7b3ae190SFariborz Jahanian CodePoint += llvm::hexDigitValue(C); 44*7b3ae190SFariborz Jahanian } 45*7b3ae190SFariborz Jahanian return CodePoint; 464586df76SDmitri Gribenko } 474586df76SDmitri Gribenko 48*7b3ae190SFariborz 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; 514586df76SDmitri Gribenko if (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 { 58*7b3ae190SFariborz Jahanian unsigned CodePoint = getCodePoint(Name); 59*7b3ae190SFariborz Jahanian return helperResolveHTMLHexCharacterReference(CodePoint); 60*7b3ae190SFariborz Jahanian } 61*7b3ae190SFariborz Jahanian 62*7b3ae190SFariborz Jahanian StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const { 63*7b3ae190SFariborz Jahanian return llvm::StringSwitch<StringRef>(Name) 64*7b3ae190SFariborz Jahanian .Case("amp", "&") 65*7b3ae190SFariborz Jahanian .Case("lt", "<") 66*7b3ae190SFariborz Jahanian .Case("gt", ">") 67*7b3ae190SFariborz Jahanian .Case("quot", "\"") 68*7b3ae190SFariborz Jahanian .Case("apos", "\'") 69*7b3ae190SFariborz Jahanian .Case("minus", "-") 70*7b3ae190SFariborz Jahanian .Case("sim", "~") 71*7b3ae190SFariborz Jahanian .Default(""); 72*7b3ae190SFariborz Jahanian } 73*7b3ae190SFariborz Jahanian 74*7b3ae190SFariborz Jahanian StringRef Lexer::HTMLDoxygenCharacterReference(StringRef Name) const { 75*7b3ae190SFariborz Jahanian return llvm::StringSwitch<StringRef>(Name) 76*7b3ae190SFariborz Jahanian .Case("copy", helperResolveHTMLHexCharacterReference(0x000A9)) 77*7b3ae190SFariborz Jahanian .Case("trade", helperResolveHTMLHexCharacterReference(0x02122)) 78*7b3ae190SFariborz Jahanian .Case("reg", helperResolveHTMLHexCharacterReference(0x000AE)) 79*7b3ae190SFariborz Jahanian .Case("lt", helperResolveHTMLHexCharacterReference(0x0003C)) 80*7b3ae190SFariborz Jahanian .Case("gt", helperResolveHTMLHexCharacterReference(0x0003C)) 81*7b3ae190SFariborz Jahanian .Case("amp", helperResolveHTMLHexCharacterReference(0x00026)) 82*7b3ae190SFariborz Jahanian .Case("apos", helperResolveHTMLHexCharacterReference(0x00027)) 83*7b3ae190SFariborz Jahanian .Case("quot", helperResolveHTMLHexCharacterReference(0x00022)) 84*7b3ae190SFariborz Jahanian .Case("lsquo", helperResolveHTMLHexCharacterReference(0x02018)) 85*7b3ae190SFariborz Jahanian .Case("rsquo", helperResolveHTMLHexCharacterReference(0x02019)) 86*7b3ae190SFariborz Jahanian .Case("ldquo", helperResolveHTMLHexCharacterReference(0x0201C)) 87*7b3ae190SFariborz Jahanian .Case("rdquo", helperResolveHTMLHexCharacterReference(0x0201D)) 88*7b3ae190SFariborz Jahanian .Case("ndash", helperResolveHTMLHexCharacterReference(0x02013)) 89*7b3ae190SFariborz Jahanian .Case("mdash", helperResolveHTMLHexCharacterReference(0x02014)) 90*7b3ae190SFariborz Jahanian .Case("Auml", helperResolveHTMLHexCharacterReference(0x000C4)) 91*7b3ae190SFariborz Jahanian .Case("Euml", helperResolveHTMLHexCharacterReference(0x000CB)) 92*7b3ae190SFariborz Jahanian .Case("Iuml", helperResolveHTMLHexCharacterReference(0x000CF)) 93*7b3ae190SFariborz Jahanian .Case("Ouml", helperResolveHTMLHexCharacterReference(0x000D6)) 94*7b3ae190SFariborz Jahanian .Case("Uuml", helperResolveHTMLHexCharacterReference(0x000DC)) 95*7b3ae190SFariborz Jahanian .Case("Yuml", helperResolveHTMLHexCharacterReference(0x00178)) 96*7b3ae190SFariborz Jahanian .Case("auml", helperResolveHTMLHexCharacterReference(0x000E4)) 97*7b3ae190SFariborz Jahanian .Case("euml", helperResolveHTMLHexCharacterReference(0x000EB)) 98*7b3ae190SFariborz Jahanian .Case("iuml", helperResolveHTMLHexCharacterReference(0x000EF)) 99*7b3ae190SFariborz Jahanian .Case("ouml", helperResolveHTMLHexCharacterReference(0x000F6)) 100*7b3ae190SFariborz Jahanian .Case("uuml", helperResolveHTMLHexCharacterReference(0x000FC)) 101*7b3ae190SFariborz Jahanian .Case("yuml", helperResolveHTMLHexCharacterReference(0x000FF)) 102*7b3ae190SFariborz Jahanian .Case("Aacute", helperResolveHTMLHexCharacterReference(0x000C1)) 103*7b3ae190SFariborz Jahanian .Case("Eacute", helperResolveHTMLHexCharacterReference(0x000C9)) 104*7b3ae190SFariborz Jahanian .Case("Iacute", helperResolveHTMLHexCharacterReference(0x000CD)) 105*7b3ae190SFariborz Jahanian .Case("Oacute", helperResolveHTMLHexCharacterReference(0x000D3)) 106*7b3ae190SFariborz Jahanian .Case("Uacute", helperResolveHTMLHexCharacterReference(0x000DA)) 107*7b3ae190SFariborz Jahanian .Case("Yacute", helperResolveHTMLHexCharacterReference(0x000DD)) 108*7b3ae190SFariborz Jahanian .Case("aacute", helperResolveHTMLHexCharacterReference(0x000E1)) 109*7b3ae190SFariborz Jahanian .Case("eacute", helperResolveHTMLHexCharacterReference(0x000E9)) 110*7b3ae190SFariborz Jahanian .Case("iacute", helperResolveHTMLHexCharacterReference(0x000ED)) 111*7b3ae190SFariborz Jahanian .Case("oacute", helperResolveHTMLHexCharacterReference(0x000F3)) 112*7b3ae190SFariborz Jahanian .Case("uacute", helperResolveHTMLHexCharacterReference(0x000FA)) 113*7b3ae190SFariborz Jahanian .Case("yacute", helperResolveHTMLHexCharacterReference(0x000FD)) 114*7b3ae190SFariborz Jahanian .Case("Agrave", helperResolveHTMLHexCharacterReference(0x000C0)) 115*7b3ae190SFariborz Jahanian .Case("Egrave", helperResolveHTMLHexCharacterReference(0x000C8)) 116*7b3ae190SFariborz Jahanian .Case("Igrave", helperResolveHTMLHexCharacterReference(0x000CC)) 117*7b3ae190SFariborz Jahanian .Case("Ograve", helperResolveHTMLHexCharacterReference(0x000D2)) 118*7b3ae190SFariborz Jahanian .Case("Ugrave", helperResolveHTMLHexCharacterReference(0x000D9)) 119*7b3ae190SFariborz Jahanian .Case("agrave", helperResolveHTMLHexCharacterReference(0x000E0)) 120*7b3ae190SFariborz Jahanian .Case("egrave", helperResolveHTMLHexCharacterReference(0x000E8)) 121*7b3ae190SFariborz Jahanian .Case("igrave", helperResolveHTMLHexCharacterReference(0x000EC)) 122*7b3ae190SFariborz Jahanian .Case("ograve", helperResolveHTMLHexCharacterReference(0x000F2)) 123*7b3ae190SFariborz Jahanian .Case("ugrave", helperResolveHTMLHexCharacterReference(0x000F9)) 124*7b3ae190SFariborz Jahanian .Case("ygrave", helperResolveHTMLHexCharacterReference(0x01EF3)) 125*7b3ae190SFariborz Jahanian .Case("Acirc", helperResolveHTMLHexCharacterReference(0x000C2)) 126*7b3ae190SFariborz Jahanian .Case("Ecirc", helperResolveHTMLHexCharacterReference(0x000CA)) 127*7b3ae190SFariborz Jahanian .Case("Icirc", helperResolveHTMLHexCharacterReference(0x000CE)) 128*7b3ae190SFariborz Jahanian .Case("Ocirc", helperResolveHTMLHexCharacterReference(0x000D4)) 129*7b3ae190SFariborz Jahanian .Case("Ucirc", helperResolveHTMLHexCharacterReference(0x000DB)) 130*7b3ae190SFariborz Jahanian .Case("acirc", helperResolveHTMLHexCharacterReference(0x000E2)) 131*7b3ae190SFariborz Jahanian .Case("ecirc", helperResolveHTMLHexCharacterReference(0x000EA)) 132*7b3ae190SFariborz Jahanian .Case("icirc", helperResolveHTMLHexCharacterReference(0x000EE)) 133*7b3ae190SFariborz Jahanian .Case("ocirc", helperResolveHTMLHexCharacterReference(0x000F4)) 134*7b3ae190SFariborz Jahanian .Case("ucirc", helperResolveHTMLHexCharacterReference(0x000FB)) 135*7b3ae190SFariborz Jahanian .Case("ycirc", helperResolveHTMLHexCharacterReference(0x00177)) 136*7b3ae190SFariborz Jahanian .Case("Atilde", helperResolveHTMLHexCharacterReference(0x000C3)) 137*7b3ae190SFariborz Jahanian .Case("Ntilde", helperResolveHTMLHexCharacterReference(0x000D1)) 138*7b3ae190SFariborz Jahanian .Case("Otilde", helperResolveHTMLHexCharacterReference(0x000D5)) 139*7b3ae190SFariborz Jahanian .Case("atilde", helperResolveHTMLHexCharacterReference(0x000E3)) 140*7b3ae190SFariborz Jahanian .Case("ntilde", helperResolveHTMLHexCharacterReference(0x000F1)) 141*7b3ae190SFariborz Jahanian .Case("otilde", helperResolveHTMLHexCharacterReference(0x000F5)) 142*7b3ae190SFariborz Jahanian .Case("szlig", helperResolveHTMLHexCharacterReference(0x000DF)) 143*7b3ae190SFariborz Jahanian .Case("ccedil", helperResolveHTMLHexCharacterReference(0x000E7)) 144*7b3ae190SFariborz Jahanian .Case("Ccedil", helperResolveHTMLHexCharacterReference(0x000C7)) 145*7b3ae190SFariborz Jahanian .Case("aring", helperResolveHTMLHexCharacterReference(0x000E5)) 146*7b3ae190SFariborz Jahanian .Case("Aring", helperResolveHTMLHexCharacterReference(0x000C5)) 147*7b3ae190SFariborz Jahanian .Case("nbsp", helperResolveHTMLHexCharacterReference(0x000A0)) 148*7b3ae190SFariborz Jahanian .Case("Gamma", helperResolveHTMLHexCharacterReference(0x00393)) 149*7b3ae190SFariborz Jahanian .Case("Delta", helperResolveHTMLHexCharacterReference(0x00394)) 150*7b3ae190SFariborz Jahanian .Case("Theta", helperResolveHTMLHexCharacterReference(0x00398)) 151*7b3ae190SFariborz Jahanian .Case("Lambda", helperResolveHTMLHexCharacterReference(0x0039B)) 152*7b3ae190SFariborz Jahanian .Case("Xi", helperResolveHTMLHexCharacterReference(0x0039E)) 153*7b3ae190SFariborz Jahanian .Case("Pi", helperResolveHTMLHexCharacterReference(0x003A0)) 154*7b3ae190SFariborz Jahanian .Case("Sigma", helperResolveHTMLHexCharacterReference(0x003A3)) 155*7b3ae190SFariborz Jahanian .Case("Upsilon", helperResolveHTMLHexCharacterReference(0x003A5)) 156*7b3ae190SFariborz Jahanian .Case("Phi", helperResolveHTMLHexCharacterReference(0x003A6)) 157*7b3ae190SFariborz Jahanian .Case("Psi", helperResolveHTMLHexCharacterReference(0x003A8)) 158*7b3ae190SFariborz Jahanian .Case("Omega", helperResolveHTMLHexCharacterReference(0x003A9)) 159*7b3ae190SFariborz Jahanian .Case("alpha", helperResolveHTMLHexCharacterReference(0x003B1)) 160*7b3ae190SFariborz Jahanian .Case("beta", helperResolveHTMLHexCharacterReference(0x003B2)) 161*7b3ae190SFariborz Jahanian .Case("gamma", helperResolveHTMLHexCharacterReference(0x003B3)) 162*7b3ae190SFariborz Jahanian .Case("delta", helperResolveHTMLHexCharacterReference(0x003B4)) 163*7b3ae190SFariborz Jahanian .Case("epsilon", helperResolveHTMLHexCharacterReference(0x003B5)) 164*7b3ae190SFariborz Jahanian .Case("zeta", helperResolveHTMLHexCharacterReference(0x003B6)) 165*7b3ae190SFariborz Jahanian .Case("eta", helperResolveHTMLHexCharacterReference(0x003B7)) 166*7b3ae190SFariborz Jahanian .Case("theta", helperResolveHTMLHexCharacterReference(0x003B8)) 167*7b3ae190SFariborz Jahanian .Case("iota", helperResolveHTMLHexCharacterReference(0x003B9)) 168*7b3ae190SFariborz Jahanian .Case("kappa", helperResolveHTMLHexCharacterReference(0x003BA)) 169*7b3ae190SFariborz Jahanian .Case("lambda", helperResolveHTMLHexCharacterReference(0x003BB)) 170*7b3ae190SFariborz Jahanian .Case("mu", helperResolveHTMLHexCharacterReference(0x003BC)) 171*7b3ae190SFariborz Jahanian .Case("nu", helperResolveHTMLHexCharacterReference(0x003BD)) 172*7b3ae190SFariborz Jahanian .Case("xi", helperResolveHTMLHexCharacterReference(0x003BE)) 173*7b3ae190SFariborz Jahanian .Case("pi", helperResolveHTMLHexCharacterReference(0x003C0)) 174*7b3ae190SFariborz Jahanian .Case("rho", helperResolveHTMLHexCharacterReference(0x003C1)) 175*7b3ae190SFariborz Jahanian .Case("sigma", helperResolveHTMLHexCharacterReference(0x003C3)) 176*7b3ae190SFariborz Jahanian .Case("tau", helperResolveHTMLHexCharacterReference(0x003C4)) 177*7b3ae190SFariborz Jahanian .Case("upsilon", helperResolveHTMLHexCharacterReference(0x003C5)) 178*7b3ae190SFariborz Jahanian .Case("phi", helperResolveHTMLHexCharacterReference(0x003C6)) 179*7b3ae190SFariborz Jahanian .Case("chi", helperResolveHTMLHexCharacterReference(0x003C7)) 180*7b3ae190SFariborz Jahanian .Case("psi", helperResolveHTMLHexCharacterReference(0x003C8)) 181*7b3ae190SFariborz Jahanian .Case("omega", helperResolveHTMLHexCharacterReference(0x003C9)) 182*7b3ae190SFariborz Jahanian .Case("sigmaf", helperResolveHTMLHexCharacterReference(0x003C2)) 183*7b3ae190SFariborz Jahanian .Case("sect", helperResolveHTMLHexCharacterReference(0x000A7)) 184*7b3ae190SFariborz Jahanian .Case("deg", helperResolveHTMLHexCharacterReference(0x000B0)) 185*7b3ae190SFariborz Jahanian .Case("prime", helperResolveHTMLHexCharacterReference(0x02032)) 186*7b3ae190SFariborz Jahanian .Case("Prime", helperResolveHTMLHexCharacterReference(0x02033)) 187*7b3ae190SFariborz Jahanian .Case("infin", helperResolveHTMLHexCharacterReference(0x0221E)) 188*7b3ae190SFariborz Jahanian .Case("empty", helperResolveHTMLHexCharacterReference(0x02205)) 189*7b3ae190SFariborz Jahanian .Case("plusmn", helperResolveHTMLHexCharacterReference(0x000B1)) 190*7b3ae190SFariborz Jahanian .Case("times", helperResolveHTMLHexCharacterReference(0x000D7)) 191*7b3ae190SFariborz Jahanian .Case("minus", helperResolveHTMLHexCharacterReference(0x02212)) 192*7b3ae190SFariborz Jahanian .Case("sdot", helperResolveHTMLHexCharacterReference(0x022C5)) 193*7b3ae190SFariborz Jahanian .Case("part", helperResolveHTMLHexCharacterReference(0x02202)) 194*7b3ae190SFariborz Jahanian .Case("nabla", helperResolveHTMLHexCharacterReference(0x02207)) 195*7b3ae190SFariborz Jahanian .Case("radic", helperResolveHTMLHexCharacterReference(0x0221A)) 196*7b3ae190SFariborz Jahanian .Case("perp", helperResolveHTMLHexCharacterReference(0x022A5)) 197*7b3ae190SFariborz Jahanian .Case("sum", helperResolveHTMLHexCharacterReference(0x02211)) 198*7b3ae190SFariborz Jahanian .Case("int", helperResolveHTMLHexCharacterReference(0x0222B)) 199*7b3ae190SFariborz Jahanian .Case("prod", helperResolveHTMLHexCharacterReference(0x0220F)) 200*7b3ae190SFariborz Jahanian .Case("sim", helperResolveHTMLHexCharacterReference(0x0223C)) 201*7b3ae190SFariborz Jahanian .Case("asymp", helperResolveHTMLHexCharacterReference(0x02248)) 202*7b3ae190SFariborz Jahanian .Case("ne", helperResolveHTMLHexCharacterReference(0x02260)) 203*7b3ae190SFariborz Jahanian .Case("equiv", helperResolveHTMLHexCharacterReference(0x02261)) 204*7b3ae190SFariborz Jahanian .Case("prop", helperResolveHTMLHexCharacterReference(0x0221D)) 205*7b3ae190SFariborz Jahanian .Case("le", helperResolveHTMLHexCharacterReference(0x02264)) 206*7b3ae190SFariborz Jahanian .Case("ge", helperResolveHTMLHexCharacterReference(0x02265)) 207*7b3ae190SFariborz Jahanian .Case("larr", helperResolveHTMLHexCharacterReference(0x02190)) 208*7b3ae190SFariborz Jahanian .Case("rarr", helperResolveHTMLHexCharacterReference(0x02192)) 209*7b3ae190SFariborz Jahanian .Case("isin", helperResolveHTMLHexCharacterReference(0x02208)) 210*7b3ae190SFariborz Jahanian .Case("notin", helperResolveHTMLHexCharacterReference(0x02209)) 211*7b3ae190SFariborz Jahanian .Case("lceil", helperResolveHTMLHexCharacterReference(0x02308)) 212*7b3ae190SFariborz Jahanian .Case("rceil", helperResolveHTMLHexCharacterReference(0x02309)) 213*7b3ae190SFariborz Jahanian .Case("lfloor", helperResolveHTMLHexCharacterReference(0x0230A)) 214*7b3ae190SFariborz Jahanian .Case("rfloor", helperResolveHTMLHexCharacterReference(0x0230B)) 215*7b3ae190SFariborz Jahanian .Default(""); 216*7b3ae190SFariborz Jahanian } 217*7b3ae190SFariborz Jahanian 218*7b3ae190SFariborz Jahanian StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const { 2194586df76SDmitri Gribenko unsigned CodePoint = 0; 2204586df76SDmitri Gribenko for (unsigned i = 0, e = Name.size(); i != e; ++i) { 221*7b3ae190SFariborz Jahanian assert(isHTMLDecimalCharacterReferenceCharacter(Name[i])); 222*7b3ae190SFariborz Jahanian CodePoint *= 10; 223*7b3ae190SFariborz Jahanian CodePoint += Name[i] - '0'; 2244586df76SDmitri Gribenko } 2254586df76SDmitri Gribenko 2264586df76SDmitri Gribenko char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT); 2274586df76SDmitri Gribenko char *ResolvedPtr = Resolved; 2284586df76SDmitri Gribenko if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr)) 2294586df76SDmitri Gribenko return StringRef(Resolved, ResolvedPtr - Resolved); 2304586df76SDmitri Gribenko else 2314586df76SDmitri Gribenko return StringRef(); 2324586df76SDmitri Gribenko } 2334586df76SDmitri Gribenko 2345188c4b9SDmitri Gribenko void Lexer::skipLineStartingDecorations() { 2355188c4b9SDmitri Gribenko // This function should be called only for C comments 2365188c4b9SDmitri Gribenko assert(CommentState == LCS_InsideCComment); 2375188c4b9SDmitri Gribenko 2385188c4b9SDmitri Gribenko if (BufferPtr == CommentEnd) 2395188c4b9SDmitri Gribenko return; 2405188c4b9SDmitri Gribenko 2415188c4b9SDmitri Gribenko switch (*BufferPtr) { 2425188c4b9SDmitri Gribenko case ' ': 2435188c4b9SDmitri Gribenko case '\t': 2445188c4b9SDmitri Gribenko case '\f': 2455188c4b9SDmitri Gribenko case '\v': { 2465188c4b9SDmitri Gribenko const char *NewBufferPtr = BufferPtr; 2475188c4b9SDmitri Gribenko NewBufferPtr++; 2485188c4b9SDmitri Gribenko if (NewBufferPtr == CommentEnd) 2495188c4b9SDmitri Gribenko return; 2505188c4b9SDmitri Gribenko 2515188c4b9SDmitri Gribenko char C = *NewBufferPtr; 2525188c4b9SDmitri Gribenko while (C == ' ' || C == '\t' || C == '\f' || C == '\v') { 2535188c4b9SDmitri Gribenko NewBufferPtr++; 2545188c4b9SDmitri Gribenko if (NewBufferPtr == CommentEnd) 2555188c4b9SDmitri Gribenko return; 2565188c4b9SDmitri Gribenko C = *NewBufferPtr; 2575188c4b9SDmitri Gribenko } 2585188c4b9SDmitri Gribenko if (C == '*') 2595188c4b9SDmitri Gribenko BufferPtr = NewBufferPtr + 1; 2605188c4b9SDmitri Gribenko break; 2615188c4b9SDmitri Gribenko } 2625188c4b9SDmitri Gribenko case '*': 2635188c4b9SDmitri Gribenko BufferPtr++; 2645188c4b9SDmitri Gribenko break; 2655188c4b9SDmitri Gribenko } 2665188c4b9SDmitri Gribenko } 2675188c4b9SDmitri Gribenko 2685188c4b9SDmitri Gribenko namespace { 269ec92531cSDmitri Gribenko /// Returns pointer to the first newline character in the string. 2705188c4b9SDmitri Gribenko const char *findNewline(const char *BufferPtr, const char *BufferEnd) { 2715188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 2725188c4b9SDmitri Gribenko const char C = *BufferPtr; 2735188c4b9SDmitri Gribenko if (C == '\n' || C == '\r') 2745188c4b9SDmitri Gribenko return BufferPtr; 2755188c4b9SDmitri Gribenko } 2765188c4b9SDmitri Gribenko return BufferEnd; 2775188c4b9SDmitri Gribenko } 2785188c4b9SDmitri Gribenko 2795188c4b9SDmitri Gribenko const char *skipNewline(const char *BufferPtr, const char *BufferEnd) { 2805188c4b9SDmitri Gribenko if (BufferPtr == BufferEnd) 2815188c4b9SDmitri Gribenko return BufferPtr; 2825188c4b9SDmitri Gribenko 2835188c4b9SDmitri Gribenko if (*BufferPtr == '\n') 2845188c4b9SDmitri Gribenko BufferPtr++; 2855188c4b9SDmitri Gribenko else { 2865188c4b9SDmitri Gribenko assert(*BufferPtr == '\r'); 2875188c4b9SDmitri Gribenko BufferPtr++; 2885188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '\n') 2895188c4b9SDmitri Gribenko BufferPtr++; 2905188c4b9SDmitri Gribenko } 2915188c4b9SDmitri Gribenko return BufferPtr; 2925188c4b9SDmitri Gribenko } 2935188c4b9SDmitri Gribenko 2944586df76SDmitri Gribenko const char *skipNamedCharacterReference(const char *BufferPtr, 2954586df76SDmitri Gribenko const char *BufferEnd) { 2964586df76SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 2974586df76SDmitri Gribenko if (!isHTMLNamedCharacterReferenceCharacter(*BufferPtr)) 2984586df76SDmitri Gribenko return BufferPtr; 2994586df76SDmitri Gribenko } 3004586df76SDmitri Gribenko return BufferEnd; 3014586df76SDmitri Gribenko } 3024586df76SDmitri Gribenko 3034586df76SDmitri Gribenko const char *skipDecimalCharacterReference(const char *BufferPtr, 3044586df76SDmitri Gribenko const char *BufferEnd) { 3054586df76SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3064586df76SDmitri Gribenko if (!isHTMLDecimalCharacterReferenceCharacter(*BufferPtr)) 3074586df76SDmitri Gribenko return BufferPtr; 3084586df76SDmitri Gribenko } 3094586df76SDmitri Gribenko return BufferEnd; 3104586df76SDmitri Gribenko } 3114586df76SDmitri Gribenko 3124586df76SDmitri Gribenko const char *skipHexCharacterReference(const char *BufferPtr, 3134586df76SDmitri Gribenko const char *BufferEnd) { 3144586df76SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3154586df76SDmitri Gribenko if (!isHTMLHexCharacterReferenceCharacter(*BufferPtr)) 3164586df76SDmitri Gribenko return BufferPtr; 3174586df76SDmitri Gribenko } 3184586df76SDmitri Gribenko return BufferEnd; 3194586df76SDmitri Gribenko } 3204586df76SDmitri Gribenko 32117709ae8SDmitri Gribenko bool isHTMLIdentifierStartingCharacter(char C) { 32217709ae8SDmitri Gribenko return (C >= 'a' && C <= 'z') || 32317709ae8SDmitri Gribenko (C >= 'A' && C <= 'Z'); 32417709ae8SDmitri Gribenko } 32517709ae8SDmitri Gribenko 3265188c4b9SDmitri Gribenko bool isHTMLIdentifierCharacter(char C) { 3275188c4b9SDmitri Gribenko return (C >= 'a' && C <= 'z') || 3285188c4b9SDmitri Gribenko (C >= 'A' && C <= 'Z') || 3295188c4b9SDmitri Gribenko (C >= '0' && C <= '9'); 3305188c4b9SDmitri Gribenko } 3315188c4b9SDmitri Gribenko 3325188c4b9SDmitri Gribenko const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) { 3335188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3345188c4b9SDmitri Gribenko if (!isHTMLIdentifierCharacter(*BufferPtr)) 3355188c4b9SDmitri Gribenko return BufferPtr; 3365188c4b9SDmitri Gribenko } 3375188c4b9SDmitri Gribenko return BufferEnd; 3385188c4b9SDmitri Gribenko } 3395188c4b9SDmitri Gribenko 3405188c4b9SDmitri Gribenko /// Skip HTML string quoted in single or double quotes. Escaping quotes inside 3415188c4b9SDmitri Gribenko /// string allowed. 3425188c4b9SDmitri Gribenko /// 3435188c4b9SDmitri Gribenko /// Returns pointer to closing quote. 3445188c4b9SDmitri Gribenko const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd) 3455188c4b9SDmitri Gribenko { 3465188c4b9SDmitri Gribenko const char Quote = *BufferPtr; 3475188c4b9SDmitri Gribenko assert(Quote == '\"' || Quote == '\''); 3485188c4b9SDmitri Gribenko 3495188c4b9SDmitri Gribenko BufferPtr++; 3505188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3515188c4b9SDmitri Gribenko const char C = *BufferPtr; 3525188c4b9SDmitri Gribenko if (C == Quote && BufferPtr[-1] != '\\') 3535188c4b9SDmitri Gribenko return BufferPtr; 3545188c4b9SDmitri Gribenko } 3555188c4b9SDmitri Gribenko return BufferEnd; 3565188c4b9SDmitri Gribenko } 3575188c4b9SDmitri Gribenko 3585188c4b9SDmitri Gribenko bool isHorizontalWhitespace(char C) { 3595188c4b9SDmitri Gribenko return C == ' ' || C == '\t' || C == '\f' || C == '\v'; 3605188c4b9SDmitri Gribenko } 3615188c4b9SDmitri Gribenko 3625188c4b9SDmitri Gribenko bool isWhitespace(char C) { 3635188c4b9SDmitri Gribenko return C == ' ' || C == '\n' || C == '\r' || 3645188c4b9SDmitri Gribenko C == '\t' || C == '\f' || C == '\v'; 3655188c4b9SDmitri Gribenko } 3665188c4b9SDmitri Gribenko 3675188c4b9SDmitri Gribenko const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) { 3685188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3695188c4b9SDmitri Gribenko if (!isWhitespace(*BufferPtr)) 3705188c4b9SDmitri Gribenko return BufferPtr; 3715188c4b9SDmitri Gribenko } 3725188c4b9SDmitri Gribenko return BufferEnd; 3735188c4b9SDmitri Gribenko } 3745188c4b9SDmitri Gribenko 375e4a3997dSDmitri Gribenko bool isWhitespace(const char *BufferPtr, const char *BufferEnd) { 376e4a3997dSDmitri Gribenko return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd; 377e4a3997dSDmitri Gribenko } 378e4a3997dSDmitri Gribenko 379ad45ad6fSDmitri Gribenko bool isCommandNameStartCharacter(char C) { 380ad45ad6fSDmitri Gribenko return (C >= 'a' && C <= 'z') || 381ad45ad6fSDmitri Gribenko (C >= 'A' && C <= 'Z'); 382ad45ad6fSDmitri Gribenko } 383ad45ad6fSDmitri Gribenko 3845188c4b9SDmitri Gribenko bool isCommandNameCharacter(char C) { 3855188c4b9SDmitri Gribenko return (C >= 'a' && C <= 'z') || 3865188c4b9SDmitri Gribenko (C >= 'A' && C <= 'Z') || 3875188c4b9SDmitri Gribenko (C >= '0' && C <= '9'); 3885188c4b9SDmitri Gribenko } 3895188c4b9SDmitri Gribenko 3905188c4b9SDmitri Gribenko const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) { 3915188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 3925188c4b9SDmitri Gribenko if (!isCommandNameCharacter(*BufferPtr)) 3935188c4b9SDmitri Gribenko return BufferPtr; 3945188c4b9SDmitri Gribenko } 3955188c4b9SDmitri Gribenko return BufferEnd; 3965188c4b9SDmitri Gribenko } 3975188c4b9SDmitri Gribenko 3985188c4b9SDmitri Gribenko /// Return the one past end pointer for BCPL comments. 3995188c4b9SDmitri Gribenko /// Handles newlines escaped with backslash or trigraph for backslahs. 4005188c4b9SDmitri Gribenko const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) { 4015188c4b9SDmitri Gribenko const char *CurPtr = BufferPtr; 4025188c4b9SDmitri Gribenko while (CurPtr != BufferEnd) { 4035188c4b9SDmitri Gribenko char C = *CurPtr; 4045188c4b9SDmitri Gribenko while (C != '\n' && C != '\r') { 4055188c4b9SDmitri Gribenko CurPtr++; 4065188c4b9SDmitri Gribenko if (CurPtr == BufferEnd) 4075188c4b9SDmitri Gribenko return BufferEnd; 4085188c4b9SDmitri Gribenko C = *CurPtr; 4095188c4b9SDmitri Gribenko } 4105188c4b9SDmitri Gribenko // We found a newline, check if it is escaped. 4115188c4b9SDmitri Gribenko const char *EscapePtr = CurPtr - 1; 4125188c4b9SDmitri Gribenko while(isHorizontalWhitespace(*EscapePtr)) 4135188c4b9SDmitri Gribenko EscapePtr--; 4145188c4b9SDmitri Gribenko 4155188c4b9SDmitri Gribenko if (*EscapePtr == '\\' || 4165188c4b9SDmitri Gribenko (EscapePtr - 2 >= BufferPtr && EscapePtr[0] == '/' && 4175188c4b9SDmitri Gribenko EscapePtr[-1] == '?' && EscapePtr[-2] == '?')) { 4185188c4b9SDmitri Gribenko // We found an escaped newline. 4195188c4b9SDmitri Gribenko CurPtr = skipNewline(CurPtr, BufferEnd); 4205188c4b9SDmitri Gribenko } else 4215188c4b9SDmitri Gribenko return CurPtr; // Not an escaped newline. 4225188c4b9SDmitri Gribenko } 4235188c4b9SDmitri Gribenko return BufferEnd; 4245188c4b9SDmitri Gribenko } 4255188c4b9SDmitri Gribenko 4265188c4b9SDmitri Gribenko /// Return the one past end pointer for C comments. 4275188c4b9SDmitri Gribenko /// Very dumb, does not handle escaped newlines or trigraphs. 4285188c4b9SDmitri Gribenko const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) { 4295188c4b9SDmitri Gribenko for ( ; BufferPtr != BufferEnd; ++BufferPtr) { 4305188c4b9SDmitri Gribenko if (*BufferPtr == '*') { 4315188c4b9SDmitri Gribenko assert(BufferPtr + 1 != BufferEnd); 4325188c4b9SDmitri Gribenko if (*(BufferPtr + 1) == '/') 4335188c4b9SDmitri Gribenko return BufferPtr; 4345188c4b9SDmitri Gribenko } 4355188c4b9SDmitri Gribenko } 4365188c4b9SDmitri Gribenko llvm_unreachable("buffer end hit before '*/' was seen"); 4375188c4b9SDmitri Gribenko } 4385188c4b9SDmitri Gribenko } // unnamed namespace 4395188c4b9SDmitri Gribenko 4405188c4b9SDmitri Gribenko void Lexer::lexCommentText(Token &T) { 4415188c4b9SDmitri Gribenko assert(CommentState == LCS_InsideBCPLComment || 4425188c4b9SDmitri Gribenko CommentState == LCS_InsideCComment); 4435188c4b9SDmitri Gribenko 4445188c4b9SDmitri Gribenko switch (State) { 4455188c4b9SDmitri Gribenko case LS_Normal: 4465188c4b9SDmitri Gribenko break; 4475188c4b9SDmitri Gribenko case LS_VerbatimBlockFirstLine: 4485188c4b9SDmitri Gribenko lexVerbatimBlockFirstLine(T); 4495188c4b9SDmitri Gribenko return; 4505188c4b9SDmitri Gribenko case LS_VerbatimBlockBody: 4515188c4b9SDmitri Gribenko lexVerbatimBlockBody(T); 4525188c4b9SDmitri Gribenko return; 4531669f702SDmitri Gribenko case LS_VerbatimLineText: 4541669f702SDmitri Gribenko lexVerbatimLineText(T); 4551669f702SDmitri Gribenko return; 456e00ffc7bSDmitri Gribenko case LS_HTMLStartTag: 457e00ffc7bSDmitri Gribenko lexHTMLStartTag(T); 4585188c4b9SDmitri Gribenko return; 459e00ffc7bSDmitri Gribenko case LS_HTMLEndTag: 460e00ffc7bSDmitri Gribenko lexHTMLEndTag(T); 461ec92531cSDmitri Gribenko return; 4625188c4b9SDmitri Gribenko } 4635188c4b9SDmitri Gribenko 4645188c4b9SDmitri Gribenko assert(State == LS_Normal); 4655188c4b9SDmitri Gribenko 4665188c4b9SDmitri Gribenko const char *TokenPtr = BufferPtr; 4675188c4b9SDmitri Gribenko assert(TokenPtr < CommentEnd); 4685188c4b9SDmitri Gribenko while (TokenPtr != CommentEnd) { 4695188c4b9SDmitri Gribenko switch(*TokenPtr) { 4705188c4b9SDmitri Gribenko case '\\': 4715188c4b9SDmitri Gribenko case '@': { 4725188c4b9SDmitri Gribenko TokenPtr++; 4735188c4b9SDmitri Gribenko if (TokenPtr == CommentEnd) { 4744586df76SDmitri Gribenko formTextToken(T, TokenPtr); 4755188c4b9SDmitri Gribenko return; 4765188c4b9SDmitri Gribenko } 4775188c4b9SDmitri Gribenko char C = *TokenPtr; 4785188c4b9SDmitri Gribenko switch (C) { 4795188c4b9SDmitri Gribenko default: 4805188c4b9SDmitri Gribenko break; 4815188c4b9SDmitri Gribenko 4825188c4b9SDmitri Gribenko case '\\': case '@': case '&': case '$': 4835188c4b9SDmitri Gribenko case '#': case '<': case '>': case '%': 4845188c4b9SDmitri Gribenko case '\"': case '.': case ':': 4855188c4b9SDmitri Gribenko // This is one of \\ \@ \& \$ etc escape sequences. 4865188c4b9SDmitri Gribenko TokenPtr++; 4875188c4b9SDmitri Gribenko if (C == ':' && TokenPtr != CommentEnd && *TokenPtr == ':') { 4885188c4b9SDmitri Gribenko // This is the \:: escape sequence. 4895188c4b9SDmitri Gribenko TokenPtr++; 4905188c4b9SDmitri Gribenko } 49160ddd8a1SDmitri Gribenko StringRef UnescapedText(BufferPtr + 1, TokenPtr - (BufferPtr + 1)); 4925188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 49360ddd8a1SDmitri Gribenko T.setText(UnescapedText); 4945188c4b9SDmitri Gribenko return; 4955188c4b9SDmitri Gribenko } 4965188c4b9SDmitri Gribenko 4975188c4b9SDmitri Gribenko // Don't make zero-length commands. 498ad45ad6fSDmitri Gribenko if (!isCommandNameStartCharacter(*TokenPtr)) { 4994586df76SDmitri Gribenko formTextToken(T, TokenPtr); 5005188c4b9SDmitri Gribenko return; 5015188c4b9SDmitri Gribenko } 5025188c4b9SDmitri Gribenko 5035188c4b9SDmitri Gribenko TokenPtr = skipCommandName(TokenPtr, CommentEnd); 5045188c4b9SDmitri Gribenko unsigned Length = TokenPtr - (BufferPtr + 1); 5055188c4b9SDmitri Gribenko 5065188c4b9SDmitri Gribenko // Hardcoded support for lexing LaTeX formula commands 5075188c4b9SDmitri Gribenko // \f$ \f[ \f] \f{ \f} as a single command. 5085188c4b9SDmitri Gribenko if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) { 5095188c4b9SDmitri Gribenko C = *TokenPtr; 5105188c4b9SDmitri Gribenko if (C == '$' || C == '[' || C == ']' || C == '{' || C == '}') { 5115188c4b9SDmitri Gribenko TokenPtr++; 5125188c4b9SDmitri Gribenko Length++; 5135188c4b9SDmitri Gribenko } 5145188c4b9SDmitri Gribenko } 5155188c4b9SDmitri Gribenko 5165188c4b9SDmitri Gribenko const StringRef CommandName(BufferPtr + 1, Length); 5175188c4b9SDmitri Gribenko 5187acbf00fSDmitri Gribenko const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); 5197acbf00fSDmitri Gribenko if (!Info) { 5207acbf00fSDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::unknown_command); 5217acbf00fSDmitri Gribenko T.setUnknownCommandName(CommandName); 5225188c4b9SDmitri Gribenko return; 5235188c4b9SDmitri Gribenko } 5247acbf00fSDmitri Gribenko if (Info->IsVerbatimBlockCommand) { 5257acbf00fSDmitri Gribenko setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info); 5267acbf00fSDmitri Gribenko return; 5277acbf00fSDmitri Gribenko } 5287acbf00fSDmitri Gribenko if (Info->IsVerbatimLineCommand) { 5297acbf00fSDmitri Gribenko setupAndLexVerbatimLine(T, TokenPtr, Info); 5305188c4b9SDmitri Gribenko return; 5315188c4b9SDmitri Gribenko } 5325188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::command); 5337acbf00fSDmitri Gribenko T.setCommandID(Info->getID()); 5345188c4b9SDmitri Gribenko return; 5355188c4b9SDmitri Gribenko } 5365188c4b9SDmitri Gribenko 5374586df76SDmitri Gribenko case '&': 5384586df76SDmitri Gribenko lexHTMLCharacterReference(T); 5394586df76SDmitri Gribenko return; 5404586df76SDmitri Gribenko 5415188c4b9SDmitri Gribenko case '<': { 5425188c4b9SDmitri Gribenko TokenPtr++; 5435188c4b9SDmitri Gribenko if (TokenPtr == CommentEnd) { 5444586df76SDmitri Gribenko formTextToken(T, TokenPtr); 5455188c4b9SDmitri Gribenko return; 5465188c4b9SDmitri Gribenko } 5475188c4b9SDmitri Gribenko const char C = *TokenPtr; 54817709ae8SDmitri Gribenko if (isHTMLIdentifierStartingCharacter(C)) 549e00ffc7bSDmitri Gribenko setupAndLexHTMLStartTag(T); 5505188c4b9SDmitri Gribenko else if (C == '/') 551e00ffc7bSDmitri Gribenko setupAndLexHTMLEndTag(T); 5524586df76SDmitri Gribenko else 5534586df76SDmitri Gribenko formTextToken(T, TokenPtr); 5544586df76SDmitri Gribenko 5555188c4b9SDmitri Gribenko return; 5565188c4b9SDmitri Gribenko } 5575188c4b9SDmitri Gribenko 5585188c4b9SDmitri Gribenko case '\n': 5595188c4b9SDmitri Gribenko case '\r': 5605188c4b9SDmitri Gribenko TokenPtr = skipNewline(TokenPtr, CommentEnd); 5615188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::newline); 5625188c4b9SDmitri Gribenko 5635188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) 5645188c4b9SDmitri Gribenko skipLineStartingDecorations(); 5655188c4b9SDmitri Gribenko return; 5665188c4b9SDmitri Gribenko 5675188c4b9SDmitri Gribenko default: { 56810af67a9SDmitri Gribenko size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr). 56910af67a9SDmitri Gribenko find_first_of("\n\r\\@&<"); 57010af67a9SDmitri Gribenko if (End != StringRef::npos) 57110af67a9SDmitri Gribenko TokenPtr += End; 57210af67a9SDmitri Gribenko else 57310af67a9SDmitri Gribenko TokenPtr = CommentEnd; 5744586df76SDmitri Gribenko formTextToken(T, TokenPtr); 5755188c4b9SDmitri Gribenko return; 5765188c4b9SDmitri Gribenko } 5775188c4b9SDmitri Gribenko } 5785188c4b9SDmitri Gribenko } 5795188c4b9SDmitri Gribenko } 5805188c4b9SDmitri Gribenko 5815188c4b9SDmitri Gribenko void Lexer::setupAndLexVerbatimBlock(Token &T, 5825188c4b9SDmitri Gribenko const char *TextBegin, 5837acbf00fSDmitri Gribenko char Marker, const CommandInfo *Info) { 5847acbf00fSDmitri Gribenko assert(Info->IsVerbatimBlockCommand); 5857acbf00fSDmitri Gribenko 5865188c4b9SDmitri Gribenko VerbatimBlockEndCommandName.clear(); 5875188c4b9SDmitri Gribenko VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@"); 5887acbf00fSDmitri Gribenko VerbatimBlockEndCommandName.append(Info->EndCommandName); 5895188c4b9SDmitri Gribenko 5905188c4b9SDmitri Gribenko formTokenWithChars(T, TextBegin, tok::verbatim_block_begin); 5917acbf00fSDmitri Gribenko T.setVerbatimBlockID(Info->getID()); 5925188c4b9SDmitri Gribenko 593ec92531cSDmitri Gribenko // If there is a newline following the verbatim opening command, skip the 594ec92531cSDmitri Gribenko // newline so that we don't create an tok::verbatim_block_line with empty 595ec92531cSDmitri Gribenko // text content. 596ec92531cSDmitri Gribenko if (BufferPtr != CommentEnd) { 597ec92531cSDmitri Gribenko const char C = *BufferPtr; 598ec92531cSDmitri Gribenko if (C == '\n' || C == '\r') { 599ec92531cSDmitri Gribenko BufferPtr = skipNewline(BufferPtr, CommentEnd); 600ec92531cSDmitri Gribenko State = LS_VerbatimBlockBody; 601ec92531cSDmitri Gribenko return; 602ec92531cSDmitri Gribenko } 603ec92531cSDmitri Gribenko } 604ec92531cSDmitri Gribenko 6055188c4b9SDmitri Gribenko State = LS_VerbatimBlockFirstLine; 6065188c4b9SDmitri Gribenko } 6075188c4b9SDmitri Gribenko 6085188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockFirstLine(Token &T) { 609e4a3997dSDmitri Gribenko again: 6105188c4b9SDmitri Gribenko assert(BufferPtr < CommentEnd); 6115188c4b9SDmitri Gribenko 6125188c4b9SDmitri Gribenko // FIXME: It would be better to scan the text once, finding either the block 6135188c4b9SDmitri Gribenko // end command or newline. 6145188c4b9SDmitri Gribenko // 6155188c4b9SDmitri Gribenko // Extract current line. 6165188c4b9SDmitri Gribenko const char *Newline = findNewline(BufferPtr, CommentEnd); 6175188c4b9SDmitri Gribenko StringRef Line(BufferPtr, Newline - BufferPtr); 6185188c4b9SDmitri Gribenko 6195188c4b9SDmitri Gribenko // Look for end command in current line. 6205188c4b9SDmitri Gribenko size_t Pos = Line.find(VerbatimBlockEndCommandName); 621ec92531cSDmitri Gribenko const char *TextEnd; 6225188c4b9SDmitri Gribenko const char *NextLine; 6235188c4b9SDmitri Gribenko if (Pos == StringRef::npos) { 6245188c4b9SDmitri Gribenko // Current line is completely verbatim. 625ec92531cSDmitri Gribenko TextEnd = Newline; 6265188c4b9SDmitri Gribenko NextLine = skipNewline(Newline, CommentEnd); 6275188c4b9SDmitri Gribenko } else if (Pos == 0) { 6285188c4b9SDmitri Gribenko // Current line contains just an end command. 6295188c4b9SDmitri Gribenko const char *End = BufferPtr + VerbatimBlockEndCommandName.size(); 63060ddd8a1SDmitri Gribenko StringRef Name(BufferPtr + 1, End - (BufferPtr + 1)); 6315188c4b9SDmitri Gribenko formTokenWithChars(T, End, tok::verbatim_block_end); 6327acbf00fSDmitri Gribenko T.setVerbatimBlockID(Traits.getCommandInfo(Name)->getID()); 6335188c4b9SDmitri Gribenko State = LS_Normal; 6345188c4b9SDmitri Gribenko return; 6355188c4b9SDmitri Gribenko } else { 6365188c4b9SDmitri Gribenko // There is some text, followed by end command. Extract text first. 637ec92531cSDmitri Gribenko TextEnd = BufferPtr + Pos; 638ec92531cSDmitri Gribenko NextLine = TextEnd; 639e4a3997dSDmitri Gribenko // If there is only whitespace before end command, skip whitespace. 640e4a3997dSDmitri Gribenko if (isWhitespace(BufferPtr, TextEnd)) { 641e4a3997dSDmitri Gribenko BufferPtr = TextEnd; 642e4a3997dSDmitri Gribenko goto again; 643e4a3997dSDmitri Gribenko } 6445188c4b9SDmitri Gribenko } 6455188c4b9SDmitri Gribenko 646ec92531cSDmitri Gribenko StringRef Text(BufferPtr, TextEnd - BufferPtr); 6475188c4b9SDmitri Gribenko formTokenWithChars(T, NextLine, tok::verbatim_block_line); 64860ddd8a1SDmitri Gribenko T.setVerbatimBlockText(Text); 6495188c4b9SDmitri Gribenko 6505188c4b9SDmitri Gribenko State = LS_VerbatimBlockBody; 6515188c4b9SDmitri Gribenko } 6525188c4b9SDmitri Gribenko 6535188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockBody(Token &T) { 6545188c4b9SDmitri Gribenko assert(State == LS_VerbatimBlockBody); 6555188c4b9SDmitri Gribenko 6565188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) 6575188c4b9SDmitri Gribenko skipLineStartingDecorations(); 6585188c4b9SDmitri Gribenko 6595188c4b9SDmitri Gribenko lexVerbatimBlockFirstLine(T); 6605188c4b9SDmitri Gribenko } 6615188c4b9SDmitri Gribenko 6627acbf00fSDmitri Gribenko void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin, 6637acbf00fSDmitri Gribenko const CommandInfo *Info) { 6647acbf00fSDmitri Gribenko assert(Info->IsVerbatimLineCommand); 6651669f702SDmitri Gribenko formTokenWithChars(T, TextBegin, tok::verbatim_line_name); 6667acbf00fSDmitri Gribenko T.setVerbatimLineID(Info->getID()); 6671669f702SDmitri Gribenko 6681669f702SDmitri Gribenko State = LS_VerbatimLineText; 6691669f702SDmitri Gribenko } 6701669f702SDmitri Gribenko 6711669f702SDmitri Gribenko void Lexer::lexVerbatimLineText(Token &T) { 6721669f702SDmitri Gribenko assert(State == LS_VerbatimLineText); 6731669f702SDmitri Gribenko 6745188c4b9SDmitri Gribenko // Extract current line. 6755188c4b9SDmitri Gribenko const char *Newline = findNewline(BufferPtr, CommentEnd); 6761669f702SDmitri Gribenko const StringRef Text(BufferPtr, Newline - BufferPtr); 6771669f702SDmitri Gribenko formTokenWithChars(T, Newline, tok::verbatim_line_text); 6785188c4b9SDmitri Gribenko T.setVerbatimLineText(Text); 6791669f702SDmitri Gribenko 6801669f702SDmitri Gribenko State = LS_Normal; 6815188c4b9SDmitri Gribenko } 6825188c4b9SDmitri Gribenko 6834586df76SDmitri Gribenko void Lexer::lexHTMLCharacterReference(Token &T) { 6844586df76SDmitri Gribenko const char *TokenPtr = BufferPtr; 6854586df76SDmitri Gribenko assert(*TokenPtr == '&'); 6864586df76SDmitri Gribenko TokenPtr++; 6874586df76SDmitri Gribenko if (TokenPtr == CommentEnd) { 6884586df76SDmitri Gribenko formTextToken(T, TokenPtr); 6894586df76SDmitri Gribenko return; 6904586df76SDmitri Gribenko } 6914586df76SDmitri Gribenko const char *NamePtr; 6924586df76SDmitri Gribenko bool isNamed = false; 6934586df76SDmitri Gribenko bool isDecimal = false; 6944586df76SDmitri Gribenko char C = *TokenPtr; 6954586df76SDmitri Gribenko if (isHTMLNamedCharacterReferenceCharacter(C)) { 6964586df76SDmitri Gribenko NamePtr = TokenPtr; 6974586df76SDmitri Gribenko TokenPtr = skipNamedCharacterReference(TokenPtr, CommentEnd); 6984586df76SDmitri Gribenko isNamed = true; 6994586df76SDmitri Gribenko } else if (C == '#') { 7004586df76SDmitri Gribenko TokenPtr++; 7014586df76SDmitri Gribenko if (TokenPtr == CommentEnd) { 7024586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7034586df76SDmitri Gribenko return; 7044586df76SDmitri Gribenko } 7054586df76SDmitri Gribenko C = *TokenPtr; 7064586df76SDmitri Gribenko if (isHTMLDecimalCharacterReferenceCharacter(C)) { 7074586df76SDmitri Gribenko NamePtr = TokenPtr; 7084586df76SDmitri Gribenko TokenPtr = skipDecimalCharacterReference(TokenPtr, CommentEnd); 7094586df76SDmitri Gribenko isDecimal = true; 7104586df76SDmitri Gribenko } else if (C == 'x' || C == 'X') { 7114586df76SDmitri Gribenko TokenPtr++; 7124586df76SDmitri Gribenko NamePtr = TokenPtr; 7134586df76SDmitri Gribenko TokenPtr = skipHexCharacterReference(TokenPtr, CommentEnd); 7144586df76SDmitri Gribenko } else { 7154586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7164586df76SDmitri Gribenko return; 7174586df76SDmitri Gribenko } 7184586df76SDmitri Gribenko } else { 7194586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7204586df76SDmitri Gribenko return; 7214586df76SDmitri Gribenko } 7224586df76SDmitri Gribenko if (NamePtr == TokenPtr || TokenPtr == CommentEnd || 7234586df76SDmitri Gribenko *TokenPtr != ';') { 7244586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7254586df76SDmitri Gribenko return; 7264586df76SDmitri Gribenko } 7274586df76SDmitri Gribenko StringRef Name(NamePtr, TokenPtr - NamePtr); 7284586df76SDmitri Gribenko TokenPtr++; // Skip semicolon. 7294586df76SDmitri Gribenko StringRef Resolved; 730*7b3ae190SFariborz Jahanian if (isNamed) { 7314586df76SDmitri Gribenko Resolved = resolveHTMLNamedCharacterReference(Name); 732*7b3ae190SFariborz Jahanian if (Resolved.empty()) { 733*7b3ae190SFariborz Jahanian Resolved = HTMLDoxygenCharacterReference(Name); 734*7b3ae190SFariborz Jahanian if (!Resolved.empty()) { 735*7b3ae190SFariborz Jahanian formTokenWithChars(T, TokenPtr, tok::text); 736*7b3ae190SFariborz Jahanian T.setText(Resolved); 737*7b3ae190SFariborz Jahanian return; 738*7b3ae190SFariborz Jahanian } 739*7b3ae190SFariborz Jahanian } 740*7b3ae190SFariborz Jahanian } 7414586df76SDmitri Gribenko else if (isDecimal) 7424586df76SDmitri Gribenko Resolved = resolveHTMLDecimalCharacterReference(Name); 7434586df76SDmitri Gribenko else 7444586df76SDmitri Gribenko Resolved = resolveHTMLHexCharacterReference(Name); 7454586df76SDmitri Gribenko 7464586df76SDmitri Gribenko if (Resolved.empty()) { 7474586df76SDmitri Gribenko formTextToken(T, TokenPtr); 7484586df76SDmitri Gribenko return; 7494586df76SDmitri Gribenko } 7504586df76SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::text); 7514586df76SDmitri Gribenko T.setText(Resolved); 7524586df76SDmitri Gribenko return; 7534586df76SDmitri Gribenko } 7544586df76SDmitri Gribenko 755e00ffc7bSDmitri Gribenko void Lexer::setupAndLexHTMLStartTag(Token &T) { 75617709ae8SDmitri Gribenko assert(BufferPtr[0] == '<' && 75717709ae8SDmitri Gribenko isHTMLIdentifierStartingCharacter(BufferPtr[1])); 7585188c4b9SDmitri Gribenko const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd); 75960ddd8a1SDmitri Gribenko StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1)); 760107618a6SDmitri Gribenko if (!isHTMLTagName(Name)) { 761107618a6SDmitri Gribenko formTextToken(T, TagNameEnd); 762107618a6SDmitri Gribenko return; 763107618a6SDmitri Gribenko } 764107618a6SDmitri Gribenko 765e00ffc7bSDmitri Gribenko formTokenWithChars(T, TagNameEnd, tok::html_start_tag); 766e00ffc7bSDmitri Gribenko T.setHTMLTagStartName(Name); 7675188c4b9SDmitri Gribenko 7685188c4b9SDmitri Gribenko BufferPtr = skipWhitespace(BufferPtr, CommentEnd); 7695188c4b9SDmitri Gribenko 77017709ae8SDmitri Gribenko const char C = *BufferPtr; 77117709ae8SDmitri Gribenko if (BufferPtr != CommentEnd && 772f26054f0SDmitri Gribenko (C == '>' || C == '/' || isHTMLIdentifierStartingCharacter(C))) 773e00ffc7bSDmitri Gribenko State = LS_HTMLStartTag; 7745188c4b9SDmitri Gribenko } 7755188c4b9SDmitri Gribenko 776e00ffc7bSDmitri Gribenko void Lexer::lexHTMLStartTag(Token &T) { 777e00ffc7bSDmitri Gribenko assert(State == LS_HTMLStartTag); 7785188c4b9SDmitri Gribenko 7795188c4b9SDmitri Gribenko const char *TokenPtr = BufferPtr; 7805188c4b9SDmitri Gribenko char C = *TokenPtr; 7815188c4b9SDmitri Gribenko if (isHTMLIdentifierCharacter(C)) { 7825188c4b9SDmitri Gribenko TokenPtr = skipHTMLIdentifier(TokenPtr, CommentEnd); 78360ddd8a1SDmitri Gribenko StringRef Ident(BufferPtr, TokenPtr - BufferPtr); 7845188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_ident); 78560ddd8a1SDmitri Gribenko T.setHTMLIdent(Ident); 7865188c4b9SDmitri Gribenko } else { 7875188c4b9SDmitri Gribenko switch (C) { 7885188c4b9SDmitri Gribenko case '=': 7895188c4b9SDmitri Gribenko TokenPtr++; 7905188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_equals); 7915188c4b9SDmitri Gribenko break; 7925188c4b9SDmitri Gribenko case '\"': 7935188c4b9SDmitri Gribenko case '\'': { 7945188c4b9SDmitri Gribenko const char *OpenQuote = TokenPtr; 7955188c4b9SDmitri Gribenko TokenPtr = skipHTMLQuotedString(TokenPtr, CommentEnd); 7965188c4b9SDmitri Gribenko const char *ClosingQuote = TokenPtr; 7975188c4b9SDmitri Gribenko if (TokenPtr != CommentEnd) // Skip closing quote. 7985188c4b9SDmitri Gribenko TokenPtr++; 7995188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_quoted_string); 8005188c4b9SDmitri Gribenko T.setHTMLQuotedString(StringRef(OpenQuote + 1, 8015188c4b9SDmitri Gribenko ClosingQuote - (OpenQuote + 1))); 8025188c4b9SDmitri Gribenko break; 8035188c4b9SDmitri Gribenko } 8045188c4b9SDmitri Gribenko case '>': 8055188c4b9SDmitri Gribenko TokenPtr++; 8065188c4b9SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_greater); 80717709ae8SDmitri Gribenko State = LS_Normal; 80817709ae8SDmitri Gribenko return; 809f26054f0SDmitri Gribenko case '/': 810f26054f0SDmitri Gribenko TokenPtr++; 811f26054f0SDmitri Gribenko if (TokenPtr != CommentEnd && *TokenPtr == '>') { 812f26054f0SDmitri Gribenko TokenPtr++; 813f26054f0SDmitri Gribenko formTokenWithChars(T, TokenPtr, tok::html_slash_greater); 8144586df76SDmitri Gribenko } else 8154586df76SDmitri Gribenko formTextToken(T, TokenPtr); 8164586df76SDmitri Gribenko 817f26054f0SDmitri Gribenko State = LS_Normal; 818f26054f0SDmitri Gribenko return; 8195188c4b9SDmitri Gribenko } 8205188c4b9SDmitri Gribenko } 8215188c4b9SDmitri Gribenko 8225188c4b9SDmitri Gribenko // Now look ahead and return to normal state if we don't see any HTML tokens 8235188c4b9SDmitri Gribenko // ahead. 8245188c4b9SDmitri Gribenko BufferPtr = skipWhitespace(BufferPtr, CommentEnd); 8255188c4b9SDmitri Gribenko if (BufferPtr == CommentEnd) { 8265188c4b9SDmitri Gribenko State = LS_Normal; 8275188c4b9SDmitri Gribenko return; 8285188c4b9SDmitri Gribenko } 8295188c4b9SDmitri Gribenko 8305188c4b9SDmitri Gribenko C = *BufferPtr; 83117709ae8SDmitri Gribenko if (!isHTMLIdentifierStartingCharacter(C) && 8325188c4b9SDmitri Gribenko C != '=' && C != '\"' && C != '\'' && C != '>') { 8335188c4b9SDmitri Gribenko State = LS_Normal; 8345188c4b9SDmitri Gribenko return; 8355188c4b9SDmitri Gribenko } 8365188c4b9SDmitri Gribenko } 8375188c4b9SDmitri Gribenko 838e00ffc7bSDmitri Gribenko void Lexer::setupAndLexHTMLEndTag(Token &T) { 8395188c4b9SDmitri Gribenko assert(BufferPtr[0] == '<' && BufferPtr[1] == '/'); 8405188c4b9SDmitri Gribenko 8415188c4b9SDmitri Gribenko const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd); 8425188c4b9SDmitri Gribenko const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd); 843107618a6SDmitri Gribenko StringRef Name(TagNameBegin, TagNameEnd - TagNameBegin); 844107618a6SDmitri Gribenko if (!isHTMLTagName(Name)) { 845107618a6SDmitri Gribenko formTextToken(T, TagNameEnd); 846107618a6SDmitri Gribenko return; 847107618a6SDmitri Gribenko } 8485188c4b9SDmitri Gribenko 8495188c4b9SDmitri Gribenko const char *End = skipWhitespace(TagNameEnd, CommentEnd); 8505188c4b9SDmitri Gribenko 851e00ffc7bSDmitri Gribenko formTokenWithChars(T, End, tok::html_end_tag); 852107618a6SDmitri Gribenko T.setHTMLTagEndName(Name); 853ec92531cSDmitri Gribenko 854ec92531cSDmitri Gribenko if (BufferPtr != CommentEnd && *BufferPtr == '>') 855e00ffc7bSDmitri Gribenko State = LS_HTMLEndTag; 856ec92531cSDmitri Gribenko } 857ec92531cSDmitri Gribenko 858e00ffc7bSDmitri Gribenko void Lexer::lexHTMLEndTag(Token &T) { 859ec92531cSDmitri Gribenko assert(BufferPtr != CommentEnd && *BufferPtr == '>'); 860ec92531cSDmitri Gribenko 861ec92531cSDmitri Gribenko formTokenWithChars(T, BufferPtr + 1, tok::html_greater); 862ec92531cSDmitri Gribenko State = LS_Normal; 8635188c4b9SDmitri Gribenko } 8645188c4b9SDmitri Gribenko 865ca7f80adSDmitri Gribenko Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits, 8666bab9113SDmitri Gribenko SourceLocation FileLoc, 8675188c4b9SDmitri Gribenko const char *BufferStart, const char *BufferEnd): 868ca7f80adSDmitri Gribenko Allocator(Allocator), Traits(Traits), 8695188c4b9SDmitri Gribenko BufferStart(BufferStart), BufferEnd(BufferEnd), 8706bab9113SDmitri Gribenko FileLoc(FileLoc), BufferPtr(BufferStart), 8715188c4b9SDmitri Gribenko CommentState(LCS_BeforeComment), State(LS_Normal) { 8725188c4b9SDmitri Gribenko } 8735188c4b9SDmitri Gribenko 8745188c4b9SDmitri Gribenko void Lexer::lex(Token &T) { 8755188c4b9SDmitri Gribenko again: 8765188c4b9SDmitri Gribenko switch (CommentState) { 8775188c4b9SDmitri Gribenko case LCS_BeforeComment: 8785188c4b9SDmitri Gribenko if (BufferPtr == BufferEnd) { 8795188c4b9SDmitri Gribenko formTokenWithChars(T, BufferPtr, tok::eof); 8805188c4b9SDmitri Gribenko return; 8815188c4b9SDmitri Gribenko } 8825188c4b9SDmitri Gribenko 8835188c4b9SDmitri Gribenko assert(*BufferPtr == '/'); 8845188c4b9SDmitri Gribenko BufferPtr++; // Skip first slash. 8855188c4b9SDmitri Gribenko switch(*BufferPtr) { 8865188c4b9SDmitri Gribenko case '/': { // BCPL comment. 8875188c4b9SDmitri Gribenko BufferPtr++; // Skip second slash. 8885188c4b9SDmitri Gribenko 8895188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd) { 8905188c4b9SDmitri Gribenko // Skip Doxygen magic marker, if it is present. 8915188c4b9SDmitri Gribenko // It might be missing because of a typo //< or /*<, or because we 8925188c4b9SDmitri Gribenko // merged this non-Doxygen comment into a bunch of Doxygen comments 8935188c4b9SDmitri Gribenko // around it: /** ... */ /* ... */ /** ... */ 8945188c4b9SDmitri Gribenko const char C = *BufferPtr; 8955188c4b9SDmitri Gribenko if (C == '/' || C == '!') 8965188c4b9SDmitri Gribenko BufferPtr++; 8975188c4b9SDmitri Gribenko } 8985188c4b9SDmitri Gribenko 8995188c4b9SDmitri Gribenko // Skip less-than symbol that marks trailing comments. 9005188c4b9SDmitri Gribenko // Skip it even if the comment is not a Doxygen one, because //< and /*< 9015188c4b9SDmitri Gribenko // are frequent typos. 9025188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '<') 9035188c4b9SDmitri Gribenko BufferPtr++; 9045188c4b9SDmitri Gribenko 9055188c4b9SDmitri Gribenko CommentState = LCS_InsideBCPLComment; 906ec92531cSDmitri Gribenko if (State != LS_VerbatimBlockBody && State != LS_VerbatimBlockFirstLine) 9075188c4b9SDmitri Gribenko State = LS_Normal; 9085188c4b9SDmitri Gribenko CommentEnd = findBCPLCommentEnd(BufferPtr, BufferEnd); 9095188c4b9SDmitri Gribenko goto again; 9105188c4b9SDmitri Gribenko } 9115188c4b9SDmitri Gribenko case '*': { // C comment. 9125188c4b9SDmitri Gribenko BufferPtr++; // Skip star. 9135188c4b9SDmitri Gribenko 9145188c4b9SDmitri Gribenko // Skip Doxygen magic marker. 9155188c4b9SDmitri Gribenko const char C = *BufferPtr; 9165188c4b9SDmitri Gribenko if ((C == '*' && *(BufferPtr + 1) != '/') || C == '!') 9175188c4b9SDmitri Gribenko BufferPtr++; 9185188c4b9SDmitri Gribenko 9195188c4b9SDmitri Gribenko // Skip less-than symbol that marks trailing comments. 9205188c4b9SDmitri Gribenko if (BufferPtr != BufferEnd && *BufferPtr == '<') 9215188c4b9SDmitri Gribenko BufferPtr++; 9225188c4b9SDmitri Gribenko 9235188c4b9SDmitri Gribenko CommentState = LCS_InsideCComment; 9245188c4b9SDmitri Gribenko State = LS_Normal; 9255188c4b9SDmitri Gribenko CommentEnd = findCCommentEnd(BufferPtr, BufferEnd); 9265188c4b9SDmitri Gribenko goto again; 9275188c4b9SDmitri Gribenko } 9285188c4b9SDmitri Gribenko default: 9295188c4b9SDmitri Gribenko llvm_unreachable("second character of comment should be '/' or '*'"); 9305188c4b9SDmitri Gribenko } 9315188c4b9SDmitri Gribenko 9325188c4b9SDmitri Gribenko case LCS_BetweenComments: { 9335188c4b9SDmitri Gribenko // Consecutive comments are extracted only if there is only whitespace 9345188c4b9SDmitri Gribenko // between them. So we can search for the start of the next comment. 9355188c4b9SDmitri Gribenko const char *EndWhitespace = BufferPtr; 9365188c4b9SDmitri Gribenko while(EndWhitespace != BufferEnd && *EndWhitespace != '/') 9375188c4b9SDmitri Gribenko EndWhitespace++; 9385188c4b9SDmitri Gribenko 9395188c4b9SDmitri Gribenko // Turn any whitespace between comments (and there is only whitespace 94017709ae8SDmitri Gribenko // between them -- guaranteed by comment extraction) into a newline. We 94117709ae8SDmitri Gribenko // have two newlines between C comments in total (first one was synthesized 94217709ae8SDmitri Gribenko // after a comment). 9435188c4b9SDmitri Gribenko formTokenWithChars(T, EndWhitespace, tok::newline); 9445188c4b9SDmitri Gribenko 9455188c4b9SDmitri Gribenko CommentState = LCS_BeforeComment; 9465188c4b9SDmitri Gribenko break; 9475188c4b9SDmitri Gribenko } 9485188c4b9SDmitri Gribenko 9495188c4b9SDmitri Gribenko case LCS_InsideBCPLComment: 9505188c4b9SDmitri Gribenko case LCS_InsideCComment: 9515188c4b9SDmitri Gribenko if (BufferPtr != CommentEnd) { 9525188c4b9SDmitri Gribenko lexCommentText(T); 9535188c4b9SDmitri Gribenko break; 9545188c4b9SDmitri Gribenko } else { 9555188c4b9SDmitri Gribenko // Skip C comment closing sequence. 9565188c4b9SDmitri Gribenko if (CommentState == LCS_InsideCComment) { 9575188c4b9SDmitri Gribenko assert(BufferPtr[0] == '*' && BufferPtr[1] == '/'); 9585188c4b9SDmitri Gribenko BufferPtr += 2; 9595188c4b9SDmitri Gribenko assert(BufferPtr <= BufferEnd); 9605188c4b9SDmitri Gribenko 9615188c4b9SDmitri Gribenko // Synthenize newline just after the C comment, regardless if there is 9625188c4b9SDmitri Gribenko // actually a newline. 9635188c4b9SDmitri Gribenko formTokenWithChars(T, BufferPtr, tok::newline); 9645188c4b9SDmitri Gribenko 9655188c4b9SDmitri Gribenko CommentState = LCS_BetweenComments; 9665188c4b9SDmitri Gribenko break; 9675188c4b9SDmitri Gribenko } else { 9685188c4b9SDmitri Gribenko // Don't synthesized a newline after BCPL comment. 9695188c4b9SDmitri Gribenko CommentState = LCS_BetweenComments; 9705188c4b9SDmitri Gribenko goto again; 9715188c4b9SDmitri Gribenko } 9725188c4b9SDmitri Gribenko } 9735188c4b9SDmitri Gribenko } 9745188c4b9SDmitri Gribenko } 9755188c4b9SDmitri Gribenko 9765188c4b9SDmitri Gribenko StringRef Lexer::getSpelling(const Token &Tok, 9775188c4b9SDmitri Gribenko const SourceManager &SourceMgr, 9785188c4b9SDmitri Gribenko bool *Invalid) const { 9795188c4b9SDmitri Gribenko SourceLocation Loc = Tok.getLocation(); 9805188c4b9SDmitri Gribenko std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(Loc); 9815188c4b9SDmitri Gribenko 9825188c4b9SDmitri Gribenko bool InvalidTemp = false; 9835188c4b9SDmitri Gribenko StringRef File = SourceMgr.getBufferData(LocInfo.first, &InvalidTemp); 9845188c4b9SDmitri Gribenko if (InvalidTemp) { 9855188c4b9SDmitri Gribenko *Invalid = true; 9865188c4b9SDmitri Gribenko return StringRef(); 9875188c4b9SDmitri Gribenko } 9885188c4b9SDmitri Gribenko 9895188c4b9SDmitri Gribenko const char *Begin = File.data() + LocInfo.second; 9905188c4b9SDmitri Gribenko return StringRef(Begin, Tok.getLength()); 9915188c4b9SDmitri Gribenko } 9925188c4b9SDmitri Gribenko 9935188c4b9SDmitri Gribenko } // end namespace comments 9945188c4b9SDmitri Gribenko } // end namespace clang 9955188c4b9SDmitri Gribenko 996