LLVM API Documentation
00001 //===- AsmLexer.cpp - Lexer for Assembly Files ----------------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This class implements the lexer for assembly files. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "llvm/MC/MCParser/AsmLexer.h" 00015 #include "llvm/MC/MCAsmInfo.h" 00016 #include "llvm/Support/MemoryBuffer.h" 00017 #include "llvm/Support/SMLoc.h" 00018 #include <cctype> 00019 #include <cerrno> 00020 #include <cstdio> 00021 #include <cstdlib> 00022 using namespace llvm; 00023 00024 AsmLexer::AsmLexer(const MCAsmInfo &_MAI) : MAI(_MAI) { 00025 CurPtr = nullptr; 00026 isAtStartOfLine = true; 00027 AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@"); 00028 } 00029 00030 AsmLexer::~AsmLexer() { 00031 } 00032 00033 void AsmLexer::setBuffer(StringRef Buf, const char *ptr) { 00034 CurBuf = Buf; 00035 00036 if (ptr) 00037 CurPtr = ptr; 00038 else 00039 CurPtr = CurBuf.begin(); 00040 00041 TokStart = nullptr; 00042 } 00043 00044 /// ReturnError - Set the error to the specified string at the specified 00045 /// location. This is defined to always return AsmToken::Error. 00046 AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { 00047 SetError(SMLoc::getFromPointer(Loc), Msg); 00048 00049 return AsmToken(AsmToken::Error, StringRef(Loc, 0)); 00050 } 00051 00052 int AsmLexer::getNextChar() { 00053 char CurChar = *CurPtr++; 00054 switch (CurChar) { 00055 default: 00056 return (unsigned char)CurChar; 00057 case 0: 00058 // A nul character in the stream is either the end of the current buffer or 00059 // a random nul in the file. Disambiguate that here. 00060 if (CurPtr - 1 != CurBuf.end()) 00061 return 0; // Just whitespace. 00062 00063 // Otherwise, return end of file. 00064 --CurPtr; // Another call to lex will return EOF again. 00065 return EOF; 00066 } 00067 } 00068 00069 /// LexFloatLiteral: [0-9]*[.][0-9]*([eE][+-]?[0-9]*)? 00070 /// 00071 /// The leading integral digit sequence and dot should have already been 00072 /// consumed, some or all of the fractional digit sequence *can* have been 00073 /// consumed. 00074 AsmToken AsmLexer::LexFloatLiteral() { 00075 // Skip the fractional digit sequence. 00076 while (isdigit(*CurPtr)) 00077 ++CurPtr; 00078 00079 // Check for exponent; we intentionally accept a slighlty wider set of 00080 // literals here and rely on the upstream client to reject invalid ones (e.g., 00081 // "1e+"). 00082 if (*CurPtr == 'e' || *CurPtr == 'E') { 00083 ++CurPtr; 00084 if (*CurPtr == '-' || *CurPtr == '+') 00085 ++CurPtr; 00086 while (isdigit(*CurPtr)) 00087 ++CurPtr; 00088 } 00089 00090 return AsmToken(AsmToken::Real, 00091 StringRef(TokStart, CurPtr - TokStart)); 00092 } 00093 00094 /// LexHexFloatLiteral matches essentially (.[0-9a-fA-F]*)?[pP][+-]?[0-9a-fA-F]+ 00095 /// while making sure there are enough actual digits around for the constant to 00096 /// be valid. 00097 /// 00098 /// The leading "0x[0-9a-fA-F]*" (i.e. integer part) has already been consumed 00099 /// before we get here. 00100 AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) { 00101 assert((*CurPtr == 'p' || *CurPtr == 'P' || *CurPtr == '.') && 00102 "unexpected parse state in floating hex"); 00103 bool NoFracDigits = true; 00104 00105 // Skip the fractional part if there is one 00106 if (*CurPtr == '.') { 00107 ++CurPtr; 00108 00109 const char *FracStart = CurPtr; 00110 while (isxdigit(*CurPtr)) 00111 ++CurPtr; 00112 00113 NoFracDigits = CurPtr == FracStart; 00114 } 00115 00116 if (NoIntDigits && NoFracDigits) 00117 return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " 00118 "expected at least one significand digit"); 00119 00120 // Make sure we do have some kind of proper exponent part 00121 if (*CurPtr != 'p' && *CurPtr != 'P') 00122 return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " 00123 "expected exponent part 'p'"); 00124 ++CurPtr; 00125 00126 if (*CurPtr == '+' || *CurPtr == '-') 00127 ++CurPtr; 00128 00129 // N.b. exponent digits are *not* hex 00130 const char *ExpStart = CurPtr; 00131 while (isdigit(*CurPtr)) 00132 ++CurPtr; 00133 00134 if (CurPtr == ExpStart) 00135 return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " 00136 "expected at least one exponent digit"); 00137 00138 return AsmToken(AsmToken::Real, StringRef(TokStart, CurPtr - TokStart)); 00139 } 00140 00141 /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@?]* 00142 static bool IsIdentifierChar(char c, bool AllowAt) { 00143 return isalnum(c) || c == '_' || c == '$' || c == '.' || 00144 (c == '@' && AllowAt) || c == '?'; 00145 } 00146 AsmToken AsmLexer::LexIdentifier() { 00147 // Check for floating point literals. 00148 if (CurPtr[-1] == '.' && isdigit(*CurPtr)) { 00149 // Disambiguate a .1243foo identifier from a floating literal. 00150 while (isdigit(*CurPtr)) 00151 ++CurPtr; 00152 if (*CurPtr == 'e' || *CurPtr == 'E' || 00153 !IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) 00154 return LexFloatLiteral(); 00155 } 00156 00157 while (IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) 00158 ++CurPtr; 00159 00160 // Handle . as a special case. 00161 if (CurPtr == TokStart+1 && TokStart[0] == '.') 00162 return AsmToken(AsmToken::Dot, StringRef(TokStart, 1)); 00163 00164 return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); 00165 } 00166 00167 /// LexSlash: Slash: / 00168 /// C-Style Comment: /* ... */ 00169 AsmToken AsmLexer::LexSlash() { 00170 switch (*CurPtr) { 00171 case '*': break; // C style comment. 00172 case '/': return ++CurPtr, LexLineComment(); 00173 default: return AsmToken(AsmToken::Slash, StringRef(CurPtr-1, 1)); 00174 } 00175 00176 // C Style comment. 00177 ++CurPtr; // skip the star. 00178 while (1) { 00179 int CurChar = getNextChar(); 00180 switch (CurChar) { 00181 case EOF: 00182 return ReturnError(TokStart, "unterminated comment"); 00183 case '*': 00184 // End of the comment? 00185 if (CurPtr[0] != '/') break; 00186 00187 ++CurPtr; // End the */. 00188 return LexToken(); 00189 } 00190 } 00191 } 00192 00193 /// LexLineComment: Comment: #[^\n]* 00194 /// : //[^\n]* 00195 AsmToken AsmLexer::LexLineComment() { 00196 // FIXME: This is broken if we happen to a comment at the end of a file, which 00197 // was .included, and which doesn't end with a newline. 00198 int CurChar = getNextChar(); 00199 while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF) 00200 CurChar = getNextChar(); 00201 00202 if (CurChar == EOF) 00203 return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); 00204 return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 0)); 00205 } 00206 00207 static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { 00208 // Skip ULL, UL, U, L and LL suffices. 00209 if (CurPtr[0] == 'U') 00210 ++CurPtr; 00211 if (CurPtr[0] == 'L') 00212 ++CurPtr; 00213 if (CurPtr[0] == 'L') 00214 ++CurPtr; 00215 } 00216 00217 // Look ahead to search for first non-hex digit, if it's [hH], then we treat the 00218 // integer as a hexadecimal, possibly with leading zeroes. 00219 static unsigned doLookAhead(const char *&CurPtr, unsigned DefaultRadix) { 00220 const char *FirstHex = nullptr; 00221 const char *LookAhead = CurPtr; 00222 while (1) { 00223 if (isdigit(*LookAhead)) { 00224 ++LookAhead; 00225 } else if (isxdigit(*LookAhead)) { 00226 if (!FirstHex) 00227 FirstHex = LookAhead; 00228 ++LookAhead; 00229 } else { 00230 break; 00231 } 00232 } 00233 bool isHex = *LookAhead == 'h' || *LookAhead == 'H'; 00234 CurPtr = isHex || !FirstHex ? LookAhead : FirstHex; 00235 if (isHex) 00236 return 16; 00237 return DefaultRadix; 00238 } 00239 00240 static AsmToken intToken(StringRef Ref, APInt &Value) 00241 { 00242 if (Value.isIntN(64)) 00243 return AsmToken(AsmToken::Integer, Ref, Value); 00244 return AsmToken(AsmToken::BigNum, Ref, Value); 00245 } 00246 00247 /// LexDigit: First character is [0-9]. 00248 /// Local Label: [0-9][:] 00249 /// Forward/Backward Label: [0-9][fb] 00250 /// Binary integer: 0b[01]+ 00251 /// Octal integer: 0[0-7]+ 00252 /// Hex integer: 0x[0-9a-fA-F]+ or [0x]?[0-9][0-9a-fA-F]*[hH] 00253 /// Decimal integer: [1-9][0-9]* 00254 AsmToken AsmLexer::LexDigit() { 00255 // Decimal integer: [1-9][0-9]* 00256 if (CurPtr[-1] != '0' || CurPtr[0] == '.') { 00257 unsigned Radix = doLookAhead(CurPtr, 10); 00258 bool isHex = Radix == 16; 00259 // Check for floating point literals. 00260 if (!isHex && (*CurPtr == '.' || *CurPtr == 'e')) { 00261 ++CurPtr; 00262 return LexFloatLiteral(); 00263 } 00264 00265 StringRef Result(TokStart, CurPtr - TokStart); 00266 00267 APInt Value(128, 0, true); 00268 if (Result.getAsInteger(Radix, Value)) 00269 return ReturnError(TokStart, !isHex ? "invalid decimal number" : 00270 "invalid hexdecimal number"); 00271 00272 // Consume the [bB][hH]. 00273 if (Radix == 2 || Radix == 16) 00274 ++CurPtr; 00275 00276 // The darwin/x86 (and x86-64) assembler accepts and ignores type 00277 // suffices on integer literals. 00278 SkipIgnoredIntegerSuffix(CurPtr); 00279 00280 return intToken(Result, Value); 00281 } 00282 00283 if (*CurPtr == 'b') { 00284 ++CurPtr; 00285 // See if we actually have "0b" as part of something like "jmp 0b\n" 00286 if (!isdigit(CurPtr[0])) { 00287 --CurPtr; 00288 StringRef Result(TokStart, CurPtr - TokStart); 00289 return AsmToken(AsmToken::Integer, Result, 0); 00290 } 00291 const char *NumStart = CurPtr; 00292 while (CurPtr[0] == '0' || CurPtr[0] == '1') 00293 ++CurPtr; 00294 00295 // Requires at least one binary digit. 00296 if (CurPtr == NumStart) 00297 return ReturnError(TokStart, "invalid binary number"); 00298 00299 StringRef Result(TokStart, CurPtr - TokStart); 00300 00301 APInt Value(128, 0, true); 00302 if (Result.substr(2).getAsInteger(2, Value)) 00303 return ReturnError(TokStart, "invalid binary number"); 00304 00305 // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL 00306 // suffixes on integer literals. 00307 SkipIgnoredIntegerSuffix(CurPtr); 00308 00309 return intToken(Result, Value); 00310 } 00311 00312 if (*CurPtr == 'x') { 00313 ++CurPtr; 00314 const char *NumStart = CurPtr; 00315 while (isxdigit(CurPtr[0])) 00316 ++CurPtr; 00317 00318 // "0x.0p0" is valid, and "0x0p0" (but not "0xp0" for example, which will be 00319 // diagnosed by LexHexFloatLiteral). 00320 if (CurPtr[0] == '.' || CurPtr[0] == 'p' || CurPtr[0] == 'P') 00321 return LexHexFloatLiteral(NumStart == CurPtr); 00322 00323 // Otherwise requires at least one hex digit. 00324 if (CurPtr == NumStart) 00325 return ReturnError(CurPtr-2, "invalid hexadecimal number"); 00326 00327 APInt Result(128, 0); 00328 if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) 00329 return ReturnError(TokStart, "invalid hexadecimal number"); 00330 00331 // Consume the optional [hH]. 00332 if (*CurPtr == 'h' || *CurPtr == 'H') 00333 ++CurPtr; 00334 00335 // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL 00336 // suffixes on integer literals. 00337 SkipIgnoredIntegerSuffix(CurPtr); 00338 00339 return intToken(StringRef(TokStart, CurPtr - TokStart), Result); 00340 } 00341 00342 // Either octal or hexadecimal. 00343 APInt Value(128, 0, true); 00344 unsigned Radix = doLookAhead(CurPtr, 8); 00345 bool isHex = Radix == 16; 00346 StringRef Result(TokStart, CurPtr - TokStart); 00347 if (Result.getAsInteger(Radix, Value)) 00348 return ReturnError(TokStart, !isHex ? "invalid octal number" : 00349 "invalid hexdecimal number"); 00350 00351 // Consume the [hH]. 00352 if (Radix == 16) 00353 ++CurPtr; 00354 00355 // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL 00356 // suffixes on integer literals. 00357 SkipIgnoredIntegerSuffix(CurPtr); 00358 00359 return intToken(Result, Value); 00360 } 00361 00362 /// LexSingleQuote: Integer: 'b' 00363 AsmToken AsmLexer::LexSingleQuote() { 00364 int CurChar = getNextChar(); 00365 00366 if (CurChar == '\\') 00367 CurChar = getNextChar(); 00368 00369 if (CurChar == EOF) 00370 return ReturnError(TokStart, "unterminated single quote"); 00371 00372 CurChar = getNextChar(); 00373 00374 if (CurChar != '\'') 00375 return ReturnError(TokStart, "single quote way too long"); 00376 00377 // The idea here being that 'c' is basically just an integral 00378 // constant. 00379 StringRef Res = StringRef(TokStart,CurPtr - TokStart); 00380 long long Value; 00381 00382 if (Res.startswith("\'\\")) { 00383 char theChar = Res[2]; 00384 switch (theChar) { 00385 default: Value = theChar; break; 00386 case '\'': Value = '\''; break; 00387 case 't': Value = '\t'; break; 00388 case 'n': Value = '\n'; break; 00389 case 'b': Value = '\b'; break; 00390 } 00391 } else 00392 Value = TokStart[1]; 00393 00394 return AsmToken(AsmToken::Integer, Res, Value); 00395 } 00396 00397 00398 /// LexQuote: String: "..." 00399 AsmToken AsmLexer::LexQuote() { 00400 int CurChar = getNextChar(); 00401 // TODO: does gas allow multiline string constants? 00402 while (CurChar != '"') { 00403 if (CurChar == '\\') { 00404 // Allow \", etc. 00405 CurChar = getNextChar(); 00406 } 00407 00408 if (CurChar == EOF) 00409 return ReturnError(TokStart, "unterminated string constant"); 00410 00411 CurChar = getNextChar(); 00412 } 00413 00414 return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); 00415 } 00416 00417 StringRef AsmLexer::LexUntilEndOfStatement() { 00418 TokStart = CurPtr; 00419 00420 while (!isAtStartOfComment(CurPtr) && // Start of line comment. 00421 !isAtStatementSeparator(CurPtr) && // End of statement marker. 00422 *CurPtr != '\n' && *CurPtr != '\r' && 00423 (*CurPtr != 0 || CurPtr != CurBuf.end())) { 00424 ++CurPtr; 00425 } 00426 return StringRef(TokStart, CurPtr-TokStart); 00427 } 00428 00429 StringRef AsmLexer::LexUntilEndOfLine() { 00430 TokStart = CurPtr; 00431 00432 while (*CurPtr != '\n' && *CurPtr != '\r' && 00433 (*CurPtr != 0 || CurPtr != CurBuf.end())) { 00434 ++CurPtr; 00435 } 00436 return StringRef(TokStart, CurPtr-TokStart); 00437 } 00438 00439 const AsmToken AsmLexer::peekTok(bool ShouldSkipSpace) { 00440 const char *SavedTokStart = TokStart; 00441 const char *SavedCurPtr = CurPtr; 00442 bool SavedAtStartOfLine = isAtStartOfLine; 00443 bool SavedSkipSpace = SkipSpace; 00444 00445 std::string SavedErr = getErr(); 00446 SMLoc SavedErrLoc = getErrLoc(); 00447 00448 SkipSpace = ShouldSkipSpace; 00449 AsmToken Token = LexToken(); 00450 00451 SetError(SavedErrLoc, SavedErr); 00452 00453 SkipSpace = SavedSkipSpace; 00454 isAtStartOfLine = SavedAtStartOfLine; 00455 CurPtr = SavedCurPtr; 00456 TokStart = SavedTokStart; 00457 00458 return Token; 00459 } 00460 00461 bool AsmLexer::isAtStartOfComment(const char *Ptr) { 00462 const char *CommentString = MAI.getCommentString(); 00463 00464 if (CommentString[1] == '\0') 00465 return CommentString[0] == Ptr[0]; 00466 00467 // FIXME: special case for the bogus "##" comment string in X86MCAsmInfoDarwin 00468 if (CommentString[1] == '#') 00469 return CommentString[0] == Ptr[0]; 00470 00471 return strncmp(Ptr, CommentString, strlen(CommentString)) == 0; 00472 } 00473 00474 bool AsmLexer::isAtStatementSeparator(const char *Ptr) { 00475 return strncmp(Ptr, MAI.getSeparatorString(), 00476 strlen(MAI.getSeparatorString())) == 0; 00477 } 00478 00479 AsmToken AsmLexer::LexToken() { 00480 TokStart = CurPtr; 00481 // This always consumes at least one character. 00482 int CurChar = getNextChar(); 00483 00484 if (isAtStartOfComment(TokStart)) { 00485 // If this comment starts with a '#', then return the Hash token and let 00486 // the assembler parser see if it can be parsed as a cpp line filename 00487 // comment. We do this only if we are at the start of a line. 00488 if (CurChar == '#' && isAtStartOfLine) 00489 return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); 00490 isAtStartOfLine = true; 00491 return LexLineComment(); 00492 } 00493 if (isAtStatementSeparator(TokStart)) { 00494 CurPtr += strlen(MAI.getSeparatorString()) - 1; 00495 return AsmToken(AsmToken::EndOfStatement, 00496 StringRef(TokStart, strlen(MAI.getSeparatorString()))); 00497 } 00498 00499 // If we're missing a newline at EOF, make sure we still get an 00500 // EndOfStatement token before the Eof token. 00501 if (CurChar == EOF && !isAtStartOfLine) { 00502 isAtStartOfLine = true; 00503 return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); 00504 } 00505 00506 isAtStartOfLine = false; 00507 switch (CurChar) { 00508 default: 00509 // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* 00510 if (isalpha(CurChar) || CurChar == '_' || CurChar == '.') 00511 return LexIdentifier(); 00512 00513 // Unknown character, emit an error. 00514 return ReturnError(TokStart, "invalid character in input"); 00515 case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); 00516 case 0: 00517 case ' ': 00518 case '\t': 00519 if (SkipSpace) { 00520 // Ignore whitespace. 00521 return LexToken(); 00522 } else { 00523 int len = 1; 00524 while (*CurPtr==' ' || *CurPtr=='\t') { 00525 CurPtr++; 00526 len++; 00527 } 00528 return AsmToken(AsmToken::Space, StringRef(TokStart, len)); 00529 } 00530 case '\n': // FALL THROUGH. 00531 case '\r': 00532 isAtStartOfLine = true; 00533 return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); 00534 case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); 00535 case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); 00536 case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); 00537 case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); 00538 case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); 00539 case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); 00540 case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); 00541 case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); 00542 case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); 00543 case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); 00544 case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); 00545 case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); 00546 case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); 00547 case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); 00548 case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1)); 00549 case '=': 00550 if (*CurPtr == '=') 00551 return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); 00552 return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); 00553 case '|': 00554 if (*CurPtr == '|') 00555 return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); 00556 return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); 00557 case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); 00558 case '&': 00559 if (*CurPtr == '&') 00560 return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); 00561 return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); 00562 case '!': 00563 if (*CurPtr == '=') 00564 return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); 00565 return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); 00566 case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); 00567 case '/': return LexSlash(); 00568 case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); 00569 case '\'': return LexSingleQuote(); 00570 case '"': return LexQuote(); 00571 case '0': case '1': case '2': case '3': case '4': 00572 case '5': case '6': case '7': case '8': case '9': 00573 return LexDigit(); 00574 case '<': 00575 switch (*CurPtr) { 00576 case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, 00577 StringRef(TokStart, 2)); 00578 case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, 00579 StringRef(TokStart, 2)); 00580 case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, 00581 StringRef(TokStart, 2)); 00582 default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); 00583 } 00584 case '>': 00585 switch (*CurPtr) { 00586 case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, 00587 StringRef(TokStart, 2)); 00588 case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, 00589 StringRef(TokStart, 2)); 00590 default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); 00591 } 00592 00593 // TODO: Quoted identifiers (objc methods etc) 00594 // local labels: [0-9][:] 00595 // Forward/backward labels: [0-9][fb] 00596 // Integers, fp constants, character constants. 00597 } 00598 }