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