LLVM API Documentation

AsmLexer.cpp
Go to the documentation of this file.
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 }