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