| author | David Anderson <dvander@alliedmods.net> |
| Thu Jun 28 00:26:55 2012 -0700 (2012-06-28) | |
| changeset 8 | 069d207a8f2a |
| parent 4 | 633176823669 |
| child 9 | 73781c5a59d7 |
| permissions | -rw-r--r-- |
1 /*
2 * Copyright (C) 2012 David Anderson
3 *
4 * This file is part of JITCraft.
5 *
6 * JITCraft is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free
8 * Software Foundation, either version 3 of the License, or (at your option)
9 * any later version.
10 *
11 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * JITCraft. If not, see http://www.gnu.org/licenses/.
17 */
18 #include <assert.h>
19 #include <ctype.h>
20 #include "Scanner.h"
22 using namespace jc;
24 const char *jc::TokenNames[] =
25 {
26 #define _(name, str) str,
27 TOKENMAP(_)
28 #undef _
29 NULL
30 };
32 Scanner::Scanner(const char *stream, size_t length)
33 : stream_(stream),
34 length_(length),
35 pushed_(false),
36 saved_('\0'),
37 pos_(stream_)
38 {
39 }
41 char
42 Scanner::getChar()
43 {
44 if (saved_ != '\0') {
45 char temp = saved_;
46 saved_ = '\0';
47 return temp;
48 }
49 if (pos_ >= stream_ + length_)
50 return '\0';
51 return *pos_++;
52 }
54 void
55 Scanner::putChar(char c)
56 {
57 assert(saved_ == '\0');
58 saved_ = c;
59 }
61 void
62 Scanner::eatSingleLine()
63 {
64 char c;
65 while ((c = getChar()) != '\0') {
66 if (c == '\n' || c == '\r')
67 break;
68 }
69 }
71 bool
72 Scanner::eatComment()
73 {
74 char c;
76 while ((c = getChar()) != '\0') {
77 while (c == '*') {
78 c = getChar();
79 if (c == '\0')
80 return false;
81 if (c == '/')
82 return true;
83 }
84 }
86 return false;
87 }
89 static inline bool
90 IsDigit(char c)
91 {
92 return c >= '0' && c <= '9';
93 }
95 // Based off the logic in sc2.c's ftoi()...
96 double
97 Scanner::ParseDouble(const char *string)
98 {
99 const char *ptr = string;
101 double number = 0.0;
102 while (IsDigit(*ptr)) {
103 number = (number * 10) + (*ptr - '0');
104 ptr++;
105 }
107 assert(*ptr == '.');
108 ptr++;
110 double fraction = 0.0;
111 double multiplier = 1.0;
112 while (IsDigit(*ptr)) {
113 fraction = (fraction * 10) + (*ptr - '0');
114 multiplier = multiplier / 10.0;
115 ptr++;
116 }
118 number += fraction * multiplier;
120 if (*ptr++ == 'e') {
121 int sign = 1;
122 if (*ptr == '-') {
123 sign = -1;
124 ptr++;
125 }
127 int exponent = 0;
128 while (IsDigit(*ptr)) {
129 exponent = (exponent * 10) + (*ptr - '0');
130 ptr++;
131 }
133 multiplier = pow(10.0, exponent * sign);
134 number *= multiplier;
135 }
137 return number;
138 }
140 TokenKind
141 Scanner::numberLiteral(char first)
142 {
143 literal_ = first;
145 char c;
146 for (;;) {
147 c = getChar();
148 if (!IsDigit(c))
149 break;
150 literal_ += c;
151 }
153 if (c != '.') {
154 putChar(c);
155 return TOK_INTEGER_LITERAL;
156 }
157 literal_ += c;
159 c = getChar();
160 if (!IsDigit(c)) {
161 assert(false);
162 return TOK_ERROR;
163 }
164 literal_ += c;
166 for (;;) {
167 c = getChar();
168 if (!IsDigit(c))
169 break;
170 literal_ += c;
171 }
173 if (c != 'e') {
174 putChar(c);
175 } else {
176 literal_ += c;
177 c = getChar();
178 if (c == '-') {
179 literal_ += c;
180 c = getChar();
181 }
182 if (!IsDigit(c)) {
183 assert(false);
184 return TOK_ERROR;
185 }
186 literal_ += c;
187 for (;;) {
188 c = getChar();
189 if (!IsDigit(c)) {
190 putChar(c);
191 break;
192 }
193 literal_ += c;
194 }
195 }
197 return TOK_FLOAT_LITERAL;
198 }
200 TokenKind
201 Scanner::identifier(char first)
202 {
203 literal_ = first;
205 char c;
206 for (;;) {
207 c = getChar();
208 if (!isascii(c) || (!isalnum(c) && c != '_')) {
209 if (c != ':')
210 putChar(c);
211 break;
212 }
213 literal_ += c;
214 }
216 if (literal_ == "new")
217 return TOK_NEW;
218 if (literal_ == "for")
219 return TOK_FOR;
220 if (literal_ == "return")
221 return TOK_RETURN;
222 if (literal_ == "if")
223 return TOK_IF;
224 if (literal_ == "else")
225 return TOK_ELSE;
226 if (literal_ == "enum")
227 return TOK_ENUM;
228 return (c == ':') ? TOK_LABEL : TOK_NAME;
229 }
231 TokenKind
232 Scanner::next()
233 {
234 assert(!pushed_);
236 for (;;) {
237 char c = getChar();
238 switch (c) {
239 case '/':
240 {
241 c = getChar();
242 if (c == '/') {
243 eatSingleLine();
244 break;
245 }
246 if (c == '*') {
247 if (!eatComment())
248 return TOK_ERROR;
249 break;
250 }
251 putChar(c);
252 return TOK_SLASH;
253 }
255 case ';': return TOK_SEMICOLON;
256 case '{': return TOK_LBRACE;
257 case '}': return TOK_RBRACE;
258 case '(': return TOK_LPAREN;
259 case ')': return TOK_RPAREN;
260 case '[': return TOK_LBRACKET;
261 case ']': return TOK_RBRACKET;
263 case '*':
264 c = getChar();
265 if (c == '=')
266 return TOK_ASSIGN_MUL;
267 putChar(c);
268 return TOK_STAR;
270 case '+':
271 c = getChar();
272 if (c == '=')
273 return TOK_ASSIGN_ADD;
274 putChar(c);
275 return TOK_PLUS;
277 case '&':
278 return TOK_BITAND;
280 case '|':
281 return TOK_BITOR;
283 case '^':
284 return TOK_BITXOR;
286 case '-': return TOK_MINUS;
287 case ',': return TOK_COMMA;
288 case '\0': return TOK_EOF;
290 case '=':
291 c = getChar();
292 if (c == '=')
293 return TOK_EQUALS;
294 putChar(c);
295 return TOK_ASSIGN;
297 case '<':
298 c = getChar();
299 if (c == '=')
300 return TOK_LE;
301 if (c == '<') {
302 c = getChar();
303 if (c == '=')
304 return TOK_ASSIGN_SHL;
305 return TOK_SHL;
306 }
307 putChar(c);
308 return TOK_LT;
310 case '>':
311 c = getChar();
312 if (c == '=')
313 return TOK_GE;
314 if (c == '>') {
315 c = getChar();
316 if (c == '>')
317 return TOK_USHR;
318 return TOK_SHR;
319 }
320 putChar(c);
321 return TOK_GT;
323 case ' ':
324 case '\t':
325 case '\r':
326 case '\f':
327 case '\n':
328 break;
330 default:
331 if (c >= '0' && c <= '9')
332 return numberLiteral(c);
333 if (c == '_' || (isascii(c) && isalpha(c)))
334 return identifier(c);
335 assert(false);
336 return TOK_ERROR;
337 }
338 }
339 }
341 TokenKind
342 Scanner::scan()
343 {
344 if (pushed_) {
345 pushed_ = false;
346 return lastToken_;
347 }
348 lastToken_ = next();
349 return lastToken_;
350 }
352 TokenKind
353 Scanner::peek()
354 {
355 if (pushed_)
356 return lastToken_;
357 scan();
358 pushed_ = true;
359 return lastToken_;
360 }