/src/keystone/llvm/lib/MC/MCParser/AsmLexer.cpp
Line | Count | Source |
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/MC/MCAsmInfo.h" |
16 | | #include "llvm/Support/MemoryBuffer.h" |
17 | | #include "llvm/Support/SMLoc.h" |
18 | | #include <cctype> |
19 | | #include <cerrno> |
20 | | #include <cstdio> |
21 | | #include <cstdlib> |
22 | | using namespace llvm_ks; |
23 | | |
24 | 170k | AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) { |
25 | 170k | CurPtr = nullptr; |
26 | 170k | isAtStartOfLine = true; |
27 | 170k | AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@"); |
28 | 170k | defaultRadix = MAI.getRadix(); |
29 | 170k | } |
30 | | |
31 | 170k | AsmLexer::~AsmLexer() { |
32 | 170k | } |
33 | | |
34 | 1.30M | void AsmLexer::setBuffer(StringRef Buf, const char *ptr) { |
35 | 1.30M | CurBuf = Buf; |
36 | | |
37 | 1.30M | if (ptr) |
38 | 559k | CurPtr = ptr; |
39 | 740k | else |
40 | 740k | CurPtr = CurBuf.begin(); |
41 | | |
42 | 1.30M | TokStart = nullptr; |
43 | 1.30M | } |
44 | | |
45 | | /// ReturnError - Set the error to the specified string at the specified |
46 | | /// location. This is defined to always return AsmToken::Error. |
47 | | AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) |
48 | 28.2M | { |
49 | | //SetError(SMLoc::getFromPointer(Loc), Msg); |
50 | | |
51 | 28.2M | return AsmToken(AsmToken::Error, StringRef(Loc, 0)); |
52 | 28.2M | } |
53 | | |
54 | 271M | int AsmLexer::getNextChar() { |
55 | 271M | char CurChar = *CurPtr++; |
56 | 271M | switch (CurChar) { |
57 | 271M | default: |
58 | 271M | return (unsigned char)CurChar; |
59 | 287k | case 0: |
60 | | // A nul character in the stream is either the end of the current buffer or |
61 | | // a random nul in the file. Disambiguate that here. |
62 | 287k | if (CurPtr - 1 != CurBuf.end()) |
63 | 0 | return 0; // Just whitespace. |
64 | | |
65 | | // Otherwise, return end of file. |
66 | 287k | --CurPtr; // Another call to lex will return EOF again. |
67 | 287k | return EOF; |
68 | 271M | } |
69 | 271M | } |
70 | | |
71 | | /// LexFloatLiteral: [0-9]*[.][0-9]*([eE][+-]?[0-9]*)? |
72 | | /// |
73 | | /// The leading integral digit sequence and dot should have already been |
74 | | /// consumed, some or all of the fractional digit sequence *can* have been |
75 | | /// consumed. |
76 | 947k | AsmToken AsmLexer::LexFloatLiteral() { |
77 | | // Skip the fractional digit sequence. |
78 | 947k | while (isdigit(*CurPtr)) |
79 | 0 | ++CurPtr; |
80 | | |
81 | | // Check for exponent; we intentionally accept a slighlty wider set of |
82 | | // literals here and rely on the upstream client to reject invalid ones (e.g., |
83 | | // "1e+"). |
84 | 947k | if (*CurPtr == 'e' || *CurPtr == 'E') { |
85 | 147k | ++CurPtr; |
86 | 147k | if (*CurPtr == '-' || *CurPtr == '+') |
87 | 54.0k | ++CurPtr; |
88 | 517k | while (isdigit(*CurPtr)) |
89 | 370k | ++CurPtr; |
90 | 147k | } |
91 | | |
92 | 947k | return AsmToken(AsmToken::Real, |
93 | 947k | StringRef(TokStart, CurPtr - TokStart)); |
94 | 947k | } |
95 | | |
96 | | /// LexHexFloatLiteral matches essentially (.[0-9a-fA-F]*)?[pP][+-]?[0-9a-fA-F]+ |
97 | | /// while making sure there are enough actual digits around for the constant to |
98 | | /// be valid. |
99 | | /// |
100 | | /// The leading "0x[0-9a-fA-F]*" (i.e. integer part) has already been consumed |
101 | | /// before we get here. |
102 | | AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) |
103 | 274k | { |
104 | 274k | assert((*CurPtr == 'p' || *CurPtr == 'P' || *CurPtr == '.') && |
105 | 274k | "unexpected parse state in floating hex"); |
106 | 274k | bool NoFracDigits = true; |
107 | | |
108 | | // Skip the fractional part if there is one |
109 | 274k | if (*CurPtr == '.') { |
110 | 136k | ++CurPtr; |
111 | | |
112 | 136k | const char *FracStart = CurPtr; |
113 | 598k | while (isxdigit(*CurPtr)) |
114 | 462k | ++CurPtr; |
115 | | |
116 | 136k | NoFracDigits = CurPtr == FracStart; |
117 | 136k | } |
118 | | |
119 | 274k | if (NoIntDigits && NoFracDigits) |
120 | 15.9k | return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " |
121 | 15.9k | "expected at least one significand digit"); |
122 | | |
123 | | // Make sure we do have some kind of proper exponent part |
124 | 258k | if (*CurPtr != 'p' && *CurPtr != 'P') |
125 | 30.9k | return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " |
126 | 30.9k | "expected exponent part 'p'"); |
127 | 227k | ++CurPtr; |
128 | | |
129 | 227k | if (*CurPtr == '+' || *CurPtr == '-') |
130 | 72.3k | ++CurPtr; |
131 | | |
132 | | // N.b. exponent digits are *not* hex |
133 | 227k | const char *ExpStart = CurPtr; |
134 | 724k | while (isdigit(*CurPtr)) |
135 | 496k | ++CurPtr; |
136 | | |
137 | 227k | if (CurPtr == ExpStart) |
138 | 32.8k | return ReturnError(TokStart, "invalid hexadecimal floating-point constant: " |
139 | 32.8k | "expected at least one exponent digit"); |
140 | | |
141 | 194k | return AsmToken(AsmToken::Real, StringRef(TokStart, CurPtr - TokStart)); |
142 | 227k | } |
143 | | |
144 | | /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@?]* |
145 | 210M | static bool IsIdentifierChar(char c, bool AllowAt) { |
146 | 210M | return isalnum(c) || c == '_' || c == '$' || c == '.' || |
147 | 49.4M | (c == '@' && AllowAt) || c == '?'; |
148 | 210M | } |
149 | 48.7M | AsmToken AsmLexer::LexIdentifier() { |
150 | | // Check for floating point literals. |
151 | 48.7M | if (CurPtr[-1] == '.' && isdigit(*CurPtr)) { |
152 | | // Disambiguate a .1243foo identifier from a floating literal. |
153 | 9.22M | while (isdigit(*CurPtr)) |
154 | 7.75M | ++CurPtr; |
155 | 1.46M | if (*CurPtr == 'e' || *CurPtr == 'E' || |
156 | 1.32M | !IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) |
157 | 947k | return LexFloatLiteral(); |
158 | 1.46M | } |
159 | | |
160 | 209M | while (IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) |
161 | 161M | ++CurPtr; |
162 | | |
163 | | // Handle . as a special case. |
164 | 47.7M | if (CurPtr == TokStart+1 && TokStart[0] == '.') |
165 | 4.71M | return AsmToken(AsmToken::Dot, StringRef(TokStart, 1)); |
166 | | |
167 | 43.0M | return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); |
168 | 47.7M | } |
169 | | |
170 | | /// LexSlash: Slash: / |
171 | | /// C-Style Comment: /* ... */ |
172 | | AsmToken AsmLexer::LexSlash() |
173 | 424k | { |
174 | 424k | switch (*CurPtr) { |
175 | 22.3k | case '*': break; // C style comment. |
176 | 83.0k | case '/': return ++CurPtr, LexLineComment(); |
177 | 319k | default: return AsmToken(AsmToken::Slash, StringRef(CurPtr-1, 1)); |
178 | 424k | } |
179 | | |
180 | | // C Style comment. |
181 | 22.3k | ++CurPtr; // skip the star. |
182 | 68.7k | while (1) { |
183 | 68.7k | int CurChar = getNextChar(); |
184 | 68.7k | switch (CurChar) { |
185 | 323 | case EOF: |
186 | 323 | return ReturnError(TokStart, "unterminated comment"); |
187 | 30.8k | case '*': |
188 | | // End of the comment? |
189 | 30.8k | if (CurPtr[0] != '/') break; |
190 | | |
191 | 22.0k | ++CurPtr; // End the */. |
192 | 22.0k | return LexToken(); |
193 | 68.7k | } |
194 | 68.7k | } |
195 | 22.3k | } |
196 | | |
197 | | /// LexLineComment: Comment: #[^\n]* |
198 | | /// : //[^\n]* |
199 | 665k | AsmToken AsmLexer::LexLineComment() { |
200 | | // FIXME: This is broken if we happen to a comment at the end of a file, which |
201 | | // was .included, and which doesn't end with a newline. |
202 | 665k | int CurChar = getNextChar(); |
203 | 13.2M | while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF) |
204 | 12.6M | CurChar = getNextChar(); |
205 | | |
206 | 665k | if (CurChar == EOF) |
207 | 3.63k | return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); |
208 | 661k | return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 0)); |
209 | 665k | } |
210 | | |
211 | 11.2M | static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { |
212 | | // Skip ULL, UL, U, L and LL suffices. |
213 | 11.2M | if (CurPtr[0] == 'U') |
214 | 54.8k | ++CurPtr; |
215 | 11.2M | if (CurPtr[0] == 'L') |
216 | 301k | ++CurPtr; |
217 | 11.2M | if (CurPtr[0] == 'L') |
218 | 119k | ++CurPtr; |
219 | 11.2M | } |
220 | | |
221 | | // Look ahead to search for first non-hex digit, if it's [hH], then we treat the |
222 | | // integer as a hexadecimal, possibly with leading zeroes. |
223 | 11.0M | static unsigned doLookAhead(const char *&CurPtr, unsigned DefaultRadix) { |
224 | 11.0M | const char *FirstHex = nullptr; |
225 | 11.0M | const char *LookAhead = CurPtr; |
226 | 33.4M | while (1) { |
227 | 33.4M | if (isdigit(*LookAhead)) { |
228 | 21.5M | ++LookAhead; |
229 | 21.5M | } else if (isxdigit(*LookAhead)) { |
230 | 794k | if (!FirstHex) |
231 | 536k | FirstHex = LookAhead; |
232 | 794k | ++LookAhead; |
233 | 11.0M | } else { |
234 | 11.0M | break; |
235 | 11.0M | } |
236 | 33.4M | } |
237 | 11.0M | bool isHex = *LookAhead == 'h' || *LookAhead == 'H'; |
238 | 11.0M | CurPtr = isHex || !FirstHex ? LookAhead : FirstHex; |
239 | 11.0M | if (isHex) |
240 | 33.5k | return 16; |
241 | 11.0M | return DefaultRadix; |
242 | 11.0M | } |
243 | | |
244 | | static AsmToken intToken(StringRef Ref, APInt &Value) |
245 | 11.2M | { |
246 | 11.2M | if (Value.isIntN(64)) |
247 | 11.0M | return AsmToken(AsmToken::Integer, Ref, Value); |
248 | 154k | return AsmToken(AsmToken::BigNum, Ref, Value); |
249 | 11.2M | } |
250 | | |
251 | | /// LexDigit: First character is [0-9]. |
252 | | /// Local Label: [0-9][:] |
253 | | /// Forward/Backward Label: [0-9][fb] |
254 | | /// Binary integer: 0b[01]+ |
255 | | /// Octal integer: 0[0-7]+ |
256 | | /// Hex integer: 0x[0-9a-fA-F]+ or [0x]?[0-9][0-9a-fA-F]*[hH] |
257 | | /// Decimal integer: [1-9][0-9]* |
258 | | AsmToken AsmLexer::LexDigit() |
259 | 11.8M | { |
260 | | // Decimal integer: [1-9][0-9]* |
261 | 11.8M | if (CurPtr[-1] != '0' || CurPtr[0] == '.') { |
262 | 7.64M | unsigned Radix = doLookAhead(CurPtr, 10); |
263 | | |
264 | 7.64M | if (defaultRadix == 16) |
265 | 7.64M | Radix = 16; |
266 | | |
267 | 7.64M | bool isHex = Radix == 16; |
268 | | // Check for floating point literals. |
269 | 7.64M | if (!isHex && (*CurPtr == '.' || *CurPtr == 'e')) { |
270 | 0 | ++CurPtr; |
271 | 0 | return LexFloatLiteral(); |
272 | 0 | } |
273 | | |
274 | 7.64M | StringRef Result(TokStart, CurPtr - TokStart); |
275 | | |
276 | 7.64M | APInt Value(128, 0, true); |
277 | 7.64M | if (Result.getAsInteger(Radix, Value)) |
278 | 0 | return ReturnError(TokStart, !isHex ? "invalid decimal number" : |
279 | 0 | "invalid hexdecimal number"); |
280 | | |
281 | | // Consume the [bB][hH]. |
282 | 7.64M | if (defaultRadix != 16) { |
283 | 0 | if (Radix == 2 || Radix == 16) |
284 | 0 | ++CurPtr; |
285 | 0 | } |
286 | | |
287 | | // The darwin/x86 (and x86-64) assembler accepts and ignores type |
288 | | // suffices on integer literals. |
289 | 7.64M | SkipIgnoredIntegerSuffix(CurPtr); |
290 | | |
291 | 7.64M | return intToken(Result, Value); |
292 | 7.64M | } |
293 | | |
294 | 4.19M | if (*CurPtr == 'b') { |
295 | 217k | ++CurPtr; |
296 | | // See if we actually have "0b" as part of something like "jmp 0b\n" |
297 | 217k | if (!isdigit(CurPtr[0])) { |
298 | 121k | --CurPtr; |
299 | 121k | StringRef Result(TokStart, CurPtr - TokStart); |
300 | 121k | return AsmToken(AsmToken::Integer, Result, 0); |
301 | 121k | } |
302 | 96.6k | const char *NumStart = CurPtr; |
303 | 449k | while (CurPtr[0] == '0' || CurPtr[0] == '1') |
304 | 353k | ++CurPtr; |
305 | | |
306 | | // Requires at least one binary digit. |
307 | 96.6k | if (CurPtr == NumStart) |
308 | 4.73k | return ReturnError(TokStart, "invalid binary number"); |
309 | | |
310 | 91.9k | StringRef Result(TokStart, CurPtr - TokStart); |
311 | | |
312 | 91.9k | APInt Value(128, 0, true); |
313 | 91.9k | if (Result.substr(2).getAsInteger(2, Value)) |
314 | 0 | return ReturnError(TokStart, "invalid binary number"); |
315 | | |
316 | | // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL |
317 | | // suffixes on integer literals. |
318 | 91.9k | SkipIgnoredIntegerSuffix(CurPtr); |
319 | | |
320 | 91.9k | return intToken(Result, Value); |
321 | 91.9k | } |
322 | | |
323 | 3.97M | if (*CurPtr == 'x' || *CurPtr == 'X') { |
324 | 526k | ++CurPtr; |
325 | 526k | const char *NumStart = CurPtr; |
326 | 3.24M | while (isxdigit(CurPtr[0])) |
327 | 2.71M | ++CurPtr; |
328 | | |
329 | | // "0x.0p0" is valid, and "0x0p0" (but not "0xp0" for example, which will be |
330 | | // diagnosed by LexHexFloatLiteral). |
331 | 526k | if (CurPtr[0] == '.' || CurPtr[0] == 'p' || CurPtr[0] == 'P') |
332 | 274k | return LexHexFloatLiteral(NumStart == CurPtr); |
333 | | |
334 | | // Otherwise requires at least one hex digit. |
335 | 252k | if (CurPtr == NumStart) |
336 | 26.4k | return ReturnError(CurPtr-2, "invalid hexadecimal number"); |
337 | | |
338 | 225k | APInt Result(128, 0); |
339 | 225k | if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) |
340 | 0 | return ReturnError(TokStart, "invalid hexadecimal number"); |
341 | | |
342 | | // Consume the optional [hH]. |
343 | 225k | if (*CurPtr == 'h' || *CurPtr == 'H') |
344 | 14.6k | ++CurPtr; |
345 | | |
346 | | // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL |
347 | | // suffixes on integer literals. |
348 | 225k | SkipIgnoredIntegerSuffix(CurPtr); |
349 | | |
350 | 225k | return intToken(StringRef(TokStart, CurPtr - TokStart), Result); |
351 | 225k | } |
352 | | |
353 | | // Either octal or hexadecimal. |
354 | 3.45M | APInt Value(128, 0, true); |
355 | 3.45M | unsigned Radix = doLookAhead(CurPtr, 8); |
356 | 3.45M | bool isHex = Radix == 16; |
357 | 3.45M | StringRef Result(TokStart, CurPtr - TokStart); |
358 | 3.45M | if (Result.getAsInteger(Radix, Value)) |
359 | 188k | return ReturnError(TokStart, !isHex ? "invalid octal number" : |
360 | 188k | "invalid hexdecimal number"); |
361 | | |
362 | | // Consume the [hH]. |
363 | 3.26M | if (Radix == 16) |
364 | 11.9k | ++CurPtr; |
365 | | |
366 | | // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL |
367 | | // suffixes on integer literals. |
368 | 3.26M | SkipIgnoredIntegerSuffix(CurPtr); |
369 | | |
370 | 3.26M | return intToken(Result, Value); |
371 | 3.45M | } |
372 | | |
373 | | /// LexSingleQuote: Integer: 'b' |
374 | | AsmToken AsmLexer::LexSingleQuote() |
375 | 518k | { |
376 | 518k | int CurChar = getNextChar(); |
377 | | |
378 | 518k | if (CurChar == '\\') |
379 | 79.6k | CurChar = getNextChar(); |
380 | | |
381 | 518k | if (CurChar == EOF) |
382 | 305 | return ReturnError(TokStart, "unterminated single quote"); |
383 | | |
384 | 518k | CurChar = getNextChar(); |
385 | | |
386 | 518k | if (CurChar != '\'') |
387 | 422k | return ReturnError(TokStart, "single quote way too long"); |
388 | | |
389 | | // The idea here being that 'c' is basically just an integral |
390 | | // constant. |
391 | 96.0k | StringRef Res = StringRef(TokStart,CurPtr - TokStart); |
392 | 96.0k | long long Value; |
393 | | |
394 | 96.0k | if (Res.startswith("\'\\")) { |
395 | 47.0k | char theChar = Res[2]; |
396 | 47.0k | switch (theChar) { |
397 | 13.2k | default: Value = theChar; break; |
398 | 4.71k | case '\'': Value = '\''; break; |
399 | 8.37k | case 't': Value = '\t'; break; |
400 | 11.2k | case 'n': Value = '\n'; break; |
401 | 9.39k | case 'b': Value = '\b'; break; |
402 | 47.0k | } |
403 | 47.0k | } else |
404 | 49.0k | Value = TokStart[1]; |
405 | | |
406 | 96.0k | return AsmToken(AsmToken::Integer, Res, Value); |
407 | 96.0k | } |
408 | | |
409 | | |
410 | | /// LexQuote: String: "..." |
411 | | AsmToken AsmLexer::LexQuote() |
412 | 1.44M | { |
413 | 1.44M | int CurChar = getNextChar(); |
414 | | // TODO: does gas allow multiline string constants? |
415 | 9.22M | while (CurChar != '"') { |
416 | 7.78M | if (CurChar == '\\') { |
417 | | // Allow \", etc. |
418 | 220k | CurChar = getNextChar(); |
419 | 220k | } |
420 | | |
421 | 7.78M | if (CurChar == EOF) |
422 | 1.97k | return ReturnError(TokStart, "unterminated string constant"); |
423 | | |
424 | 7.77M | CurChar = getNextChar(); |
425 | 7.77M | } |
426 | | |
427 | 1.44M | return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); |
428 | 1.44M | } |
429 | | |
430 | 35.0k | StringRef AsmLexer::LexUntilEndOfStatement() { |
431 | 35.0k | TokStart = CurPtr; |
432 | | |
433 | 1.82M | while (!isAtStartOfComment(CurPtr) && // Start of line comment. |
434 | 1.81M | !isAtStatementSeparator(CurPtr) && // End of statement marker. |
435 | 1.80M | *CurPtr != '\n' && *CurPtr != '\r' && |
436 | 1.78M | (*CurPtr != 0 || CurPtr != CurBuf.end())) { |
437 | 1.78M | ++CurPtr; |
438 | 1.78M | } |
439 | 35.0k | return StringRef(TokStart, CurPtr-TokStart); |
440 | 35.0k | } |
441 | | |
442 | 1.94M | StringRef AsmLexer::LexUntilEndOfLine() { |
443 | 1.94M | TokStart = CurPtr; |
444 | | |
445 | 19.4M | while (*CurPtr != '\n' && *CurPtr != '\r' && |
446 | 17.5M | (*CurPtr != 0 || CurPtr != CurBuf.end())) { |
447 | 17.5M | ++CurPtr; |
448 | 17.5M | } |
449 | 1.94M | return StringRef(TokStart, CurPtr-TokStart); |
450 | 1.94M | } |
451 | | |
452 | | size_t AsmLexer::peekTokens(MutableArrayRef<AsmToken> Buf, |
453 | | bool ShouldSkipSpace) |
454 | 276k | { |
455 | 276k | const char *SavedTokStart = TokStart; |
456 | 276k | const char *SavedCurPtr = CurPtr; |
457 | 276k | bool SavedAtStartOfLine = isAtStartOfLine; |
458 | 276k | bool SavedSkipSpace = SkipSpace; |
459 | | |
460 | 276k | std::string SavedErr = getErr(); |
461 | 276k | SMLoc SavedErrLoc = getErrLoc(); |
462 | | |
463 | 276k | SkipSpace = ShouldSkipSpace; |
464 | | |
465 | 276k | size_t ReadCount; |
466 | 556k | for (ReadCount = 0; ReadCount < Buf.size(); ++ReadCount) { |
467 | 279k | AsmToken Token = LexToken(); |
468 | | |
469 | 279k | Buf[ReadCount] = Token; |
470 | | |
471 | 279k | if (Token.is(AsmToken::Eof)) |
472 | 161 | break; |
473 | 279k | } |
474 | | |
475 | 276k | SetError(SavedErrLoc, SavedErr); |
476 | | |
477 | 276k | SkipSpace = SavedSkipSpace; |
478 | 276k | isAtStartOfLine = SavedAtStartOfLine; |
479 | 276k | CurPtr = SavedCurPtr; |
480 | 276k | TokStart = SavedTokStart; |
481 | | |
482 | 276k | return ReadCount; |
483 | 276k | } |
484 | | |
485 | 249M | bool AsmLexer::isAtStartOfComment(const char *Ptr) { |
486 | 249M | const char *CommentString = MAI.getCommentString(); |
487 | | |
488 | 249M | if (CommentString[1] == '\0') |
489 | 229M | return CommentString[0] == Ptr[0]; |
490 | | |
491 | | // FIXME: special case for the bogus "##" comment string in X86MCAsmInfoDarwin |
492 | 19.8M | if (CommentString[1] == '#') |
493 | 0 | return CommentString[0] == Ptr[0]; |
494 | | |
495 | 19.8M | return strncmp(Ptr, CommentString, strlen(CommentString)) == 0; |
496 | 19.8M | } |
497 | | |
498 | 248M | bool AsmLexer::isAtStatementSeparator(const char *Ptr) { |
499 | 248M | return strncmp(Ptr, MAI.getSeparatorString(), |
500 | 248M | strlen(MAI.getSeparatorString())) == 0; |
501 | 248M | } |
502 | | |
503 | | AsmToken AsmLexer::LexToken() |
504 | 247M | { |
505 | 247M | TokStart = CurPtr; |
506 | | // This always consumes at least one character. |
507 | 247M | int CurChar = getNextChar(); |
508 | | |
509 | 247M | if (isAtStartOfComment(TokStart)) { |
510 | | // If this comment starts with a '#', then return the Hash token and let |
511 | | // the assembler parser see if it can be parsed as a cpp line filename |
512 | | // comment. We do this only if we are at the start of a line. |
513 | 1.29M | if (CurChar == '#' && isAtStartOfLine) |
514 | 711k | return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); |
515 | 582k | isAtStartOfLine = true; |
516 | 582k | return LexLineComment(); |
517 | 1.29M | } |
518 | 246M | if (isAtStatementSeparator(TokStart)) { |
519 | 62.3M | CurPtr += strlen(MAI.getSeparatorString()) - 1; |
520 | 62.3M | return AsmToken(AsmToken::EndOfStatement, |
521 | 62.3M | StringRef(TokStart, strlen(MAI.getSeparatorString()))); |
522 | 62.3M | } |
523 | | |
524 | | // If we're missing a newline at EOF, make sure we still get an |
525 | | // EndOfStatement token before the Eof token. |
526 | 184M | if (CurChar == EOF && !isAtStartOfLine) { |
527 | 141k | isAtStartOfLine = true; |
528 | 141k | return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); |
529 | 141k | } |
530 | | |
531 | 184M | isAtStartOfLine = false; |
532 | 184M | switch (CurChar) { |
533 | 76.2M | default: |
534 | | // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* |
535 | 76.2M | if (isalpha(CurChar) || CurChar == '_' || CurChar == '.') |
536 | 48.7M | return LexIdentifier(); |
537 | | |
538 | | // Unknown character, emit an error. |
539 | 27.5M | return ReturnError(TokStart, "invalid character in input"); |
540 | 139k | case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); |
541 | 0 | case 0: |
542 | 7.85M | case ' ': |
543 | 9.96M | case '\t': |
544 | 9.96M | if (SkipSpace) { |
545 | | // Ignore whitespace. |
546 | 9.96M | return LexToken(); |
547 | 9.96M | } else { |
548 | 267 | int len = 1; |
549 | 490 | while (*CurPtr==' ' || *CurPtr=='\t') { |
550 | 223 | CurPtr++; |
551 | 223 | len++; |
552 | 223 | } |
553 | 267 | return AsmToken(AsmToken::Space, StringRef(TokStart, len)); |
554 | 267 | } |
555 | 14.0M | case '\n': // FALL THROUGH. |
556 | 17.8M | case '\r': |
557 | 17.8M | isAtStartOfLine = true; |
558 | 17.8M | return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); |
559 | 384k | case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); |
560 | 2.63M | case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); |
561 | 6.88M | case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); |
562 | 616k | case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); |
563 | 1.69M | case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); |
564 | 812k | case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); |
565 | 516k | case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); |
566 | 119k | case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); |
567 | 332k | case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); |
568 | 263k | case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); |
569 | 783k | case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); |
570 | 24.6M | case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); |
571 | 6.52M | case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); |
572 | 958k | case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); |
573 | 1.31M | case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1)); |
574 | 4.88M | case '=': |
575 | 4.88M | if (*CurPtr == '=') |
576 | 25.9k | return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); |
577 | 4.85M | return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); |
578 | 1.52M | case '|': |
579 | 1.52M | if (*CurPtr == '|') |
580 | 470k | return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); |
581 | 1.05M | return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); |
582 | 430k | case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); |
583 | 576k | case '&': |
584 | 576k | if (*CurPtr == '&') |
585 | 45.5k | return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); |
586 | 530k | return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); |
587 | 321k | case '!': |
588 | 321k | if (*CurPtr == '=') |
589 | 15.0k | return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); |
590 | 306k | return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); |
591 | 445k | case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); |
592 | 424k | case '/': return LexSlash(); |
593 | 5.40M | case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); |
594 | 518k | case '\'': return LexSingleQuote(); |
595 | 1.44M | case '"': return LexQuote(); |
596 | 7.85M | case '0': case '1': case '2': case '3': case '4': |
597 | 11.8M | case '5': case '6': case '7': case '8': case '9': |
598 | 11.8M | return LexDigit(); |
599 | 3.21M | case '<': |
600 | 3.21M | switch (*CurPtr) { |
601 | 210k | case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, |
602 | 210k | StringRef(TokStart, 2)); |
603 | 16.7k | case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, |
604 | 16.7k | StringRef(TokStart, 2)); |
605 | 11.9k | case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, |
606 | 11.9k | StringRef(TokStart, 2)); |
607 | 2.97M | default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); |
608 | 3.21M | } |
609 | 460k | case '>': |
610 | 460k | switch (*CurPtr) { |
611 | 76.5k | case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, |
612 | 76.5k | StringRef(TokStart, 2)); |
613 | 60.0k | case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, |
614 | 60.0k | StringRef(TokStart, 2)); |
615 | 323k | default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); |
616 | 460k | } |
617 | | |
618 | | // TODO: Quoted identifiers (objc methods etc) |
619 | | // local labels: [0-9][:] |
620 | | // Forward/backward labels: [0-9][fb] |
621 | | // Integers, fp constants, character constants. |
622 | 184M | } |
623 | 184M | } |