Mercurial > projects > dmdscript-tango
view dmdscript_tango/lexer.d @ 3:8363a4bf6a8f
rename package: dmdscript to dmdscript_tango
author | saaadel |
---|---|
date | Sun, 24 Jan 2010 18:33:05 +0200 |
parents | 55c2951c07be |
children |
line wrap: on
line source
/* Digital Mars DMDScript source code. * Copyright (c) 2000-2002 by Chromium Communications * D version Copyright (c) 2004-2005 by Digital Mars * All Rights Reserved * written by Walter Bright * www.digitalmars.com * Use at your own risk. There is no warranty, express or implied. * License for redistribution is by the GNU General Public License in gpl.txt. * * A binary, non-exclusive license for commercial use can be * purchased from www.digitalmars.com/dscript/buy.html. * * DMDScript is implemented in the D Programming Language, * www.digitalmars.com/d/ * * For a C++ implementation of DMDScript, including COM support, * see www.digitalmars.com/dscript/cppscript.html. */ /* Lexical Analyzer */ module dmdscript_tango.lexer; import std.stdio; import std.string; import std.utf; import std.outbuffer; import std.ctype; import std.c.stdlib; import dmdscript_tango.script; import dmdscript_tango.text; import dmdscript_tango.identifier; import dmdscript_tango.scopex; import dmdscript_tango.textgen.errmsgs; /* Tokens: ( ) [ ] { } < > <= >= == != === !== << >> <<= >>= >>> >>>= + - += -= * / % *= /= %= & | ^ &= |= ^= = ! ~ ++ -- . : , ? && || */ alias int TOK; enum { TOKreserved, // Other TOKlparen, TOKrparen, TOKlbracket, TOKrbracket, TOKlbrace, TOKrbrace, TOKcolon, TOKneg, TOKpos, TOKsemicolon, TOKeof, TOKarray, TOKcall, TOKarraylit, TOKobjectlit, TOKcomma, TOKassert, // Operators TOKless, TOKgreater, TOKlessequal, TOKgreaterequal, TOKequal, TOKnotequal, TOKidentity, TOKnonidentity, TOKshiftleft, TOKshiftright, TOKshiftleftass, TOKshiftrightass, TOKushiftright, TOKushiftrightass, TOKplus, TOKminus, TOKplusass, TOKminusass, TOKmultiply, TOKdivide, TOKpercent, TOKmultiplyass, TOKdivideass, TOKpercentass, TOKand, TOKor, TOKxor, TOKandass, TOKorass, TOKxorass, TOKassign, TOKnot, TOKtilde, TOKplusplus, TOKminusminus, TOKdot, TOKquestion, TOKandand, TOKoror, // Leaf operators TOKnumber, TOKidentifier, TOKstring, TOKregexp, TOKreal, // Keywords TOKbreak, TOKcase, TOKcontinue, TOKdefault, TOKdelete, TOKdo, TOKelse, TOKexport, TOKfalse, TOKfor, TOKfunction, TOKif, TOKimport, TOKin, TOKnew, TOKnull, TOKreturn, TOKswitch, TOKthis, TOKtrue, TOKtypeof, TOKvar, TOKvoid, TOKwhile, TOKwith, // Reserved for ECMA extensions TOKcatch, TOKclass, TOKconst, TOKdebugger, TOKenum, TOKextends, TOKfinally, TOKsuper, TOKthrow, TOKtry, // Java keywords reserved for unknown reasons TOKabstract, TOKboolean, TOKbyte, TOKchar, TOKdouble, TOKfinal, TOKfloat, TOKgoto, TOKimplements, TOKinstanceof, TOKint, TOKinterface, TOKlong, TOKnative, TOKpackage, TOKprivate, TOKprotected, TOKpublic, TOKshort, TOKstatic, TOKsynchronized, TOKthrows, TOKtransient, TOKmax }; int isoctal(dchar c) { return ('0' <= c && c <= '7'); } int isasciidigit(dchar c) { return ('0' <= c && c <= '9'); } int isasciilower(dchar c) { return ('a' <= c && c <= 'z'); } int isasciiupper(dchar c) { return ('A' <= c && c <= 'Z'); } int ishex(dchar c) { return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); } /******************************************************/ struct Token { Token *next; tchar *ptr; // pointer to first character of this token within buffer uint linnum; TOK value; tchar *sawLineTerminator; // where we saw the last line terminator union { number_t intvalue; real_t realvalue; tchar[] string; Identifier *ident; }; static tchar[] tochars[TOKmax]; static Token* alloc(Lexer* lex) { Token *t; if (lex.freelist) { t = lex.freelist; lex.freelist = t.next; return t; } return new Token(); } void print() { writefln(toString()); } char[] toString() { char[] p; switch (value) { case TOKnumber: p = std.string.format(intvalue); break; case TOKreal: long l = cast(long)realvalue; if (l == realvalue) p = std.string.format(l); else p = std.string.format(realvalue); break; case TOKstring: case TOKregexp: p = string; break; case TOKidentifier: p = ident.toString(); break; default: p = toString(value); break; } return p; } static char[] toString(TOK value) { char[] p; p = tochars[value]; if (!p) p = std.string.format("TOK%d", value); return p; } } /*******************************************************************/ class Lexer { Identifier[tchar[]] stringtable; Token* freelist; char[] sourcename; // for error message strings tchar[] base; // pointer to start of buffer tchar* end; // past end of buffer tchar* p; // current character uint currentline; Token token; OutBuffer stringbuffer; int useStringtable; // use for Identifiers ErrInfo errinfo; // syntax error information static bool inited; this(char[] sourcename, tchar[] base, int useStringtable) { //writefln("Lexer::Lexer(base = '%s')\n",base); if (!inited) init(); std.c.string.memset(&token, 0, token.sizeof); this.useStringtable = useStringtable; this.sourcename = sourcename; if (!base.length || (base[length - 1] != 0 && base[length - 1] != 0x1A)) base ~= cast(tchar)0x1A; this.base = base; this.end = base.ptr + base.length; p = base.ptr; currentline = 1; freelist = null; } ~this() { //writef(L"~Lexer()\n"); freelist = null; sourcename = null; base = null; end = null; p = null; } dchar get(tchar* p) { size_t idx = p - base.ptr; return std.utf.decode(base, idx); } tchar* inc(tchar* p) { size_t idx = p - base.ptr; std.utf.decode(base, idx); return base.ptr + idx; } void error(int msgnum) { error(errmsgtbl[msgnum]); } void error(...) { uint linnum = 1; tchar* s; tchar* slinestart; tchar* slineend; tchar[] buf; //FuncLog funclog(L"Lexer.error()"); //writefln("TEXT START ------------\n%ls\nTEXT END ------------------", base); // Find the beginning of the line slinestart = base.ptr; for (s = base.ptr; s != p; s++) { if (*s == '\n') { linnum++; slinestart = s + 1; } } // Find the end of the line for (;;) { switch (*s) { case '\n': case 0: case 0x1A: break; default: s++; continue; } break; } slineend = s; buf = std.string.format("%s(%d) : Error: ", sourcename, linnum); void putc(dchar c) { std.utf.encode(buf, c); } std.format.doFormat(&putc, _arguments, _argptr); if (!errinfo.message) { uint len; errinfo.message = buf; errinfo.linnum = linnum; errinfo.charpos = p - slinestart; len = slineend - slinestart; errinfo.srcline = slinestart[0 .. len]; } // Consume input until the end while (*p != 0x1A && *p != 0) p++; token.next = null; // dump any lookahead version (none) { writefln(errinfo.message); fflush(stdout); exit(EXIT_FAILURE); } } /************************************************ * Given source text, convert loc to a string for the corresponding line. */ static tchar[] locToSrcline(tchar *src, Loc loc) { tchar *slinestart; tchar *slineend; tchar *s; uint linnum = 1; uint len; if (!src) return null; slinestart = src; for (s = src; ; s++) { switch (*s) { case '\n': if (linnum == loc) { slineend = s; break; } slinestart = s + 1; linnum++; continue; case 0: case 0x1A: slineend = s; break; default: continue; } break; } // Remove trailing \r's while (slinestart < slineend && slineend[-1] == '\r') --slineend; len = slineend - slinestart; return slinestart[0 .. len]; } TOK nextToken() { Token *t; if (token.next) { t = token.next; token = *t; t.next = freelist; freelist = t; } else { scan(&token); } //token.print(); return token.value; } Token *peek(Token *ct) { Token *t; if (ct.next) t = ct.next; else { t = Token.alloc(&this); scan(t); t.next = null; ct.next = t; } return t; } void insertSemicolon(tchar *loc) { // Push current token back into the input, and // create a new current token that is a semicolon Token *t; t = Token.alloc(&this); *t = token; token.next = t; token.value = TOKsemicolon; token.ptr = loc; token.sawLineTerminator = null; } /********************************** * Horrible kludge to support disambiguating TOKregexp from TOKdivide. * The idea is, if we are looking for a TOKdivide, and find instead * a TOKregexp, we back up and rescan. */ void rescan() { token.next = null; // no lookahead // should put on freelist p = token.ptr + 1; } /**************************** * Turn next token in buffer into a token. */ void scan(Token *t) { tchar c; dchar d; //writefln("Lexer.scan()"); t.sawLineTerminator = null; for (;;) { t.ptr = p; //t.linnum = currentline; //writefln("p = %x",cast(uint)p); //writefln("p = %x, *p = x%02x, '%s'",cast(uint)p,*p,*p); switch (*p) { case 0: case 0x1A: t.value = TOKeof; // end of file return; case ' ': case '\t': case '\v': case '\f': case 0xA0: // no-break space p++; continue; // skip white space case '\n': // line terminator currentline++; case '\r': t.sawLineTerminator = p; p++; continue; case '"': case '\'': t.string = string(*p); t.value = TOKstring; return; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': t.value = number(t); return; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case '$': Lidentifier: { tchar[] id; do { p = inc(p); d = get(p); if (d == '\\' && p[1] == 'u') { Lidentifier2: id = t.ptr[0 .. p - t.ptr].dup; p++; std.utf.encode(id, unicode()); for (;;) { d = get(p); if (d == '\\' && p[1] == 'u') { p++; std.utf.encode(id, unicode()); } else if (isalnum(d) || d == '_' || d == '$') { id ~= cast(tchar)d; p = inc(p); } else goto Lidentifier3; } } } while (isalnum(d) || d == '_' || d == '$'); // This should be isalnum -- any Unicode letter is allowed id = t.ptr[0 .. p - t.ptr]; Lidentifier3: t.value = isKeyword(id); if (t.value) return; if (useStringtable) { //Identifier* i = &stringtable[id]; Identifier* i = id in stringtable; if (!i) { stringtable[id] = Identifier.init; i = id in stringtable; } i.value.putVstring(id); i.value.toHash(); t.ident = i; } else t.ident = Identifier.build(id); t.value = TOKidentifier; return; } case '/': p++; c = *p; if (c == '=') { p++; t.value = TOKdivideass; return; } else if (c == '*') { p++; for ( ; ; p++) { c = *p; Lcomment: switch (c) { case '*': p++; c = *p; if (c == '/') { p++; break; } goto Lcomment; case '\n': currentline++; case '\r': t.sawLineTerminator = p; continue; case 0: case 0x1A: error(ERR_BAD_C_COMMENT); t.value = TOKeof; return; default: continue; } break; } continue; } else if (c == '/') { for (;;) { p++; switch (*p) { case '\n': currentline++; case '\r': t.sawLineTerminator = p; break; case 0: case 0x1A: // end of file t.value = TOKeof; return; default: continue; } break; } p++; continue; } else if ((t.string = regexp()) != null) t.value = TOKregexp; else t.value = TOKdivide; return; case '.': tchar *q; q = p + 1; c = *q; if (isdigit(c)) t.value = number(t); else { t.value = TOKdot; p = q; } return; case '&': p++; c = *p; if (c == '=') { p++; t.value = TOKandass; } else if (c == '&') { p++; t.value = TOKandand; } else t.value = TOKand; return; case '|': p++; c = *p; if (c == '=') { p++; t.value = TOKorass; } else if (c == '|') { p++; t.value = TOKoror; } else t.value = TOKor; return; case '-': p++; c = *p; if (c == '=') { p++; t.value = TOKminusass; } else if (c == '-') { p++; // If the last token in the file is -. then // treat it as EOF. This is to accept broken // scripts that forgot to protect the closing -. // with a // comment. if (*p == '>') { // Scan ahead to see if it's the last token tchar *q; q = p; for (;;) { switch (*++q) { case 0: case 0x1A: t.value = TOKeof; p = q; return; case ' ': case '\t': case '\v': case '\f': case '\n': case '\r': case 0xA0: // no-break space continue; default: assert(0); } break; } } t.value = TOKminusminus; } else t.value = TOKminus; return; case '+': p++; c = *p; if (c == '=') { p++; t.value = TOKplusass; } else if (c == '+') { p++; t.value = TOKplusplus; } else t.value = TOKplus; return; case '<': p++; c = *p; if (c == '=') { p++; t.value = TOKlessequal; } else if (c == '<') { p++; c = *p; if (c == '=') { p++; t.value = TOKshiftleftass; } else t.value = TOKshiftleft; } else if (c == '!' && p[1] == '-' && p[2] == '-') { // Special comment to end of line p += 2; for (;;) { p++; switch (*p) { case '\n': currentline++; case '\r': t.sawLineTerminator = p; break; case 0: case 0x1A: // end of file error(ERR_BAD_HTML_COMMENT); t.value = TOKeof; return; default: continue; } break; } p++; continue; } else t.value = TOKless; return; case '>': p++; c = *p; if (c == '=') { p++; t.value = TOKgreaterequal; } else if (c == '>') { p++; c = *p; if (c == '=') { p++; t.value = TOKshiftrightass; } else if (c == '>') { p++; c = *p; if (c == '=') { p++; t.value = TOKushiftrightass; } else t.value = TOKushiftright; } else t.value = TOKshiftright; } else t.value = TOKgreater; return; case '(': p++; t.value = TOKlparen; return; case ')': p++; t.value = TOKrparen; return; case '[': p++; t.value = TOKlbracket; return; case ']': p++; t.value = TOKrbracket; return; case '{': p++; t.value = TOKlbrace; return; case '}': p++; t.value = TOKrbrace; return; case '~': p++; t.value = TOKtilde; return; case '?': p++; t.value = TOKquestion; return; case ',': p++; t.value = TOKcomma; return; case ';': p++; t.value = TOKsemicolon; return; case ':': p++; t.value = TOKcolon; return; case '*': p++; c = *p; if (c == '=') { p++; t.value = TOKmultiplyass; } else t.value = TOKmultiply; return; case '%': p++; c = *p; if (c == '=') { p++; t.value = TOKpercentass; } else t.value = TOKpercent; return; case '^': p++; c = *p; if (c == '=') { p++; t.value = TOKxorass; } else t.value = TOKxor; return; case '=': p++; c = *p; if (c == '=') { p++; c = *p; if (c == '=') { p++; t.value = TOKidentity; } else t.value = TOKequal; } else t.value = TOKassign; return; case '!': p++; c = *p; if (c == '=') { p++; c = *p; if (c == '=') { p++; t.value = TOKnonidentity; } else t.value = TOKnotequal; } else t.value = TOKnot; return; case '\\': if (p[1] == 'u') { // \uXXXX starts an identifier goto Lidentifier2; } default: d = get(p); if (isalpha(d)) // This should be isalpha -- any Unicode letter goto Lidentifier; else { if (isprint(d)) error(errmsgtbl[ERR_BAD_CHAR_C], d); else error(errmsgtbl[ERR_BAD_CHAR_X], d); } continue; } } } /******************************************* * Parse escape sequence. */ dchar escapeSequence() { uint c; int n; c = *p; p++; switch (c) { case '\'': case '"': case '?': case '\\': break; case 'a': c = 7; break; case 'b': c = 8; break; case 'f': c = 12; break; case 'n': c = 10; break; case 'r': c = 13; break; case 't': c = 9; break; case 'v': version (JSCRIPT_ESCAPEV_BUG) { } else { c = 11; } break; case 'x': c = *p; p++; if (ishex(c)) { uint v; n = 0; v = 0; for (;;) { if (isdigit(c)) c -= '0'; else if (isasciilower(c)) c -= 'a' - 10; else // 'A' <= c && c <= 'Z' c -= 'A' - 10; v = v * 16 + c; c = *p; if (++n >= 2 || !ishex(c)) break; p++; } if (n == 1) error(ERR_BAD_HEX_SEQUENCE); c = v; } else error(errmsgtbl[ERR_UNDEFINED_ESC_SEQUENCE], c); break; default: if (c > 0x7F) { p--; c = get(p); p = inc(p); } if (isoctal(c)) { uint v; n = 0; v = 0; for (;;) { v = v * 8 + (c - '0'); c = *p; if (++n >= 3 || !isoctal(c)) break; p++; } c = v; } // Don't throw error, just accept it //error("undefined escape sequence \\%c\n",c); break; } return c; } /************************************** */ tchar[] string(tchar quote) { tchar c; dchar d; tchar[] stringbuffer; //printf("Lexer.string('%c')\n", quote); p++; for (;;) { c = *p; switch (c) { case '"': case '\'': p++; if (c == quote) return stringbuffer; break; case '\\': p++; if (*p == 'u') d = unicode(); else d = escapeSequence(); std.utf.encode(stringbuffer, d); continue; case '\n': case '\r': p++; error(errmsgtbl[ERR_STRING_NO_END_QUOTE], quote); return null; case 0: case 0x1A: error(ERR_UNTERMINATED_STRING); return null; default: p++; break; } stringbuffer ~= c; } assert(0); } /************************************** * Scan regular expression. Return null with buffer * pointer intact if it is not a regexp. */ tchar[] regexp() { tchar c; tchar* s; tchar* start; /* RegExpLiteral: RegExpBody RegExpFlags RegExpFlags: empty | RegExpFlags ContinuingIdentifierCharacter RegExpBody: / RegExpFirstChar RegExpChars / RegExpFirstChar: OrdinaryRegExpFirstChar | \ NonTerminator OrdinaryRegExpFirstChar: NonTerminator except \ | / | * RegExpChars: empty | RegExpChars RegExpChar RegExpChar: OrdinaryRegExpChar | \ NonTerminator OrdinaryRegExpChar: NonTerminator except \ | / */ //writefln("Lexer.regexp()\n"); start = p - 1; s = p; // Do RegExpBody for (;;) { c = *s; s++; switch (c) { case '\\': if (s == p) return null; c = *s; switch (c) { case '\r': case '\n': // new line case 0: // end of file case 0x1A: // end of file return null; // not a regexp default: break; } s++; continue; case '/': if (s == p + 1) return null; break; case '\r': case '\n': // new line case 0: // end of file case 0x1A: // end of file return null; // not a regexp case '*': if (s == p + 1) return null; default: continue; } break; } // Do RegExpFlags for (;;) { c = *s; if (isalnum(c) || c == '_' || c == '$') { s++; } else break; } // Finish pattern & return it p = s; return start[0 .. s - start].dup; } /*************************************** */ dchar unicode() { dchar value; uint n; dchar c; value = 0; p++; for (n = 0; n < 4; n++) { c = *p; if (!ishex(c)) { error(ERR_BAD_U_SEQUENCE); break; } p++; if (isdigit(c)) c -= '0'; else if (isasciilower(c)) c -= 'a' - 10; else // 'A' <= c && c <= 'Z' c -= 'A' - 10; value <<= 4; value |= c; } return value; } /******************************************** * Read a number. */ TOK number(Token *t) { tchar *start; number_t intvalue; real realvalue; int base = 10; tchar c; start = p; for (;;) { c = *p; p++; switch (c) { case '0': // ECMA grammar implies that numbers with leading 0 // like 015 are illegal. But other scripts allow them. if (p - start == 1) // if leading 0 base = 8; case '1': case '2': case '3': case '4': case '5': case '6': case '7': break; case '8': case '9': // decimal digits if (base == 8) // and octal base base = 10; // means back to decimal base break; default: p--; Lnumber: if (base == 0) base = 10; intvalue = 0; foreach (tchar v; start[0 .. p - start]) { if ('0' <= v && v <= '9') v -= '0'; else if ('a' <= v && v <= 'f') v -= ('a' - 10); else if ('A' <= v && v <= 'F') v -= ('A' - 10); else assert(0); assert(v < base); if ((number_t.max - v) / base < intvalue) { realvalue = 0; foreach (tchar w; start[0 .. p - start]) { if ('0' <= w && w <= '9') w -= '0'; else if ('a' <= w && w <= 'f') w -= ('a' - 10); else if ('A' <= w && w <= 'F') w -= ('A' - 10); else assert(0); realvalue *= base; realvalue += v; } t.realvalue = realvalue; return TOKreal; } intvalue *= base; intvalue += v; } t.realvalue = cast(double)intvalue; return TOKreal; case 'x': case 'X': if (p - start != 2 || !ishex(*p)) goto Lerr; do p++; while (ishex(*p)); start += 2; base = 16; goto Lnumber; case '.': while (isdigit(*p)) p++; if (*p == 'e' || *p == 'E') { p++; goto Lexponent; } goto Ldouble; case 'e': case 'E': Lexponent: if (*p == '+' || *p == '-') p++; if (!isdigit(*p)) goto Lerr; do p++; while (isdigit(*p)); goto Ldouble; Ldouble: // convert double realvalue = std.c.stdlib.strtod(toStringz(start[0 .. p - start]), null); t.realvalue = realvalue; return TOKreal; } } Lerr: error(ERR_UNRECOGNIZED_N_LITERAL); return TOKeof; } static TOK isKeyword(tchar[] s) { if (s[0] >= 'a' && s[0] <= 'w') switch (s.length) { case 2: if (s[0] == 'i') { if (s[1] == 'f') return TOKif; if (s[1] == 'n') return TOKin; } else if (s[0] == 'd' && s[1] == 'o') return TOKdo; break; case 3: switch (s[0]) { case 'f': if (s[1] == 'o' && s[2] == 'r') return TOKfor; break; case 'i': if (s[1] == 'n' && s[2] == 't') return TOKint; break; case 'n': if (s[1] == 'e' && s[2] == 'w') return TOKnew; break; case 't': if (s[1] == 'r' && s[2] == 'y') return TOKtry; break; case 'v': if (s[1] == 'a' && s[2] == 'r') return TOKvar; break; default: break; } break; case 4: switch (s[0]) { case 'b': if (s[1] == 'y' && s[2] == 't' && s[3] == 'e') return TOKbyte; break; case 'c': if (s[1] == 'a' && s[2] == 's' && s[3] == 'e') return TOKcase; if (s[1] == 'h' && s[2] == 'a' && s[3] == 'r') return TOKchar; break; case 'e': if (s[1] == 'l' && s[2] == 's' && s[3] == 'e') return TOKelse; if (s[1] == 'n' && s[2] == 'u' && s[3] == 'm') return TOKenum; break; case 'g': if (s[1] == 'o' && s[2] == 't' && s[3] == 'o') return TOKgoto; break; case 'l': if (s[1] == 'o' && s[2] == 'n' && s[3] == 'g') return TOKlong; break; case 'n': if (s[1] == 'u' && s[2] == 'l' && s[3] == 'l') return TOKnull; break; case 't': if (s[1] == 'h' && s[2] == 'i' && s[3] == 's') return TOKthis; if (s[1] == 'r' && s[2] == 'u' && s[3] == 'e') return TOKtrue; break; case 'w': if (s[1] == 'i' && s[2] == 't' && s[3] == 'h') return TOKwith; break; case 'v': if (s[1] == 'o' && s[2] == 'i' && s[3] == 'd') return TOKvoid; break; default: break; } break; case 5: switch (s) { case "break": return TOKbreak; case "catch": return TOKcatch; case "class": return TOKclass; case "const": return TOKconst; case "false": return TOKfalse; case "final": return TOKfinal; case "float": return TOKfloat; case "short": return TOKshort; case "super": return TOKsuper; case "throw": return TOKthrow; case "while": return TOKwhile; default: break; } break; case 6: switch (s) { case "delete": return TOKdelete; case "double": return TOKdouble; case "export": return TOKexport; case "import": return TOKimport; case "native": return TOKnative; case "public": return TOKpublic; case "return": return TOKreturn; case "static": return TOKstatic; case "switch": return TOKswitch; case "throws": return TOKthrows; case "typeof": return TOKtypeof; default: break; } break; case 7: switch (s) { case "boolean": return TOKboolean; case "default": return TOKdefault; case "extends": return TOKextends; case "finally": return TOKfinally; case "package": return TOKpackage; case "private": return TOKprivate; default: break; } break; case 8: switch (s) { case "abstract": return TOKabstract; case "continue": return TOKcontinue; case "debugger": return TOKdebugger; case "function": return TOKfunction; default: break; } break; case 9: switch (s) { case "interface": return TOKinterface; case "protected": return TOKprotected; case "transient": return TOKtransient; default: break; } break; case 10: switch (s) { case "implements": return TOKimplements; case "instanceof": return TOKinstanceof; default: break; } break; case 12: if (s == "synchronized") return TOKsynchronized; break; default: break; } return TOKreserved; // not a keyword } } /**************************************** */ struct Keyword { tchar[] name; TOK value; } static Keyword keywords[] = [ // { "", TOK }, { "break", TOKbreak }, { "case", TOKcase }, { "continue", TOKcontinue }, { "default", TOKdefault }, { "delete", TOKdelete }, { "do", TOKdo }, { "else", TOKelse }, { "export", TOKexport }, { "false", TOKfalse }, { "for", TOKfor }, { "function", TOKfunction }, { "if", TOKif }, { "import", TOKimport }, { "in", TOKin }, { "new", TOKnew }, { "null", TOKnull }, { "return", TOKreturn }, { "switch", TOKswitch }, { "this", TOKthis }, { "true", TOKtrue }, { "typeof", TOKtypeof }, { "var", TOKvar }, { "void", TOKvoid }, { "while", TOKwhile }, { "with", TOKwith }, { "catch", TOKcatch }, { "class", TOKclass }, { "const", TOKconst }, { "debugger", TOKdebugger }, { "enum", TOKenum }, { "extends", TOKextends }, { "finally", TOKfinally }, { "super", TOKsuper }, { "throw", TOKthrow }, { "try", TOKtry }, { "abstract", TOKabstract }, { "boolean", TOKboolean }, { "byte", TOKbyte }, { "char", TOKchar }, { "double", TOKdouble }, { "final", TOKfinal }, { "float", TOKfloat }, { "goto", TOKgoto }, { "implements", TOKimplements }, { "instanceof", TOKinstanceof }, { "int", TOKint }, { "interface", TOKinterface }, { "long", TOKlong }, { "native", TOKnative }, { "package", TOKpackage }, { "private", TOKprivate }, { "protected", TOKprotected }, { "public", TOKpublic }, { "short", TOKshort }, { "static", TOKstatic }, { "synchronized", TOKsynchronized }, { "throws", TOKthrows }, { "transient", TOKtransient }, ]; void init() { uint u; TOK v; for (u = 0; u < keywords.length; u++) { tchar[] s; //writefln("keyword[%d] = '%s'", u, keywords[u].name); s = keywords[u].name; v = keywords[u].value; //writefln("tochars[%d] = '%s'", v, s); Token.tochars[v] = s; } Token.tochars[TOKreserved] = "reserved"; Token.tochars[TOKeof] = "EOF"; Token.tochars[TOKlbrace] = "{"; Token.tochars[TOKrbrace] = "}"; Token.tochars[TOKlparen] = "("; Token.tochars[TOKrparen] = ""; Token.tochars[TOKlbracket] = "["; Token.tochars[TOKrbracket] = "]"; Token.tochars[TOKcolon] = ":"; Token.tochars[TOKsemicolon] = ";"; Token.tochars[TOKcomma] = ","; Token.tochars[TOKor] = "|"; Token.tochars[TOKorass] = "|="; Token.tochars[TOKxor] = "^"; Token.tochars[TOKxorass] = "^="; Token.tochars[TOKassign] = "="; Token.tochars[TOKless] = "<"; Token.tochars[TOKgreater] = ">"; Token.tochars[TOKlessequal] = "<="; Token.tochars[TOKgreaterequal] = ">="; Token.tochars[TOKequal] = "=="; Token.tochars[TOKnotequal] = "!="; Token.tochars[TOKidentity] = "==="; Token.tochars[TOKnonidentity] = "!=="; Token.tochars[TOKshiftleft] = "<<"; Token.tochars[TOKshiftright] = ">>"; Token.tochars[TOKushiftright] = ">>>"; Token.tochars[TOKplus] = "+"; Token.tochars[TOKplusass] = "+="; Token.tochars[TOKminus] = "-"; Token.tochars[TOKminusass] = "-="; Token.tochars[TOKmultiply] = "*"; Token.tochars[TOKmultiplyass] = "*="; Token.tochars[TOKdivide] = "/"; Token.tochars[TOKdivideass] = "/="; Token.tochars[TOKpercent] = "%"; Token.tochars[TOKpercentass] = "%="; Token.tochars[TOKand] = "&"; Token.tochars[TOKandass] = "&="; Token.tochars[TOKdot] = "."; Token.tochars[TOKquestion] = "?"; Token.tochars[TOKtilde] = "~"; Token.tochars[TOKnot] = "!"; Token.tochars[TOKandand] = "&&"; Token.tochars[TOKoror] = "||"; Token.tochars[TOKplusplus] = "++"; Token.tochars[TOKminusminus] = "--"; Token.tochars[TOKcall] = "CALL"; Lexer.inited = true; }