root/trunk/dlexer.d

Revision 14, 35.2 kB (checked in by Jaymz031602, 4 years ago)

--

  • Property svn:executable set to *
Line 
1 // dlexer - D language lexer
2 // (C) Copyright 2004-2005 James Dunne
3
4 // Please feel free to distribute this module in any form you like.  I only ask that you
5 // give credit where credit is due.  You may make modifications to this module.  If you do
6 // so, you may provide your modifications publicly, but you are not required to.
7
8 module  dlexer;
9
10 import  std.stream;
11 import  std.string;
12 import  std.ctype;
13
14 private import std.c.stdlib;    // for strtod and strtold
15
16 alias std.ctype.isdigit isdigit;
17
18 // Set this version identifier to enable interpretation of escaped characters within parsed strings
19 // If this is disabled, the strings are copied directly, escape sequences and all.
20
21 // version = interpret_slashes;
22
23 // Enumeration of D language tokens taken from DMD's lexer.h
24 enum : uint {
25     TOKreserved,
26
27     // Other
28     TOKlparen,  TOKrparen,
29     TOKlbracket,    TOKrbracket,
30     TOKlcurly,  TOKrcurly,
31     TOKcolon,   TOKneg,
32     TOKsemicolon,   TOKdotdotdot,
33     TOKeof,     TOKcast,
34     TOKnull,    TOKassert,
35     TOKtrue,    TOKfalse,
36     TOKarray,   TOKcall,
37     TOKaddress, TOKtypedot,
38     TOKtype,    TOKthrow,
39     TOKnew,     TOKdelete,
40     TOKstar,    TOKsymoff,
41     TOKvar,     TOKdotvar,
42     TOKdotti,   TOKdotexp,
43     TOKdottype, TOKslice,
44     TOKarraylength, TOKversion,
45     TOKmodule,  TOKdollar,
46     TOKtemplate,    TOKinstance,
47     TOKdeclaration, TOKtypeof,
48     TOKpragma,  TOKdsymbol,
49     TOKtypeid,  TOKuadd,
50
51     // Operators
52     TOKlt,      TOKgt,
53     TOKle,      TOKge,
54     TOKequal,   TOKnotequal,
55     TOKidentity,    TOKnotidentity,
56     TOKindex,
57
58     // NCEG floating point compares
59     // !<>=     <>    <>=    !>     !>=   !<     !<=   !<>
60     TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue,
61
62     TOKshl,     TOKshr,
63     TOKshlass,  TOKshrass,
64     TOKushr,    TOKushrass,
65     TOKcat,     TOKcatass,  // ~ ~=
66     TOKadd,     TOKmin,     TOKaddass,  TOKminass,
67     TOKmul,     TOKdiv,     TOKmod,
68     TOKmulass,  TOKdivass,  TOKmodass,
69     TOKand,     TOKor,      TOKxor,
70     TOKandass,  TOKorass,   TOKxorass,
71     TOKassign,  TOKnot,     TOKtilde,
72     TOKplusplus,    TOKminusminus,
73     TOKdot,     TOKarrow,   TOKcomma,
74     TOKquestion,    TOKandand,  TOKoror,
75
76     // Numeric literals
77     TOKint32v, TOKuns32v,
78     TOKint64v, TOKuns64v,
79     TOKfloat32v, TOKfloat64v, TOKfloat80v,
80     TOKimaginary32v, TOKimaginary64v, TOKimaginary80v,
81
82     // Char constants
83     TOKcharv, TOKwcharv, TOKdcharv,
84
85     // Leaf operators
86     TOKidentifier,  TOKstring,
87     TOKthis,    TOKsuper,
88
89     // Basic types
90     TOKvoid,
91     TOKint8, TOKuns8,
92     TOKint16, TOKuns16,
93     TOKint32, TOKuns32,
94     TOKint64, TOKuns64,
95     TOKfloat32, TOKfloat64, TOKfloat80,
96     TOKimaginary32, TOKimaginary64, TOKimaginary80,
97     TOKcomplex32, TOKcomplex64, TOKcomplex80,
98     TOKchar, TOKwchar, TOKdchar, TOKbit,
99
100     // Aggregates
101     TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
102     TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction,
103     TOKmixin,
104
105     TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
106     TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile,
107     TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout,
108     TOKauto, TOKpackage,
109
110     // Statements
111     TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
112     TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
113     TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally,
114     TOKasm, TOKforeach,
115
116     // Contracts
117     TOKbody, TOKinvariant,
118
119     // Testing
120     TOKunittest,
121
122     TOKmax
123 }
124
125 // A table converting token values into string representations:
126 char[]  toktostr[TOKmax] = [
127     TOKreserved : "reserved",
128
129     // Other
130     TOKlparen : "(",
131     TOKrparen : ")",
132     TOKlbracket : "[",
133     TOKrbracket : "]",
134     TOKlcurly : "{",
135     TOKrcurly : "}",
136     TOKcolon : ":",
137     TOKneg : "-",
138     TOKsemicolon : ";",
139     TOKdotdotdot : "...",
140     TOKeof : "EOF",
141     TOKcast : "cast",
142     TOKnull : "null",
143     TOKassert : "assert",
144     TOKtrue : "true",
145     TOKfalse : "false",
146     TOKarray : "[]",
147     TOKcall : "call",
148     TOKaddress : "#",
149     TOKtypedot : "typedot",
150     TOKtype : "type",
151     TOKthrow : "throw",
152     TOKnew : "new",
153     TOKdelete : "delete",
154     TOKstar : "*",
155     TOKsymoff : "symoff",
156     TOKvar : "var",
157     TOKdotvar : "dotvar",
158     TOKdotti : "dotti",
159     TOKdotexp : "dotexp",
160     TOKdottype : "dottype",
161     TOKslice : "..",
162     TOKarraylength : "arraylength",
163     TOKversion : "version",
164     TOKmodule : "module",
165     TOKdollar : "$",
166     TOKtemplate : "template",
167     TOKinstance : "instance",
168     TOKdeclaration : "declaration",
169     TOKtypeof : "typeof",
170     TOKpragma : "pragma",
171     TOKdsymbol : "dsymbol",
172     TOKtypeid : "typeid",
173     TOKuadd : "uadd",
174
175     // Operators
176     TOKlt : "<",
177     TOKgt : ">",
178     TOKle : "<=",
179     TOKge : ">=",
180     TOKequal : "==",
181     TOKnotequal : "!=",
182     TOKidentity : "===",
183     TOKnotidentity : "!==",
184     TOKindex : "[]",
185
186     // NCEG floating point compares
187     // !<>=     <>    <>=    !>     !>=   !<     !<=   !<>
188
189     // NOTE:  These could be horribly wrong
190     TOKunord : "!<>=",
191     TOKue : "!<>",
192     TOKlg : "<>",
193     TOKleg : "<>=",
194     TOKule : "!>",
195     TOKul : "!>=",
196     TOKuge : "!<",
197     TOKug : "!<=",
198
199     TOKshl : "<<",
200     TOKshr : ">>",
201     TOKshlass : "<<=",
202     TOKshrass : ">>=",
203     TOKushr : ">>>",
204     TOKushrass : ">>>=",
205     TOKcat : "~",
206     TOKcatass : "~=",   // ~ ~=
207     TOKadd : "+",
208     TOKmin : "-",
209     TOKaddass : "+=",
210     TOKminass : "-=",
211     TOKmul : "*",
212     TOKdiv : "/",
213     TOKmod : "%",
214     TOKmulass : "*=",
215     TOKdivass : "/=",
216     TOKmodass : "%=",
217     TOKand : "&",
218     TOKor : "|",
219     TOKxor : "^",
220     TOKandass : "&=",
221     TOKorass : "|=",
222     TOKxorass : "^=",
223     TOKassign : "=",
224     TOKnot : "!",
225     TOKtilde : "~",
226     TOKplusplus : "++",
227     TOKminusminus : "--",
228     TOKdot : ".",
229     TOKarrow : "->",
230     TOKcomma : ",",
231     TOKquestion : "?",
232     TOKandand : "&&",
233     TOKoror : "||",
234
235     // Numeric literals
236     TOKint32v : "int32v", TOKuns32v : "uns32v",
237     TOKint64v : "int64v", TOKuns64v : "uns64v",
238     TOKfloat32v : "float32v", TOKfloat64v : "float64v", TOKfloat80v : "float80v",
239     TOKimaginary32v : "imaginary32v", TOKimaginary64v : "imaginary64v", TOKimaginary80v : "imaginary80v",
240
241     // Char constants
242     TOKcharv : "charv", TOKwcharv : "wcharv", TOKdcharv : "dcharv",
243
244     // Leaf operators
245     TOKidentifier : "identifier",   TOKstring : "string",
246     TOKthis : "this",   TOKsuper : "super",
247
248     // Basic types
249     TOKvoid : "void",
250     TOKint8 : "byte", TOKuns8 : "ubyte",
251     TOKint16 : "short", TOKuns16 : "ushort",
252     TOKint32 : "int", TOKuns32 : "uint",
253     TOKint64 : "long", TOKuns64 : "ulong",
254     TOKfloat32 : "float", TOKfloat64 : "double", TOKfloat80 : "real",
255     TOKimaginary32 : "ifloat", TOKimaginary64 : "idouble", TOKimaginary80 : "ireal",
256     TOKcomplex32 : "cfloat", TOKcomplex64 : "cdouble", TOKcomplex80 : "creal",
257     TOKchar : "char", TOKwchar : "wchar", TOKdchar : "dchar", TOKbit : "bit",
258
259     // Aggregates
260     TOKstruct : "struct", TOKclass : "class", TOKinterface : "interface", TOKunion : "union", TOKenum : "enum", TOKimport : "import",
261     TOKtypedef : "typedef", TOKalias : "alias", TOKoverride : "override", TOKdelegate : "delegate", TOKfunction : "function",
262     TOKmixin : "mixin",
263
264     TOKalign : "align", TOKextern : "extern", TOKprivate : "private", TOKprotected : "protected", TOKpublic : "public", TOKexport : "export",
265     TOKstatic : "static", /*TOKvirtual : "virtual",*/ TOKfinal : "final", TOKconst : "const", TOKabstract : "abstract", TOKvolatile : "volatile",
266     TOKdebug : "debug", TOKdeprecated : "deprecated", TOKin : "in", TOKout : "out", TOKinout : "inout",
267     TOKauto : "auto", TOKpackage : "package",
268
269     // Statements
270     TOKif : "if", TOKelse : "else", TOKwhile : "while", TOKfor : "for", TOKdo : "do", TOKswitch : "switch",
271     TOKcase : "case", TOKdefault : "default", TOKbreak : "break", TOKcontinue : "continue", TOKwith : "with",
272     TOKsynchronized : "synchronized", TOKreturn : "return", TOKgoto : "goto", TOKtry : "try", TOKcatch : "catch", TOKfinally : "finally",
273     TOKasm : "asm", TOKforeach : "foreach",
274
275     // Contracts
276     TOKbody : "body", TOKinvariant : "invariant",
277
278     // Testing
279     TOKunittest : "unittest",
280 ];
281
282 class Identifier {
283     int     value;
284     char[]  string;
285
286     this(char[] string, int value) {
287         this.value = value;
288         this.string = string;
289     };
290 };
291
292 // A language token:
293 class Token {
294     // The kind of token:
295     uint    value;
296     Token   next;
297
298     // The value for the token:
299     union {
300         // The identifier or value of the token:
301         Identifier  ident;
302
303         char[]      ustring;
304
305         // Integers
306         int         int32value;
307         uint        uns32value;
308         long        int64value;
309         ulong       uns64value;
310
311         // Floats
312         real        float80value;
313     };
314
315     char[] toString() {
316         return toktostr[value];
317     };
318
319     static char[] toChars(uint value) {
320         return toktostr[value];
321     };
322 }
323
324 // Exception thrown during parsing of D language:
325 class DLexerException : Error {
326     public:
327         this(DLexer dlx, char[] msg) {
328             // Construct an error message with the filename and line number:
329             super(dlx.filename ~ "(" ~ format("%d", dlx.line) ~ ")" ~ ": " ~ msg);
330         }
331 }
332
333 // Check for octal digit:
334 int isodigit(dchar x) {
335     if (!isdigit(x) || (x == '8') || (x == '9')) return 0;
336     return -1;
337 }
338
339 class Loc {
340     public:
341         int linnum;
342
343         this() {
344         }
345 }
346
347 // The D language lexer (tokenizer):
348 class DLexer {
349         static uint[char[]] keywords;
350         // Initialize the keyword->tokenvalue AA:
351         static this() {
352             // Add all the keywords' values into the AA:
353             keywords["this"] = TOKthis;
354             keywords["super"] = TOKsuper;
355             keywords["assert"] = TOKassert;
356             keywords["null"] = TOKnull;
357             keywords["true"] = TOKtrue;
358             keywords["false"] = TOKfalse;
359             keywords["cast"] = TOKcast;
360             keywords["new"] = TOKnew;
361             keywords["delete"] = TOKdelete;
362             keywords["throw"] = TOKthrow;
363             keywords["module"] = TOKmodule;
364             keywords["pragma"] = TOKpragma;
365             keywords["typeof"] = TOKtypeof;
366             keywords["typeid"] = TOKtypeid;
367
368             keywords["template"] = TOKtemplate;
369             keywords["instance"] = TOKinstance;
370
371             keywords["void"] = TOKvoid;
372             keywords["byte"] = TOKint8;
373             keywords["ubyte"] = TOKuns8;
374             keywords["short"] = TOKint16;
375             keywords["ushort"] = TOKuns16;
376             keywords["int"] = TOKint32;
377             keywords["uint"] = TOKuns32;
378             keywords["long"] = TOKint64;
379             keywords["ulong"] = TOKuns64;
380             keywords["float"] = TOKfloat32;
381             keywords["double"] = TOKfloat64;
382             keywords["real"] = TOKfloat80;
383
384             keywords["bit"] = TOKbit;
385             keywords["char"] = TOKchar;
386             keywords["wchar"] = TOKwchar;
387             keywords["dchar"] = TOKdchar;
388
389             keywords["ifloat"] = TOKimaginary32;
390             keywords["idouble"] = TOKimaginary64;
391             keywords["ireal"] = TOKimaginary80;
392
393             keywords["cfloat"] = TOKcomplex32;
394             keywords["cdouble"] = TOKcomplex64;
395             keywords["creal"] = TOKcomplex80;
396
397             keywords["delegate"] = TOKdelegate;
398             keywords["function"] = TOKfunction;
399
400             keywords["is"] = TOKidentity;
401             keywords["if"] = TOKif;
402             keywords["else"] = TOKelse;
403             keywords["while"] = TOKwhile;
404             keywords["for"] = TOKfor;
405             keywords["do"] = TOKdo;
406             keywords["switch"] = TOKswitch;
407             keywords["case"] = TOKcase;
408             keywords["default"] = TOKdefault;
409             keywords["break"] = TOKbreak;
410             keywords["continue"] = TOKcontinue;
411             keywords["synchronized"] = TOKsynchronized;
412             keywords["return"] = TOKreturn;
413             keywords["goto"] = TOKgoto;
414             keywords["try"] = TOKtry;
415             keywords["catch"] = TOKcatch;
416             keywords["finally"] = TOKfinally;
417             keywords["with"] = TOKwith;
418             keywords["asm"] = TOKasm;
419             keywords["foreach"] = TOKforeach;
420
421             keywords["struct"] = TOKstruct;
422             keywords["class"] = TOKclass;
423             keywords["interface"] = TOKinterface;
424             keywords["union"] = TOKunion;
425             keywords["enum"] = TOKenum;
426             keywords["import"] = TOKimport;
427             keywords["mixin"] = TOKmixin;
428             keywords["static"] = TOKstatic;
429             /*keywords["virtual"] = TOKvirtual;*/
430             keywords["final"] = TOKfinal;
431             keywords["const"] = TOKconst;
432             keywords["typedef"] = TOKtypedef;
433             keywords["alias"] = TOKalias;
434             keywords["override"] = TOKoverride;
435             keywords["abstract"] = TOKabstract;
436             keywords["volatile"] = TOKvolatile;
437             keywords["debug"] = TOKdebug;
438             keywords["deprecated"] = TOKdeprecated;
439             keywords["in"] = TOKin;
440             keywords["out"] = TOKout;
441             keywords["inout"] = TOKinout;
442             keywords["auto"] = TOKauto;
443
444             keywords["align"] = TOKalign;
445             keywords["extern"] = TOKextern;
446             keywords["private"] = TOKprivate;
447             keywords["package"] = TOKpackage;
448             keywords["protected"] = TOKprotected;
449             keywords["public"] = TOKpublic;
450             keywords["export"] = TOKexport;
451
452             keywords["body"] = TOKbody;
453             keywords["invariant"] = TOKinvariant;
454             keywords["unittest"] = TOKunittest;
455             keywords["version"] = TOKversion;
456         }
457
458     protected:
459         Token               token;
460         Identifier[char[]]  identifiers;
461         Loc                 loc;
462
463     private:
464         char[]  file;       // The input file
465         uint    p;          // Current character
466
467         char[]  wysiwygString(char tc) {
468             char    c;
469             char[]  s;
470             uint    i;
471
472             i = 0;
473             ++p;
474             s.length = 16;
475             while (p < file.length) {
476                 c = file[p++];
477                 switch (c) {
478                     case '\n':
479                         ++line;
480                         break;
481
482                     case '\r':
483                         if (file[p] == '\n')
484                             continue;   // ignore
485                         c = '\n';   // treat EndOfLine as \n character
486                         ++line;
487                         break;
488
489                     case 0x1A:
490                         error("unterminated string constant starting at %s", s);
491                         return null;
492
493                     case '"', '`':
494                         if (c == tc) {
495                             s.length = i;
496                             return s;
497                         }
498                         break;
499
500                     default:
501                         break;
502                 }
503
504                 if (i == s.length) s.length = s.length * 2;
505                 s[i++] = c;
506             }
507             s.length = i;
508             return s;
509         }
510
511         // Test this!
512         char[]  hexString() {
513             char    c;
514             uint    n = 0, i = 0;
515             char[]  s;
516             ubyte   v;
517
518             p++;
519             s.length = 16;
520             while (p < file.length) {
521                 c = file[p++];
522                 switch (c) {
523                     case ' ', '\t', '\v', '\f':
524                         continue;           // skip white space
525
526                     case '\r':
527                         if (file[p] == '\n')
528                             continue;           // ignore
529                         // Treat isolated '\r' as if it were a '\n'
530                     case '\n':
531                         ++line;
532                         continue;
533
534                     case 0x1A:
535                         error("unterminated string constant starting at %s", s);
536                         return null;
537
538                     case '"':
539                         if (n & 1) {
540                             error("odd number (%d) of hex characters in hex string", n);
541                             return null;
542                         }
543                         s.length = i;
544                         return s;
545
546                     default:
547                         if (c >= '0' && c <= '9')
548                             c -= '0';
549                         else if (c >= 'a' && c <= 'f')
550                             c -= 'a' - 10;
551                         else if (c >= 'A' && c <= 'F')
552                             c -= 'A' - 10;
553                         else
554                             error("non-hex character '%c'", c);
555                         if (n & 1) {
556                             v = (v << 4) | c;
557                             if (i == s.length) s.length = s.length * 2;
558                             s[i++] = v;
559                         } else
560                             v = c;
561                         ++n;
562                         break;
563                 }
564             }
565             return null;
566         }
567
568     public:
569         char[]  filename;   // Filename
570         uint    line;       // Current line
571
572         // Initialize the lexer with the full source code as a string:
573         this(char[] filename, char[] src) {<