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