LCOV - code coverage report
Current view: top level - lib/MC/MCParser - AsmLexer.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 397 411 96.6 %
Date: 2017-09-14 15:23:50 Functions: 21 21 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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       14882 : AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) {
      34       14882 :   AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@");
      35        7441 : }
      36             : 
      37             : AsmLexer::~AsmLexer() = default;
      38             : 
      39      335706 : void AsmLexer::setBuffer(StringRef Buf, const char *ptr) {
      40      335706 :   CurBuf = Buf;
      41             : 
      42      335706 :   if (ptr)
      43      164135 :     CurPtr = ptr;
      44             :   else
      45      171571 :     CurPtr = CurBuf.begin();
      46             : 
      47      335706 :   TokStart = nullptr;
      48      335706 : }
      49             : 
      50             : /// ReturnError - Set the error to the specified string at the specified
      51             : /// location.  This is defined to always return AsmToken::Error.
      52         127 : AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) {
      53         381 :   SetError(SMLoc::getFromPointer(Loc), Msg);
      54             : 
      55         254 :   return AsmToken(AsmToken::Error, StringRef(Loc, CurPtr - Loc));
      56             : }
      57             : 
      58    33004262 : int AsmLexer::getNextChar() {
      59    66008524 :   if (CurPtr == CurBuf.end())
      60             :     return EOF;
      61    32996626 :   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       10805 : AsmToken AsmLexer::LexFloatLiteral() {
      70             :   // Skip the fractional digit sequence.
      71       37387 :   while (isdigit(*CurPtr))
      72       13291 :     ++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       10805 :   if (*CurPtr == 'e' || *CurPtr == 'E') {
      78         119 :     ++CurPtr;
      79         119 :     if (*CurPtr == '-' || *CurPtr == '+')
      80         111 :       ++CurPtr;
      81         575 :     while (isdigit(*CurPtr))
      82         228 :       ++CurPtr;
      83             :   }
      84             : 
      85             :   return AsmToken(AsmToken::Real,
      86       21610 :                   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          24 : AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) {
      96             :   assert((*CurPtr == 'p' || *CurPtr == 'P' || *CurPtr == '.') &&
      97             :          "unexpected parse state in floating hex");
      98          24 :   bool NoFracDigits = true;
      99             : 
     100             :   // Skip the fractional part if there is one
     101          24 :   if (*CurPtr == '.') {
     102          18 :     ++CurPtr;
     103             : 
     104          18 :     const char *FracStart = CurPtr;
     105          50 :     while (isxdigit(*CurPtr))
     106          16 :       ++CurPtr;
     107             : 
     108          18 :     NoFracDigits = CurPtr == FracStart;
     109             :   }
     110             : 
     111          24 :   if (NoIntDigits && NoFracDigits)
     112             :     return ReturnError(TokStart, "invalid hexadecimal floating-point constant: "
     113          12 :                                  "expected at least one significand digit");
     114             : 
     115             :   // Make sure we do have some kind of proper exponent part
     116          20 :   if (*CurPtr != 'p' && *CurPtr != 'P')
     117             :     return ReturnError(TokStart, "invalid hexadecimal floating-point constant: "
     118           6 :                                  "expected exponent part 'p'");
     119          18 :   ++CurPtr;
     120             : 
     121          18 :   if (*CurPtr == '+' || *CurPtr == '-')
     122          10 :     ++CurPtr;
     123             : 
     124             :   // N.b. exponent digits are *not* hex
     125          18 :   const char *ExpStart = CurPtr;
     126          50 :   while (isdigit(*CurPtr))
     127          16 :     ++CurPtr;
     128             : 
     129          18 :   if (CurPtr == ExpStart)
     130             :     return ReturnError(TokStart, "invalid hexadecimal floating-point constant: "
     131          12 :                                  "expected at least one exponent digit");
     132             : 
     133          24 :   return AsmToken(AsmToken::Real, StringRef(TokStart, CurPtr - TokStart));
     134             : }
     135             : 
     136             : /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@?]*
     137    29198871 : static bool IsIdentifierChar(char c, bool AllowAt) {
     138    34612318 :   return isalnum(c) || c == '_' || c == '$' || c == '.' ||
     139    33917660 :          (c == '@' && AllowAt) || c == '?';
     140             : }
     141             : 
     142     2358484 : AsmToken AsmLexer::LexIdentifier() {
     143             :   // Check for floating point literals.
     144     2358484 :   if (CurPtr[-1] == '.' && isdigit(*CurPtr)) {
     145             :     // Disambiguate a .1243foo identifier from a floating literal.
     146         171 :     while (isdigit(*CurPtr))
     147          61 :       ++CurPtr;
     148          98 :     if (*CurPtr == 'e' || *CurPtr == 'E' ||
     149          49 :         !IsIdentifierChar(*CurPtr, AllowAtInIdentifier))
     150          10 :       return LexFloatLiteral();
     151             :   }
     152             : 
     153    56039170 :   while (IsIdentifierChar(*CurPtr, AllowAtInIdentifier))
     154    26840348 :     ++CurPtr;
     155             : 
     156             :   // Handle . as a special case.
     157     2358474 :   if (CurPtr == TokStart+1 && TokStart[0] == '.')
     158         604 :     return AsmToken(AsmToken::Dot, StringRef(TokStart, 1));
     159             : 
     160     4716344 :   return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart));
     161             : }
     162             : 
     163             : /// LexSlash: Slash: /
     164             : ///           C-Style Comment: /* ... */
     165      246106 : AsmToken AsmLexer::LexSlash() {
     166      246106 :   switch (*CurPtr) {
     167          13 :   case '*':
     168          13 :     IsAtStartOfStatement = false;
     169             :     break; // C style comment.
     170      245987 :   case '/':
     171      245987 :     ++CurPtr;
     172      245987 :     return LexLineComment();
     173         106 :   default:
     174         106 :     IsAtStartOfStatement = false;
     175         212 :     return AsmToken(AsmToken::Slash, StringRef(TokStart, 1));
     176             :   }
     177             : 
     178             :   // C Style comment.
     179          13 :   ++CurPtr;  // skip the star.
     180          13 :   const char *CommentTextStart = CurPtr;
     181         266 :   while (CurPtr != CurBuf.end()) {
     182         133 :     switch (*CurPtr++) {
     183          13 :     case '*':
     184             :       // End of the comment?
     185          13 :       if (*CurPtr != '/')
     186             :         break;
     187             :       // If we have a CommentConsumer, notify it about the comment.
     188          13 :       if (CommentConsumer) {
     189           0 :         CommentConsumer->HandleComment(
     190             :             SMLoc::getFromPointer(CommentTextStart),
     191           0 :             StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart));
     192             :       }
     193          13 :       ++CurPtr;   // End the */.
     194             :       return AsmToken(AsmToken::Comment,
     195          26 :                       StringRef(TokStart, CurPtr - TokStart));
     196             :     }
     197             :   }
     198           0 :   return ReturnError(TokStart, "unterminated comment");
     199             : }
     200             : 
     201             : /// LexLineComment: Comment: #[^\n]*
     202             : ///                        : //[^\n]*
     203      456459 : 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      456459 :   const char *CommentTextStart = CurPtr;
     209      456459 :   int CurChar = getNextChar();
     210    49114373 :   while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF)
     211    24328957 :     CurChar = getNextChar();
     212             : 
     213             :   // If we have a CommentConsumer, notify it about the comment.
     214      456459 :   if (CommentConsumer) {
     215           0 :     CommentConsumer->HandleComment(
     216             :         SMLoc::getFromPointer(CommentTextStart),
     217           0 :         StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart));
     218             :   }
     219             : 
     220      456459 :   IsAtStartOfLine = true;
     221             :   // This is a whole line comment. leave newline
     222      456459 :   if (IsAtStartOfStatement)
     223             :     return AsmToken(AsmToken::EndOfStatement,
     224      882590 :                     StringRef(TokStart, CurPtr - TokStart));
     225       15164 :   IsAtStartOfStatement = true;
     226             : 
     227             :   return AsmToken(AsmToken::EndOfStatement,
     228       30328 :                   StringRef(TokStart, CurPtr - 1 - TokStart));
     229             : }
     230             : 
     231             : static void SkipIgnoredIntegerSuffix(const char *&CurPtr) {
     232             :   // Skip ULL, UL, U, L and LL suffices.
     233      386926 :   if (CurPtr[0] == 'U')
     234           7 :     ++CurPtr;
     235      386926 :   if (CurPtr[0] == 'L')
     236          16 :     ++CurPtr;
     237      386926 :   if (CurPtr[0] == 'L')
     238           4 :     ++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      362983 : static unsigned doLookAhead(const char *&CurPtr, unsigned DefaultRadix) {
     244      362983 :   const char *FirstHex = nullptr;
     245      362983 :   const char *LookAhead = CurPtr;
     246             :   while (true) {
     247      574800 :     if (isdigit(*LookAhead)) {
     248      211617 :       ++LookAhead;
     249      363183 :     } else if (isxdigit(*LookAhead)) {
     250         200 :       if (!FirstHex)
     251         184 :         FirstHex = LookAhead;
     252         200 :       ++LookAhead;
     253             :     } else {
     254             :       break;
     255             :     }
     256             :   }
     257      362983 :   bool isHex = *LookAhead == 'h' || *LookAhead == 'H';
     258      362983 :   CurPtr = isHex || !FirstHex ? LookAhead : FirstHex;
     259      362983 :   if (isHex)
     260             :     return 16;
     261      362977 :   return DefaultRadix;
     262             : }
     263             : 
     264      386926 : static AsmToken intToken(StringRef Ref, APInt &Value)
     265             : {
     266      386926 :   if (Value.isIntN(64))
     267     1160769 :     return AsmToken(AsmToken::Integer, Ref, Value);
     268           9 :   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      397759 : AsmToken AsmLexer::LexDigit() {
     279             :   // MASM-flavor binary integer: [01]+[bB]
     280             :   // MASM-flavor hexadecimal integer: [0-9][0-9a-fA-F]*[hH]
     281      397759 :   if (IsParsingMSInlineAsm && isdigit(CurPtr[-1])) {
     282         393 :     const char *FirstNonBinary = (CurPtr[-1] != '0' && CurPtr[-1] != '1') ?
     283             :                                    CurPtr - 1 : nullptr;
     284             :     const char *OldCurPtr = CurPtr;
     285         771 :     while (isxdigit(*CurPtr)) {
     286         189 :       if (*CurPtr != '0' && *CurPtr != '1' && !FirstNonBinary)
     287          41 :         FirstNonBinary = CurPtr;
     288         189 :       ++CurPtr;
     289             :     }
     290             : 
     291         393 :     unsigned Radix = 0;
     292         393 :     if (*CurPtr == 'h' || *CurPtr == 'H') {
     293             :       // hexadecimal number
     294          22 :       ++CurPtr;
     295          22 :       Radix = 16;
     296         564 :     } else if (FirstNonBinary && FirstNonBinary + 1 == CurPtr &&
     297         193 :                (*FirstNonBinary == 'b' || *FirstNonBinary == 'B'))
     298           3 :       Radix = 2;
     299             : 
     300         393 :     if (Radix == 2 || Radix == 16) {
     301          50 :       StringRef Result(TokStart, CurPtr - TokStart);
     302          50 :       APInt Value(128, 0, true);
     303             : 
     304          25 :       if (Result.drop_back().getAsInteger(Radix, Value))
     305             :         return ReturnError(TokStart, Radix == 2 ? "invalid binary number" :
     306           0 :                              "invalid hexdecimal number");
     307             : 
     308             :       // MSVC accepts and ignores type suffices on integer literals.
     309          50 :       SkipIgnoredIntegerSuffix(CurPtr);
     310             : 
     311          25 :       return intToken(Result, Value);
     312             :    }
     313             : 
     314             :     // octal/decimal integers, or floating point numbers, fall through
     315         368 :     CurPtr = OldCurPtr;
     316             :   }
     317             : 
     318             :   // Decimal integer: [1-9][0-9]*
     319      397734 :   if (CurPtr[-1] != '0' || CurPtr[0] == '.') {
     320      325213 :     unsigned Radix = doLookAhead(CurPtr, 10);
     321      325213 :     bool isHex = Radix == 16;
     322             :     // Check for floating point literals.
     323      325213 :     if (!isHex && (*CurPtr == '.' || *CurPtr == 'e')) {
     324       10795 :       ++CurPtr;
     325       10795 :       return LexFloatLiteral();
     326             :     }
     327             : 
     328      628836 :     StringRef Result(TokStart, CurPtr - TokStart);
     329             : 
     330      314418 :     APInt Value(128, 0, true);
     331      314418 :     if (Result.getAsInteger(Radix, Value))
     332             :       return ReturnError(TokStart, !isHex ? "invalid decimal number" :
     333           0 :                            "invalid hexdecimal number");
     334             : 
     335             :     // Consume the [bB][hH].
     336      314418 :     if (Radix == 2 || Radix == 16)
     337           3 :       ++CurPtr;
     338             : 
     339             :     // The darwin/x86 (and x86-64) assembler accepts and ignores type
     340             :     // suffices on integer literals.
     341      628836 :     SkipIgnoredIntegerSuffix(CurPtr);
     342             : 
     343      314418 :     return intToken(Result, Value);
     344             :   }
     345             : 
     346       72521 :   if (!IsParsingMSInlineAsm && ((*CurPtr == 'b') || (*CurPtr == 'B'))) {
     347          13 :     ++CurPtr;
     348             :     // See if we actually have "0b" as part of something like "jmp 0b\n"
     349          13 :     if (!isdigit(CurPtr[0])) {
     350           9 :       --CurPtr;
     351          18 :       StringRef Result(TokStart, CurPtr - TokStart);
     352           9 :       return AsmToken(AsmToken::Integer, Result, 0);
     353             :     }
     354             :     const char *NumStart = CurPtr;
     355         274 :     while (CurPtr[0] == '0' || CurPtr[0] == '1')
     356         135 :       ++CurPtr;
     357             : 
     358             :     // Requires at least one binary digit.
     359           4 :     if (CurPtr == NumStart)
     360           0 :       return ReturnError(TokStart, "invalid binary number");
     361             : 
     362           8 :     StringRef Result(TokStart, CurPtr - TokStart);
     363             : 
     364           4 :     APInt Value(128, 0, true);
     365           4 :     if (Result.substr(2).getAsInteger(2, Value))
     366           0 :       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           8 :     SkipIgnoredIntegerSuffix(CurPtr);
     371             : 
     372           4 :     return intToken(Result, Value);
     373             :   }
     374             : 
     375       72508 :   if ((*CurPtr == 'x') || (*CurPtr == 'X')) {
     376       34738 :     ++CurPtr;
     377       34738 :     const char *NumStart = CurPtr;
     378      277264 :     while (isxdigit(CurPtr[0]))
     379      121263 :       ++CurPtr;
     380             : 
     381             :     // "0x.0p0" is valid, and "0x0p0" (but not "0xp0" for example, which will be
     382             :     // diagnosed by LexHexFloatLiteral).
     383       34738 :     if (CurPtr[0] == '.' || CurPtr[0] == 'p' || CurPtr[0] == 'P')
     384          24 :       return LexHexFloatLiteral(NumStart == CurPtr);
     385             : 
     386             :     // Otherwise requires at least one hex digit.
     387       34714 :     if (CurPtr == NumStart)
     388           6 :       return ReturnError(CurPtr-2, "invalid hexadecimal number");
     389             : 
     390       34712 :     APInt Result(128, 0);
     391       69424 :     if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result))
     392           0 :       return ReturnError(TokStart, "invalid hexadecimal number");
     393             : 
     394             :     // Consume the optional [hH].
     395       34712 :     if (!IsParsingMSInlineAsm && (*CurPtr == 'h' || *CurPtr == 'H'))
     396           2 :       ++CurPtr;
     397             : 
     398             :     // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL
     399             :     // suffixes on integer literals.
     400       69424 :     SkipIgnoredIntegerSuffix(CurPtr);
     401             : 
     402       69424 :     return intToken(StringRef(TokStart, CurPtr - TokStart), Result);
     403             :   }
     404             : 
     405             :   // Either octal or hexadecimal.
     406       37770 :   APInt Value(128, 0, true);
     407       37770 :   unsigned Radix = doLookAhead(CurPtr, 8);
     408       37770 :   bool isHex = Radix == 16;
     409       75540 :   StringRef Result(TokStart, CurPtr - TokStart);
     410       37770 :   if (Result.getAsInteger(Radix, Value))
     411             :     return ReturnError(TokStart, !isHex ? "invalid octal number" :
     412           9 :                        "invalid hexdecimal number");
     413             : 
     414             :   // Consume the [hH].
     415       37767 :   if (Radix == 16)
     416           3 :     ++CurPtr;
     417             : 
     418             :   // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL
     419             :   // suffixes on integer literals.
     420       75534 :   SkipIgnoredIntegerSuffix(CurPtr);
     421             : 
     422       37767 :   return intToken(Result, Value);
     423             : }
     424             : 
     425             : /// LexSingleQuote: Integer: 'b'
     426         130 : AsmToken AsmLexer::LexSingleQuote() {
     427         130 :   int CurChar = getNextChar();
     428             : 
     429         130 :   if (CurChar == '\\')
     430           5 :     CurChar = getNextChar();
     431             : 
     432         130 :   if (CurChar == EOF)
     433           0 :     return ReturnError(TokStart, "unterminated single quote");
     434             : 
     435         130 :   CurChar = getNextChar();
     436             : 
     437         130 :   if (CurChar != '\'')
     438         330 :     return ReturnError(TokStart, "single quote way too long");
     439             : 
     440             :   // The idea here being that 'c' is basically just an integral
     441             :   // constant.
     442          40 :   StringRef Res = StringRef(TokStart,CurPtr - TokStart);
     443             :   long long Value;
     444             : 
     445          25 :   if (Res.startswith("\'\\")) {
     446          10 :     char theChar = Res[2];
     447           5 :     switch (theChar) {
     448           2 :       default: Value = theChar; break;
     449             :       case '\'': Value = '\''; break;
     450           1 :       case 't': Value = '\t'; break;
     451           1 :       case 'n': Value = '\n'; break;
     452           0 :       case 'b': Value = '\b'; break;
     453             :     }
     454             :   } else
     455          15 :     Value = TokStart[1];
     456             : 
     457             :   return AsmToken(AsmToken::Integer, Res, Value);
     458             : }
     459             : 
     460             : /// LexQuote: String: "..."
     461       67813 : AsmToken AsmLexer::LexQuote() {
     462       67813 :   int CurChar = getNextChar();
     463             :   // TODO: does gas allow multiline string constants?
     464      226889 :   while (CurChar != '"') {
     465       79538 :     if (CurChar == '\\') {
     466             :       // Allow \", etc.
     467         330 :       CurChar = getNextChar();
     468             :     }
     469             : 
     470       79538 :     if (CurChar == EOF)
     471           0 :       return ReturnError(TokStart, "unterminated string constant");
     472             : 
     473       79538 :     CurChar = getNextChar();
     474             :   }
     475             : 
     476      135626 :   return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart));
     477             : }
     478             : 
     479         278 : StringRef AsmLexer::LexUntilEndOfStatement() {
     480         278 :   TokStart = CurPtr;
     481             : 
     482       22651 :   while (!isAtStartOfComment(CurPtr) &&     // Start of line comment.
     483       15286 :          !isAtStatementSeparator(CurPtr) && // End of statement marker.
     484       30016 :          *CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) {
     485        7365 :     ++CurPtr;
     486             :   }
     487         278 :   return StringRef(TokStart, CurPtr-TokStart);
     488             : }
     489             : 
     490          27 : StringRef AsmLexer::LexUntilEndOfLine() {
     491          27 :   TokStart = CurPtr;
     492             : 
     493        1314 :   while (*CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) {
     494         429 :     ++CurPtr;
     495             :   }
     496          27 :   return StringRef(TokStart, CurPtr-TokStart);
     497             : }
     498             : 
     499      330468 : size_t AsmLexer::peekTokens(MutableArrayRef<AsmToken> Buf,
     500             :                             bool ShouldSkipSpace) {
     501      991404 :   SaveAndRestore<const char *> SavedTokenStart(TokStart);
     502      991404 :   SaveAndRestore<const char *> SavedCurPtr(CurPtr);
     503      991404 :   SaveAndRestore<bool> SavedAtStartOfLine(IsAtStartOfLine);
     504      991404 :   SaveAndRestore<bool> SavedAtStartOfStatement(IsAtStartOfStatement);
     505      991404 :   SaveAndRestore<bool> SavedSkipSpace(SkipSpace, ShouldSkipSpace);
     506      991404 :   SaveAndRestore<bool> SavedIsPeeking(IsPeeking, true);
     507      991404 :   std::string SavedErr = getErr();
     508      330468 :   SMLoc SavedErrLoc = getErrLoc();
     509             : 
     510             :   size_t ReadCount;
     511      782680 :   for (ReadCount = 0; ReadCount < Buf.size(); ++ReadCount) {
     512      904425 :     AsmToken Token = LexToken();
     513             : 
     514      904426 :     Buf[ReadCount] = Token;
     515             : 
     516      452213 :     if (Token.is(AsmToken::Eof))
     517             :       break;
     518             :   }
     519             : 
     520      660936 :   SetError(SavedErrLoc, SavedErr);
     521      660936 :   return ReadCount;
     522             : }
     523             : 
     524     7956798 : bool AsmLexer::isAtStartOfComment(const char *Ptr) {
     525     7956798 :   StringRef CommentString = MAI.getCommentString();
     526             : 
     527     7956798 :   if (CommentString.size() == 1)
     528    15361858 :     return CommentString[0] == Ptr[0];
     529             : 
     530             :   // Allow # preprocessor commments also be counted as comments for "##" cases
     531      551738 :   if (CommentString[1] == '#')
     532       96212 :     return CommentString[0] == Ptr[0];
     533             : 
     534      227763 :   return strncmp(Ptr, CommentString.data(), CommentString.size()) == 0;
     535             : }
     536             : 
     537     7868044 : bool AsmLexer::isAtStatementSeparator(const char *Ptr) {
     538     7868044 :   return strncmp(Ptr, MAI.getSeparatorString(),
     539    15736088 :                  strlen(MAI.getSeparatorString())) == 0;
     540             : }
     541             : 
     542     8070900 : AsmToken AsmLexer::LexToken() {
     543     8070900 :   TokStart = CurPtr;
     544             :   // This always consumes at least one character.
     545     8070900 :   int CurChar = getNextChar();
     546             : 
     547     8070900 :   if (!IsPeeking && CurChar == '#' && IsAtStartOfStatement) {
     548             :     // If this starts with a '#', this may be a cpp
     549             :     // hash directive and otherwise a line comment.
     550      973960 :     AsmToken TokenBuf[2];
     551      121745 :     MutableArrayRef<AsmToken> Buf(TokenBuf, 2);
     552      121745 :     size_t num = peekTokens(Buf, true);
     553             :     // There cannot be a space preceeding this
     554      121912 :     if (IsAtStartOfLine && num == 2 && TokenBuf[0].is(AsmToken::Integer) &&
     555         167 :         TokenBuf[1].is(AsmToken::String)) {
     556          27 :       CurPtr = TokStart; // reset curPtr;
     557          27 :       StringRef s = LexUntilEndOfLine();
     558          54 :       UnLex(TokenBuf[1]);
     559          54 :       UnLex(TokenBuf[0]);
     560          27 :       return AsmToken(AsmToken::HashDirective, s);
     561             :     }
     562      121718 :     return LexLineComment();
     563             :   }
     564             : 
     565     7949155 :   if (isAtStartOfComment(TokStart))
     566       88754 :     return LexLineComment();
     567             : 
     568     7860401 :   if (isAtStatementSeparator(TokStart)) {
     569      237412 :     CurPtr += strlen(MAI.getSeparatorString()) - 1;
     570      237412 :     IsAtStartOfLine = true;
     571      237412 :     IsAtStartOfStatement = true;
     572             :     return AsmToken(AsmToken::EndOfStatement,
     573      474824 :                     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     7622989 :   if (CurChar == EOF && !IsAtStartOfStatement) {
     579         215 :     IsAtStartOfLine = true;
     580         215 :     IsAtStartOfStatement = true;
     581         430 :     return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1));
     582             :   }
     583     7622774 :   IsAtStartOfLine = false;
     584     7622774 :   bool OldIsAtStartOfStatement = IsAtStartOfStatement;
     585     7622774 :   IsAtStartOfStatement = false;
     586     7622774 :   switch (CurChar) {
     587     2358484 :   default:
     588             :     // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
     589     2358484 :     if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
     590     2358484 :       return LexIdentifier();
     591             : 
     592             :     // Unknown character, emit an error.
     593           0 :     return ReturnError(TokStart, "invalid character in input");
     594        7412 :   case EOF:
     595        7412 :     IsAtStartOfLine = true;
     596        7412 :     IsAtStartOfStatement = true;
     597       14824 :     return AsmToken(AsmToken::Eof, StringRef(TokStart, 0));
     598     1926601 :   case 0:
     599             :   case ' ':
     600             :   case '\t':
     601     1926601 :     IsAtStartOfStatement = OldIsAtStartOfStatement;
     602     8543039 :     while (*CurPtr == ' ' || *CurPtr == '\t')
     603     3308219 :       CurPtr++;
     604     1926601 :     if (SkipSpace)
     605     1925204 :       return LexToken(); // Ignore whitespace.
     606             :     else
     607        2794 :       return AsmToken(AsmToken::Space, StringRef(TokStart, CurPtr - TokStart));
     608     1239014 :   case '\n':
     609             :   case '\r':
     610     1239014 :     IsAtStartOfLine = true;
     611     1239014 :     IsAtStartOfStatement = true;
     612     2478028 :     return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1));
     613      462496 :   case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1));
     614       15624 :   case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1));
     615      152840 :   case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1));
     616         370 :   case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1));
     617       67502 :   case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1));
     618       67156 :   case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1));
     619      211502 :   case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1));
     620      211564 :   case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1));
     621       39734 :   case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1));
     622       39806 :   case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1));
     623        3818 :   case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1));
     624     1069344 :   case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1));
     625       87880 :   case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1));
     626        3330 :   case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1));
     627         834 :   case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1));
     628        4139 :   case '=':
     629        4139 :     if (*CurPtr == '=') {
     630          36 :       ++CurPtr;
     631          72 :       return AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2));
     632             :     }
     633        8206 :     return AsmToken(AsmToken::Equal, StringRef(TokStart, 1));
     634        3309 :   case '|':
     635        3309 :     if (*CurPtr == '|') {
     636          10 :       ++CurPtr;
     637          20 :       return AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2));
     638             :     }
     639        6598 :     return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1));
     640         384 :   case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1));
     641          98 :   case '&':
     642          98 :     if (*CurPtr == '&') {
     643           9 :       ++CurPtr;
     644          18 :       return AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2));
     645             :     }
     646         178 :     return AsmToken(AsmToken::Amp, StringRef(TokStart, 1));
     647        2282 :   case '!':
     648        2282 :     if (*CurPtr == '=') {
     649          87 :       ++CurPtr;
     650         174 :       return AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2));
     651             :     }
     652        4390 :     return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1));
     653      137232 :   case '%':
     654      137232 :     if (MAI.hasMipsExpressions()) {
     655             :       AsmToken::TokenKind Operator;
     656             :       unsigned OperatorLength;
     657             : 
     658        1024 :       std::tie(Operator, OperatorLength) =
     659        2048 :           StringSwitch<std::pair<AsmToken::TokenKind, unsigned>>(
     660             :               StringRef(CurPtr))
     661        4096 :               .StartsWith("call16", {AsmToken::PercentCall16, 7})
     662        4096 :               .StartsWith("call_hi", {AsmToken::PercentCall_Hi, 8})
     663        4096 :               .StartsWith("call_lo", {AsmToken::PercentCall_Lo, 8})
     664        4096 :               .StartsWith("dtprel_hi", {AsmToken::PercentDtprel_Hi, 10})
     665        4096 :               .StartsWith("dtprel_lo", {AsmToken::PercentDtprel_Lo, 10})
     666        4096 :               .StartsWith("got_disp", {AsmToken::PercentGot_Disp, 9})
     667        4096 :               .StartsWith("got_hi", {AsmToken::PercentGot_Hi, 7})
     668        4096 :               .StartsWith("got_lo", {AsmToken::PercentGot_Lo, 7})
     669        4096 :               .StartsWith("got_ofst", {AsmToken::PercentGot_Ofst, 9})
     670        4096 :               .StartsWith("got_page", {AsmToken::PercentGot_Page, 9})
     671        4096 :               .StartsWith("gottprel", {AsmToken::PercentGottprel, 9})
     672        4096 :               .StartsWith("got", {AsmToken::PercentGot, 4})
     673        4096 :               .StartsWith("gp_rel", {AsmToken::PercentGp_Rel, 7})
     674        4096 :               .StartsWith("higher", {AsmToken::PercentHigher, 7})
     675        4096 :               .StartsWith("highest", {AsmToken::PercentHighest, 8})
     676        4096 :               .StartsWith("hi", {AsmToken::PercentHi, 3})
     677        4096 :               .StartsWith("lo", {AsmToken::PercentLo, 3})
     678        4096 :               .StartsWith("neg", {AsmToken::PercentNeg, 4})
     679        4096 :               .StartsWith("pcrel_hi", {AsmToken::PercentPcrel_Hi, 9})
     680        4096 :               .StartsWith("pcrel_lo", {AsmToken::PercentPcrel_Lo, 9})
     681        4096 :               .StartsWith("tlsgd", {AsmToken::PercentTlsgd, 6})
     682        4096 :               .StartsWith("tlsldm", {AsmToken::PercentTlsldm, 7})
     683        4096 :               .StartsWith("tprel_hi", {AsmToken::PercentTprel_Hi, 9})
     684        4096 :               .StartsWith("tprel_lo", {AsmToken::PercentTprel_Lo, 9})
     685        4096 :               .Default({AsmToken::Percent, 1});
     686             : 
     687        1024 :       if (Operator != AsmToken::Percent) {
     688        1010 :         CurPtr += OperatorLength - 1;
     689        2020 :         return AsmToken(Operator, StringRef(TokStart, OperatorLength));
     690             :       }
     691             :     }
     692      272444 :     return AsmToken(AsmToken::Percent, StringRef(TokStart, 1));
     693      246106 :   case '/':
     694      246106 :     IsAtStartOfStatement = OldIsAtStartOfStatement;
     695      246106 :     return LexSlash();
     696       29358 :   case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1));
     697         130 :   case '\'': return LexSingleQuote();
     698       67813 :   case '"': return LexQuote();
     699      397759 :   case '0': case '1': case '2': case '3': case '4':
     700             :   case '5': case '6': case '7': case '8': case '9':
     701      397759 :     return LexDigit();
     702         555 :   case '<':
     703         555 :     switch (*CurPtr) {
     704         508 :     case '<':
     705         508 :       ++CurPtr;
     706        1016 :       return AsmToken(AsmToken::LessLess, StringRef(TokStart, 2));
     707           9 :     case '=':
     708           9 :       ++CurPtr;
     709          18 :       return AsmToken(AsmToken::LessEqual, StringRef(TokStart, 2));
     710           7 :     case '>':
     711           7 :       ++CurPtr;
     712          14 :       return AsmToken(AsmToken::LessGreater, StringRef(TokStart, 2));
     713          31 :     default:
     714          62 :       return AsmToken(AsmToken::Less, StringRef(TokStart, 1));
     715             :     }
     716          69 :   case '>':
     717          69 :     switch (*CurPtr) {
     718          32 :     case '>':
     719          32 :       ++CurPtr;
     720          64 :       return AsmToken(AsmToken::GreaterGreater, StringRef(TokStart, 2));
     721           9 :     case '=':
     722           9 :       ++CurPtr;
     723          18 :       return AsmToken(AsmToken::GreaterEqual, StringRef(TokStart, 2));
     724          28 :     default:
     725          56 :       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             : }

Generated by: LCOV version 1.13