0
|
1
|
|
2 /* Digital Mars DMDScript source code.
|
|
3 * Copyright (c) 2000-2002 by Chromium Communications
|
|
4 * D version Copyright (c) 2004-2005 by Digital Mars
|
|
5 * All Rights Reserved
|
|
6 * written by Walter Bright
|
|
7 * www.digitalmars.com
|
|
8 * Use at your own risk. There is no warranty, express or implied.
|
|
9 * License for redistribution is by the GNU General Public License in gpl.txt.
|
|
10 *
|
|
11 * A binary, non-exclusive license for commercial use can be
|
|
12 * purchased from www.digitalmars.com/dscript/buy.html.
|
|
13 *
|
|
14 * DMDScript is implemented in the D Programming Language,
|
|
15 * www.digitalmars.com/d/
|
|
16 *
|
|
17 * For a C++ implementation of DMDScript, including COM support,
|
|
18 * see www.digitalmars.com/dscript/cppscript.html.
|
|
19 */
|
|
20
|
|
21 /* Lexical Analyzer
|
|
22 */
|
|
23
|
3
|
24 module dmdscript_tango.lexer;
|
0
|
25
|
|
26 import std.stdio;
|
|
27 import std.string;
|
|
28 import std.utf;
|
|
29 import std.outbuffer;
|
|
30 import std.ctype;
|
|
31 import std.c.stdlib;
|
|
32
|
3
|
33 import dmdscript_tango.script;
|
|
34 import dmdscript_tango.text;
|
|
35 import dmdscript_tango.identifier;
|
|
36 import dmdscript_tango.scopex;
|
|
37 import dmdscript_tango.textgen.errmsgs;
|
0
|
38
|
|
39 /* Tokens:
|
|
40 ( )
|
|
41 [ ]
|
|
42 { }
|
|
43 < > <= >= == !=
|
|
44 === !==
|
|
45 << >> <<= >>= >>> >>>=
|
|
46 + - += -=
|
|
47 * / % *= /= %=
|
|
48 & | ^ &= |= ^=
|
|
49 = ! ~
|
|
50 ++ --
|
|
51 . : ,
|
|
52 ? && ||
|
|
53 */
|
|
54
|
|
55 alias int TOK;
|
|
56
|
|
57 enum
|
|
58 {
|
|
59 TOKreserved,
|
|
60
|
|
61 // Other
|
|
62 TOKlparen, TOKrparen,
|
|
63 TOKlbracket, TOKrbracket,
|
|
64 TOKlbrace, TOKrbrace,
|
|
65 TOKcolon, TOKneg,
|
|
66 TOKpos,
|
|
67 TOKsemicolon, TOKeof,
|
|
68 TOKarray, TOKcall,
|
|
69 TOKarraylit, TOKobjectlit,
|
|
70 TOKcomma, TOKassert,
|
|
71
|
|
72 // Operators
|
|
73 TOKless, TOKgreater,
|
|
74 TOKlessequal, TOKgreaterequal,
|
|
75 TOKequal, TOKnotequal,
|
|
76 TOKidentity, TOKnonidentity,
|
|
77 TOKshiftleft, TOKshiftright,
|
|
78 TOKshiftleftass, TOKshiftrightass,
|
|
79 TOKushiftright, TOKushiftrightass,
|
|
80 TOKplus, TOKminus, TOKplusass, TOKminusass,
|
|
81 TOKmultiply, TOKdivide, TOKpercent,
|
|
82 TOKmultiplyass, TOKdivideass, TOKpercentass,
|
|
83 TOKand, TOKor, TOKxor,
|
|
84 TOKandass, TOKorass, TOKxorass,
|
|
85 TOKassign, TOKnot, TOKtilde,
|
|
86 TOKplusplus, TOKminusminus,
|
|
87 TOKdot,
|
|
88 TOKquestion, TOKandand, TOKoror,
|
|
89
|
|
90 // Leaf operators
|
|
91 TOKnumber, TOKidentifier, TOKstring,
|
|
92 TOKregexp, TOKreal,
|
|
93
|
|
94 // Keywords
|
|
95 TOKbreak, TOKcase, TOKcontinue,
|
|
96 TOKdefault, TOKdelete, TOKdo,
|
|
97 TOKelse, TOKexport, TOKfalse,
|
|
98 TOKfor, TOKfunction, TOKif,
|
|
99 TOKimport, TOKin, TOKnew,
|
|
100 TOKnull, TOKreturn, TOKswitch,
|
|
101 TOKthis, TOKtrue, TOKtypeof,
|
|
102 TOKvar, TOKvoid, TOKwhile,
|
|
103 TOKwith,
|
|
104
|
|
105 // Reserved for ECMA extensions
|
|
106 TOKcatch, TOKclass,
|
|
107 TOKconst, TOKdebugger,
|
|
108 TOKenum, TOKextends,
|
|
109 TOKfinally, TOKsuper,
|
|
110 TOKthrow, TOKtry,
|
|
111
|
|
112 // Java keywords reserved for unknown reasons
|
|
113 TOKabstract, TOKboolean,
|
|
114 TOKbyte, TOKchar,
|
|
115 TOKdouble, TOKfinal,
|
|
116 TOKfloat, TOKgoto,
|
|
117 TOKimplements, TOKinstanceof,
|
|
118 TOKint, TOKinterface,
|
|
119 TOKlong, TOKnative,
|
|
120 TOKpackage, TOKprivate,
|
|
121 TOKprotected, TOKpublic,
|
|
122 TOKshort, TOKstatic,
|
|
123 TOKsynchronized, TOKthrows,
|
|
124 TOKtransient,
|
|
125
|
|
126 TOKmax
|
|
127 };
|
|
128
|
|
129 int isoctal(dchar c) { return ('0' <= c && c <= '7'); }
|
|
130 int isasciidigit(dchar c) { return ('0' <= c && c <= '9'); }
|
|
131 int isasciilower(dchar c) { return ('a' <= c && c <= 'z'); }
|
|
132 int isasciiupper(dchar c) { return ('A' <= c && c <= 'Z'); }
|
|
133 int ishex(dchar c) { return
|
|
134 ('0' <= c && c <= '9') ||
|
|
135 ('a' <= c && c <= 'f') ||
|
|
136 ('A' <= c && c <= 'F'); }
|
|
137
|
|
138
|
|
139 /******************************************************/
|
|
140
|
|
141 struct Token
|
|
142 {
|
|
143 Token *next;
|
|
144 tchar *ptr; // pointer to first character of this token within buffer
|
|
145 uint linnum;
|
|
146 TOK value;
|
|
147 tchar *sawLineTerminator; // where we saw the last line terminator
|
|
148 union
|
|
149 {
|
|
150 number_t intvalue;
|
|
151 real_t realvalue;
|
|
152 tchar[] string;
|
|
153 Identifier *ident;
|
|
154 };
|
|
155
|
|
156 static tchar[] tochars[TOKmax];
|
|
157
|
|
158 static Token* alloc(Lexer* lex)
|
|
159 { Token *t;
|
|
160
|
|
161 if (lex.freelist)
|
|
162 {
|
|
163 t = lex.freelist;
|
|
164 lex.freelist = t.next;
|
|
165 return t;
|
|
166 }
|
|
167
|
|
168 return new Token();
|
|
169 }
|
|
170
|
|
171 void print()
|
|
172 {
|
|
173 writefln(toString());
|
|
174 }
|
|
175
|
|
176 char[] toString()
|
|
177 { char[] p;
|
|
178
|
|
179 switch (value)
|
|
180 {
|
|
181 case TOKnumber:
|
|
182 p = std.string.format(intvalue);
|
|
183 break;
|
|
184
|
|
185 case TOKreal:
|
|
186 long l = cast(long)realvalue;
|
|
187 if (l == realvalue)
|
|
188 p = std.string.format(l);
|
|
189 else
|
|
190 p = std.string.format(realvalue);
|
|
191 break;
|
|
192
|
|
193 case TOKstring:
|
|
194 case TOKregexp:
|
|
195 p = string;
|
|
196 break;
|
|
197
|
|
198 case TOKidentifier:
|
|
199 p = ident.toString();
|
|
200 break;
|
|
201
|
|
202 default:
|
|
203 p = toString(value);
|
|
204 break;
|
|
205 }
|
|
206 return p;
|
|
207 }
|
|
208
|
|
209 static char[] toString(TOK value)
|
|
210 { char[] p;
|
|
211
|
|
212 p = tochars[value];
|
|
213 if (!p)
|
|
214 p = std.string.format("TOK%d", value);
|
|
215 return p;
|
|
216 }
|
|
217 }
|
|
218
|
|
219
|
|
220
|
|
221
|
|
222 /*******************************************************************/
|
|
223
|
|
224 class Lexer
|
|
225 {
|
|
226 Identifier[tchar[]] stringtable;
|
|
227 Token* freelist;
|
|
228
|
|
229 char[] sourcename; // for error message strings
|
|
230
|
|
231 tchar[] base; // pointer to start of buffer
|
|
232 tchar* end; // past end of buffer
|
|
233 tchar* p; // current character
|
|
234 uint currentline;
|
|
235 Token token;
|
|
236 OutBuffer stringbuffer;
|
|
237 int useStringtable; // use for Identifiers
|
|
238
|
|
239 ErrInfo errinfo; // syntax error information
|
|
240 static bool inited;
|
|
241
|
|
242 this(char[] sourcename, tchar[] base, int useStringtable)
|
|
243 {
|
|
244 //writefln("Lexer::Lexer(base = '%s')\n",base);
|
|
245 if (!inited)
|
|
246 init();
|
|
247
|
|
248 std.c.string.memset(&token, 0, token.sizeof);
|
|
249 this.useStringtable = useStringtable;
|
|
250 this.sourcename = sourcename;
|
|
251 if (!base.length || (base[length - 1] != 0 && base[length - 1] != 0x1A))
|
|
252 base ~= cast(tchar)0x1A;
|
|
253 this.base = base;
|
|
254 this.end = base.ptr + base.length;
|
|
255 p = base.ptr;
|
|
256 currentline = 1;
|
|
257 freelist = null;
|
|
258 }
|
|
259
|
|
260
|
|
261 ~this()
|
|
262 {
|
|
263 //writef(L"~Lexer()\n");
|
|
264 freelist = null;
|
|
265 sourcename = null;
|
|
266 base = null;
|
|
267 end = null;
|
|
268 p = null;
|
|
269 }
|
|
270
|
|
271 dchar get(tchar* p)
|
|
272 {
|
|
273 size_t idx = p - base.ptr;
|
|
274 return std.utf.decode(base, idx);
|
|
275 }
|
|
276
|
|
277 tchar* inc(tchar* p)
|
|
278 {
|
|
279 size_t idx = p - base.ptr;
|
|
280 std.utf.decode(base, idx);
|
|
281 return base.ptr + idx;
|
|
282 }
|
|
283
|
|
284 void error(int msgnum)
|
|
285 {
|
|
286 error(errmsgtbl[msgnum]);
|
|
287 }
|
|
288
|
|
289 void error(...)
|
|
290 {
|
|
291 uint linnum = 1;
|
|
292 tchar* s;
|
|
293 tchar* slinestart;
|
|
294 tchar* slineend;
|
|
295 tchar[] buf;
|
|
296
|
|
297 //FuncLog funclog(L"Lexer.error()");
|
|
298 //writefln("TEXT START ------------\n%ls\nTEXT END ------------------", base);
|
|
299
|
|
300 // Find the beginning of the line
|
|
301 slinestart = base.ptr;
|
|
302 for (s = base.ptr; s != p; s++)
|
|
303 {
|
|
304 if (*s == '\n')
|
|
305 { linnum++;
|
|
306 slinestart = s + 1;
|
|
307 }
|
|
308 }
|
|
309
|
|
310 // Find the end of the line
|
|
311 for (;;)
|
|
312 {
|
|
313 switch (*s)
|
|
314 {
|
|
315 case '\n':
|
|
316 case 0:
|
|
317 case 0x1A:
|
|
318 break;
|
|
319 default:
|
|
320 s++;
|
|
321 continue;
|
|
322 }
|
|
323 break;
|
|
324 }
|
|
325 slineend = s;
|
|
326
|
|
327 buf = std.string.format("%s(%d) : Error: ", sourcename, linnum);
|
|
328
|
|
329 void putc(dchar c)
|
|
330 {
|
|
331 std.utf.encode(buf, c);
|
|
332 }
|
|
333
|
|
334 std.format.doFormat(&putc, _arguments, _argptr);
|
|
335
|
|
336 if (!errinfo.message)
|
|
337 { uint len;
|
|
338
|
|
339 errinfo.message = buf;
|
|
340 errinfo.linnum = linnum;
|
|
341 errinfo.charpos = p - slinestart;
|
|
342
|
|
343 len = slineend - slinestart;
|
|
344 errinfo.srcline = slinestart[0 .. len];
|
|
345 }
|
|
346
|
|
347 // Consume input until the end
|
|
348 while (*p != 0x1A && *p != 0)
|
|
349 p++;
|
|
350 token.next = null; // dump any lookahead
|
|
351
|
|
352 version (none)
|
|
353 {
|
|
354 writefln(errinfo.message);
|
|
355 fflush(stdout);
|
|
356 exit(EXIT_FAILURE);
|
|
357 }
|
|
358 }
|
|
359
|
|
360 /************************************************
|
|
361 * Given source text, convert loc to a string for the corresponding line.
|
|
362 */
|
|
363
|
|
364 static tchar[] locToSrcline(tchar *src, Loc loc)
|
|
365 {
|
|
366 tchar *slinestart;
|
|
367 tchar *slineend;
|
|
368 tchar *s;
|
|
369 uint linnum = 1;
|
|
370 uint len;
|
|
371
|
|
372 if (!src)
|
|
373 return null;
|
|
374 slinestart = src;
|
|
375 for (s = src; ; s++)
|
|
376 {
|
|
377 switch (*s)
|
|
378 {
|
|
379 case '\n':
|
|
380 if (linnum == loc)
|
|
381 {
|
|
382 slineend = s;
|
|
383 break;
|
|
384 }
|
|
385 slinestart = s + 1;
|
|
386 linnum++;
|
|
387 continue;
|
|
388
|
|
389 case 0:
|
|
390 case 0x1A:
|
|
391 slineend = s;
|
|
392 break;
|
|
393
|
|
394 default:
|
|
395 continue;
|
|
396 }
|
|
397 break;
|
|
398 }
|
|
399
|
|
400 // Remove trailing \r's
|
|
401 while (slinestart < slineend && slineend[-1] == '\r')
|
|
402 --slineend;
|
|
403
|
|
404 len = slineend - slinestart;
|
|
405 return slinestart[0 .. len];
|
|
406 }
|
|
407
|
|
408
|
|
409 TOK nextToken()
|
|
410 { Token *t;
|
|
411
|
|
412 if (token.next)
|
|
413 {
|
|
414 t = token.next;
|
|
415 token = *t;
|
|
416 t.next = freelist;
|
|
417 freelist = t;
|
|
418 }
|
|
419 else
|
|
420 {
|
|
421 scan(&token);
|
|
422 }
|
|
423 //token.print();
|
|
424 return token.value;
|
|
425 }
|
|
426
|
|
427 Token *peek(Token *ct)
|
|
428 { Token *t;
|
|
429
|
|
430 if (ct.next)
|
|
431 t = ct.next;
|
|
432 else
|
|
433 {
|
|
434 t = Token.alloc(&this);
|
|
435 scan(t);
|
|
436 t.next = null;
|
|
437 ct.next = t;
|
|
438 }
|
|
439 return t;
|
|
440 }
|
|
441
|
|
442 void insertSemicolon(tchar *loc)
|
|
443 {
|
|
444 // Push current token back into the input, and
|
|
445 // create a new current token that is a semicolon
|
|
446 Token *t;
|
|
447
|
|
448 t = Token.alloc(&this);
|
|
449 *t = token;
|
|
450 token.next = t;
|
|
451 token.value = TOKsemicolon;
|
|
452 token.ptr = loc;
|
|
453 token.sawLineTerminator = null;
|
|
454 }
|
|
455
|
|
456 /**********************************
|
|
457 * Horrible kludge to support disambiguating TOKregexp from TOKdivide.
|
|
458 * The idea is, if we are looking for a TOKdivide, and find instead
|
|
459 * a TOKregexp, we back up and rescan.
|
|
460 */
|
|
461
|
|
462 void rescan()
|
|
463 {
|
|
464 token.next = null; // no lookahead
|
|
465 // should put on freelist
|
|
466 p = token.ptr + 1;
|
|
467 }
|
|
468
|
|
469
|
|
470 /****************************
|
|
471 * Turn next token in buffer into a token.
|
|
472 */
|
|
473
|
|
474 void scan(Token *t)
|
|
475 { tchar c;
|
|
476 dchar d;
|
|
477
|
|
478 //writefln("Lexer.scan()");
|
|
479 t.sawLineTerminator = null;
|
|
480 for (;;)
|
|
481 {
|
|
482 t.ptr = p;
|
|
483 //t.linnum = currentline;
|
|
484 //writefln("p = %x",cast(uint)p);
|
|
485 //writefln("p = %x, *p = x%02x, '%s'",cast(uint)p,*p,*p);
|
|
486 switch (*p)
|
|
487 {
|
|
488 case 0:
|
|
489 case 0x1A:
|
|
490 t.value = TOKeof; // end of file
|
|
491 return;
|
|
492
|
|
493 case ' ':
|
|
494 case '\t':
|
|
495 case '\v':
|
|
496 case '\f':
|
|
497 case 0xA0: // no-break space
|
|
498 p++;
|
|
499 continue; // skip white space
|
|
500
|
|
501 case '\n': // line terminator
|
|
502 currentline++;
|
|
503 case '\r':
|
|
504 t.sawLineTerminator = p;
|
|
505 p++;
|
|
506 continue;
|
|
507
|
|
508 case '"':
|
|
509 case '\'':
|
|
510 t.string = string(*p);
|
|
511 t.value = TOKstring;
|
|
512 return;
|
|
513
|
|
514 case '0': case '1': case '2': case '3': case '4':
|
|
515 case '5': case '6': case '7': case '8': case '9':
|
|
516 t.value = number(t);
|
|
517 return;
|
|
518
|
|
519 case 'a': case 'b': case 'c': case 'd': case 'e':
|
|
520 case 'f': case 'g': case 'h': case 'i': case 'j':
|
|
521 case 'k': case 'l': case 'm': case 'n': case 'o':
|
|
522 case 'p': case 'q': case 'r': case 's': case 't':
|
|
523 case 'u': case 'v': case 'w': case 'x': case 'y':
|
|
524 case 'z':
|
|
525 case 'A': case 'B': case 'C': case 'D': case 'E':
|
|
526 case 'F': case 'G': case 'H': case 'I': case 'J':
|
|
527 case 'K': case 'L': case 'M': case 'N': case 'O':
|
|
528 case 'P': case 'Q': case 'R': case 'S': case 'T':
|
|
529 case 'U': case 'V': case 'W': case 'X': case 'Y':
|
|
530 case 'Z':
|
|
531 case '_':
|
|
532 case '$':
|
|
533 Lidentifier:
|
|
534 { tchar[] id;
|
|
535
|
|
536 do
|
|
537 {
|
|
538 p = inc(p);
|
|
539 d = get(p);
|
|
540 if (d == '\\' && p[1] == 'u')
|
|
541 {
|
|
542 Lidentifier2:
|
|
543 id = t.ptr[0 .. p - t.ptr].dup;
|
|
544 p++;
|
|
545 std.utf.encode(id, unicode());
|
|
546 for (;;)
|
|
547 {
|
|
548 d = get(p);
|
|
549 if (d == '\\' && p[1] == 'u')
|
|
550 {
|
|
551 p++;
|
|
552 std.utf.encode(id, unicode());
|
|
553 }
|
|
554 else if (isalnum(d) || d == '_' || d == '$')
|
|
555 { id ~= cast(tchar)d;
|
|
556 p = inc(p);
|
|
557 }
|
|
558 else
|
|
559 goto Lidentifier3;
|
|
560 }
|
|
561 }
|
|
562 } while (isalnum(d) || d == '_' || d == '$'); // This should be isalnum -- any Unicode letter is allowed
|
|
563 id = t.ptr[0 .. p - t.ptr];
|
|
564 Lidentifier3:
|
|
565 t.value = isKeyword(id);
|
|
566 if (t.value)
|
|
567 return;
|
|
568 if (useStringtable)
|
|
569 { //Identifier* i = &stringtable[id];
|
|
570 Identifier* i = id in stringtable;
|
|
571 if (!i)
|
|
572 { stringtable[id] = Identifier.init;
|
|
573 i = id in stringtable;
|
|
574 }
|
|
575 i.value.putVstring(id);
|
|
576 i.value.toHash();
|
|
577 t.ident = i;
|
|
578 }
|
|
579 else
|
|
580 t.ident = Identifier.build(id);
|
|
581 t.value = TOKidentifier;
|
|
582 return;
|
|
583 }
|
|
584
|
|
585 case '/':
|
|
586 p++;
|
|
587 c = *p;
|
|
588 if (c == '=')
|
|
589 {
|
|
590 p++;
|
|
591 t.value = TOKdivideass;
|
|
592 return;
|
|
593 }
|
|
594 else if (c == '*')
|
|
595 {
|
|
596 p++;
|
|
597 for ( ; ; p++)
|
|
598 {
|
|
599 c = *p;
|
|
600 Lcomment:
|
|
601 switch (c)
|
|
602 {
|
|
603 case '*':
|
|
604 p++;
|
|
605 c = *p;
|
|
606 if (c == '/')
|
|
607 {
|
|
608 p++;
|
|
609 break;
|
|
610 }
|
|
611 goto Lcomment;
|
|
612
|
|
613 case '\n':
|
|
614 currentline++;
|
|
615 case '\r':
|
|
616 t.sawLineTerminator = p;
|
|
617 continue;
|
|
618
|
|
619 case 0:
|
|
620 case 0x1A:
|
|
621 error(ERR_BAD_C_COMMENT);
|
|
622 t.value = TOKeof;
|
|
623 return;
|
|
624
|
|
625 default:
|
|
626 continue;
|
|
627 }
|
|
628 break;
|
|
629 }
|
|
630 continue;
|
|
631 }
|
|
632 else if (c == '/')
|
|
633 {
|
|
634 for (;;)
|
|
635 {
|
|
636 p++;
|
|
637 switch (*p)
|
|
638 {
|
|
639 case '\n':
|
|
640 currentline++;
|
|
641 case '\r':
|
|
642 t.sawLineTerminator = p;
|
|
643 break;
|
|
644
|
|
645 case 0:
|
|
646 case 0x1A: // end of file
|
|
647 t.value = TOKeof;
|
|
648 return;
|
|
649
|
|
650 default:
|
|
651 continue;
|
|
652 }
|
|
653 break;
|
|
654 }
|
|
655 p++;
|
|
656 continue;
|
|
657 }
|
|
658 else if ((t.string = regexp()) != null)
|
|
659 t.value = TOKregexp;
|
|
660 else
|
|
661 t.value = TOKdivide;
|
|
662 return;
|
|
663
|
|
664 case '.':
|
|
665 tchar *q;
|
|
666 q = p + 1;
|
|
667 c = *q;
|
|
668 if (isdigit(c))
|
|
669 t.value = number(t);
|
|
670 else
|
|
671 { t.value = TOKdot;
|
|
672 p = q;
|
|
673 }
|
|
674 return;
|
|
675
|
|
676 case '&':
|
|
677 p++;
|
|
678 c = *p;
|
|
679 if (c == '=')
|
|
680 {
|
|
681 p++;
|
|
682 t.value = TOKandass;
|
|
683 }
|
|
684 else if (c == '&')
|
|
685 {
|
|
686 p++;
|
|
687 t.value = TOKandand;
|
|
688 }
|
|
689 else
|
|
690 t.value = TOKand;
|
|
691 return;
|
|
692
|
|
693 case '|':
|
|
694 p++;
|
|
695 c = *p;
|
|
696 if (c == '=')
|
|
697 {
|
|
698 p++;
|
|
699 t.value = TOKorass;
|
|
700 }
|
|
701 else if (c == '|')
|
|
702 {
|
|
703 p++;
|
|
704 t.value = TOKoror;
|
|
705 }
|
|
706 else
|
|
707 t.value = TOKor;
|
|
708 return;
|
|
709
|
|
710 case '-':
|
|
711 p++;
|
|
712 c = *p;
|
|
713 if (c == '=')
|
|
714 {
|
|
715 p++;
|
|
716 t.value = TOKminusass;
|
|
717 }
|
|
718 else if (c == '-')
|
|
719 {
|
|
720 p++;
|
|
721
|
|
722 // If the last token in the file is -. then
|
|
723 // treat it as EOF. This is to accept broken
|
|
724 // scripts that forgot to protect the closing -.
|
|
725 // with a // comment.
|
|
726 if (*p == '>')
|
|
727 {
|
|
728 // Scan ahead to see if it's the last token
|
|
729 tchar *q;
|
|
730
|
|
731 q = p;
|
|
732 for (;;)
|
|
733 {
|
|
734 switch (*++q)
|
|
735 {
|
|
736 case 0:
|
|
737 case 0x1A:
|
|
738 t.value = TOKeof;
|
|
739 p = q;
|
|
740 return;
|
|
741
|
|
742 case ' ':
|
|
743 case '\t':
|
|
744 case '\v':
|
|
745 case '\f':
|
|
746 case '\n':
|
|
747 case '\r':
|
|
748 case 0xA0: // no-break space
|
|
749 continue;
|
|
750
|
|
751 default:
|
|
752 assert(0);
|
|
753 }
|
|
754 break;
|
|
755 }
|
|
756 }
|
|
757 t.value = TOKminusminus;
|
|
758 }
|
|
759 else
|
|
760 t.value = TOKminus;
|
|
761 return;
|
|
762
|
|
763 case '+':
|
|
764 p++;
|
|
765 c = *p;
|
|
766 if (c == '=')
|
|
767 { p++;
|
|
768 t.value = TOKplusass;
|
|
769 }
|
|
770 else if (c == '+')
|
|
771 { p++;
|
|
772 t.value = TOKplusplus;
|
|
773 }
|
|
774 else
|
|
775 t.value = TOKplus;
|
|
776 return;
|
|
777
|
|
778 case '<':
|
|
779 p++;
|
|
780 c = *p;
|
|
781 if (c == '=')
|
|
782 { p++;
|
|
783 t.value = TOKlessequal;
|
|
784 }
|
|
785 else if (c == '<')
|
|
786 { p++;
|
|
787 c = *p;
|
|
788 if (c == '=')
|
|
789 { p++;
|
|
790 t.value = TOKshiftleftass;
|
|
791 }
|
|
792 else
|
|
793 t.value = TOKshiftleft;
|
|
794 }
|
|
795 else if (c == '!' && p[1] == '-' && p[2] == '-')
|
|
796 { // Special comment to end of line
|
|
797 p += 2;
|
|
798 for (;;)
|
|
799 {
|
|
800 p++;
|
|
801 switch (*p)
|
|
802 {
|
|
803 case '\n':
|
|
804 currentline++;
|
|
805 case '\r':
|
|
806 t.sawLineTerminator = p;
|
|
807 break;
|
|
808
|
|
809 case 0:
|
|
810 case 0x1A: // end of file
|
|
811 error(ERR_BAD_HTML_COMMENT);
|
|
812 t.value = TOKeof;
|
|
813 return;
|
|
814
|
|
815 default:
|
|
816 continue;
|
|
817 }
|
|
818 break;
|
|
819 }
|
|
820 p++;
|
|
821 continue;
|
|
822 }
|
|
823 else
|
|
824 t.value = TOKless;
|
|
825 return;
|
|
826
|
|
827 case '>':
|
|
828 p++;
|
|
829 c = *p;
|
|
830 if (c == '=')
|
|
831 { p++;
|
|
832 t.value = TOKgreaterequal;
|
|
833 }
|
|
834 else if (c == '>')
|
|
835 { p++;
|
|
836 c = *p;
|
|
837 if (c == '=')
|
|
838 { p++;
|
|
839 t.value = TOKshiftrightass;
|
|
840 }
|
|
841 else if (c == '>')
|
|
842 { p++;
|
|
843 c = *p;
|
|
844 if (c == '=')
|
|
845 { p++;
|
|
846 t.value = TOKushiftrightass;
|
|
847 }
|
|
848 else
|
|
849 t.value = TOKushiftright;
|
|
850 }
|
|
851 else
|
|
852 t.value = TOKshiftright;
|
|
853 }
|
|
854 else
|
|
855 t.value = TOKgreater;
|
|
856 return;
|
|
857
|
|
858 case '(': p++; t.value = TOKlparen; return;
|
|
859 case ')': p++; t.value = TOKrparen; return;
|
|
860 case '[': p++; t.value = TOKlbracket; return;
|
|
861 case ']': p++; t.value = TOKrbracket; return;
|
|
862 case '{': p++; t.value = TOKlbrace; return;
|
|
863 case '}': p++; t.value = TOKrbrace; return;
|
|
864 case '~': p++; t.value = TOKtilde; return;
|
|
865 case '?': p++; t.value = TOKquestion; return;
|
|
866 case ',': p++; t.value = TOKcomma; return;
|
|
867 case ';': p++; t.value = TOKsemicolon; return;
|
|
868 case ':': p++; t.value = TOKcolon; return;
|
|
869
|
|
870 case '*':
|
|
871 p++;
|
|
872 c = *p;
|
|
873 if (c == '=')
|
|
874 { p++;
|
|
875 t.value = TOKmultiplyass;
|
|
876 }
|
|
877 else
|
|
878 t.value = TOKmultiply;
|
|
879 return;
|
|
880
|
|
881 case '%':
|
|
882 p++;
|
|
883 c = *p;
|
|
884 if (c == '=')
|
|
885 { p++;
|
|
886 t.value = TOKpercentass;
|
|
887 }
|
|
888 else
|
|
889 t.value = TOKpercent;
|
|
890 return;
|
|
891
|
|
892 case '^':
|
|
893 p++;
|
|
894 c = *p;
|
|
895 if (c == '=')
|
|
896 { p++;
|
|
897 t.value = TOKxorass;
|
|
898 }
|
|
899 else
|
|
900 t.value = TOKxor;
|
|
901 return;
|
|
902
|
|
903 case '=':
|
|
904 p++;
|
|
905 c = *p;
|
|
906 if (c == '=')
|
|
907 { p++;
|
|
908 c = *p;
|
|
909 if (c == '=')
|
|
910 { p++;
|
|
911 t.value = TOKidentity;
|
|
912 }
|
|
913 else
|
|
914 t.value = TOKequal;
|
|
915 }
|
|
916 else
|
|
917 t.value = TOKassign;
|
|
918 return;
|
|
919
|
|
920 case '!':
|
|
921 p++;
|
|
922 c = *p;
|
|
923 if (c == '=')
|
|
924 { p++;
|
|
925 c = *p;
|
|
926 if (c == '=')
|
|
927 { p++;
|
|
928 t.value = TOKnonidentity;
|
|
929 }
|
|
930 else
|
|
931 t.value = TOKnotequal;
|
|
932 }
|
|
933 else
|
|
934 t.value = TOKnot;
|
|
935 return;
|
|
936
|
|
937 case '\\':
|
|
938 if (p[1] == 'u')
|
|
939 {
|
|
940 // \uXXXX starts an identifier
|
|
941 goto Lidentifier2;
|
|
942 }
|
|
943 default:
|
|
944 d = get(p);
|
|
945 if (isalpha(d)) // This should be isalpha -- any Unicode letter
|
|
946 goto Lidentifier;
|
|
947 else
|
|
948 {
|
|
949 if (isprint(d))
|
|
950 error(errmsgtbl[ERR_BAD_CHAR_C], d);
|
|
951 else
|
|
952 error(errmsgtbl[ERR_BAD_CHAR_X], d);
|
|
953 }
|
|
954 continue;
|
|
955 }
|
|
956 }
|
|
957 }
|
|
958
|
|
959 /*******************************************
|
|
960 * Parse escape sequence.
|
|
961 */
|
|
962
|
|
963 dchar escapeSequence()
|
|
964 { uint c;
|
|
965 int n;
|
|
966
|
|
967 c = *p;
|
|
968 p++;
|
|
969 switch (c)
|
|
970 {
|
|
971 case '\'':
|
|
972 case '"':
|
|
973 case '?':
|
|
974 case '\\':
|
|
975 break;
|
|
976 case 'a':
|
|
977 c = 7;
|
|
978 break;
|
|
979 case 'b':
|
|
980 c = 8;
|
|
981 break;
|
|
982 case 'f':
|
|
983 c = 12;
|
|
984 break;
|
|
985 case 'n':
|
|
986 c = 10;
|
|
987 break;
|
|
988 case 'r':
|
|
989 c = 13;
|
|
990 break;
|
|
991 case 't':
|
|
992 c = 9;
|
|
993 break;
|
|
994
|
|
995 case 'v':
|
|
996 version (JSCRIPT_ESCAPEV_BUG)
|
|
997 {
|
|
998 }
|
|
999 else
|
|
1000 {
|
|
1001 c = 11;
|
|
1002 }
|
|
1003 break;
|
|
1004
|
|
1005 case 'x':
|
|
1006 c = *p;
|
|
1007 p++;
|
|
1008 if (ishex(c))
|
|
1009 { uint v;
|
|
1010
|
|
1011 n = 0;
|
|
1012 v = 0;
|
|
1013 for (;;)
|
|
1014 {
|
|
1015 if (isdigit(c))
|
|
1016 c -= '0';
|
|
1017 else if (isasciilower(c))
|
|
1018 c -= 'a' - 10;
|
|
1019 else // 'A' <= c && c <= 'Z'
|
|
1020 c -= 'A' - 10;
|
|
1021 v = v * 16 + c;
|
|
1022 c = *p;
|
|
1023 if (++n >= 2 || !ishex(c))
|
|
1024 break;
|
|
1025 p++;
|
|
1026 }
|
|
1027 if (n == 1)
|
|
1028 error(ERR_BAD_HEX_SEQUENCE);
|
|
1029 c = v;
|
|
1030 }
|
|
1031 else
|
|
1032 error(errmsgtbl[ERR_UNDEFINED_ESC_SEQUENCE], c);
|
|
1033 break;
|
|
1034
|
|
1035 default:
|
|
1036 if (c > 0x7F)
|
|
1037 { p--;
|
|
1038 c = get(p);
|
|
1039 p = inc(p);
|
|
1040 }
|
|
1041 if (isoctal(c))
|
|
1042 { uint v;
|
|
1043
|
|
1044 n = 0;
|
|
1045 v = 0;
|
|
1046 for (;;)
|
|
1047 {
|
|
1048 v = v * 8 + (c - '0');
|
|
1049 c = *p;
|
|
1050 if (++n >= 3 || !isoctal(c))
|
|
1051 break;
|
|
1052 p++;
|
|
1053 }
|
|
1054 c = v;
|
|
1055 }
|
|
1056 // Don't throw error, just accept it
|
|
1057 //error("undefined escape sequence \\%c\n",c);
|
|
1058 break;
|
|
1059 }
|
|
1060 return c;
|
|
1061 }
|
|
1062
|
|
1063 /**************************************
|
|
1064 */
|
|
1065
|
|
1066 tchar[] string(tchar quote)
|
|
1067 { tchar c;
|
|
1068 dchar d;
|
|
1069 tchar[] stringbuffer;
|
|
1070
|
|
1071 //printf("Lexer.string('%c')\n", quote);
|
|
1072 p++;
|
|
1073 for (;;)
|
|
1074 {
|
|
1075 c = *p;
|
|
1076 switch (c)
|
|
1077 {
|
|
1078 case '"':
|
|
1079 case '\'':
|
|
1080 p++;
|
|
1081 if (c == quote)
|
|
1082 return stringbuffer;
|
|
1083 break;
|
|
1084
|
|
1085 case '\\':
|
|
1086 p++;
|
|
1087 if (*p == 'u')
|
|
1088 d = unicode();
|
|
1089 else
|
|
1090 d = escapeSequence();
|
|
1091 std.utf.encode(stringbuffer, d);
|
|
1092 continue;
|
|
1093
|
|
1094 case '\n':
|
|
1095 case '\r':
|
|
1096 p++;
|
|
1097 error(errmsgtbl[ERR_STRING_NO_END_QUOTE], quote);
|
|
1098 return null;
|
|
1099
|
|
1100 case 0:
|
|
1101 case 0x1A:
|
|
1102 error(ERR_UNTERMINATED_STRING);
|
|
1103 return null;
|
|
1104
|
|
1105 default:
|
|
1106 p++;
|
|
1107 break;
|
|
1108 }
|
|
1109 stringbuffer ~= c;
|
|
1110 }
|
|
1111 assert(0);
|
|
1112 }
|
|
1113
|
|
1114 /**************************************
|
|
1115 * Scan regular expression. Return null with buffer
|
|
1116 * pointer intact if it is not a regexp.
|
|
1117 */
|
|
1118
|
|
1119 tchar[] regexp()
|
|
1120 { tchar c;
|
|
1121 tchar* s;
|
|
1122 tchar* start;
|
|
1123
|
|
1124 /*
|
|
1125 RegExpLiteral: RegExpBody RegExpFlags
|
|
1126 RegExpFlags:
|
|
1127 empty
|
|
1128 | RegExpFlags ContinuingIdentifierCharacter
|
|
1129 RegExpBody: / RegExpFirstChar RegExpChars /
|
|
1130 RegExpFirstChar:
|
|
1131 OrdinaryRegExpFirstChar
|
|
1132 | \ NonTerminator
|
|
1133 OrdinaryRegExpFirstChar: NonTerminator except \ | / | *
|
|
1134 RegExpChars:
|
|
1135 empty
|
|
1136 | RegExpChars RegExpChar
|
|
1137 RegExpChar:
|
|
1138 OrdinaryRegExpChar
|
|
1139 | \ NonTerminator
|
|
1140 OrdinaryRegExpChar: NonTerminator except \ | /
|
|
1141 */
|
|
1142
|
|
1143 //writefln("Lexer.regexp()\n");
|
|
1144 start = p - 1;
|
|
1145 s = p;
|
|
1146
|
|
1147 // Do RegExpBody
|
|
1148 for (;;)
|
|
1149 {
|
|
1150 c = *s;
|
|
1151 s++;
|
|
1152 switch (c)
|
|
1153 {
|
|
1154 case '\\':
|
|
1155 if (s == p)
|
|
1156 return null;
|
|
1157 c = *s;
|
|
1158 switch (c)
|
|
1159 {
|
|
1160 case '\r':
|
|
1161 case '\n': // new line
|
|
1162 case 0: // end of file
|
|
1163 case 0x1A: // end of file
|
|
1164 return null; // not a regexp
|
|
1165 default:
|
|
1166 break;
|
|
1167 }
|
|
1168 s++;
|
|
1169 continue;
|
|
1170
|
|
1171 case '/':
|
|
1172 if (s == p + 1)
|
|
1173 return null;
|
|
1174 break;
|
|
1175
|
|
1176 case '\r':
|
|
1177 case '\n': // new line
|
|
1178 case 0: // end of file
|
|
1179 case 0x1A: // end of file
|
|
1180 return null; // not a regexp
|
|
1181
|
|
1182 case '*':
|
|
1183 if (s == p + 1)
|
|
1184 return null;
|
|
1185 default:
|
|
1186 continue;
|
|
1187 }
|
|
1188 break;
|
|
1189 }
|
|
1190
|
|
1191 // Do RegExpFlags
|
|
1192 for (;;)
|
|
1193 {
|
|
1194 c = *s;
|
|
1195 if (isalnum(c) || c == '_' || c == '$')
|
|
1196 {
|
|
1197 s++;
|
|
1198 }
|
|
1199 else
|
|
1200 break;
|
|
1201 }
|
|
1202
|
|
1203 // Finish pattern & return it
|
|
1204 p = s;
|
|
1205 return start[0 .. s - start].dup;
|
|
1206 }
|
|
1207
|
|
1208 /***************************************
|
|
1209 */
|
|
1210
|
|
1211 dchar unicode()
|
|
1212 {
|
|
1213 dchar value;
|
|
1214 uint n;
|
|
1215 dchar c;
|
|
1216
|
|
1217 value = 0;
|
|
1218 p++;
|
|
1219 for (n = 0; n < 4; n++)
|
|
1220 {
|
|
1221 c = *p;
|
|
1222 if (!ishex(c))
|
|
1223 { error(ERR_BAD_U_SEQUENCE);
|
|
1224 break;
|
|
1225 }
|
|
1226 p++;
|
|
1227 if (isdigit(c))
|
|
1228 c -= '0';
|
|
1229 else if (isasciilower(c))
|
|
1230 c -= 'a' - 10;
|
|
1231 else // 'A' <= c && c <= 'Z'
|
|
1232 c -= 'A' - 10;
|
|
1233 value <<= 4;
|
|
1234 value |= c;
|
|
1235 }
|
|
1236 return value;
|
|
1237 }
|
|
1238
|
|
1239 /********************************************
|
|
1240 * Read a number.
|
|
1241 */
|
|
1242
|
|
1243 TOK number(Token *t)
|
|
1244 { tchar *start;
|
|
1245 number_t intvalue;
|
|
1246 real realvalue;
|
|
1247 int base = 10;
|
|
1248 tchar c;
|
|
1249
|
|
1250 start = p;
|
|
1251 for (;;)
|
|
1252 {
|
|
1253 c = *p;
|
|
1254 p++;
|
|
1255 switch (c)
|
|
1256 {
|
|
1257 case '0':
|
|
1258 // ECMA grammar implies that numbers with leading 0
|
|
1259 // like 015 are illegal. But other scripts allow them.
|
|
1260 if (p - start == 1) // if leading 0
|
|
1261 base = 8;
|
|
1262 case '1': case '2': case '3': case '4': case '5':
|
|
1263 case '6': case '7':
|
|
1264 break;
|
|
1265
|
|
1266 case '8': case '9': // decimal digits
|
|
1267 if (base == 8) // and octal base
|
|
1268 base = 10; // means back to decimal base
|
|
1269 break;
|
|
1270
|
|
1271 default:
|
|
1272 p--;
|
|
1273 Lnumber:
|
|
1274 if (base == 0)
|
|
1275 base = 10;
|
|
1276 intvalue = 0;
|
|
1277 foreach (tchar v; start[0 .. p - start])
|
|
1278 {
|
|
1279 if ('0' <= v && v <= '9')
|
|
1280 v -= '0';
|
|
1281 else if ('a' <= v && v <= 'f')
|
|
1282 v -= ('a' - 10);
|
|
1283 else if ('A' <= v && v <= 'F')
|
|
1284 v -= ('A' - 10);
|
|
1285 else
|
|
1286 assert(0);
|
|
1287 assert(v < base);
|
|
1288 if ((number_t.max - v) / base < intvalue)
|
|
1289 {
|
|
1290 realvalue = 0;
|
|
1291 foreach (tchar w; start[0 .. p - start])
|
|
1292 {
|
|
1293 if ('0' <= w && w <= '9')
|
|
1294 w -= '0';
|
|
1295 else if ('a' <= w && w <= 'f')
|
|
1296 w -= ('a' - 10);
|
|
1297 else if ('A' <= w && w <= 'F')
|
|
1298 w -= ('A' - 10);
|
|
1299 else
|
|
1300 assert(0);
|
|
1301 realvalue *= base;
|
|
1302 realvalue += v;
|
|
1303 }
|
|
1304 t.realvalue = realvalue;
|
|
1305 return TOKreal;
|
|
1306 }
|
|
1307 intvalue *= base;
|
|
1308 intvalue += v;
|
|
1309 }
|
|
1310 t.realvalue = cast(double)intvalue;
|
|
1311 return TOKreal;
|
|
1312
|
|
1313 case 'x':
|
|
1314 case 'X':
|
|
1315 if (p - start != 2 || !ishex(*p))
|
|
1316 goto Lerr;
|
|
1317 do
|
|
1318 p++;
|
|
1319 while (ishex(*p));
|
|
1320 start += 2;
|
|
1321 base = 16;
|
|
1322 goto Lnumber;
|
|
1323
|
|
1324 case '.':
|
|
1325 while (isdigit(*p))
|
|
1326 p++;
|
|
1327 if (*p == 'e' || *p == 'E')
|
|
1328 { p++;
|
|
1329 goto Lexponent;
|
|
1330 }
|
|
1331 goto Ldouble;
|
|
1332
|
|
1333 case 'e':
|
|
1334 case 'E':
|
|
1335 Lexponent:
|
|
1336 if (*p == '+' || *p == '-')
|
|
1337 p++;
|
|
1338 if (!isdigit(*p))
|
|
1339 goto Lerr;
|
|
1340 do
|
|
1341 p++;
|
|
1342 while (isdigit(*p));
|
|
1343 goto Ldouble;
|
|
1344
|
|
1345 Ldouble:
|
|
1346 // convert double
|
|
1347 realvalue = std.c.stdlib.strtod(toStringz(start[0 .. p - start]), null);
|
|
1348 t.realvalue = realvalue;
|
|
1349 return TOKreal;
|
|
1350 }
|
|
1351 }
|
|
1352
|
|
1353 Lerr:
|
|
1354 error(ERR_UNRECOGNIZED_N_LITERAL);
|
|
1355 return TOKeof;
|
|
1356 }
|
|
1357
|
|
1358 static TOK isKeyword(tchar[] s)
|
|
1359 {
|
|
1360 if (s[0] >= 'a' && s[0] <= 'w')
|
|
1361 switch (s.length)
|
|
1362 {
|
|
1363 case 2:
|
|
1364 if (s[0] == 'i')
|
|
1365 {
|
|
1366 if (s[1] == 'f')
|
|
1367 return TOKif;
|
|
1368 if (s[1] == 'n')
|
|
1369 return TOKin;
|
|
1370 }
|
|
1371 else if (s[0] == 'd' && s[1] == 'o')
|
|
1372 return TOKdo;
|
|
1373 break;
|
|
1374
|
|
1375 case 3:
|
|
1376 switch (s[0])
|
|
1377 {
|
|
1378 case 'f':
|
|
1379 if (s[1] == 'o' && s[2] == 'r')
|
|
1380 return TOKfor;
|
|
1381 break;
|
|
1382 case 'i':
|
|
1383 if (s[1] == 'n' && s[2] == 't')
|
|
1384 return TOKint;
|
|
1385 break;
|
|
1386 case 'n':
|
|
1387 if (s[1] == 'e' && s[2] == 'w')
|
|
1388 return TOKnew;
|
|
1389 break;
|
|
1390 case 't':
|
|
1391 if (s[1] == 'r' && s[2] == 'y')
|
|
1392 return TOKtry;
|
|
1393 break;
|
|
1394 case 'v':
|
|
1395 if (s[1] == 'a' && s[2] == 'r')
|
|
1396 return TOKvar;
|
|
1397 break;
|
|
1398 default:
|
|
1399 break;
|
|
1400 }
|
|
1401 break;
|
|
1402
|
|
1403 case 4:
|
|
1404 switch (s[0])
|
|
1405 {
|
|
1406 case 'b':
|
|
1407 if (s[1] == 'y' && s[2] == 't' && s[3] == 'e')
|
|
1408 return TOKbyte;
|
|
1409 break;
|
|
1410 case 'c':
|
|
1411 if (s[1] == 'a' && s[2] == 's' && s[3] == 'e')
|
|
1412 return TOKcase;
|
|
1413 if (s[1] == 'h' && s[2] == 'a' && s[3] == 'r')
|
|
1414 return TOKchar;
|
|
1415 break;
|
|
1416 case 'e':
|
|
1417 if (s[1] == 'l' && s[2] == 's' && s[3] == 'e')
|
|
1418 return TOKelse;
|
|
1419 if (s[1] == 'n' && s[2] == 'u' && s[3] == 'm')
|
|
1420 return TOKenum;
|
|
1421 break;
|
|
1422 case 'g':
|
|
1423 if (s[1] == 'o' && s[2] == 't' && s[3] == 'o')
|
|
1424 return TOKgoto;
|
|
1425 break;
|
|
1426 case 'l':
|
|
1427 if (s[1] == 'o' && s[2] == 'n' && s[3] == 'g')
|
|
1428 return TOKlong;
|
|
1429 break;
|
|
1430 case 'n':
|
|
1431 if (s[1] == 'u' && s[2] == 'l' && s[3] == 'l')
|
|
1432 return TOKnull;
|
|
1433 break;
|
|
1434 case 't':
|
|
1435 if (s[1] == 'h' && s[2] == 'i' && s[3] == 's')
|
|
1436 return TOKthis;
|
|
1437 if (s[1] == 'r' && s[2] == 'u' && s[3] == 'e')
|
|
1438 return TOKtrue;
|
|
1439 break;
|
|
1440 case 'w':
|
|
1441 if (s[1] == 'i' && s[2] == 't' && s[3] == 'h')
|
|
1442 return TOKwith;
|
|
1443 break;
|
|
1444 case 'v':
|
|
1445 if (s[1] == 'o' && s[2] == 'i' && s[3] == 'd')
|
|
1446 return TOKvoid;
|
|
1447 break;
|
|
1448 default:
|
|
1449 break;
|
|
1450 }
|
|
1451 break;
|
|
1452
|
|
1453 case 5:
|
|
1454 switch (s)
|
|
1455 {
|
|
1456 case "break": return TOKbreak;
|
|
1457 case "catch": return TOKcatch;
|
|
1458 case "class": return TOKclass;
|
|
1459 case "const": return TOKconst;
|
|
1460 case "false": return TOKfalse;
|
|
1461 case "final": return TOKfinal;
|
|
1462 case "float": return TOKfloat;
|
|
1463 case "short": return TOKshort;
|
|
1464 case "super": return TOKsuper;
|
|
1465 case "throw": return TOKthrow;
|
|
1466 case "while": return TOKwhile;
|
|
1467 default:
|
|
1468 break;
|
|
1469 }
|
|
1470 break;
|
|
1471
|
|
1472 case 6:
|
|
1473 switch (s)
|
|
1474 {
|
|
1475 case "delete": return TOKdelete;
|
|
1476 case "double": return TOKdouble;
|
|
1477 case "export": return TOKexport;
|
|
1478 case "import": return TOKimport;
|
|
1479 case "native": return TOKnative;
|
|
1480 case "public": return TOKpublic;
|
|
1481 case "return": return TOKreturn;
|
|
1482 case "static": return TOKstatic;
|
|
1483 case "switch": return TOKswitch;
|
|
1484 case "throws": return TOKthrows;
|
|
1485 case "typeof": return TOKtypeof;
|
|
1486 default:
|
|
1487 break;
|
|
1488 }
|
|
1489 break;
|
|
1490
|
|
1491 case 7:
|
|
1492 switch (s)
|
|
1493 {
|
|
1494 case "boolean": return TOKboolean;
|
|
1495 case "default": return TOKdefault;
|
|
1496 case "extends": return TOKextends;
|
|
1497 case "finally": return TOKfinally;
|
|
1498 case "package": return TOKpackage;
|
|
1499 case "private": return TOKprivate;
|
|
1500 default:
|
|
1501 break;
|
|
1502 }
|
|
1503 break;
|
|
1504
|
|
1505 case 8:
|
|
1506 switch (s)
|
|
1507 {
|
|
1508 case "abstract": return TOKabstract;
|
|
1509 case "continue": return TOKcontinue;
|
|
1510 case "debugger": return TOKdebugger;
|
|
1511 case "function": return TOKfunction;
|
|
1512 default:
|
|
1513 break;
|
|
1514 }
|
|
1515 break;
|
|
1516
|
|
1517 case 9:
|
|
1518 switch (s)
|
|
1519 {
|
|
1520 case "interface": return TOKinterface;
|
|
1521 case "protected": return TOKprotected;
|
|
1522 case "transient": return TOKtransient;
|
|
1523 default:
|
|
1524 break;
|
|
1525 }
|
|
1526 break;
|
|
1527
|
|
1528 case 10:
|
|
1529 switch (s)
|
|
1530 {
|
|
1531 case "implements": return TOKimplements;
|
|
1532 case "instanceof": return TOKinstanceof;
|
|
1533 default:
|
|
1534 break;
|
|
1535 }
|
|
1536 break;
|
|
1537
|
|
1538 case 12:
|
|
1539 if (s == "synchronized") return TOKsynchronized;
|
|
1540 break;
|
|
1541
|
|
1542 default:
|
|
1543 break;
|
|
1544 }
|
|
1545 return TOKreserved; // not a keyword
|
|
1546 }
|
|
1547 }
|
|
1548
|
|
1549
|
|
1550 /****************************************
|
|
1551 */
|
|
1552
|
|
1553 struct Keyword
|
|
1554 { tchar[] name;
|
|
1555 TOK value;
|
|
1556 }
|
|
1557
|
|
1558 static Keyword keywords[] =
|
|
1559 [
|
|
1560 // { "", TOK },
|
|
1561
|
|
1562 { "break", TOKbreak },
|
|
1563 { "case", TOKcase },
|
|
1564 { "continue", TOKcontinue },
|
|
1565 { "default", TOKdefault },
|
|
1566 { "delete", TOKdelete },
|
|
1567 { "do", TOKdo },
|
|
1568 { "else", TOKelse },
|
|
1569 { "export", TOKexport },
|
|
1570 { "false", TOKfalse },
|
|
1571 { "for", TOKfor },
|
|
1572 { "function", TOKfunction },
|
|
1573 { "if", TOKif },
|
|
1574 { "import", TOKimport },
|
|
1575 { "in", TOKin },
|
|
1576 { "new", TOKnew },
|
|
1577 { "null", TOKnull },
|
|
1578 { "return", TOKreturn },
|
|
1579 { "switch", TOKswitch },
|
|
1580 { "this", TOKthis },
|
|
1581 { "true", TOKtrue },
|
|
1582 { "typeof", TOKtypeof },
|
|
1583 { "var", TOKvar },
|
|
1584 { "void", TOKvoid },
|
|
1585 { "while", TOKwhile },
|
|
1586 { "with", TOKwith },
|
|
1587
|
|
1588 { "catch", TOKcatch },
|
|
1589 { "class", TOKclass },
|
|
1590 { "const", TOKconst },
|
|
1591 { "debugger", TOKdebugger },
|
|
1592 { "enum", TOKenum },
|
|
1593 { "extends", TOKextends },
|
|
1594 { "finally", TOKfinally },
|
|
1595 { "super", TOKsuper },
|
|
1596 { "throw", TOKthrow },
|
|
1597 { "try", TOKtry },
|
|
1598
|
|
1599 { "abstract", TOKabstract },
|
|
1600 { "boolean", TOKboolean },
|
|
1601 { "byte", TOKbyte },
|
|
1602 { "char", TOKchar },
|
|
1603 { "double", TOKdouble },
|
|
1604 { "final", TOKfinal },
|
|
1605 { "float", TOKfloat },
|
|
1606 { "goto", TOKgoto },
|
|
1607 { "implements", TOKimplements },
|
|
1608 { "instanceof", TOKinstanceof },
|
|
1609 { "int", TOKint },
|
|
1610 { "interface", TOKinterface },
|
|
1611 { "long", TOKlong },
|
|
1612 { "native", TOKnative },
|
|
1613 { "package", TOKpackage },
|
|
1614 { "private", TOKprivate },
|
|
1615 { "protected", TOKprotected },
|
|
1616 { "public", TOKpublic },
|
|
1617 { "short", TOKshort },
|
|
1618 { "static", TOKstatic },
|
|
1619 { "synchronized", TOKsynchronized },
|
|
1620 { "throws", TOKthrows },
|
|
1621 { "transient", TOKtransient },
|
|
1622 ];
|
|
1623
|
|
1624 void init()
|
|
1625 {
|
|
1626 uint u;
|
|
1627 TOK v;
|
|
1628
|
|
1629 for (u = 0; u < keywords.length; u++)
|
|
1630 { tchar[] s;
|
|
1631
|
|
1632 //writefln("keyword[%d] = '%s'", u, keywords[u].name);
|
|
1633 s = keywords[u].name;
|
|
1634 v = keywords[u].value;
|
|
1635
|
|
1636 //writefln("tochars[%d] = '%s'", v, s);
|
|
1637 Token.tochars[v] = s;
|
|
1638 }
|
|
1639
|
|
1640 Token.tochars[TOKreserved] = "reserved";
|
|
1641 Token.tochars[TOKeof] = "EOF";
|
|
1642 Token.tochars[TOKlbrace] = "{";
|
|
1643 Token.tochars[TOKrbrace] = "}";
|
|
1644 Token.tochars[TOKlparen] = "(";
|
|
1645 Token.tochars[TOKrparen] = "";
|
|
1646 Token.tochars[TOKlbracket] = "[";
|
|
1647 Token.tochars[TOKrbracket] = "]";
|
|
1648 Token.tochars[TOKcolon] = ":";
|
|
1649 Token.tochars[TOKsemicolon] = ";";
|
|
1650 Token.tochars[TOKcomma] = ",";
|
|
1651 Token.tochars[TOKor] = "|";
|
|
1652 Token.tochars[TOKorass] = "|=";
|
|
1653 Token.tochars[TOKxor] = "^";
|
|
1654 Token.tochars[TOKxorass] = "^=";
|
|
1655 Token.tochars[TOKassign] = "=";
|
|
1656 Token.tochars[TOKless] = "<";
|
|
1657 Token.tochars[TOKgreater] = ">";
|
|
1658 Token.tochars[TOKlessequal] = "<=";
|
|
1659 Token.tochars[TOKgreaterequal] = ">=";
|
|
1660 Token.tochars[TOKequal] = "==";
|
|
1661 Token.tochars[TOKnotequal] = "!=";
|
|
1662 Token.tochars[TOKidentity] = "===";
|
|
1663 Token.tochars[TOKnonidentity] = "!==";
|
|
1664 Token.tochars[TOKshiftleft] = "<<";
|
|
1665 Token.tochars[TOKshiftright] = ">>";
|
|
1666 Token.tochars[TOKushiftright] = ">>>";
|
|
1667 Token.tochars[TOKplus] = "+";
|
|
1668 Token.tochars[TOKplusass] = "+=";
|
|
1669 Token.tochars[TOKminus] = "-";
|
|
1670 Token.tochars[TOKminusass] = "-=";
|
|
1671 Token.tochars[TOKmultiply] = "*";
|
|
1672 Token.tochars[TOKmultiplyass] = "*=";
|
|
1673 Token.tochars[TOKdivide] = "/";
|
|
1674 Token.tochars[TOKdivideass] = "/=";
|
|
1675 Token.tochars[TOKpercent] = "%";
|
|
1676 Token.tochars[TOKpercentass] = "%=";
|
|
1677 Token.tochars[TOKand] = "&";
|
|
1678 Token.tochars[TOKandass] = "&=";
|
|
1679 Token.tochars[TOKdot] = ".";
|
|
1680 Token.tochars[TOKquestion] = "?";
|
|
1681 Token.tochars[TOKtilde] = "~";
|
|
1682 Token.tochars[TOKnot] = "!";
|
|
1683 Token.tochars[TOKandand] = "&&";
|
|
1684 Token.tochars[TOKoror] = "||";
|
|
1685 Token.tochars[TOKplusplus] = "++";
|
|
1686 Token.tochars[TOKminusminus] = "--";
|
|
1687 Token.tochars[TOKcall] = "CALL";
|
|
1688
|
|
1689 Lexer.inited = true;
|
|
1690 }
|
|
1691
|