2004-02-04 Marek Safar <marek.safar@seznam.cz>
[mono.git] / mcs / mbas / mb-tokenizer.cs
1 //
2 // Mono.MonoBASIC.Tokenizer.cs: The Tokenizer for the MonoBASIC compiler
3 //
4 // Author: A Rafael D Teixeira (rafaelteixeirabr@hotmail.com)
5 //         
6 // Based on cs-tokenizer.cs by Miguel de Icaza (miguel@gnu.org)
7 //
8 // Licensed under the terms of the GNU GPL
9 //
10 // Copyright (C) 2001 A Rafael D Teixeira
11 //
12
13 namespace Mono.MonoBASIC
14 {
15         using System;
16         using System.Text;
17         using System.Collections;
18         using System.IO;
19         using System.Globalization;
20         using Mono.Languages;
21         using Mono.MonoBASIC;
22         
23         /// <summary>
24         ///    Tokenizer for MonoBASIC source code. 
25         /// </summary>
26         
27         public class Tokenizer : yyParser.yyInput
28         {
29                 TextReader reader;
30                 // TODO: public SourceFile file_name;
31                 public string file_name;
32                 public string ref_name;
33                 public int ref_line = 1;
34                 public int line = 1;
35                 public int col = 1;
36                 public int current_token = Token.EOL;
37                 bool handle_get_set = false;
38                 bool cant_have_a_type_character = false;
39
40                 public int ExpandedTabsSize = 4; 
41
42                 public string location {
43                         get {
44                                 string det;
45
46                                 if (current_token == Token.ERROR)
47                                         det = "detail: " + error_details;
48                                 else
49                                         det = "";
50                                 
51                                 return "Line:     "+line+" Col: "+col + "\n" +
52                                        "VirtLine: "+ref_line +
53                                        " Token: "+current_token + " " + det;
54                         }
55                 }
56
57                 public bool properties {
58                         get {
59                                 return handle_get_set;
60                         }
61
62                         set {
63                                 handle_get_set = value;
64                         }
65                 }
66                 
67                 //
68                 // Class variables
69                 // 
70                 static Hashtable keywords;
71                 static NumberStyles styles;
72                 static NumberFormatInfo csharp_format_info;
73                 
74                 //
75                 // Pre-processor
76                 //
77                 Hashtable defines;
78
79                 const int TAKING        = 1;
80                 const int TAKEN_BEFORE  = 2;
81                 const int ELSE_SEEN     = 4;
82                 const int PARENT_TAKING = 8;
83                 const int REGION        = 16;           
84
85                 //
86                 // pre-processor if stack state:
87                 //
88                 Stack ifstack;
89
90                 //
91                 // Values for the associated token returned
92                 //
93                 StringBuilder number;
94                 int putback_char;
95                 Object val;
96                 
97                 //
98                 // Details about the error encoutered by the tokenizer
99                 //
100                 string error_details;
101                 
102                 public string error {
103                         get {
104                                 return error_details;
105                         }
106                 }
107                 
108                 public int Line {
109                         get {
110                                 return line;
111                         }
112                 }
113
114                 public int Col {
115                         get {
116                                 return col;
117                         }
118                 }
119                 
120                 static void initTokens ()
121                 {
122                         keywords = new Hashtable ();
123
124                         keywords.Add ("addhandler", Token.ADDHANDLER);
125                         keywords.Add ("addressof", Token.ADDRESSOF);
126                         keywords.Add ("alias", Token.ALIAS);
127                         keywords.Add ("and", Token.AND);
128                         keywords.Add ("andalso", Token.ANDALSO);
129                         keywords.Add ("ansi", Token.ANSI);
130                         keywords.Add ("as", Token.AS);
131                         keywords.Add ("assembly", Token.ASSEMBLY);
132                         keywords.Add ("auto", Token.AUTO);
133                         keywords.Add ("binary", Token.BINARY);
134                         keywords.Add ("boolean", Token.BOOLEAN);
135                         keywords.Add ("byref", Token.BYREF);
136                         keywords.Add ("byte", Token.BYTE);
137                         keywords.Add ("byval", Token.BYVAL);
138                         keywords.Add ("call", Token.CALL);
139                         keywords.Add ("case", Token.CASE);
140                         keywords.Add ("catch", Token.CATCH);
141                         keywords.Add ("cbool", Token.CBOOL);
142                         keywords.Add ("cbyte", Token.CBYTE);
143                         keywords.Add ("cchar", Token.CCHAR);
144                         keywords.Add ("cdate", Token.CDATE);
145                         keywords.Add ("cdec", Token.CDEC);
146                         keywords.Add ("cdbl", Token.CDBL);
147                         keywords.Add ("char", Token.CHAR);
148                         keywords.Add ("cint", Token.CINT);
149                         keywords.Add ("class", Token.CLASS);
150                         keywords.Add ("clng", Token.CLNG);
151                         keywords.Add ("cobj", Token.COBJ);
152                         keywords.Add ("compare", Token.COMPARE);
153                         keywords.Add ("const", Token.CONST);
154                         keywords.Add ("cshort", Token.CSHORT);
155                         keywords.Add ("csng", Token.CSNG);
156                         keywords.Add ("cstr", Token.CSTR);
157                         keywords.Add ("ctype", Token.CTYPE);
158                         keywords.Add ("date", Token.DATE);
159                         keywords.Add ("decimal", Token.DECIMAL);
160                         keywords.Add ("declare", Token.DECLARE);
161                         keywords.Add ("default", Token.DEFAULT);
162                         keywords.Add ("delegate", Token.DELEGATE);
163                         keywords.Add ("dim", Token.DIM);
164                         keywords.Add ("do", Token.DO);
165                         keywords.Add ("double", Token.DOUBLE);
166                         keywords.Add ("each", Token.EACH);
167                         keywords.Add ("else", Token.ELSE);
168                         keywords.Add ("elseif", Token.ELSEIF);
169                         keywords.Add ("end", Token.END);
170                         keywords.Add ("enum", Token.ENUM);
171                         keywords.Add ("erase", Token.ERASE);
172                         keywords.Add ("error", Token.ERROR);
173                         keywords.Add ("event", Token.EVENT);
174                         keywords.Add ("exit", Token.EXIT);
175                         keywords.Add ("explicit", Token.EXPLICIT);
176                         keywords.Add ("false", Token.FALSE);
177                         keywords.Add ("finally", Token.FINALLY);
178                         keywords.Add ("for", Token.FOR);
179                         keywords.Add ("friend", Token.FRIEND);
180                         keywords.Add ("function", Token.FUNCTION);
181                         keywords.Add ("get", Token.GET);
182                         //keywords.Add ("gettype", Token.GETTYPE);
183                         keywords.Add ("goto", Token.GOTO);
184                         keywords.Add ("handles", Token.HANDLES);
185                         keywords.Add ("if", Token.IF);
186                         keywords.Add ("implements", Token.IMPLEMENTS);
187                         keywords.Add ("imports", Token.IMPORTS);
188                         keywords.Add ("in", Token.IN);
189                         keywords.Add ("inherits", Token.INHERITS);
190                         keywords.Add ("integer", Token.INTEGER);
191                         keywords.Add ("interface", Token.INTERFACE);
192                         keywords.Add ("is", Token.IS);
193                         keywords.Add ("let ", Token.LET );
194                         keywords.Add ("lib ", Token.LIB );
195                         keywords.Add ("like ", Token.LIKE );
196                         keywords.Add ("long", Token.LONG);
197                         keywords.Add ("loop", Token.LOOP);
198                         keywords.Add ("me", Token.ME);
199                         keywords.Add ("mod", Token.MOD);
200                         keywords.Add ("module", Token.MODULE);
201                         keywords.Add ("mustinherit", Token.MUSTINHERIT);
202                         keywords.Add ("mustoverride", Token.MUSTOVERRIDE);
203                         keywords.Add ("mybase", Token.MYBASE);
204                         keywords.Add ("myclass", Token.MYCLASS);
205                         keywords.Add ("namespace", Token.NAMESPACE);
206                         keywords.Add ("new", Token.NEW);
207                         keywords.Add ("next", Token.NEXT);
208                         keywords.Add ("not", Token.NOT);
209                         keywords.Add ("nothing", Token.NOTHING);
210                         keywords.Add ("notinheritable", Token.NOTINHERITABLE);
211                         keywords.Add ("notoverridable", Token.NOTOVERRIDABLE);
212                         keywords.Add ("object", Token.OBJECT);
213                         keywords.Add ("off", Token.OFF);
214                         keywords.Add ("on", Token.ON);
215                         keywords.Add ("option", Token.OPTION);
216                         keywords.Add ("optional", Token.OPTIONAL);
217                         keywords.Add ("or", Token.OR);
218                         keywords.Add ("orelse", Token.ORELSE);
219                         keywords.Add ("overloads", Token.OVERLOADS);
220                         keywords.Add ("overridable", Token.OVERRIDABLE);
221                         keywords.Add ("overrides", Token.OVERRIDES);
222                         keywords.Add ("paramarray", Token.PARAM_ARRAY);
223                         keywords.Add ("preserve", Token.PRESERVE);
224                         keywords.Add ("private", Token.PRIVATE);
225                         keywords.Add ("property", Token.PROPERTY);
226                         keywords.Add ("protected", Token.PROTECTED);
227                         keywords.Add ("public", Token.PUBLIC);
228                         keywords.Add ("raiseevent", Token.RAISEEVENT);
229                         keywords.Add ("readonly", Token.READONLY);
230                         keywords.Add ("redim", Token.REDIM);
231                         keywords.Add ("rem", Token.REM);
232                         keywords.Add ("removehandler", Token.REMOVEHANDLER);
233                         keywords.Add ("resume", Token.RESUME);
234                         keywords.Add ("return", Token.RETURN);
235                         keywords.Add ("select", Token.SELECT);
236                         keywords.Add ("set", Token.SET);
237                         keywords.Add ("shadows", Token.SHADOWS);
238                         keywords.Add ("shared", Token.SHARED);
239                         keywords.Add ("short", Token.SHORT);
240                         keywords.Add ("single", Token.SINGLE);
241                         keywords.Add ("sizeof", Token.SIZEOF);
242                         keywords.Add ("static", Token.STATIC);
243                         keywords.Add ("step", Token.STEP);
244                         keywords.Add ("stop", Token.STOP);
245                         keywords.Add ("strict", Token.STRICT);
246                         keywords.Add ("string", Token.STRING);
247                         keywords.Add ("structure", Token.STRUCTURE);
248                         keywords.Add ("sub", Token.SUB);
249                         keywords.Add ("synclock", Token.SYNCLOCK);
250                         keywords.Add ("text", Token.TEXT);
251                         keywords.Add ("then", Token.THEN);
252                         keywords.Add ("throw", Token.THROW);
253                         keywords.Add ("to", Token.TO);
254                         keywords.Add ("true", Token.TRUE);
255                         keywords.Add ("try", Token.TRY);
256                         keywords.Add ("typeof", Token.TYPEOF);
257                         keywords.Add ("unicode", Token.UNICODE);
258                         keywords.Add ("until", Token.UNTIL);
259                         keywords.Add ("variant", Token.VARIANT);
260                         keywords.Add ("when", Token.WHEN);
261                         keywords.Add ("while", Token.WHILE);
262                         keywords.Add ("with", Token.WITH);
263                         keywords.Add ("withevents", Token.WITHEVENTS);
264                         keywords.Add ("writeonly", Token.WRITEONLY);
265                         keywords.Add ("xor", Token.XOR);
266
267                         if (Parser.UseExtendedSyntax){
268                                 keywords.Add ("yield", Token.YIELD);
269                         }
270
271                 }
272
273                 //
274                 // Class initializer
275                 // 
276                 static Tokenizer ()
277                 {
278                         initTokens ();
279                         csharp_format_info = new NumberFormatInfo ();
280                         csharp_format_info.CurrencyDecimalSeparator = ".";
281                         styles = NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint;
282                 }
283
284                 bool is_keyword (string name)
285                 {
286                         bool res;
287
288                         res = keywords.Contains(name.ToLower());
289                         if ((name == "get" || name == "set") && handle_get_set == false)
290                                 return false;
291                         return res;
292                 }
293
294                 int getKeyword (string name)
295                 {
296                         return (int) (keywords [name.ToLower()]);
297                 }
298                 
299                 public Location Location {
300                         get {
301                                 return new Location (ref_line, col);
302                         }
303                 }
304                 
305                 void define (string def)
306                 {
307                         if (!RootContext.AllDefines.Contains(def)){
308                                 RootContext.AllDefines [def] = true;
309                         }
310                         if (defines.Contains (def))
311                                 return;
312                         defines [def] = true;
313                 }
314
315                 public bool PropertyParsing {
316                         get {
317                                 return handle_get_set;
318                         }
319
320                         set {
321                                 handle_get_set = value;
322                         }
323                 }
324                                 
325                 bool is_identifier_start_character (char c)
326                 {
327                         return Char.IsLetter (c) || c == '_' ;
328                 }
329
330                 bool is_identifier_part_character (char c)
331                 {
332                         return (Char.IsLetter (c) || Char.IsDigit (c) || c == '_');
333                 }
334
335                 int is_punct (char c, ref bool doread)
336                 {
337                         int d;
338                         int t;
339
340                         doread = false;
341                         
342                         error_details = c.ToString();
343                         
344                         d = peekChar ();
345                         
346                         switch (c){
347                         case '[':
348                                 return Token.OPEN_BRACKET;
349                         case ']':
350                                 return Token.CLOSE_BRACKET;
351                         case '{':
352                                 return Token.OPEN_BRACE;
353                         case '}':
354                                 return Token.CLOSE_BRACE;                               
355                         case '(':
356                                 return Token.OPEN_PARENS;
357                         case ')':
358                                 return Token.CLOSE_PARENS;
359                         case ',':
360                                 return Token.COMMA;
361                         case '?':
362                                 return Token.INTERR;
363                         case '!':
364                                 if (is_identifier_start_character((char)d) || cant_have_a_type_character)
365                                         return Token.EXCLAMATION;
366                                 return Token.SINGLETYPECHAR;
367                         case '$':
368                                 if (cant_have_a_type_character)
369                                         return Token.ERROR;
370                                 return Token.DOLAR_SIGN;
371                         case '@':
372                                 if (cant_have_a_type_character)
373                                         return Token.ERROR;
374                                 return Token.AT_SIGN;
375                         case '%':
376                                 if (cant_have_a_type_character)
377                                         return Token.ERROR;
378                                 return Token.PERCENT;
379                         case '#':
380                                 if (!tokens_seen)
381                                 {
382                                         workout_preprocessing_directive();
383                                         return Token.NONE;
384                                 } 
385                                 if (cant_have_a_type_character) 
386                                         return ExtractDateTimeLiteral();
387                                 return Token.NUMBER_SIGN;
388                         case '&':
389                                 if (!cant_have_a_type_character)
390                                         return Token.LONGTYPECHAR;
391                                 t = handle_integer_literal_in_other_bases(d);
392                                 if (t == Token.NONE) {
393                                         if (d == '=') {
394                                                 doread = true;
395                                                 t = Token.OP_CONCAT_ASSIGN;
396                                         } else 
397                                                 t = Token.OP_CONCAT;
398                                 }
399                                 return t;                       
400                         }
401
402                         if (c == '+'){
403                                 if (d == '+')
404                                         t = Token.OP_INC;
405                                 else if (d == '=')
406                                         t = Token.OP_ADD_ASSIGN;
407                                 else
408                                         return Token.PLUS;
409                                 doread = true;
410                                 return t;
411                         }
412                         if (c == '-'){
413                                 if (d == '=')
414                                         t = Token.OP_SUB_ASSIGN;
415                                 else
416                                         return Token.MINUS;
417                                 doread = true;
418                                 return t;
419                         }
420
421                         if (c == '='){
422                                 return Token.ASSIGN;
423                         }
424
425                         if (c == '*'){
426                                 if (d == '='){
427                                         doread = true;
428                                         return Token.OP_MULT_ASSIGN;
429                                 }
430                                 return Token.STAR;
431                         }
432
433                         if (c == '/'){
434                                 if (d == '='){
435                                         doread = true;
436                                         return Token.OP_DIV_ASSIGN;
437                                 }
438                                 return Token.DIV;
439                         }
440
441                         if (c == '\\'){
442                                 if (d == '='){
443                                         doread = true;
444                                         return Token.OP_IDIV_ASSIGN;
445                                 }
446                                 return Token.OP_IDIV;
447                         }
448
449                         if (c == '^'){
450                                 if (d == '='){
451                                         doread = true;
452                                         return Token.OP_EXP_ASSIGN;
453                                 }
454                                 return Token.OP_EXP;
455                         }
456
457                         if (c == '<'){
458                                 if (d == '>')
459                                 {
460                                         doread = true;
461                                         return Token.OP_NE;
462                                 }
463                                 if (d == '='){
464                                         doread = true;
465                                         return Token.OP_LE;
466                                 }
467                                 if (d == '<')
468                                 {
469                                         doread = true;
470                                         return Token.OP_SHIFT_LEFT;
471                                 }
472                                 return Token.OP_LT;
473                         }
474
475                         if (c == '>'){
476                                 if (d == '='){
477                                         doread = true;
478                                         return Token.OP_GE;
479                                 }
480                                 if (d == '>')
481                                 {
482                                         doread = true;
483                                         return Token.OP_SHIFT_RIGHT;
484                                 }
485                                 return Token.OP_GT;
486                         }
487                         
488                         if (c == ':'){
489                                 if (d == '='){
490                                         doread = true;
491                                         return Token.ATTR_ASSIGN;
492                                 }
493                                 return Token.COLON;
494                         }                       
495                         
496                         return Token.ERROR;
497                 }
498
499                 bool decimal_digits (int c)
500                 {
501                         int d;
502                         bool seen_digits = false;
503                         
504                         if (c != -1)
505                                 number.Append ((char) c);
506                         
507                         while ((d = peekChar ()) != -1){
508                                 if (Char.IsDigit ((char)d)){
509                                         number.Append ((char) d);
510                                         getChar ();
511                                         seen_digits = true;
512                                 } else
513                                         break;
514                         }
515                         return seen_digits;
516                 }
517
518                 
519                 int real_type_suffix (int c)
520                 {
521                         int t;
522                         
523                         switch (c){
524                         case 'F': case 'f':
525                                 t =  Token.LITERAL_SINGLE;
526                                 break;
527                         case 'R': case 'r':
528                                 t = Token.LITERAL_DOUBLE;
529                                 break;
530                         case 'D': case 'd':
531                                  t= Token.LITERAL_DECIMAL;
532                                 break;
533                         default:
534                                 return Token.NONE;
535                         }
536                         getChar ();
537                         return t;
538                 }
539
540                 int integer_type_suffix (int c)
541                 {
542                         int t;
543                         
544                         try {
545                         
546                                 switch (c){
547                                 case 'S': case 's':
548                                         t =  Token.LITERAL_INTEGER; // SHORT ?
549                                         val = ((IConvertible)val).ToInt16(null);
550                                         break;
551                                 case 'I': case 'i':
552                                         t = Token.LITERAL_INTEGER;
553                                         val = ((IConvertible)val).ToInt32(null);
554                                         break;
555                                 case 'L': case 'l':
556                                          t= Token.LITERAL_INTEGER; // LONG ?
557                                          val = ((IConvertible)val).ToInt64(null);
558                                         break;
559                                 default:
560                                         if ((long)val <= System.Int32.MaxValue &&
561                                                 (long)val >= System.Int32.MinValue) {
562                                                 val = ((IConvertible)val).ToInt32(null);
563                                                 return Token.LITERAL_INTEGER;
564                                         } else {
565                                                 val = ((IConvertible)val).ToInt64(null);
566                                                 return Token.LITERAL_INTEGER; // LONG ?
567                                         }
568                                 }
569                                 getChar ();
570                                 return t;
571                         } catch (Exception e) {
572                                 val = e.ToString();
573                                 return Token.ERROR;
574                         }
575                 }
576                 
577                 int adjust_real (int t)
578                 {
579                         string s = number.ToString ();
580
581                         switch (t){
582                         case Token.LITERAL_DECIMAL:
583                                 val = new System.Decimal ();
584                                 val = System.Decimal.Parse (
585                                         s, styles, csharp_format_info);
586                                 break;
587                         case Token.LITERAL_DOUBLE:
588                                 val = new System.Double ();
589                                 val = System.Double.Parse (
590                                         s, styles, csharp_format_info);
591                                 break;
592                         case Token.LITERAL_SINGLE:
593                                 val = new System.Double ();
594                                 val = (float) System.Double.Parse (
595                                         s, styles, csharp_format_info);
596                                 break;
597
598                         case Token.NONE:
599                                 val = new System.Double ();
600                                 val = System.Double.Parse (
601                                         s, styles, csharp_format_info);
602                                 t = Token.LITERAL_DOUBLE;
603                                 break;
604                         }
605                         return t;
606                 }
607
608                 long hex_digits ()
609                 {
610                         StringBuilder hexNumber = new StringBuilder ();
611                         
612                         int d;
613
614                         while ((d = peekChar ()) != -1){
615                                 char e = Char.ToUpper ((char) d);
616                                 
617                                 if (Char.IsDigit (e) || (e >= 'A' && e <= 'F')){
618                                         hexNumber.Append (e);
619                                         getChar ();
620                                 } else
621                                         break;
622                         }
623                         return System.Int64.Parse (hexNumber.ToString(), NumberStyles.HexNumber);
624                 }
625
626                 long octal_digits ()
627                 {
628                         long valueToReturn = 0;
629                         
630                         int d;
631
632                         while ((d = peekChar ()) != -1){
633                                 char e = (char)d;                       
634                                 if (Char.IsDigit (e) && (e < '8')){
635                                         valueToReturn *= 8;
636                                         valueToReturn += (d - (int)'0');
637                                         getChar ();
638                                 } else
639                                         break;
640                         }
641                         
642                         return valueToReturn;
643                 }
644
645                 int handle_integer_literal_in_other_bases(int peek)
646                 {
647                         if (peek == 'h' || peek == 'H'){
648                                 getChar ();
649                                 val = hex_digits ();
650                                 return integer_type_suffix (peekChar ());
651                         }
652                         
653                         if (peek == 'o' || peek == 'O'){
654                                 getChar ();
655                                 val = octal_digits ();
656                                 return integer_type_suffix (peekChar ());
657                         }
658                         
659                         return Token.NONE;
660                 }
661                 
662                 //
663                 // Invoked if we know we have .digits or digits
664                 //
665                 int is_number (int c)
666                 {
667                         bool is_real = false;
668                         number = new StringBuilder ();
669                         int type;
670
671                         number.Length = 0;
672
673                         if (Char.IsDigit ((char)c)){
674                                 decimal_digits (c);
675                                 c = peekChar ();
676                         }
677
678                         //
679                         // We need to handle the case of
680                         // "1.1" vs "1.ToString()" (LITERAL_SINGLE vs NUMBER DOT IDENTIFIER)
681                         //
682                         if (c == '.'){
683                                 if (decimal_digits (getChar())){
684                                         is_real = true;
685                                         c = peekChar ();
686                                 } else {
687                                         putback ('.');
688                                         number.Length -= 1;
689                                         val = System.Int64.Parse(number.ToString());
690                                         return integer_type_suffix('.');
691                                 }
692                         }
693                         
694                         if (c == 'e' || c == 'E'){
695                                 is_real = true;
696                                 number.Append ("e");
697                                 getChar ();
698                                 
699                                 c = peekChar ();
700                                 if (c == '+'){
701                                         number.Append ((char) c);
702                                         getChar ();
703                                         c = peekChar ();
704                                 } else if (c == '-'){
705                                         number.Append ((char) c);
706                                         getChar ();
707                                         c = peekChar ();
708                                 }
709                                 decimal_digits (-1);
710                                 c = peekChar ();
711                         }
712
713                         type = real_type_suffix (c);
714                         if (type == Token.NONE && !is_real){
715                                 val = System.Int64.Parse(number.ToString());
716                                 return integer_type_suffix(c);
717                         }
718                         
719                         return adjust_real (type);
720                 }
721                         
722                 int getChar ()
723                 {
724                         if (putback_char != -1){
725                                 int x = putback_char;
726                                 putback_char = -1;
727
728                                 return x;
729                         }
730                         return reader.Read ();
731                 }
732
733                 int peekChar ()
734                 {
735                         if (putback_char != -1)
736                                 return putback_char;
737                         return reader.Peek ();
738                 }
739
740                 void putback (int c)
741                 {
742                         if (putback_char != -1)
743                                 throw new Exception ("This should not happen putback on putback");
744                         putback_char = c;
745                 }
746
747                 public bool advance ()
748                 {
749                         return current_token != Token.EOF ;
750                 }
751
752                 public Object Value {
753                         get {
754                                 return val;
755                         }
756                 }
757
758                 public Object value ()
759                 {
760                         return val;
761                 }
762
763                 private bool IsEOL(int currentChar)
764                 {
765                         if (currentChar ==  0x0D)
766                         {
767                                 if (peekChar() ==  0x0A) // if it is a CR-LF pair consume LF also
768                                         getChar();
769
770                                 return true;
771                         }
772                         return (currentChar ==  -1 || currentChar ==  0x0A || currentChar ==  0x2028 || currentChar ==  0x2029);
773                 }
774
775                 private int DropComments()              
776                 {
777                         int d;
778                         while (!IsEOL(d = getChar ()))
779                                 col++;
780                         line++;
781                         ref_line++;
782                         col = 0;
783
784                         return Token.EOL;
785                 }       
786                         
787                 public int token ()
788                 {
789                         int lastToken = current_token;
790                         do
791                         {
792                                 current_token = xtoken ();
793                                 if (current_token == 0) 
794                                         return Token.EOF;
795                                 if (current_token == Token.REM)
796                                         current_token = DropComments();
797                         } while (lastToken == Token.EOL && current_token == Token.EOL);
798
799                         return current_token;
800                 }
801
802                 private string GetIdentifier()
803                 {
804                         int c = getChar();
805                         if (is_identifier_start_character ((char) c))
806                                 return GetIdentifier(c);
807                         else
808                                 return null;
809                 }
810
811                 private string GetIdentifier(int c)
812                 {
813                         StringBuilder id = new StringBuilder ();
814
815                         id.Append ((char) c);
816                                 
817                         while ((c = peekChar ()) != -1) 
818                         {
819                                 if (is_identifier_part_character ((char) c))
820                                 {
821                                         id.Append ((char)getChar ());
822                                         col++;
823                                 } 
824                                 else 
825                                         break;
826                         }
827                         
828                         cant_have_a_type_character = false;
829                         
830                         return id.ToString ();
831                 }
832
833                 private bool is_doublequote(int currentChar)
834                 {
835                         return (currentChar == '"' || 
836                                         currentChar == 0x201C || // unicode left double-quote character
837                                         currentChar == 0x201D);  // unicode right double-quote character
838                 }
839                 
840                 private bool is_whitespace(int c)
841                 {
842                         return (c == ' ' || c == '\t' || c == '\v' || c == '\r' || c == 0xa0);
843                 }
844                 
845                 private bool tokens_seen = false;
846
847                 public int xtoken ()
848                 {
849                         int t;
850                         bool doread = false;
851                         int c;
852
853                         val = null;
854                         for (;(c = getChar ()) != -1; col++) {
855                         
856                                 // Handle line continuation character
857                                 if (c == '_') 
858                                 {
859                                         int d = peekChar();
860                                         if (!is_identifier_part_character((char)d)) {
861                                                 while ((c = getChar ()) != -1 && !IsEOL(c)) {}
862                                                 c = getChar ();                 
863                                         }               
864                                 }
865
866                                 // white space
867                                 if (is_whitespace(c)) {
868                                         // expand tabs for location
869                                         if (c == '\t')
870                                                 col = (((col + ExpandedTabsSize) / ExpandedTabsSize) * ExpandedTabsSize) - 1;
871                                         cant_have_a_type_character = true;
872                                         continue;
873                                 }
874                                 
875                                 // Handle line comments.
876                                 if (c == '\'')
877                                         return Token.REM;                                       
878                                 
879                                 // Handle EOL.
880                                 if (IsEOL(c))
881                                 {
882                                         cant_have_a_type_character = true;
883                                         line++;
884                                         ref_line++;
885                                         col = 0;
886                                         tokens_seen = false;
887                                         if (current_token == Token.EOL) // if last token was also EOL keep skipping
888                                                 continue;
889                                         return Token.EOL;
890                                 }
891                                 
892                                 // Handle escaped identifiers
893                                 if (c == '[')
894                                 {
895                                         if ((val = GetIdentifier()) == null)
896                                                 break;
897                                         if ((c = getChar()) != ']')
898                                                 break;
899                                         tokens_seen = true;
900                                         return Token.IDENTIFIER;
901                                 }
902
903                                 // Handle unescaped identifiers
904                                 if (is_identifier_start_character ((char) c))
905                                 {
906                                         string id;
907                                         if ((id = GetIdentifier(c)) == null)
908                                                 break;
909                                         val = id;
910                                         tokens_seen = true;
911                                         if (is_keyword(id) && (current_token != Token.DOT))
912                                                 return getKeyword(id);
913                                         return Token.IDENTIFIER;
914                                 }
915
916                                 // Treat string literals
917                                 if (is_doublequote(c)) {
918                                         cant_have_a_type_character = true;
919                                         return ExtractStringOrCharLiteral(c);
920                                 }
921                         
922                                 // handle numeric literals
923                                 if (c == '.')
924                                 {
925                                         cant_have_a_type_character = true;
926                                         tokens_seen = true;
927                                         if (Char.IsDigit ((char) peekChar ()))
928                                                 return is_number (c);
929                                         return Token.DOT;
930                                 }
931                                 
932                                 if (Char.IsDigit ((char) c))
933                                 {
934                                         cant_have_a_type_character = true;
935                                         tokens_seen = true;
936                                         return is_number (c);
937                                 }
938
939                                 if ((t = is_punct ((char)c, ref doread)) != Token.ERROR) {
940                                         cant_have_a_type_character = true;
941
942                                         if (t == Token.NONE)
943                                                 continue;
944                                                 
945                                         if (doread){
946                                                 getChar ();
947                                                 col++;
948                                         }
949                                         tokens_seen = true;
950                                         return t;
951                                 }
952                                 
953                                 error_details = ((char)c).ToString ();
954                                 return Token.ERROR;
955                         }
956
957                         if (current_token != Token.EOL) // if last token wasn't EOL send it before EOF
958                                 return Token.EOL;
959                         
960                         return Token.EOF;
961                 }
962
963                 private int ExtractDateTimeLiteral()
964                 {
965                         int c;
966                         
967                         StringBuilder sb = new StringBuilder();
968                         for (;(c = getChar ()) != -1; col++)
969                         {
970                                 if (c == '#') {
971                                         val = ParseDateLiteral(sb);
972                                         return Token.LITERAL_DATE;
973                                 }
974                                 if (IsEOL(c)) {
975                                         col = 0;
976                                         line++;
977                                         ref_line++;
978                                         break;
979                                 } 
980                                 sb.Append((char)c);
981                         }
982                         return Token.ERROR;
983                 }
984                 
985                 private int ExtractStringOrCharLiteral(int c)
986                 {
987                         StringBuilder s = new StringBuilder ();
988
989                         tokens_seen = true;
990
991                         while ((c = getChar ()) != -1){
992                                 if (is_doublequote(c)){
993                                         if (is_doublequote(peekChar()))
994                                                 getChar();
995                                         else {
996                                                 //handle Char Literals
997                                                 if (peekChar() == 'C' || peekChar() == 'c') {
998                                                         getChar();
999                                                         if (s.Length == 1) {
1000                                                                 val = s[0];
1001                                                                 return Token.LITERAL_CHARACTER;
1002                                                         } else {
1003                                                                 val = "Incorrect length for a character literal";
1004                                                                 return Token.ERROR;
1005                                                         }                                                       
1006                                                 } else {
1007                                                         val = s.ToString ();
1008                                                         return Token.LITERAL_STRING;
1009                                                 }
1010                                         }
1011                                 }
1012
1013                                 if (IsEOL(c))
1014                                         return Token.ERROR;
1015                                                         
1016                                 s.Append ((char) c);
1017                         }
1018                                         
1019                         return Token.ERROR;
1020                 }
1021
1022                 private void workout_preprocessing_directive()
1023                 {
1024                         int c;
1025                         bool cont = true;
1026                                                 
1027                 start_again:
1028                                                 
1029                         cont = handle_preprocessing_directive (cont);
1030         
1031                         if (cont) {
1032                                 col = 0;
1033                                 return;
1034                         }
1035                         col = 1;
1036         
1037                         bool skipping = false;
1038                         for (;(c = getChar ()) != -1; col++) {
1039                                 if (is_whitespace(c))
1040                                         continue;
1041                                 if (IsEOL(c)) {
1042                                         col = 0;
1043                                         line++;
1044                                         ref_line++;
1045                                         skipping = false;
1046                                         continue;
1047                                 } 
1048                                 if (c != '#') {
1049                                         skipping = true;
1050                                         continue;
1051                                 }       
1052                                 if (c == '#' && !skipping)
1053                                         goto start_again;
1054                         }
1055                         tokens_seen = false;
1056                         if (c == -1)
1057                                 Report.Error (1027, Location, "#endif/#endregion expected");
1058                 }
1059                 
1060                 static IFormatProvider enUSculture = new CultureInfo("en-US", true);
1061
1062                 private DateTime ParseDateLiteral(StringBuilder value)
1063                 {
1064                         try
1065                         {
1066                                 return DateTime.Parse(value.ToString(),
1067                                                   enUSculture,
1068                                                   DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces);
1069                         }
1070                         catch (FormatException)
1071                         {
1072                                 Report.Error (1, Location, "Invalid date literal");             //TODO: What is the correct error number and message?
1073                         }
1074                         catch (Exception)
1075                         {
1076                                 Report.Error (1, Location, "Error parsing date literal");       //TODO: What is the correct error number and message?
1077                         }
1078                         return new DateTime();
1079                 }
1080  
1081
1082                 public void cleanup ()
1083                 {
1084 /* borrowed from mcs - have to work it to have preprocessing in mbas
1085
1086                         if (ifstack != null && ifstack.Count >= 1) {
1087                                 int state = (int) ifstack.Pop ();
1088                                 if ((state & REGION) != 0)
1089                                         Report.Error (1038, "#endregion directive expected");
1090                                 else 
1091                                         Report.Error (1027, "#endif directive expected");
1092                         }
1093 */                              
1094                 }
1095
1096                 public Tokenizer (System.IO.TextReader input, string fname, ArrayList defines)
1097                 {
1098                         this.ref_name = fname;
1099                         reader = input;
1100                         putback_char = -1;
1101                         
1102                         Location.Push (fname);
1103                 }
1104
1105                 static StringBuilder static_cmd_arg = new StringBuilder ();
1106                 
1107                 void get_cmd_arg (out string cmd, out string arg)
1108                 {
1109                         int c;
1110                         
1111                         tokens_seen = false;
1112                         arg = "";
1113                         static_cmd_arg.Length = 0;
1114                                 
1115                         while ((c = getChar ()) != -1 && (c != '\n') && (c != ' ') && (c != '\t') && (c != '\r')){
1116                                 static_cmd_arg.Append ((char) c);
1117                         }
1118
1119                         cmd = static_cmd_arg.ToString().ToLower();
1120
1121                         if (c == '\n'){
1122                                 line++;
1123                                 ref_line++;
1124                                 return;
1125                         } else if (c == '\r')
1126                                 col = 0;
1127
1128                         // skip over white space
1129                         while ((c = getChar ()) != -1 && (c != '\n') && ((c == '\r') || (c == ' ') || (c == '\t')))
1130                                 ;
1131
1132                         if (c == '\n'){
1133                                 line++;
1134                                 ref_line++;
1135                                 return;
1136                         } else if (c == '\r'){
1137                                 col = 0;
1138                                 return;
1139                         }
1140                         
1141                         static_cmd_arg.Length = 0;
1142                         static_cmd_arg.Append ((char) c);
1143                         
1144                         while ((c = getChar ()) != -1 && (c != '\n') && (c != '\r')){
1145                                 static_cmd_arg.Append ((char) c);
1146                         }
1147
1148                         if (c == '\n'){
1149                                 line++;
1150                                 ref_line++;
1151                         } else if (c == '\r')
1152                                 col = 0;
1153                         arg = static_cmd_arg.ToString ().Trim ();
1154                         
1155                         if (cmd == "end" && arg.ToLower() == "region") {
1156                                 cmd = "end region";
1157                                 arg = "";       
1158                         }
1159                         if (cmd == "end" && arg.ToLower() == "if") {
1160                                 cmd = "end if";
1161                                 arg = "";       
1162                         }                       
1163                                 
1164                 }
1165
1166                 //
1167                 // Handles the #line directive
1168                 //
1169                 bool PreProcessLine (string arg)
1170                 {
1171                         if (arg == "")
1172                                 return false;
1173
1174                         if (arg == "default"){
1175                                 ref_line = line;
1176                                 ref_name = file_name;
1177                                 Location.Push (ref_name);
1178                                 return true;
1179                         }
1180                         
1181                         try {
1182                                 int pos;
1183
1184                                 if ((pos = arg.IndexOf (' ')) != -1 && pos != 0){
1185                                         ref_line = System.Int32.Parse (arg.Substring (0, pos));
1186                                         pos++;
1187                                         
1188                                         char [] quotes = { '\"' };
1189                                         
1190                                         string name = arg.Substring (pos). Trim (quotes);
1191                                         ref_name = name; // TODO: Synchronize with mcs: Location.LookupFile (name);
1192                                         Location.Push (ref_name);
1193                                 } else {
1194                                         ref_line = System.Int32.Parse (arg);
1195                                 }
1196                         } catch {
1197                                 return false;
1198                         }
1199                         
1200                         return true;
1201                 }
1202
1203                 //
1204                 // Handles #define and #undef
1205                 //
1206                 void PreProcessDefinition (bool is_define, string arg)
1207                 {
1208                         if (arg == "" || arg == "true" || arg == "false"){
1209                                 Report.Error (1001, Location, "Missing identifer to pre-processor directive");
1210                                 return;
1211                         }
1212
1213                         char[] whitespace = { ' ', '\t' };
1214                         if (arg.IndexOfAny (whitespace) != -1){
1215                                 Report.Error (1025, Location, "Single-line comment or end-of-line expected");
1216                                 return;
1217                         }
1218
1219                         foreach (char c in arg){
1220                                 if (!Char.IsLetter (c) && (c != '_')){
1221                                         Report.Error (1001, Location, "Identifier expected");
1222                                         return;
1223                                 }
1224                         }
1225
1226                         if (is_define){
1227                                 if (defines == null)
1228                                         defines = new Hashtable ();
1229                                 define (arg);
1230                         } else {
1231                                 if (defines == null)
1232                                         return;
1233                                 if (defines.Contains (arg))
1234                                         defines.Remove (arg);
1235                         }
1236                 }
1237
1238                 bool eval_val (string s)
1239                 {
1240                         if (s == "true")
1241                                 return true;
1242                         if (s == "false")
1243                                 return false;
1244                         
1245                         if (defines == null)
1246                                 return false;
1247                         if (defines.Contains (s))
1248                                 return true;
1249
1250                         return false;
1251                 }
1252
1253                 bool pp_primary (ref string s)
1254                 {
1255                         s = s.Trim ();
1256                         int len = s.Length;
1257
1258                         if (len > 0){
1259                                 char c = s [0];
1260                                 
1261                                 if (c == '('){
1262                                         s = s.Substring (1);
1263                                         bool val = pp_expr (ref s);
1264                                         if (s.Length > 0 && s [0] == ')'){
1265                                                 s = s.Substring (1);
1266                                                 return val;
1267                                         }
1268                                         Error_InvalidDirective ();
1269                                         return false;
1270                                 }
1271                                 
1272                                 if (is_identifier_start_character (c)){
1273                                         int j = 1;
1274
1275                                         while (j < len){
1276                                                 c = s [j];
1277                                                 
1278                                                 if (is_identifier_part_character (c)){
1279                                                         j++;
1280                                                         continue;
1281                                                 }
1282                                                 bool v = eval_val (s.Substring (0, j));
1283                                                 s = s.Substring (j);
1284                                                 return v;
1285                                         }
1286                                         bool vv = eval_val (s);
1287                                         s = "";
1288                                         return vv;
1289                                 }
1290                         }
1291                         Error_InvalidDirective ();
1292                         return false;
1293                 }
1294                 
1295                 bool pp_unary (ref string s)
1296                 {
1297                         s = s.Trim ();
1298                         int len = s.Length;
1299
1300                         if (len > 0){
1301                                 if (s [0] == '!'){
1302                                         if (len > 1 && s [1] == '='){
1303                                                 Error_InvalidDirective ();
1304                                                 return false;
1305                                         }
1306                                         s = s.Substring (1);
1307                                         return ! pp_primary (ref s);
1308                                 } else
1309                                         return pp_primary (ref s);
1310                         } else {
1311                                 Error_InvalidDirective ();
1312                                 return false;
1313                         }
1314                 }
1315                 
1316                 bool pp_eq (ref string s)
1317                 {
1318                         bool va = pp_unary (ref s);
1319
1320                         s = s.Trim ();
1321                         int len = s.Length;
1322                         if (len > 0){
1323                                 if (s [0] == '='){
1324                                         if (len > 2 && s [1] == '='){
1325                                                 s = s.Substring (2);
1326                                                 return va == pp_unary (ref s);
1327                                         } else {
1328                                                 Error_InvalidDirective ();
1329                                                 return false;
1330                                         }
1331                                 } else if (s [0] == '!' && len > 1 && s [1] == '='){
1332                                         s = s.Substring (2);
1333
1334                                         return va != pp_unary (ref s);
1335
1336                                 } 
1337                         }
1338
1339                         return va;
1340                                 
1341                 }
1342                 
1343                 bool pp_and (ref string s)
1344                 {
1345                         bool va = pp_eq (ref s);
1346
1347                         s = s.Trim ();
1348                         int len = s.Length;
1349                         if (len > 0){
1350                                 if (s [0] == '&'){
1351                                         if (len > 2 && s [1] == '&'){
1352                                                 s = s.Substring (2);
1353                                                 return (va & pp_eq (ref s));
1354                                         } else {
1355                                                 Error_InvalidDirective ();
1356                                                 return false;
1357                                         }
1358                                 } 
1359                         }
1360                         return va;
1361                 }
1362                 
1363                 //
1364                 // Evaluates an expression for `#if' or `#elif'
1365                 //
1366                 bool pp_expr (ref string s)
1367                 {
1368                         bool va = pp_and (ref s);
1369                         s = s.Trim ();
1370                         int len = s.Length;
1371                         if (len > 0){
1372                                 char c = s [0];
1373                                 
1374                                 if (c == '|'){
1375                                         if (len > 2 && s [1] == '|'){
1376                                                 s = s.Substring (2);
1377                                                 return va | pp_expr (ref s);
1378                                         } else {
1379                                                 Error_InvalidDirective ();
1380                                                 return false;
1381                                         }
1382                                 } 
1383                         }
1384                         
1385                         return va;
1386                 }
1387
1388                 bool eval (string s)
1389                 {
1390                         bool v = pp_expr (ref s);
1391                         s = s.Trim ();
1392                         if (s.Length != 0){
1393                                 Error_InvalidDirective ();
1394                                 return false;
1395                         }
1396
1397                         return v;
1398                 }
1399                 
1400                 void Error_InvalidDirective ()
1401                 {
1402                         Report.Error (1517, Location, "Invalid pre-processor directive");
1403                 }
1404
1405                 void Error_UnexpectedDirective (string extra)
1406                 {
1407                         Report.Error (
1408                                 1028, Location,
1409                                 "Unexpected processor directive (" + extra + ")");
1410                 }
1411
1412                 void Error_TokensSeen ()
1413                 {
1414                         Report.Error (
1415                                 1032, Location,
1416                                 "Cannot define or undefine pre-processor symbols after a token in the file");
1417                 }
1418                 
1419                 //
1420                 // if true, then the code continues processing the code
1421                 // if false, the code stays in a loop until another directive is
1422                 // reached.
1423                 //
1424                 bool handle_preprocessing_directive (bool caller_is_taking)
1425                 {
1426                         char [] blank = { ' ', '\t' };
1427                         string cmd, arg;
1428                         bool region_directive = false;
1429
1430                         get_cmd_arg (out cmd, out arg);
1431                         // Eat any trailing whitespaces and single-line comments
1432                         if (arg.IndexOf ("//") != -1)
1433                                 arg = arg.Substring (0, arg.IndexOf ("//"));
1434                         arg = arg.TrimEnd (' ', '\t');
1435
1436                         //
1437                         // The first group of pre-processing instructions is always processed
1438                         //
1439                         switch (cmd.ToLower()){
1440                         case "line":
1441                                 if (!PreProcessLine (arg))
1442                                         Report.Error (
1443                                                 1576, Location,
1444                                                 "Argument to #line directive is missing or invalid");
1445                                 return true;
1446
1447                         case "region":
1448                                 region_directive = true;
1449                                 arg = "true";
1450                                 goto case "if";
1451
1452                         case "end region":
1453                                 region_directive = true;
1454                                 goto case "end if";
1455                                 
1456                         case "if":
1457                                 if (arg == ""){
1458                                         Error_InvalidDirective ();
1459                                         return true;
1460                                 }
1461                                 bool taking = false;
1462                                 if (ifstack == null)
1463                                         ifstack = new Stack ();
1464
1465                                 if (ifstack.Count == 0){
1466                                         taking = true;
1467                                 } else {
1468                                         int state = (int) ifstack.Peek ();
1469                                         if ((state & TAKING) != 0)
1470                                                 taking = true;
1471                                 }
1472
1473                                 if (eval (arg) && taking){
1474                                         int push = TAKING | TAKEN_BEFORE | PARENT_TAKING;
1475                                         if (region_directive)
1476                                                 push |= REGION;
1477                                         ifstack.Push (push);
1478                                         return true;
1479                                 } else {
1480                                         int push = (taking ? PARENT_TAKING : 0);
1481                                         if (region_directive)
1482                                                 push |= REGION;
1483                                         ifstack.Push (push);
1484                                         return false;
1485                                 }
1486                                 
1487                         case "end if":
1488                                 if (ifstack == null || ifstack.Count == 0){
1489                                         Error_UnexpectedDirective ("no #if for this #end if");
1490                                         return true;
1491                                 } else {
1492                                         int pop = (int) ifstack.Pop ();
1493                                         
1494                                         if (region_directive && ((pop & REGION) == 0))
1495                                                 Report.Error (1027, Location, "#end if directive expected");
1496                                         else if (!region_directive && ((pop & REGION) != 0))
1497                                                 Report.Error (1038, Location, "#end region directive expected");
1498                                         
1499                                         if (ifstack.Count == 0)
1500                                                 return true;
1501                                         else {
1502                                                 int state = (int) ifstack.Peek ();
1503
1504                                                 if ((state & TAKING) != 0)
1505                                                         return true;
1506                                                 else
1507                                                         return false;
1508                                         }
1509                                 }
1510
1511                         case "elseif":
1512                                 if (ifstack == null || ifstack.Count == 0){
1513                                         Error_UnexpectedDirective ("no #if for this #elif");
1514                                         return true;
1515                                 } else {
1516                                         int state = (int) ifstack.Peek ();
1517
1518                                         if ((state & REGION) != 0) {
1519                                                 Report.Error (1038, Location, "#end region directive expected");
1520                                                 return true;
1521                                         }
1522
1523                                         if ((state & ELSE_SEEN) != 0){
1524                                                 Error_UnexpectedDirective ("#elif not valid after #else");
1525                                                 return true;
1526                                         }
1527
1528                                         if ((state & (TAKEN_BEFORE | TAKING)) != 0)
1529                                                 return false;
1530
1531                                         if (eval (arg) && ((state & PARENT_TAKING) != 0)){
1532                                                 state = (int) ifstack.Pop ();
1533                                                 ifstack.Push (state | TAKING | TAKEN_BEFORE);
1534                                                 return true;
1535                                         } else 
1536                                                 return false;
1537                                 }
1538
1539                         case "else":
1540                                 if (ifstack == null || ifstack.Count == 0){
1541                                         Report.Error (
1542                                                 1028, Location,
1543                                                 "Unexpected processor directive (no #if for this #else)");
1544                                         return true;
1545                                 } else {
1546                                         int state = (int) ifstack.Peek ();
1547
1548                                         if ((state & REGION) != 0) {
1549                                                 Report.Error (1038, Location, "#end region directive expected");
1550                                                 return true;
1551                                         }
1552
1553                                         if ((state & ELSE_SEEN) != 0){
1554                                                 Error_UnexpectedDirective ("#else within #else");
1555                                                 return true;
1556                                         }
1557
1558                                         ifstack.Pop ();
1559
1560                                         bool ret;
1561                                         if ((state & TAKEN_BEFORE) == 0){
1562                                                 ret = ((state & PARENT_TAKING) != 0);
1563                                         } else
1564                                                 ret = false;
1565                                         
1566                                         if (ret)
1567                                                 state |= TAKING;
1568                                         else
1569                                                 state &= ~TAKING;
1570                                         
1571                                         ifstack.Push (state | ELSE_SEEN);
1572                                         
1573                                         return ret;
1574                                 }
1575                         }
1576
1577                         //
1578                         // These are only processed if we are in a `taking' block
1579                         //
1580                         if (!caller_is_taking)
1581                                 return false;
1582                                         
1583                         switch (cmd.ToLower()){
1584                         case "define":
1585                                 /* if (any_token_seen){
1586                                         Error_TokensSeen ();
1587                                         return true;
1588                                 } */
1589                                 PreProcessDefinition (true, arg);
1590                                 return true;
1591
1592                         case "undef":
1593                                 /* if (any_token_seen){
1594                                         Error_TokensSeen ();
1595                                         return true;
1596                                 } */
1597                                 PreProcessDefinition (false, arg);
1598                                 return true;
1599
1600                         case "error":
1601                                 Report.Error (1029, Location, "#error: '" + arg + "'");
1602                                 return true;
1603
1604                         case "warning":
1605                                 Report.Warning (1030, Location, "#warning: '" + arg + "'");
1606                                 return true;
1607                         }
1608
1609                         Report.Error (1024, Location, "Preprocessor directive expected (got: " + cmd + ")");
1610                         return true;
1611                 }
1612
1613         }
1614 }