make the lexer unique strings it lexes instead of passing them back as
[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   if (*CurPtr != '*')
113     return asmtok::Slash;
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 /// LexHash: Comment: #[^\n]*
133 asmtok::TokKind AsmLexer::LexHash() {
134   int CurChar = getNextChar();
135   while (CurChar != '\n' && CurChar != '\n' && CurChar != EOF)
136     CurChar = getNextChar();
137   
138   if (CurChar == EOF)
139     return asmtok::Eof;
140   return asmtok::EndOfStatement;
141 }
142
143
144 /// LexDigit: First character is [0-9].
145 ///   Local Label: [0-9][:]
146 ///   Forward/Backward Label: [0-9][fb]
147 ///   Binary integer: 0b[01]+
148 ///   Octal integer: 0[0-7]+
149 ///   Hex integer: 0x[0-9a-fA-F]+
150 ///   Decimal integer: [1-9][0-9]*
151 /// TODO: FP literal.
152 asmtok::TokKind AsmLexer::LexDigit() {
153   if (*CurPtr == ':')
154     return ReturnError(TokStart, "FIXME: local label not implemented");
155   if (*CurPtr == 'f' || *CurPtr == 'b')
156     return ReturnError(TokStart, "FIXME: directional label not implemented");
157   
158   // Decimal integer: [1-9][0-9]*
159   if (CurPtr[-1] != '0') {
160     while (isdigit(*CurPtr))
161       ++CurPtr;
162     CurIntVal = strtoll(TokStart, 0, 10);
163     return asmtok::IntVal;
164   }
165   
166   if (*CurPtr == 'b') {
167     ++CurPtr;
168     const char *NumStart = CurPtr;
169     while (CurPtr[0] == '0' || CurPtr[0] == '1')
170       ++CurPtr;
171     
172     // Requires at least one binary digit.
173     if (CurPtr == NumStart)
174       return ReturnError(CurPtr-2, "Invalid binary number");
175     CurIntVal = strtoll(NumStart, 0, 2);
176     return asmtok::IntVal;
177   }
178  
179   if (*CurPtr == 'x') {
180     ++CurPtr;
181     const char *NumStart = CurPtr;
182     while (isxdigit(CurPtr[0]))
183       ++CurPtr;
184     
185     // Requires at least one hex digit.
186     if (CurPtr == NumStart)
187       return ReturnError(CurPtr-2, "Invalid hexadecimal number");
188     
189     errno = 0;
190     CurIntVal = strtoll(NumStart, 0, 16);
191     if (errno == EINVAL)
192       return ReturnError(CurPtr-2, "Invalid hexadecimal number");
193     if (errno == ERANGE) {
194       errno = 0;
195       CurIntVal = (int64_t)strtoull(NumStart, 0, 16);
196       if (errno == EINVAL)
197         return ReturnError(CurPtr-2, "Invalid hexadecimal number");
198       if (errno == ERANGE)
199         return ReturnError(CurPtr-2, "Hexadecimal number out of range");
200     }
201     return asmtok::IntVal;
202   }
203   
204   // Must be an octal number, it starts with 0.
205   while (*CurPtr >= '0' && *CurPtr <= '7')
206     ++CurPtr;
207   CurIntVal = strtoll(TokStart, 0, 8);
208   return asmtok::IntVal;
209 }
210
211 /// LexQuote: String: "..."
212 asmtok::TokKind AsmLexer::LexQuote() {
213   int CurChar = getNextChar();
214   // TODO: does gas allow multiline string constants?
215   while (CurChar != '"') {
216     if (CurChar == '\\') {
217       // Allow \", etc.
218       CurChar = getNextChar();
219     }
220     
221     if (CurChar == EOF)
222       return ReturnError(TokStart, "unterminated string constant");
223
224     CurChar = getNextChar();
225   }
226   
227   // Unique string, include quotes for now.
228   CurStrVal =
229     getSS(TheStringSet).GetOrCreateValue(TokStart, CurPtr, 0).getKeyData();
230   return asmtok::String;
231 }
232
233
234 asmtok::TokKind AsmLexer::LexToken() {
235   TokStart = CurPtr;
236   // This always consumes at least one character.
237   int CurChar = getNextChar();
238   
239   switch (CurChar) {
240   default:
241     // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
242     if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
243       return LexIdentifier();
244     
245     // Unknown character, emit an error.
246     return ReturnError(TokStart, "invalid character in input");
247   case EOF: return asmtok::Eof;
248   case 0:
249   case ' ':
250   case '\t':
251     // Ignore whitespace.
252     return LexToken();
253   case '\n': // FALL THROUGH.
254   case '\r': // FALL THROUGH.
255   case ';': return asmtok::EndOfStatement;
256   case ':': return asmtok::Colon;
257   case '+': return asmtok::Plus;
258   case '-': return asmtok::Minus;
259   case '~': return asmtok::Tilde;
260   case '(': return asmtok::LParen;
261   case ')': return asmtok::RParen;
262   case '*': return asmtok::Star;
263   case ',': return asmtok::Comma;
264   case '$': return asmtok::Dollar;
265   case '|': return asmtok::Pipe;
266   case '^': return asmtok::Caret;
267   case '&': return asmtok::Amp;
268   case '!': return asmtok::Exclaim;
269   case '%': return LexPercent();
270   case '/': return LexSlash();
271   case '#': return LexHash();
272   case '"': return LexQuote();
273   case '0': case '1': case '2': case '3': case '4':
274   case '5': case '6': case '7': case '8': case '9':
275     return LexDigit();
276   case '<':
277     if (*CurPtr == '<') {
278       ++CurPtr;
279       return asmtok::LessLess;
280     }
281     // Don't have any use for bare '<' yet.
282     return ReturnError(TokStart, "invalid character in input");
283   case '>':
284     if (*CurPtr == '>') {
285       ++CurPtr;
286       return asmtok::GreaterGreater;
287     }
288     // Don't have any use for bare '>' yet.
289     return ReturnError(TokStart, "invalid character in input");
290       
291   // TODO: Quoted identifiers (objc methods etc)
292   // local labels: [0-9][:]
293   // Forward/backward labels: [0-9][fb]
294   // Integers, fp constants, character constants.
295   }
296 }