Teach lib/VMCore/ConstantFold.cpp how to set the inbounds keyword and
[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 (*CurPtr != ';' &&  // End of statement marker.
236          *CurPtr != '\n' &&
237          *CurPtr != '\r' &&
238          (*CurPtr != 0 || CurPtr != CurBuf->getBufferEnd())) {
239     // check for start of line comment.
240     for (const char *p = MAI.getCommentString(); *p != 0; ++p)
241       if (*CurPtr == *p)
242         break;
243     ++CurPtr;
244   }
245   return StringRef(TokStart, CurPtr-TokStart);
246 }
247
248 AsmToken AsmLexer::LexToken() {
249   TokStart = CurPtr;
250   // This always consumes at least one character.
251   int CurChar = getNextChar();
252   
253   for (const char *p = MAI.getCommentString(); *p != 0; ++p)
254     if (CurChar == *p)
255       return LexLineComment();
256
257   switch (CurChar) {
258   default:
259     // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
260     if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
261       return LexIdentifier();
262     
263     // Unknown character, emit an error.
264     return ReturnError(TokStart, "invalid character in input");
265   case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0));
266   case 0:
267   case ' ':
268   case '\t':
269     // Ignore whitespace.
270     return LexToken();
271   case '\n': // FALL THROUGH.
272   case '\r': // FALL THROUGH.
273   case ';': return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1));
274   case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1));
275   case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1));
276   case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1));
277   case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1));
278   case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1));
279   case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1));
280   case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1));
281   case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1));
282   case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1));
283   case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1));
284   case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1));
285   case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1));
286   case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1));
287   case '=': 
288     if (*CurPtr == '=')
289       return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2));
290     return AsmToken(AsmToken::Equal, StringRef(TokStart, 1));
291   case '|': 
292     if (*CurPtr == '|')
293       return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2));
294     return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1));
295   case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1));
296   case '&': 
297     if (*CurPtr == '&')
298       return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2));
299     return AsmToken(AsmToken::Amp, StringRef(TokStart, 1));
300   case '!': 
301     if (*CurPtr == '=')
302       return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2));
303     return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1));
304   case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1));
305   case '/': return LexSlash();
306   case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1));
307   case '"': return LexQuote();
308   case '0': case '1': case '2': case '3': case '4':
309   case '5': case '6': case '7': case '8': case '9':
310     return LexDigit();
311   case '<':
312     switch (*CurPtr) {
313     case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, 
314                                         StringRef(TokStart, 2));
315     case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, 
316                                         StringRef(TokStart, 2));
317     case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, 
318                                         StringRef(TokStart, 2));
319     default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1));
320     }
321   case '>':
322     switch (*CurPtr) {
323     case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, 
324                                         StringRef(TokStart, 2));
325     case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, 
326                                         StringRef(TokStart, 2));
327     default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1));
328     }
329       
330   // TODO: Quoted identifiers (objc methods etc)
331   // local labels: [0-9][:]
332   // Forward/backward labels: [0-9][fb]
333   // Integers, fp constants, character constants.
334   }
335 }