1 //===- AsmLexer.cpp - Lexer for Assembly Files ----------------------------===// 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 class implements the lexer for assembly files. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/MC/MCParser/AsmLexer.h" 15 #include "llvm/ADT/APInt.h" 16 #include "llvm/ADT/ArrayRef.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/ADT/StringSwitch.h" 19 #include "llvm/MC/MCAsmInfo.h" 20 #include "llvm/MC/MCParser/MCAsmLexer.h" 21 #include "llvm/Support/SMLoc.h" 22 #include "llvm/Support/SaveAndRestore.h" 23 #include <cassert> 24 #include <cctype> 25 #include <cstdio> 26 #include <cstring> 27 #include <string> 28 #include <tuple> 29 #include <utility> 30 31 using namespace llvm; 32 33 AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) { 34 AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@"); 35 } 36 37 AsmLexer::~AsmLexer() = default; 38 39 void AsmLexer::setBuffer(StringRef Buf, const char *ptr) { 40 CurBuf = Buf; 41 42 if (ptr) 43 CurPtr = ptr; 44 else 45 CurPtr = CurBuf.begin(); 46 47 TokStart = nullptr; 48 } 49 50 /// ReturnError - Set the error to the specified string at the specified 51 /// location. This is defined to always return AsmToken::Error. 52 AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { 53 SetError(SMLoc::getFromPointer(Loc), Msg); 54 55 return AsmToken(AsmToken::Error, StringRef(Loc, CurPtr - Loc)); 56 } 57 58 int AsmLexer::getNextChar() { 59 if (CurPtr == CurBuf.end()) 60 return EOF; 61 return (unsigned char)*CurPtr++; 62 } 63 64 /// LexFloatLiteral: [0-9]*[.][0-9]*([eE][+-]?[0-9]*)? 65 /// 66 /// The leading integral digit sequence and dot should have already been 67 /// consumed, some or all of the fractional digit sequence *can* have been 68 /// consumed. 69 AsmToken AsmLexer::LexFloatLiteral() { 70 // Skip the fractional digit sequence. 71 while (isdigit(*CurPtr)) 72 ++CurPtr; 73 74 // Check for exponent; we intentionally accept a slighlty wider set of 75 // literals here and rely on the upstream client to reject invalid ones (e.g., 76 // "1e+"). 77 if (*CurPtr == 'e' || *CurPtr == 'E') { 78 ++CurPtr; 79 if (*CurPtr == '-' || *CurPtr == '+') 80 ++CurPtr; 81 while (isdigit(*CurPtr)) 82 ++CurPtr; 83 } 84 85 return AsmToken(AsmToken::Real, 86 StringRef(TokStart, CurPtr - TokStart)); 87 } 88 89 /// LexHexFloatLiteral matches essentially (.[0-9a-fA-F]*)?[pP][+-]?[0-9a-fA-F]+ 90 /// while making sure there are enough actual digits around for the constant to 91 /// be valid. 92 /// 93 /// The leading "0x[0-9a-fA-F]*" (i.e. integer part) has already been consumed 94 /// before we get here. 95 AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) { 96 assert((*CurPtr == 'p' || *CurPtr == 'P' || *CurPtr == '.') && 97 "unexpected parse state in floating hex"); 98 bool NoFracDigits = true; 99 100 // Skip the fractional part if there is one 101 if (*CurPtr == '.') { 102 ++CurPtr; 103 104 const char *FracStart = CurPtr; 105 while (isxdigit(*CurPtr)) 106 ++CurPtr; 107 108 NoFracDigits = CurPtr == FracStart; 109 } 110 111 if (NoIntDigits && NoFracDigits) 112 return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " 113 "expected at least one significand digit"); 114 115 // Make sure we do have some kind of proper exponent part 116 if (*CurPtr != 'p' && *CurPtr != 'P') 117 return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " 118 "expected exponent part 'p'"); 119 ++CurPtr; 120 121 if (*CurPtr == '+' || *CurPtr == '-') 122 ++CurPtr; 123 124 // N.b. exponent digits are *not* hex 125 const char *ExpStart = CurPtr; 126 while (isdigit(*CurPtr)) 127 ++CurPtr; 128 129 if (CurPtr == ExpStart) 130 return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " 131 "expected at least one exponent digit"); 132 133 return AsmToken(AsmToken::Real, StringRef(TokStart, CurPtr - TokStart)); 134 } 135 136 /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@?]* 137 static bool IsIdentifierChar(char c, bool AllowAt) { 138 return isalnum(c) || c == '_' || c == '$' || c == '.' || 139 (c == '@' && AllowAt) || c == '?'; 140 } 141 142 AsmToken AsmLexer::LexIdentifier() { 143 // Check for floating point literals. 144 if (CurPtr[-1] == '.' && isdigit(*CurPtr)) { 145 // Disambiguate a .1243foo identifier from a floating literal. 146 while (isdigit(*CurPtr)) 147 ++CurPtr; 148 if (*CurPtr == 'e' || *CurPtr == 'E' || 149 !IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) 150 return LexFloatLiteral(); 151 } 152 153 while (IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) 154 ++CurPtr; 155 156 // Handle . as a special case. 157 if (CurPtr == TokStart+1 && TokStart[0] == '.') 158 return AsmToken(AsmToken::Dot, StringRef(TokStart, 1)); 159 160 return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); 161 } 162 163 /// LexSlash: Slash: / 164 /// C-Style Comment: /* ... */ 165 AsmToken AsmLexer::LexSlash() { 166 switch (*CurPtr) { 167 case '*': 168 IsAtStartOfStatement = false; 169 break; // C style comment. 170 case '/': 171 ++CurPtr; 172 return LexLineComment(); 173 default: 174 IsAtStartOfStatement = false; 175 return AsmToken(AsmToken::Slash, StringRef(TokStart, 1)); 176 } 177 178 // C Style comment. 179 ++CurPtr; // skip the star. 180 const char *CommentTextStart = CurPtr; 181 while (CurPtr != CurBuf.end()) { 182 switch (*CurPtr++) { 183 case '*': 184 // End of the comment? 185 if (*CurPtr != '/') 186 break; 187 // If we have a CommentConsumer, notify it about the comment. 188 if (CommentConsumer) { 189 CommentConsumer->HandleComment( 190 SMLoc::getFromPointer(CommentTextStart), 191 StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart)); 192 } 193 ++CurPtr; // End the */. 194 return AsmToken(AsmToken::Comment, 195 StringRef(TokStart, CurPtr - TokStart)); 196 } 197 } 198 return ReturnError(TokStart, "unterminated comment"); 199 } 200 201 /// LexLineComment: Comment: #[^\n]* 202 /// : //[^\n]* 203 AsmToken AsmLexer::LexLineComment() { 204 // Mark This as an end of statement with a body of the 205 // comment. While it would be nicer to leave this two tokens, 206 // backwards compatability with TargetParsers makes keeping this in this form 207 // better. 208 const char *CommentTextStart = CurPtr; 209 int CurChar = getNextChar(); 210 while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF) 211 CurChar = getNextChar(); 212 213 // If we have a CommentConsumer, notify it about the comment. 214 if (CommentConsumer) { 215 CommentConsumer->HandleComment( 216 SMLoc::getFromPointer(CommentTextStart), 217 StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart)); 218 } 219 220 IsAtStartOfLine = true; 221 // This is a whole line comment. leave newline 222 if (IsAtStartOfStatement) 223 return AsmToken(AsmToken::EndOfStatement, 224 StringRef(TokStart, CurPtr - TokStart)); 225 IsAtStartOfStatement = true; 226 227 return AsmToken(AsmToken::EndOfStatement, 228 StringRef(TokStart, CurPtr - 1 - TokStart)); 229 } 230 231 static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { 232 // Skip ULL, UL, U, L and LL suffices. 233 if (CurPtr[0] == 'U') 234 ++CurPtr; 235 if (CurPtr[0] == 'L') 236 ++CurPtr; 237 if (CurPtr[0] == 'L') 238 ++CurPtr; 239 } 240 241 // Look ahead to search for first non-hex digit, if it's [hH], then we treat the 242 // integer as a hexadecimal, possibly with leading zeroes. 243 static unsigned doLookAhead(const char *&CurPtr, unsigned DefaultRadix) { 244 const char *FirstHex = nullptr; 245 const char *LookAhead = CurPtr; 246 while (true) { 247 if (isdigit(*LookAhead)) { 248 ++LookAhead; 249 } else if (isxdigit(*LookAhead)) { 250 if (!FirstHex) 251 FirstHex = LookAhead; 252 ++LookAhead; 253 } else { 254 break; 255 } 256 } 257 bool isHex = *LookAhead == 'h' || *LookAhead == 'H'; 258 CurPtr = isHex || !FirstHex ? LookAhead : FirstHex; 259 if (isHex) 260 return 16; 261 return DefaultRadix; 262 } 263 264 static AsmToken intToken(StringRef Ref, APInt &Value) 265 { 266 if (Value.isIntN(64)) 267 return AsmToken(AsmToken::Integer, Ref, Value); 268 return AsmToken(AsmToken::BigNum, Ref, Value); 269 } 270 271 /// LexDigit: First character is [0-9]. 272 /// Local Label: [0-9][:] 273 /// Forward/Backward Label: [0-9][fb] 274 /// Binary integer: 0b[01]+ 275 /// Octal integer: 0[0-7]+ 276 /// Hex integer: 0x[0-9a-fA-F]+ or [0x]?[0-9][0-9a-fA-F]*[hH] 277 /// Decimal integer: [1-9][0-9]* 278 AsmToken AsmLexer::LexDigit() { 279 // MASM-flavor binary integer: [01]+[bB] 280 // MASM-flavor hexadecimal integer: [0-9][0-9a-fA-F]*[hH] 281 if (IsParsingMSInlineAsm && isdigit(CurPtr[-1])) { 282 const char *FirstNonBinary = (CurPtr[-1] != '0' && CurPtr[-1] != '1') ? 283 CurPtr - 1 : nullptr; 284 const char *OldCurPtr = CurPtr; 285 while (isxdigit(*CurPtr)) { 286 if (*CurPtr != '0' && *CurPtr != '1' && !FirstNonBinary) 287 FirstNonBinary = CurPtr; 288 ++CurPtr; 289 } 290 291 unsigned Radix = 0; 292 if (*CurPtr == 'h' || *CurPtr == 'H') { 293 // hexadecimal number 294 ++CurPtr; 295 Radix = 16; 296 } else if (FirstNonBinary && FirstNonBinary + 1 == CurPtr && 297 (*FirstNonBinary == 'b' || *FirstNonBinary == 'B')) 298 Radix = 2; 299 300 if (Radix == 2 || Radix == 16) { 301 StringRef Result(TokStart, CurPtr - TokStart); 302 APInt Value(128, 0, true); 303 304 if (Result.drop_back().getAsInteger(Radix, Value)) 305 return ReturnError(TokStart, Radix == 2 ? "invalid binary number" : 306 "invalid hexdecimal number"); 307 308 // MSVC accepts and ignores type suffices on integer literals. 309 SkipIgnoredIntegerSuffix(CurPtr); 310 311 return intToken(Result, Value); 312 } 313 314 // octal/decimal integers, or floating point numbers, fall through 315 CurPtr = OldCurPtr; 316 } 317 318 // Decimal integer: [1-9][0-9]* 319 if (CurPtr[-1] != '0' || CurPtr[0] == '.') { 320 unsigned Radix = doLookAhead(CurPtr, 10); 321 bool isHex = Radix == 16; 322 // Check for floating point literals. 323 if (!isHex && (*CurPtr == '.' || *CurPtr == 'e')) { 324 ++CurPtr; 325 return LexFloatLiteral(); 326 } 327 328 StringRef Result(TokStart, CurPtr - TokStart); 329 330 APInt Value(128, 0, true); 331 if (Result.getAsInteger(Radix, Value)) 332 return ReturnError(TokStart, !isHex ? "invalid decimal number" : 333 "invalid hexdecimal number"); 334 335 // Consume the [bB][hH]. 336 if (Radix == 2 || Radix == 16) 337 ++CurPtr; 338 339 // The darwin/x86 (and x86-64) assembler accepts and ignores type 340 // suffices on integer literals. 341 SkipIgnoredIntegerSuffix(CurPtr); 342 343 return intToken(Result, Value); 344 } 345 346 if (!IsParsingMSInlineAsm && ((*CurPtr == 'b') || (*CurPtr == 'B'))) { 347 ++CurPtr; 348 // See if we actually have "0b" as part of something like "jmp 0b\n" 349 if (!isdigit(CurPtr[0])) { 350 --CurPtr; 351 StringRef Result(TokStart, CurPtr - TokStart); 352 return AsmToken(AsmToken::Integer, Result, 0); 353 } 354 const char *NumStart = CurPtr; 355 while (CurPtr[0] == '0' || CurPtr[0] == '1') 356 ++CurPtr; 357 358 // Requires at least one binary digit. 359 if (CurPtr == NumStart) 360 return ReturnError(TokStart, "invalid binary number"); 361 362 StringRef Result(TokStart, CurPtr - TokStart); 363 364 APInt Value(128, 0, true); 365 if (Result.substr(2).getAsInteger(2, Value)) 366 return ReturnError(TokStart, "invalid binary number"); 367 368 // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL 369 // suffixes on integer literals. 370 SkipIgnoredIntegerSuffix(CurPtr); 371 372 return intToken(Result, Value); 373 } 374 375 if ((*CurPtr == 'x') || (*CurPtr == 'X')) { 376 ++CurPtr; 377 const char *NumStart = CurPtr; 378 while (isxdigit(CurPtr[0])) 379 ++CurPtr; 380 381 // "0x.0p0" is valid, and "0x0p0" (but not "0xp0" for example, which will be 382 // diagnosed by LexHexFloatLiteral). 383 if (CurPtr[0] == '.' || CurPtr[0] == 'p' || CurPtr[0] == 'P') 384 return LexHexFloatLiteral(NumStart == CurPtr); 385 386 // Otherwise requires at least one hex digit. 387 if (CurPtr == NumStart) 388 return ReturnError(CurPtr-2, "invalid hexadecimal number"); 389 390 APInt Result(128, 0); 391 if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) 392 return ReturnError(TokStart, "invalid hexadecimal number"); 393 394 // Consume the optional [hH]. 395 if (!IsParsingMSInlineAsm && (*CurPtr == 'h' || *CurPtr == 'H')) 396 ++CurPtr; 397 398 // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL 399 // suffixes on integer literals. 400 SkipIgnoredIntegerSuffix(CurPtr); 401 402 return intToken(StringRef(TokStart, CurPtr - TokStart), Result); 403 } 404 405 // Either octal or hexadecimal. 406 APInt Value(128, 0, true); 407 unsigned Radix = doLookAhead(CurPtr, 8); 408 bool isHex = Radix == 16; 409 StringRef Result(TokStart, CurPtr - TokStart); 410 if (Result.getAsInteger(Radix, Value)) 411 return ReturnError(TokStart, !isHex ? "invalid octal number" : 412 "invalid hexdecimal number"); 413 414 // Consume the [hH]. 415 if (Radix == 16) 416 ++CurPtr; 417 418 // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL 419 // suffixes on integer literals. 420 SkipIgnoredIntegerSuffix(CurPtr); 421 422 return intToken(Result, Value); 423 } 424 425 /// LexSingleQuote: Integer: 'b' 426 AsmToken AsmLexer::LexSingleQuote() { 427 int CurChar = getNextChar(); 428 429 if (CurChar == '\\') 430 CurChar = getNextChar(); 431 432 if (CurChar == EOF) 433 return ReturnError(TokStart, "unterminated single quote"); 434 435 CurChar = getNextChar(); 436 437 if (CurChar != '\'') 438 return ReturnError(TokStart, "single quote way too long"); 439 440 // The idea here being that 'c' is basically just an integral 441 // constant. 442 StringRef Res = StringRef(TokStart,CurPtr - TokStart); 443 long long Value; 444 445 if (Res.startswith("\'\\")) { 446 char theChar = Res[2]; 447 switch (theChar) { 448 default: Value = theChar; break; 449 case '\'': Value = '\''; break; 450 case 't': Value = '\t'; break; 451 case 'n': Value = '\n'; break; 452 case 'b': Value = '\b'; break; 453 } 454 } else 455 Value = TokStart[1]; 456 457 return AsmToken(AsmToken::Integer, Res, Value); 458 } 459 460 /// LexQuote: String: "..." 461 AsmToken AsmLexer::LexQuote() { 462 int CurChar = getNextChar(); 463 // TODO: does gas allow multiline string constants? 464 while (CurChar != '"') { 465 if (CurChar == '\\') { 466 // Allow \", etc. 467 CurChar = getNextChar(); 468 } 469 470 if (CurChar == EOF) 471 return ReturnError(TokStart, "unterminated string constant"); 472 473 CurChar = getNextChar(); 474 } 475 476 return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); 477 } 478 479 StringRef AsmLexer::LexUntilEndOfStatement() { 480 TokStart = CurPtr; 481 482 while (!isAtStartOfComment(CurPtr) && // Start of line comment. 483 !isAtStatementSeparator(CurPtr) && // End of statement marker. 484 *CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) { 485 ++CurPtr; 486 } 487 return StringRef(TokStart, CurPtr-TokStart); 488 } 489 490 StringRef AsmLexer::LexUntilEndOfLine() { 491 TokStart = CurPtr; 492 493 while (*CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) { 494 ++CurPtr; 495 } 496 return StringRef(TokStart, CurPtr-TokStart); 497 } 498 499 size_t AsmLexer::peekTokens(MutableArrayRef<AsmToken> Buf, 500 bool ShouldSkipSpace) { 501 SaveAndRestore<const char *> SavedTokenStart(TokStart); 502 SaveAndRestore<const char *> SavedCurPtr(CurPtr); 503 SaveAndRestore<bool> SavedAtStartOfLine(IsAtStartOfLine); 504 SaveAndRestore<bool> SavedAtStartOfStatement(IsAtStartOfStatement); 505 SaveAndRestore<bool> SavedSkipSpace(SkipSpace, ShouldSkipSpace); 506 SaveAndRestore<bool> SavedIsPeeking(IsPeeking, true); 507 std::string SavedErr = getErr(); 508 SMLoc SavedErrLoc = getErrLoc(); 509 510 size_t ReadCount; 511 for (ReadCount = 0; ReadCount < Buf.size(); ++ReadCount) { 512 AsmToken Token = LexToken(); 513 514 Buf[ReadCount] = Token; 515 516 if (Token.is(AsmToken::Eof)) 517 break; 518 } 519 520 SetError(SavedErrLoc, SavedErr); 521 return ReadCount; 522 } 523 524 bool AsmLexer::isAtStartOfComment(const char *Ptr) { 525 StringRef CommentString = MAI.getCommentString(); 526 527 if (CommentString.size() == 1) 528 return CommentString[0] == Ptr[0]; 529 530 // Allow # preprocessor commments also be counted as comments for "##" cases 531 if (CommentString[1] == '#') 532 return CommentString[0] == Ptr[0]; 533 534 return strncmp(Ptr, CommentString.data(), CommentString.size()) == 0; 535 } 536 537 bool AsmLexer::isAtStatementSeparator(const char *Ptr) { 538 return strncmp(Ptr, MAI.getSeparatorString(), 539 strlen(MAI.getSeparatorString())) == 0; 540 } 541 542 AsmToken AsmLexer::LexToken() { 543 TokStart = CurPtr; 544 // This always consumes at least one character. 545 int CurChar = getNextChar(); 546 547 if (!IsPeeking && CurChar == '#' && IsAtStartOfStatement) { 548 // If this starts with a '#', this may be a cpp 549 // hash directive and otherwise a line comment. 550 AsmToken TokenBuf[2]; 551 MutableArrayRef<AsmToken> Buf(TokenBuf, 2); 552 size_t num = peekTokens(Buf, true); 553 // There cannot be a space preceeding this 554 if (IsAtStartOfLine && num == 2 && TokenBuf[0].is(AsmToken::Integer) && 555 TokenBuf[1].is(AsmToken::String)) { 556 CurPtr = TokStart; // reset curPtr; 557 StringRef s = LexUntilEndOfLine(); 558 UnLex(TokenBuf[1]); 559 UnLex(TokenBuf[0]); 560 return AsmToken(AsmToken::HashDirective, s); 561 } 562 return LexLineComment(); 563 } 564 565 if (isAtStartOfComment(TokStart)) 566 return LexLineComment(); 567 568 if (isAtStatementSeparator(TokStart)) { 569 CurPtr += strlen(MAI.getSeparatorString()) - 1; 570 IsAtStartOfLine = true; 571 IsAtStartOfStatement = true; 572 return AsmToken(AsmToken::EndOfStatement, 573 StringRef(TokStart, strlen(MAI.getSeparatorString()))); 574 } 575 576 // If we're missing a newline at EOF, make sure we still get an 577 // EndOfStatement token before the Eof token. 578 if (CurChar == EOF && !IsAtStartOfStatement) { 579 IsAtStartOfLine = true; 580 IsAtStartOfStatement = true; 581 return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); 582 } 583 IsAtStartOfLine = false; 584 bool OldIsAtStartOfStatement = IsAtStartOfStatement; 585 IsAtStartOfStatement = false; 586 switch (CurChar) { 587 default: 588 // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* 589 if (isalpha(CurChar) || CurChar == '_' || CurChar == '.') 590 return LexIdentifier(); 591 592 // Unknown character, emit an error. 593 return ReturnError(TokStart, "invalid character in input"); 594 case EOF: 595 IsAtStartOfLine = true; 596 IsAtStartOfStatement = true; 597 return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); 598 case 0: 599 case ' ': 600 case '\t': 601 IsAtStartOfStatement = OldIsAtStartOfStatement; 602 while (*CurPtr == ' ' || *CurPtr == '\t') 603 CurPtr++; 604 if (SkipSpace) 605 return LexToken(); // Ignore whitespace. 606 else 607 return AsmToken(AsmToken::Space, StringRef(TokStart, CurPtr - TokStart)); 608 case '\n': 609 case '\r': 610 IsAtStartOfLine = true; 611 IsAtStartOfStatement = true; 612 return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); 613 case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); 614 case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); 615 case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); 616 case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); 617 case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); 618 case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); 619 case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); 620 case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); 621 case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); 622 case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); 623 case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); 624 case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); 625 case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); 626 case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); 627 case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1)); 628 case '=': 629 if (*CurPtr == '=') { 630 ++CurPtr; 631 return AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); 632 } 633 return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); 634 case '|': 635 if (*CurPtr == '|') { 636 ++CurPtr; 637 return AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); 638 } 639 return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); 640 case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); 641 case '&': 642 if (*CurPtr == '&') { 643 ++CurPtr; 644 return AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); 645 } 646 return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); 647 case '!': 648 if (*CurPtr == '=') { 649 ++CurPtr; 650 return AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); 651 } 652 return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); 653 case '%': 654 if (MAI.hasMipsExpressions()) { 655 AsmToken::TokenKind Operator; 656 unsigned OperatorLength; 657 658 std::tie(Operator, OperatorLength) = 659 StringSwitch<std::pair<AsmToken::TokenKind, unsigned>>( 660 StringRef(CurPtr)) 661 .StartsWith("call16", {AsmToken::PercentCall16, 7}) 662 .StartsWith("call_hi", {AsmToken::PercentCall_Hi, 8}) 663 .StartsWith("call_lo", {AsmToken::PercentCall_Lo, 8}) 664 .StartsWith("dtprel_hi", {AsmToken::PercentDtprel_Hi, 10}) 665 .StartsWith("dtprel_lo", {AsmToken::PercentDtprel_Lo, 10}) 666 .StartsWith("got_disp", {AsmToken::PercentGot_Disp, 9}) 667 .StartsWith("got_hi", {AsmToken::PercentGot_Hi, 7}) 668 .StartsWith("got_lo", {AsmToken::PercentGot_Lo, 7}) 669 .StartsWith("got_ofst", {AsmToken::PercentGot_Ofst, 9}) 670 .StartsWith("got_page", {AsmToken::PercentGot_Page, 9}) 671 .StartsWith("gottprel", {AsmToken::PercentGottprel, 9}) 672 .StartsWith("got", {AsmToken::PercentGot, 4}) 673 .StartsWith("gp_rel", {AsmToken::PercentGp_Rel, 7}) 674 .StartsWith("higher", {AsmToken::PercentHigher, 7}) 675 .StartsWith("highest", {AsmToken::PercentHighest, 8}) 676 .StartsWith("hi", {AsmToken::PercentHi, 3}) 677 .StartsWith("lo", {AsmToken::PercentLo, 3}) 678 .StartsWith("neg", {AsmToken::PercentNeg, 4}) 679 .StartsWith("pcrel_hi", {AsmToken::PercentPcrel_Hi, 9}) 680 .StartsWith("pcrel_lo", {AsmToken::PercentPcrel_Lo, 9}) 681 .StartsWith("tlsgd", {AsmToken::PercentTlsgd, 6}) 682 .StartsWith("tlsldm", {AsmToken::PercentTlsldm, 7}) 683 .StartsWith("tprel_hi", {AsmToken::PercentTprel_Hi, 9}) 684 .StartsWith("tprel_lo", {AsmToken::PercentTprel_Lo, 9}) 685 .Default({AsmToken::Percent, 1}); 686 687 if (Operator != AsmToken::Percent) { 688 CurPtr += OperatorLength - 1; 689 return AsmToken(Operator, StringRef(TokStart, OperatorLength)); 690 } 691 } 692 return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); 693 case '/': 694 IsAtStartOfStatement = OldIsAtStartOfStatement; 695 return LexSlash(); 696 case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); 697 case '\'': return LexSingleQuote(); 698 case '"': return LexQuote(); 699 case '0': case '1': case '2': case '3': case '4': 700 case '5': case '6': case '7': case '8': case '9': 701 return LexDigit(); 702 case '<': 703 switch (*CurPtr) { 704 case '<': 705 ++CurPtr; 706 return AsmToken(AsmToken::LessLess, StringRef(TokStart, 2)); 707 case '=': 708 ++CurPtr; 709 return AsmToken(AsmToken::LessEqual, StringRef(TokStart, 2)); 710 case '>': 711 ++CurPtr; 712 return AsmToken(AsmToken::LessGreater, StringRef(TokStart, 2)); 713 default: 714 return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); 715 } 716 case '>': 717 switch (*CurPtr) { 718 case '>': 719 ++CurPtr; 720 return AsmToken(AsmToken::GreaterGreater, StringRef(TokStart, 2)); 721 case '=': 722 ++CurPtr; 723 return AsmToken(AsmToken::GreaterEqual, StringRef(TokStart, 2)); 724 default: 725 return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); 726 } 727 728 // TODO: Quoted identifiers (objc methods etc) 729 // local labels: [0-9][:] 730 // Forward/backward labels: [0-9][fb] 731 // Integers, fp constants, character constants. 732 } 733 } 734