fix an overly conservative caching issue that caused memdep to
[oota-llvm.git] / tools / llvm-mc / AsmLexer.cpp
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 "AsmLexer.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/Support/MemoryBuffer.h"
17 #include "llvm/Config/config.h"  // for strtoull.
18 #include "llvm/MC/MCAsmInfo.h"
19 #include <cerrno>
20 #include <cstdio>
21 #include <cstdlib>
22 using namespace llvm;
23
24 AsmLexer::AsmLexer(SourceMgr &SM, const MCAsmInfo &_MAI) : SrcMgr(SM),
25                                                            MAI(_MAI)  {
26   CurBuffer = 0;
27   CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
28   CurPtr = CurBuf->getBufferStart();
29   TokStart = 0;
30 }
31
32 AsmLexer::~AsmLexer() {
33 }
34
35 SMLoc AsmLexer::getLoc() const {
36   return SMLoc::getFromPointer(TokStart);
37 }
38
39 void AsmLexer::PrintMessage(SMLoc Loc, const std::string &Msg, 
40                             const char *Type) const {
41   SrcMgr.PrintMessage(Loc, Msg, Type);
42 }
43
44 /// ReturnError - Set the error to the specified string at the specified
45 /// location.  This is defined to always return AsmToken::Error.
46 AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) {
47   SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), Msg, "error");
48   return AsmToken(AsmToken::Error, StringRef(Loc, 0));
49 }
50
51 /// EnterIncludeFile - Enter the specified file.  This prints an error and
52 /// returns true on failure.
53 bool AsmLexer::EnterIncludeFile(const std::string &Filename) {
54   int NewBuf = SrcMgr.AddIncludeFile(Filename, SMLoc::getFromPointer(CurPtr));
55   if (NewBuf == -1)
56     return true;
57   
58   // Save the line number and lex buffer of the includer.
59   CurBuffer = NewBuf;
60   CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
61   CurPtr = CurBuf->getBufferStart();
62   return false;
63 }
64
65
66 int AsmLexer::getNextChar() {
67   char CurChar = *CurPtr++;
68   switch (CurChar) {
69   default:
70     return (unsigned char)CurChar;
71   case 0: {
72     // A nul character in the stream is either the end of the current buffer or
73     // a random nul in the file.  Disambiguate that here.
74     if (CurPtr-1 != CurBuf->getBufferEnd())
75       return 0;  // Just whitespace.
76     
77     // If this is the end of an included file, pop the parent file off the
78     // include stack.
79     SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
80     if (ParentIncludeLoc != SMLoc()) {
81       CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc);
82       CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
83       CurPtr = ParentIncludeLoc.getPointer();
84       
85       // Reset the token start pointer to the start of the new file.
86       TokStart = CurPtr;
87       
88       return getNextChar();
89     }
90     
91     // Otherwise, return end of file.
92     --CurPtr;  // Another call to lex will return EOF again.  
93     return EOF;
94   }
95   }
96 }
97
98 /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
99 AsmToken AsmLexer::LexIdentifier() {
100   while (isalnum(*CurPtr) || *CurPtr == '_' || *CurPtr == '$' ||
101          *CurPtr == '.' || *CurPtr == '@')
102     ++CurPtr;
103   return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart));
104 }
105
106 /// LexSlash: Slash: /
107 ///           C-Style Comment: /* ... */
108 AsmToken AsmLexer::LexSlash() {
109   switch (*CurPtr) {
110   case '*': break; // C style comment.
111   case '/': return ++CurPtr, LexLineComment();
112   default:  return AsmToken(AsmToken::Slash, StringRef(CurPtr, 1));
113   }
114
115   // C Style comment.
116   ++CurPtr;  // skip the star.
117   while (1) {
118     int CurChar = getNextChar();
119     switch (CurChar) {
120     case EOF:
121       return ReturnError(TokStart, "unterminated comment");
122     case '*':
123       // End of the comment?
124       if (CurPtr[0] != '/') break;
125       
126       ++CurPtr;   // End the */.
127       return LexToken();
128     }
129   }
130 }
131
132 /// LexLineComment: Comment: #[^\n]*
133 ///                        : //[^\n]*
134 AsmToken AsmLexer::LexLineComment() {
135   // FIXME: This is broken if we happen to a comment at the end of a file, which
136   // was .included, and which doesn't end with a newline.
137   int CurChar = getNextChar();
138   while (CurChar != '\n' && CurChar != '\n' && CurChar != EOF)
139     CurChar = getNextChar();
140   
141   if (CurChar == EOF)
142     return AsmToken(AsmToken::Eof, StringRef(CurPtr, 0));
143   return AsmToken(AsmToken::EndOfStatement, StringRef(CurPtr, 0));
144 }
145
146
147 /// LexDigit: First character is [0-9].
148 ///   Local Label: [0-9][:]
149 ///   Forward/Backward Label: [0-9][fb]
150 ///   Binary integer: 0b[01]+
151 ///   Octal integer: 0[0-7]+
152 ///   Hex integer: 0x[0-9a-fA-F]+
153 ///   Decimal integer: [1-9][0-9]*
154 /// TODO: FP literal.
155 AsmToken AsmLexer::LexDigit() {
156   if (*CurPtr == ':')
157     return ReturnError(TokStart, "FIXME: local label not implemented");
158   if (*CurPtr == 'f' || *CurPtr == 'b')
159     return ReturnError(TokStart, "FIXME: directional label not implemented");
160   
161   // Decimal integer: [1-9][0-9]*
162   if (CurPtr[-1] != '0') {
163     while (isdigit(*CurPtr))
164       ++CurPtr;
165     return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), 
166                     strtoll(TokStart, 0, 10));
167   }
168   
169   if (*CurPtr == 'b') {
170     ++CurPtr;
171     const char *NumStart = CurPtr;
172     while (CurPtr[0] == '0' || CurPtr[0] == '1')
173       ++CurPtr;
174     
175     // Requires at least one binary digit.
176     if (CurPtr == NumStart)
177       return ReturnError(CurPtr-2, "Invalid binary number");
178     return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart),
179                     strtoll(NumStart, 0, 2));
180   }
181  
182   if (*CurPtr == 'x') {
183     ++CurPtr;
184     const char *NumStart = CurPtr;
185     while (isxdigit(CurPtr[0]))
186       ++CurPtr;
187     
188     // Requires at least one hex digit.
189     if (CurPtr == NumStart)
190       return ReturnError(CurPtr-2, "Invalid hexadecimal number");
191     
192     errno = 0;
193     if (errno == EINVAL)
194       return ReturnError(CurPtr-2, "Invalid hexadecimal number");
195     if (errno == ERANGE) {
196       errno = 0;
197       if (errno == EINVAL)
198         return ReturnError(CurPtr-2, "Invalid hexadecimal number");
199       if (errno == ERANGE)
200         return ReturnError(CurPtr-2, "Hexadecimal number out of range");
201     }
202     return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart),
203                     (int64_t) strtoull(NumStart, 0, 16));
204   }
205   
206   // Must be an octal number, it starts with 0.
207   while (*CurPtr >= '0' && *CurPtr <= '7')
208     ++CurPtr;
209   return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart),
210                   strtoll(TokStart, 0, 8));
211 }
212
213 /// LexQuote: String: "..."
214 AsmToken AsmLexer::LexQuote() {
215   int CurChar = getNextChar();
216   // TODO: does gas allow multiline string constants?
217   while (CurChar != '"') {
218     if (CurChar == '\\') {
219       // Allow \", etc.
220       CurChar = getNextChar();
221     }
222     
223     if (CurChar == EOF)
224       return ReturnError(TokStart, "unterminated string constant");
225
226     CurChar = getNextChar();
227   }
228   
229   return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart));
230 }
231
232 StringRef AsmLexer::LexUntilEndOfStatement() {
233   TokStart = CurPtr;
234
235   while (!isAtStartOfComment(*CurPtr) && // Start of line comment.
236           *CurPtr != ';' &&  // End of statement marker.
237          *CurPtr != '\n' &&
238          *CurPtr != '\r' &&
239          (*CurPtr != 0 || CurPtr != CurBuf->getBufferEnd())) {
240     ++CurPtr;
241   }
242   return StringRef(TokStart, CurPtr-TokStart);
243 }
244
245 bool AsmLexer::isAtStartOfComment(char Char) {
246   // FIXME: This won't work for multi-character comment indicators like "//".
247   return Char == *MAI.getCommentString();
248 }
249
250 AsmToken AsmLexer::LexToken() {
251   TokStart = CurPtr;
252   // This always consumes at least one character.
253   int CurChar = getNextChar();
254   
255   if (isAtStartOfComment(CurChar))
256     return LexLineComment();
257
258   switch (CurChar) {
259   default:
260     // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
261     if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
262       return LexIdentifier();
263     
264     // Unknown character, emit an error.
265     return ReturnError(TokStart, "invalid character in input");
266   case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0));
267   case 0:
268   case ' ':
269   case '\t':
270     // Ignore whitespace.
271     return LexToken();
272   case '\n': // FALL THROUGH.
273   case '\r': // FALL THROUGH.
274   case ';': return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1));
275   case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1));
276   case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1));
277   case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1));
278   case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1));
279   case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1));
280   case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1));
281   case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1));
282   case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1));
283   case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1));
284   case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1));
285   case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1));
286   case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1));
287   case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1));
288   case '=': 
289     if (*CurPtr == '=')
290       return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2));
291     return AsmToken(AsmToken::Equal, StringRef(TokStart, 1));
292   case '|': 
293     if (*CurPtr == '|')
294       return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2));
295     return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1));
296   case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1));
297   case '&': 
298     if (*CurPtr == '&')
299       return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2));
300     return AsmToken(AsmToken::Amp, StringRef(TokStart, 1));
301   case '!': 
302     if (*CurPtr == '=')
303       return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2));
304     return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1));
305   case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1));
306   case '/': return LexSlash();
307   case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1));
308   case '"': return LexQuote();
309   case '0': case '1': case '2': case '3': case '4':
310   case '5': case '6': case '7': case '8': case '9':
311     return LexDigit();
312   case '<':
313     switch (*CurPtr) {
314     case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, 
315                                         StringRef(TokStart, 2));
316     case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, 
317                                         StringRef(TokStart, 2));
318     case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, 
319                                         StringRef(TokStart, 2));
320     default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1));
321     }
322   case '>':
323     switch (*CurPtr) {
324     case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, 
325                                         StringRef(TokStart, 2));
326     case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, 
327                                         StringRef(TokStart, 2));
328     default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1));
329     }
330       
331   // TODO: Quoted identifiers (objc methods etc)
332   // local labels: [0-9][:]
333   // Forward/backward labels: [0-9][fb]
334   // Integers, fp constants, character constants.
335   }
336 }