1 //===--- CommentLexer.h - Lexer for structured comments ---------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines lexer for structured comments and supporting token class. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_AST_COMMENTLEXER_H 15 #define LLVM_CLANG_AST_COMMENTLEXER_H 16 17 #include "clang/Basic/Diagnostic.h" 18 #include "clang/Basic/SourceManager.h" 19 #include "llvm/ADT/SmallString.h" 20 #include "llvm/ADT/SmallVector.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/Support/Allocator.h" 23 #include "llvm/Support/raw_ostream.h" 24 25 namespace clang { 26 namespace comments { 27 28 class Lexer; 29 class TextTokenRetokenizer; 30 struct CommandInfo; 31 class CommandTraits; 32 33 namespace tok { 34 enum TokenKind { 35 eof, 36 newline, 37 text, 38 unknown_command, // Command that does not have an ID. 39 backslash_command, // Command with an ID, that used backslash marker. 40 at_command, // Command with an ID, that used 'at' marker. 41 verbatim_block_begin, 42 verbatim_block_line, 43 verbatim_block_end, 44 verbatim_line_name, 45 verbatim_line_text, 46 html_start_tag, // <tag 47 html_ident, // attr 48 html_equals, // = 49 html_quoted_string, // "blah\"blah" or 'blah\'blah' 50 html_greater, // > 51 html_slash_greater, // /> 52 html_end_tag // </tag 53 }; 54 } // end namespace tok 55 56 /// \brief Comment token. 57 class Token { 58 friend class Lexer; 59 friend class TextTokenRetokenizer; 60 61 /// The location of the token. 62 SourceLocation Loc; 63 64 /// The actual kind of the token. 65 tok::TokenKind Kind; 66 67 /// Length of the token spelling in comment. Can be 0 for synthenized 68 /// tokens. 69 unsigned Length; 70 71 /// Contains text value associated with a token. 72 const char *TextPtr; 73 74 /// Integer value associated with a token. 75 /// 76 /// If the token is a konwn command, contains command ID and TextPtr is 77 /// unused (command spelling can be found with CommandTraits). Otherwise, 78 /// contains the length of the string that starts at TextPtr. 79 unsigned IntVal; 80 81 public: 82 SourceLocation getLocation() const LLVM_READONLY { return Loc; } 83 void setLocation(SourceLocation SL) { Loc = SL; } 84 85 SourceLocation getEndLocation() const LLVM_READONLY { 86 if (Length == 0 || Length == 1) 87 return Loc; 88 return Loc.getLocWithOffset(Length - 1); 89 } 90 91 tok::TokenKind getKind() const LLVM_READONLY { return Kind; } 92 void setKind(tok::TokenKind K) { Kind = K; } 93 94 bool is(tok::TokenKind K) const LLVM_READONLY { return Kind == K; } 95 bool isNot(tok::TokenKind K) const LLVM_READONLY { return Kind != K; } 96 97 unsigned getLength() const LLVM_READONLY { return Length; } 98 void setLength(unsigned L) { Length = L; } 99 100 StringRef getText() const LLVM_READONLY { 101 assert(is(tok::text)); 102 return StringRef(TextPtr, IntVal); 103 } 104 105 void setText(StringRef Text) { 106 assert(is(tok::text)); 107 TextPtr = Text.data(); 108 IntVal = Text.size(); 109 } 110 111 StringRef getUnknownCommandName() const LLVM_READONLY { 112 assert(is(tok::unknown_command)); 113 return StringRef(TextPtr, IntVal); 114 } 115 116 void setUnknownCommandName(StringRef Name) { 117 assert(is(tok::unknown_command)); 118 TextPtr = Name.data(); 119 IntVal = Name.size(); 120 } 121 122 unsigned getCommandID() const LLVM_READONLY { 123 assert(is(tok::backslash_command) || is(tok::at_command)); 124 return IntVal; 125 } 126 127 void setCommandID(unsigned ID) { 128 assert(is(tok::backslash_command) || is(tok::at_command)); 129 IntVal = ID; 130 } 131 132 unsigned getVerbatimBlockID() const LLVM_READONLY { 133 assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end)); 134 return IntVal; 135 } 136 137 void setVerbatimBlockID(unsigned ID) { 138 assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end)); 139 IntVal = ID; 140 } 141 142 StringRef getVerbatimBlockText() const LLVM_READONLY { 143 assert(is(tok::verbatim_block_line)); 144 return StringRef(TextPtr, IntVal); 145 } 146 147 void setVerbatimBlockText(StringRef Text) { 148 assert(is(tok::verbatim_block_line)); 149 TextPtr = Text.data(); 150 IntVal = Text.size(); 151 } 152 153 unsigned getVerbatimLineID() const LLVM_READONLY { 154 assert(is(tok::verbatim_line_name)); 155 return IntVal; 156 } 157 158 void setVerbatimLineID(unsigned ID) { 159 assert(is(tok::verbatim_line_name)); 160 IntVal = ID; 161 } 162 163 StringRef getVerbatimLineText() const LLVM_READONLY { 164 assert(is(tok::verbatim_line_text)); 165 return StringRef(TextPtr, IntVal); 166 } 167 168 void setVerbatimLineText(StringRef Text) { 169 assert(is(tok::verbatim_line_text)); 170 TextPtr = Text.data(); 171 IntVal = Text.size(); 172 } 173 174 StringRef getHTMLTagStartName() const LLVM_READONLY { 175 assert(is(tok::html_start_tag)); 176 return StringRef(TextPtr, IntVal); 177 } 178 179 void setHTMLTagStartName(StringRef Name) { 180 assert(is(tok::html_start_tag)); 181 TextPtr = Name.data(); 182 IntVal = Name.size(); 183 } 184 185 StringRef getHTMLIdent() const LLVM_READONLY { 186 assert(is(tok::html_ident)); 187 return StringRef(TextPtr, IntVal); 188 } 189 190 void setHTMLIdent(StringRef Name) { 191 assert(is(tok::html_ident)); 192 TextPtr = Name.data(); 193 IntVal = Name.size(); 194 } 195 196 StringRef getHTMLQuotedString() const LLVM_READONLY { 197 assert(is(tok::html_quoted_string)); 198 return StringRef(TextPtr, IntVal); 199 } 200 201 void setHTMLQuotedString(StringRef Str) { 202 assert(is(tok::html_quoted_string)); 203 TextPtr = Str.data(); 204 IntVal = Str.size(); 205 } 206 207 StringRef getHTMLTagEndName() const LLVM_READONLY { 208 assert(is(tok::html_end_tag)); 209 return StringRef(TextPtr, IntVal); 210 } 211 212 void setHTMLTagEndName(StringRef Name) { 213 assert(is(tok::html_end_tag)); 214 TextPtr = Name.data(); 215 IntVal = Name.size(); 216 } 217 218 void dump(const Lexer &L, const SourceManager &SM) const; 219 }; 220 221 /// \brief Comment lexer. 222 class Lexer { 223 private: 224 Lexer(const Lexer &) = delete; 225 void operator=(const Lexer &) = delete; 226 227 /// Allocator for strings that are semantic values of tokens and have to be 228 /// computed (for example, resolved decimal character references). 229 llvm::BumpPtrAllocator &Allocator; 230 231 DiagnosticsEngine &Diags; 232 233 const CommandTraits &Traits; 234 235 const char *const BufferStart; 236 const char *const BufferEnd; 237 SourceLocation FileLoc; 238 239 const char *BufferPtr; 240 241 /// One past end pointer for the current comment. For BCPL comments points 242 /// to newline or BufferEnd, for C comments points to star in '*/'. 243 const char *CommentEnd; 244 245 enum LexerCommentState { 246 LCS_BeforeComment, 247 LCS_InsideBCPLComment, 248 LCS_InsideCComment, 249 LCS_BetweenComments 250 }; 251 252 /// Low-level lexer state, track if we are inside or outside of comment. 253 LexerCommentState CommentState; 254 255 enum LexerState { 256 /// Lexing normal comment text 257 LS_Normal, 258 259 /// Finished lexing verbatim block beginning command, will lex first body 260 /// line. 261 LS_VerbatimBlockFirstLine, 262 263 /// Lexing verbatim block body line-by-line, skipping line-starting 264 /// decorations. 265 LS_VerbatimBlockBody, 266 267 /// Finished lexing verbatim line beginning command, will lex text (one 268 /// line). 269 LS_VerbatimLineText, 270 271 /// Finished lexing \verbatim <TAG \endverbatim part, lexing tag attributes. 272 LS_HTMLStartTag, 273 274 /// Finished lexing \verbatim </TAG \endverbatim part, lexing '>'. 275 LS_HTMLEndTag 276 }; 277 278 /// Current lexing mode. 279 LexerState State; 280 281 /// If State is LS_VerbatimBlock, contains the name of verbatim end 282 /// command, including command marker. 283 SmallString<16> VerbatimBlockEndCommandName; 284 285 /// Given a character reference name (e.g., "lt"), return the character that 286 /// it stands for (e.g., "<"). 287 StringRef resolveHTMLNamedCharacterReference(StringRef Name) const; 288 289 /// Given a Unicode codepoint as base-10 integer, return the character. 290 StringRef resolveHTMLDecimalCharacterReference(StringRef Name) const; 291 292 /// Given a Unicode codepoint as base-16 integer, return the character. 293 StringRef resolveHTMLHexCharacterReference(StringRef Name) const; 294 295 void formTokenWithChars(Token &Result, const char *TokEnd, 296 tok::TokenKind Kind); 297 298 void formTextToken(Token &Result, const char *TokEnd) { 299 StringRef Text(BufferPtr, TokEnd - BufferPtr); 300 formTokenWithChars(Result, TokEnd, tok::text); 301 Result.setText(Text); 302 } 303 304 SourceLocation getSourceLocation(const char *Loc) const { 305 assert(Loc >= BufferStart && Loc <= BufferEnd && 306 "Location out of range for this buffer!"); 307 308 const unsigned CharNo = Loc - BufferStart; 309 return FileLoc.getLocWithOffset(CharNo); 310 } 311 312 DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { 313 return Diags.Report(Loc, DiagID); 314 } 315 316 /// Eat string matching regexp \code \s*\* \endcode. 317 void skipLineStartingDecorations(); 318 319 /// Lex stuff inside comments. CommentEnd should be set correctly. 320 void lexCommentText(Token &T); 321 322 void setupAndLexVerbatimBlock(Token &T, 323 const char *TextBegin, 324 char Marker, const CommandInfo *Info); 325 326 void lexVerbatimBlockFirstLine(Token &T); 327 328 void lexVerbatimBlockBody(Token &T); 329 330 void setupAndLexVerbatimLine(Token &T, const char *TextBegin, 331 const CommandInfo *Info); 332 333 void lexVerbatimLineText(Token &T); 334 335 void lexHTMLCharacterReference(Token &T); 336 337 void setupAndLexHTMLStartTag(Token &T); 338 339 void lexHTMLStartTag(Token &T); 340 341 void setupAndLexHTMLEndTag(Token &T); 342 343 void lexHTMLEndTag(Token &T); 344 345 public: 346 Lexer(llvm::BumpPtrAllocator &Allocator, DiagnosticsEngine &Diags, 347 const CommandTraits &Traits, 348 SourceLocation FileLoc, 349 const char *BufferStart, const char *BufferEnd); 350 351 void lex(Token &T); 352 353 StringRef getSpelling(const Token &Tok, 354 const SourceManager &SourceMgr, 355 bool *Invalid = nullptr) const; 356 }; 357 358 } // end namespace comments 359 } // end namespace clang 360 361 #endif 362 363