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