This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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                 public Tokenizer (System.IO.TextReader input, string fname, ArrayList defines)
285                 {
286                         this.ref_name = fname;
287                         reader = input;
288                         putback_char = -1;
289                         
290                         Location.Push (fname);
291                 }
292
293                 bool is_keyword (string name)
294                 {
295                         bool res;
296                         name = name.ToLower();
297
298                         res = keywords.Contains(name);
299                         if ((name == "GET" || name == "SET") && handle_get_set == false)
300                                 return false;
301                         return res;
302                 }
303
304                 int getKeyword (string name)
305                 {
306                         return (int) (keywords [name.ToLower()]);
307                 }
308                 
309                 public Location Location {
310                         get {
311                                 return new Location (ref_line, col);
312                         }
313                 }
314                 
315                 void define (string def)
316                 {
317                         if (!RootContext.AllDefines.Contains(def)){
318                                 RootContext.AllDefines [def] = true;
319                         }
320                         if (defines.Contains (def))
321                                 return;
322                         defines [def] = true;
323                 }
324
325                 public bool PropertyParsing {
326                         get {
327                                 return handle_get_set;
328                         }
329
330                         set {
331                                 handle_get_set = value;
332                         }
333                 }
334                                 
335                 bool is_identifier_start_character (char c)
336                 {
337                         return Char.IsLetter (c) || c == '_' ;
338                 }
339
340                 bool is_identifier_part_character (char c)
341                 {
342                         return (Char.IsLetter (c) || Char.IsDigit (c) || c == '_');
343                 }
344
345                 int is_punct (char c, ref bool doread)
346                 {
347                         int d;
348                         int t;
349
350                         doread = false;
351                         
352                         error_details = c.ToString();
353                         
354                         d = peekChar ();
355                         
356                         switch (c){
357                         case '[':
358                                 return Token.OPEN_BRACKET;
359                         case ']':
360                                 return Token.CLOSE_BRACKET;
361                         case '{':
362                                 return Token.OPEN_BRACE;
363                         case '}':
364                                 return Token.CLOSE_BRACE;                               
365                         case '(':
366                                 return Token.OPEN_PARENS;
367                         case ')':
368                                 return Token.CLOSE_PARENS;
369                         case ',':
370                                 return Token.COMMA;
371                         case '?':
372                                 return Token.INTERR;
373                         case '!':
374                                 if (is_identifier_start_character((char)d) || cant_have_a_type_character)
375                                         return Token.EXCLAMATION;
376                                 return Token.SINGLETYPECHAR;
377                         case '$':
378                                 if (cant_have_a_type_character)
379                                         return Token.ERROR;
380                                 return Token.DOLAR_SIGN;
381                         case '@':
382                                 if (cant_have_a_type_character)
383                                         return Token.ERROR;
384                                 return Token.AT_SIGN;
385                         case '%':
386                                 if (cant_have_a_type_character)
387                                         return Token.ERROR;
388                                 return Token.PERCENT;
389                         case '#':
390                                 if (!tokens_seen)
391                                 {
392                                         workout_preprocessing_directive();
393                                         return Token.NONE;
394                                 } 
395                                 if (cant_have_a_type_character) 
396                                         return ExtractDateTimeLiteral();
397                                 return Token.NUMBER_SIGN;
398                         case '&':
399                                 if (!cant_have_a_type_character)
400                                         return Token.LONGTYPECHAR;
401                                 t = handle_integer_literal_in_other_bases(d);
402                                 if (t == Token.NONE) {
403                                         if (d == '=') {
404                                                 doread = true;
405                                                 t = Token.OP_CONCAT_ASSIGN;
406                                         } else 
407                                                 t = Token.OP_CONCAT;
408                                 }
409                                 return t;                       
410                         }
411
412                         if (c == '+'){
413                                 if (d == '+')
414                                         t = Token.OP_INC;
415                                 else if (d == '=')
416                                         t = Token.OP_ADD_ASSIGN;
417                                 else
418                                         return Token.PLUS;
419                                 doread = true;
420                                 return t;
421                         }
422                         if (c == '-'){
423                                 if (d == '=')
424                                         t = Token.OP_SUB_ASSIGN;
425                                 else
426                                         return Token.MINUS;
427                                 doread = true;
428                                 return t;
429                         }
430
431                         if (c == '='){
432                                 return Token.ASSIGN;
433                         }
434
435                         if (c == '*'){
436                                 if (d == '='){
437                                         doread = true;
438                                         return Token.OP_MULT_ASSIGN;
439                                 }
440                                 return Token.STAR;
441                         }
442
443                         if (c == '/'){
444                                 if (d == '='){
445                                         doread = true;
446                                         return Token.OP_DIV_ASSIGN;
447                                 }
448                                 return Token.DIV;
449                         }
450
451                         if (c == '\\'){
452                                 if (d == '='){
453                                         doread = true;
454                                         return Token.OP_IDIV_ASSIGN;
455                                 }
456                                 return Token.OP_IDIV;
457                         }
458
459                         if (c == '^'){
460                                 if (d == '='){
461                                         doread = true;
462                                         return Token.OP_EXP_ASSIGN;
463                                 }
464                                 return Token.OP_EXP;
465                         }
466
467                         if (c == '<'){
468                                 if (d == '>')
469                                 {
470                                         doread = true;
471                                         return Token.OP_NE;
472                                 }
473                                 if (d == '='){
474                                         doread = true;
475                                         return Token.OP_LE;
476                                 }
477                                 if (d == '<')
478                                 {
479                                         doread = true;
480                                         return Token.OP_SHIFT_LEFT;
481                                 }
482                                 return Token.OP_LT;
483                         }
484
485                         if (c == '>'){
486                                 if (d == '='){
487                                         doread = true;
488                                         return Token.OP_GE;
489                                 }
490                                 if (d == '>')
491                                 {
492                                         doread = true;
493                                         return Token.OP_SHIFT_RIGHT;
494                                 }
495                                 return Token.OP_GT;
496                         }
497                         
498                         if (c == ':'){
499                                 if (d == '='){
500                                         doread = true;
501                                         return Token.ATTR_ASSIGN;
502                                 }
503                                 return Token.COLON;
504                         }                       
505                         
506                         return Token.ERROR;
507                 }
508
509                 bool decimal_digits (int c)
510                 {
511                         int d;
512                         bool seen_digits = false;
513                         
514                         if (c != -1)
515                                 number.Append ((char) c);
516                         
517                         while ((d = peekChar ()) != -1){
518                                 if (Char.IsDigit ((char)d)){
519                                         number.Append ((char) d);
520                                         getChar ();
521                                         seen_digits = true;
522                                 } else
523                                         break;
524                         }
525                         return seen_digits;
526                 }
527
528                 
529                 int real_type_suffix (int c)
530                 {
531                         int t;
532                         
533                         switch (c){
534                         case 'F': case 'f':
535                                 t =  Token.LITERAL_SINGLE;
536                                 break;
537                         case 'R': case 'r':
538                                 t = Token.LITERAL_DOUBLE;
539                                 break;
540                         case 'D': case 'd':
541                                  t= Token.LITERAL_DECIMAL;
542                                 break;
543                         default:
544                                 return Token.NONE;
545                         }
546                         getChar ();
547                         return t;
548                 }
549
550                 int integer_type_suffix (int c)
551                 {
552                         int t;
553                         
554                         try {
555                         
556                                 switch (c){
557                                 case 'S': case 's':
558                                         t =  Token.LITERAL_INTEGER; // SHORT ?
559                                         val = ((IConvertible)val).ToInt16(null);
560                                         break;
561                                 case 'I': case 'i':
562                                         t = Token.LITERAL_INTEGER;
563                                         val = ((IConvertible)val).ToInt32(null);
564                                         break;
565                                 case 'L': case 'l':
566                                          t= Token.LITERAL_INTEGER; // LONG ?
567                                          val = ((IConvertible)val).ToInt64(null);
568                                         break;
569                                 default:
570                                         if ((long)val <= System.Int32.MaxValue &&
571                                                 (long)val >= System.Int32.MinValue) {
572                                                 val = ((IConvertible)val).ToInt32(null);
573                                                 return Token.LITERAL_INTEGER;
574                                         } else {
575                                                 val = ((IConvertible)val).ToInt64(null);
576                                                 return Token.LITERAL_INTEGER; // LONG ?
577                                         }
578                                 }
579                                 getChar ();
580                                 return t;
581                         } catch (Exception e) {
582                                 val = e.ToString();
583                                 return Token.ERROR;
584                         }
585                 }
586                 
587                 int adjust_real (int t)
588                 {
589                         string s = number.ToString ();
590
591                         switch (t){
592                         case Token.LITERAL_DECIMAL:
593                                 val = new System.Decimal ();
594                                 val = System.Decimal.Parse (
595                                         s, styles, csharp_format_info);
596                                 break;
597                         case Token.LITERAL_DOUBLE:
598                                 val = new System.Double ();
599                                 val = System.Double.Parse (
600                                         s, styles, csharp_format_info);
601                                 break;
602                         case Token.LITERAL_SINGLE:
603                                 val = new System.Double ();
604                                 val = (float) System.Double.Parse (
605                                         s, styles, csharp_format_info);
606                                 break;
607
608                         case Token.NONE:
609                                 val = new System.Double ();
610                                 val = System.Double.Parse (
611                                         s, styles, csharp_format_info);
612                                 t = Token.LITERAL_DOUBLE;
613                                 break;
614                         }
615                         return t;
616                 }
617
618                 long hex_digits ()
619                 {
620                         StringBuilder hexNumber = new StringBuilder ();
621                         
622                         int d;
623
624                         while ((d = peekChar ()) != -1){
625                                 char e = Char.ToUpper ((char) d);
626                                 
627                                 if (Char.IsDigit (e) || (e >= 'A' && e <= 'F')){
628                                         hexNumber.Append (e);
629                                         getChar ();
630                                 } else
631                                         break;
632                         }
633                         return System.Int64.Parse (hexNumber.ToString(), NumberStyles.HexNumber);
634                 }
635
636                 long octal_digits ()
637                 {
638                         long valueToReturn = 0;
639                         
640                         int d;
641
642                         while ((d = peekChar ()) != -1){
643                                 char e = (char)d;                       
644                                 if (Char.IsDigit (e) && (e < '8')){
645                                         valueToReturn *= 8;
646                                         valueToReturn += (d - (int)'0');
647                                         getChar ();
648                                 } else
649                                         break;
650                         }
651                         
652                         return valueToReturn;
653                 }
654
655                 int handle_integer_literal_in_other_bases(int peek)
656                 {
657                         if (peek == 'h' || peek == 'H'){
658                                 getChar ();
659                                 val = hex_digits ();
660                                 return integer_type_suffix (peekChar ());
661                         }
662                         
663                         if (peek == 'o' || peek == 'O'){
664                                 getChar ();
665                                 val = octal_digits ();
666                                 return integer_type_suffix (peekChar ());
667                         }
668                         
669                         return Token.NONE;
670                 }
671                 
672                 //
673                 // Invoked if we know we have .digits or digits
674                 //
675                 int is_number (int c)
676                 {
677                         bool is_real = false;
678                         number = new StringBuilder ();
679                         int type;
680
681                         number.Length = 0;
682
683                         if (Char.IsDigit ((char)c)){
684                                 decimal_digits (c);
685                                 c = peekChar ();
686                         }
687
688                         //
689                         // We need to handle the case of
690                         // "1.1" vs "1.ToString()" (LITERAL_SINGLE vs NUMBER DOT IDENTIFIER)
691                         //
692                         if (c == '.'){
693                                 if (decimal_digits (getChar())){
694                                         is_real = true;
695                                         c = peekChar ();
696                                 } else {
697                                         putback ('.');
698                                         number.Length -= 1;
699                                         val = System.Int64.Parse(number.ToString());
700                                         return integer_type_suffix('.');
701                                 }
702                         }
703                         
704                         if (c == 'e' || c == 'E'){
705                                 is_real = true;
706                                 number.Append ("e");
707                                 getChar ();
708                                 
709                                 c = peekChar ();
710                                 if (c == '+'){
711                                         number.Append ((char) c);
712                                         getChar ();
713                                         c = peekChar ();
714                                 } else if (c == '-'){
715                                         number.Append ((char) c);
716                                         getChar ();
717                                         c = peekChar ();
718                                 }
719                                 decimal_digits (-1);
720                                 c = peekChar ();
721                         }
722
723                         type = real_type_suffix (c);
724                         if (type == Token.NONE && !is_real){
725                                 val = System.Int64.Parse(number.ToString());
726                                 return integer_type_suffix(c);
727                         }
728                         
729                         return adjust_real (type);
730                 }
731                         
732                 int getChar ()
733                 {
734                         if (putback_char != -1){
735                                 int x = putback_char;
736                                 putback_char = -1;
737
738                                 return x;
739                         }
740                         return reader.Read ();
741                 }
742
743                 int peekChar ()
744                 {
745                         if (putback_char != -1)
746                                 return putback_char;
747                         return reader.Peek ();
748                 }
749
750                 void putback (int c)
751                 {
752                         if (putback_char != -1)
753                                 throw new Exception ("This should not happen putback on putback");
754                         putback_char = c;
755                 }
756
757                 public bool advance ()
758                 {
759                         return current_token != Token.EOF ;
760                 }
761
762                 public Object Value {
763                         get {
764                                 return val;
765                         }
766                 }
767
768                 public Object value ()
769                 {
770                         return val;
771                 }
772
773                 private bool IsEOL(int currentChar)
774                 {
775                         if (currentChar ==  0x0D)
776                         {
777                                 if (peekChar() ==  0x0A) // if it is a CR-LF pair consume LF also
778                                         getChar();
779
780                                 return true;
781                         }
782                         return (currentChar ==  -1 || currentChar ==  0x0A || currentChar ==  0x2028 || currentChar ==  0x2029);
783                 }
784
785                 private int DropComments()              
786                 {
787                         int d;
788                         while (!IsEOL(d = getChar ()))
789                                 col++;
790                         line++;
791                         ref_line++;
792                         col = 0;
793
794                         return Token.EOL;
795                 }       
796                         
797                 public int token ()
798                 {
799                         int lastToken = current_token;
800                         do
801                         {
802                                 current_token = xtoken ();
803                                 if (current_token == 0) 
804                                         return Token.EOF;
805                                 if (current_token == Token.REM)
806                                         current_token = DropComments();
807                         } while (lastToken == Token.EOL && current_token == Token.EOL);
808
809                         return current_token;
810                 }
811
812                 private string GetIdentifier()
813                 {
814                         int c = getChar();
815                         if (is_identifier_start_character ((char) c))
816                                 return GetIdentifier(c);
817                         else
818                                 return null;
819                 }
820
821                 private string GetIdentifier(int c)
822                 {
823                         StringBuilder id = new StringBuilder ();
824
825                         id.Append ((char) c);
826                                 
827                         while ((c = peekChar ()) != -1) 
828                         {
829                                 if (is_identifier_part_character ((char) c))
830                                 {
831                                         id.Append ((char)getChar ());
832                                         col++;
833                                 } 
834                                 else 
835                                         break;
836                         }
837                         
838                         cant_have_a_type_character = false;
839                         
840                         return id.ToString ();
841                 }
842
843                 private bool is_doublequote(int currentChar)
844                 {
845                         return (currentChar == '"' || 
846                                         currentChar == 0x201C || // unicode left double-quote character
847                                         currentChar == 0x201D);  // unicode right double-quote character
848                 }
849                 
850                 private bool is_whitespace(int c)
851                 {
852                         return (c == ' ' || c == '\t' || c == '\v' || c == '\r' || c == 0xa0);
853                 }
854                 
855                 private bool tokens_seen = false;
856                 
857                 private void nextLine()
858                 {
859                         cant_have_a_type_character = true;
860                         line++;
861                         ref_line++;
862                         col = 0;
863                         tokens_seen = false;
864                 }
865
866                 public int xtoken ()
867                 {
868                         int t;
869                         bool doread = false;
870                         int c;
871
872                         val = null;
873                         for (;(c = getChar ()) != -1; col++) {
874                         
875                                 // Handle line continuation character
876                                 if (c == '_') 
877                                 {
878                                         int d = peekChar();
879                                         if (!is_identifier_part_character((char)d)) {
880                                                 while ((c = getChar ()) != -1 && !IsEOL(c)) {}
881                                                 c = getChar ();                 
882                                         }               
883                                 }
884
885                                 // white space
886                                 if (is_whitespace(c)) {
887                                         // expand tabs for location
888                                         if (c == '\t')
889                                                 col = (((col + ExpandedTabsSize) / ExpandedTabsSize) * ExpandedTabsSize) - 1;
890                                         cant_have_a_type_character = true;
891                                         continue;
892                                 }
893                                 
894                                 // Handle line comments.
895                                 if (c == '\'')
896                                         return Token.REM;                                       
897                                 
898                                 // Handle EOL.
899                                 if (IsEOL(c))
900                                 {
901                                         nextLine();
902                                         if (current_token == Token.EOL) // if last token was also EOL keep skipping
903                                                 continue;
904                                         return Token.EOL;
905                                 }
906                                 
907                                 // Handle escaped identifiers
908                                 if (c == '[')
909                                 {
910                                         if ((val = GetIdentifier()) == null)
911                                                 break;
912                                         if ((c = getChar()) != ']')
913                                                 break;
914                                         tokens_seen = true;
915                                         return Token.IDENTIFIER;
916                                 }
917
918                                 // Handle unescaped identifiers
919                                 if (is_identifier_start_character ((char) c))
920                                 {
921                                         string id;
922                                         if ((id = GetIdentifier(c)) == null)
923                                                 break;
924                                         val = id;
925                                         tokens_seen = true;
926                                         if (is_keyword(id) && (current_token != Token.DOT))
927                                                 return getKeyword(id);
928                                         return Token.IDENTIFIER;
929                                 }
930
931                                 // Treat string literals
932                                 if (is_doublequote(c)) {
933                                         cant_have_a_type_character = true;
934                                         return ExtractStringOrCharLiteral(c);
935                                 }
936                         
937                                 // handle numeric literals
938                                 if (c == '.')
939                                 {
940                                         cant_have_a_type_character = true;
941                                         tokens_seen = true;
942                                         if (Char.IsDigit ((char) peekChar ()))
943                                                 return is_number (c);
944                                         return Token.DOT;
945                                 }
946                                 
947                                 if (Char.IsDigit ((char) c))
948                                 {
949                                         cant_have_a_type_character = true;
950                                         tokens_seen = true;
951                                         return is_number (c);
952                                 }
953
954                                 if ((t = is_punct ((char)c, ref doread)) != Token.ERROR) {
955                                         cant_have_a_type_character = true;
956
957                                         if (t == Token.NONE)
958                                                 continue;
959                                                 
960                                         if (doread){
961                                                 getChar ();
962                                                 col++;
963                                         }
964                                         tokens_seen = true;
965                                         return t;
966                                 }
967                                 
968                                 error_details = ((char)c).ToString ();
969                                 return Token.ERROR;
970                         }
971
972                         if (current_token != Token.EOL) // if last token wasn't EOL send it before EOF
973                                 return Token.EOL;
974                         
975                         return Token.EOF;
976                 }
977
978                 private int ExtractDateTimeLiteral()
979                 {
980                         int c;
981                         
982                         StringBuilder sb = new StringBuilder();
983                         for (;(c = getChar ()) != -1; col++)
984                         {
985                                 if (c == '#') {
986                                         val = ParseDateLiteral(sb);
987                                         return Token.LITERAL_DATE;
988                                 }
989                                 if (IsEOL(c)) {
990                                         nextLine();
991                                         break;
992                                 } 
993                                 if (c == '-')
994                                         c = '/';
995                                 sb.Append((char)c);
996                         }
997                         return Token.ERROR;
998                 }
999                 
1000                 private int ExtractStringOrCharLiteral(int c)
1001                 {
1002                         StringBuilder s = new StringBuilder ();
1003
1004                         tokens_seen = true;
1005
1006                         while ((c = getChar ()) != -1){
1007                                 if (is_doublequote(c)){
1008                                         if (is_doublequote(peekChar()))
1009                                                 getChar();
1010                                         else {
1011                                                 //handle Char Literals
1012                                                 if (peekChar() == 'C' || peekChar() == 'c') {
1013                                                         getChar();
1014                                                         if (s.Length == 1) {
1015                                                                 val = s[0];
1016                                                                 return Token.LITERAL_CHARACTER;
1017                                                         } else {
1018                                                                 val = "Incorrect length for a character literal";
1019                                                                 return Token.ERROR;
1020                                                         }                                                       
1021                                                 } else {
1022                                                         val = s.ToString ();
1023                                                         return Token.LITERAL_STRING;
1024                                                 }
1025                                         }
1026                                 }
1027
1028                                 if (IsEOL(c))
1029                                 {
1030                                         nextLine();
1031                                         return Token.ERROR;
1032                                 }
1033                         
1034                                 s.Append ((char) c);
1035                         }
1036                                         
1037                         return Token.ERROR;
1038                 }
1039
1040                 private void workout_preprocessing_directive()
1041                 {
1042                         int c;
1043                         bool cont = true;
1044                                                 
1045                 start_again:
1046                                                 
1047                         cont = handle_preprocessing_directive (cont);
1048         
1049                         if (cont) {
1050                                 col = 0;
1051                                 return;
1052                         }
1053                         col = 1;
1054         
1055                         bool skipping = false;
1056                         for (;(c = getChar ()) != -1; col++) {
1057                                 if (is_whitespace(c))
1058                                         continue;
1059                                 if (IsEOL(c)) {
1060                                         col = 0;
1061                                         line++;
1062                                         ref_line++;
1063                                         skipping = false;
1064                                         continue;
1065                                 } 
1066                                 if (c != '#') {
1067                                         skipping = true;
1068                                         continue;
1069                                 }       
1070                                 if (c == '#' && !skipping)
1071                                         goto start_again;
1072                         }
1073                         tokens_seen = false;
1074                         if (c == -1)
1075                                 Report.Error (1027, Location, "#endif/#endregion expected");
1076                 }
1077                 
1078                 static IFormatProvider enUSculture = new CultureInfo("en-US", true);
1079
1080                 private DateTime ParseDateLiteral(StringBuilder value)
1081                 {
1082                         try
1083                         {
1084                                 return DateTime.Parse(value.ToString(),
1085                                                   enUSculture,
1086                                                   DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces);
1087                         }
1088                         catch (FormatException ex)
1089                         {
1090                                 //TODO: What is the correct error number and message?
1091                                 Report.Error (1, Location, string.Format("Invalid date literal '{0}'", value.ToString()) 
1092                                         + Environment.NewLine + ex.ToString());
1093                         }
1094                         catch (Exception)
1095                         {
1096                                 Report.Error (1, Location, "Error parsing date literal");       //TODO: What is the correct error number and message?
1097                         }
1098                         return new DateTime();
1099                 }
1100  
1101
1102                 public void cleanup ()
1103                 {
1104 /* borrowed from mcs - have to work it to have preprocessing in mbas
1105
1106                         if (ifstack != null && ifstack.Count >= 1) {
1107                                 int state = (int) ifstack.Pop ();
1108                                 if ((state & REGION) != 0)
1109                                         Report.Error (1038, "#endregion directive expected");
1110                                 else 
1111                                         Report.Error (1027, "#endif directive expected");
1112                         }
1113 */                              
1114                 }
1115
1116                 static StringBuilder static_cmd_arg = new StringBuilder ();
1117                 
1118                 void get_cmd_arg (out string cmd, out string arg)
1119                 {
1120                         int c;
1121                         
1122                         tokens_seen = false;
1123                         cmd = "";
1124                         arg = "";
1125                                 
1126                         // skip over white space
1127                         while ((c = getChar ()) != -1 && (c != '\n') && (c != '\r') && ((c == ' ') || (c == '\t')))
1128                                 ;
1129
1130                         if (c == '\n'){
1131                                 line++;
1132                                 ref_line++;
1133                                 return;
1134                         } else if (c == '\r')
1135                                 col = 0;
1136                                 
1137                         static_cmd_arg.Length = 0;
1138                         static_cmd_arg.Append ((char) c);
1139                         
1140
1141                         while ((c = getChar ()) != -1 && (c != '\n') && (c != ' ') && (c != '\t') && (c != '\r')){
1142                                 static_cmd_arg.Append ((char) c);
1143                         }
1144
1145                         cmd = static_cmd_arg.ToString().ToLower();
1146
1147                         if (c == '\n'){
1148                                 line++;
1149                                 ref_line++;
1150                                 return;
1151                         } else if (c == '\r')
1152                                 col = 0;
1153
1154                         // skip over white space
1155                         while ((c = getChar ()) != -1 && (c != '\n') && (c != '\r') && ((c == ' ') || (c == '\t')))
1156                                 ;
1157
1158                         if (c == '\n'){
1159                                 line++;
1160                                 ref_line++;
1161                                 return;
1162                         } else if (c == '\r'){
1163                                 col = 0;
1164                                 return;
1165                         }
1166                         
1167                         static_cmd_arg.Length = 0;
1168                         static_cmd_arg.Append ((char) c);
1169                         
1170                         while ((c = getChar ()) != -1 && (c != '\n') && (c != '\r')){
1171                                 static_cmd_arg.Append ((char) c);
1172                         }
1173
1174                         if (c == '\n'){
1175                                 line++;
1176                                 ref_line++;
1177                         } else if (c == '\r')
1178                                 col = 0;
1179                         arg = static_cmd_arg.ToString ().Trim ();
1180                         
1181                         if (cmd == "end" && arg.ToLower() == "region") {
1182                                 cmd = "end region";
1183                                 arg = "";       
1184                         }
1185                         if (cmd == "end" && arg.ToLower() == "if") {
1186                                 cmd = "end if";
1187                                 arg = "";       
1188                         }                       
1189                                 
1190                 }
1191
1192                 //
1193                 // Handles the #line directive
1194                 //
1195                 bool PreProcessLine (string arg)
1196                 {
1197                         if (arg == "")
1198                                 return false;
1199
1200                         if (arg == "default"){
1201                                 ref_line = line;
1202                                 ref_name = file_name;
1203                                 Location.Push (ref_name);
1204                                 return true;
1205                         }
1206                         
1207                         try {
1208                                 int pos;
1209
1210                                 if ((pos = arg.IndexOf (' ')) != -1 && pos != 0){
1211                                         ref_line = System.Int32.Parse (arg.Substring (0, pos));
1212                                         pos++;
1213                                         
1214                                         char [] quotes = { '\"' };
1215                                         
1216                                         string name = arg.Substring (pos). Trim (quotes);
1217                                         ref_name = name; // TODO: Synchronize with mcs: Location.LookupFile (name);
1218                                         Location.Push (ref_name);
1219                                 } else {
1220                                         ref_line = System.Int32.Parse (arg);
1221                                 }
1222                         } catch {
1223                                 return false;
1224                         }
1225                         
1226                         return true;
1227                 }
1228
1229                 //
1230                 // Handles #define and #undef
1231                 //
1232                 void PreProcessDefinition (bool is_define, string arg)
1233                 {
1234                         if (arg == "" || arg == "true" || arg == "false"){
1235                                 Report.Error (1001, Location, "Missing identifer to pre-processor directive");
1236                                 return;
1237                         }
1238
1239                         char[] whitespace = { ' ', '\t' };
1240                         if (arg.IndexOfAny (whitespace) != -1){
1241                                 Report.Error (1025, Location, "Single-line comment or end-of-line expected");
1242                                 return;
1243                         }
1244
1245                         foreach (char c in arg){
1246                                 if (!Char.IsLetter (c) && (c != '_')){
1247                                         Report.Error (1001, Location, "Identifier expected");
1248                                         return;
1249                                 }
1250                         }
1251
1252                         if (is_define){
1253                                 if (defines == null)
1254                                         defines = new Hashtable ();
1255                                 define (arg);
1256                         } else {
1257                                 if (defines == null)
1258                                         return;
1259                                 if (defines.Contains (arg))
1260                                         defines.Remove (arg);
1261                         }
1262                 }
1263
1264                 bool eval_val (string s)
1265                 {
1266                         if (s == "true")
1267                                 return true;
1268                         if (s == "false")
1269                                 return false;
1270                         
1271                         if (defines == null)
1272                                 return false;
1273                         if (defines.Contains (s))
1274                                 return true;
1275
1276                         return false;
1277                 }
1278
1279                 bool pp_primary (ref string s)
1280                 {
1281                         s = s.Trim ();
1282                         int len = s.Length;
1283
1284                         if (len > 0){
1285                                 char c = s [0];
1286                                 
1287                                 if (c == '('){
1288                                         s = s.Substring (1);
1289                                         bool val = pp_expr (ref s);
1290                                         if (s.Length > 0 && s [0] == ')'){
1291                                                 s = s.Substring (1);
1292                                                 return val;
1293                                         }
1294                                         Error_InvalidDirective ();
1295                                         return false;
1296                                 }
1297                                 
1298                                 if (is_identifier_start_character (c)){
1299                                         int j = 1;
1300
1301                                         while (j < len){
1302                                                 c = s [j];
1303                                                 
1304                                                 if (is_identifier_part_character (c)){
1305                                                         j++;
1306                                                         continue;
1307                                                 }
1308                                                 bool v = eval_val (s.Substring (0, j));
1309                                                 s = s.Substring (j);
1310                                                 return v;
1311                                         }
1312                                         bool vv = eval_val (s);
1313                                         s = "";
1314                                         return vv;
1315                                 }
1316                         }
1317                         Error_InvalidDirective ();
1318                         return false;
1319                 }
1320                 
1321                 bool pp_unary (ref string s)
1322                 {
1323                         s = s.Trim ();
1324                         int len = s.Length;
1325
1326                         if (len > 0){
1327                                 if (s [0] == '!'){
1328                                         if (len > 1 && s [1] == '='){
1329                                                 Error_InvalidDirective ();
1330                                                 return false;
1331                                         }
1332                                         s = s.Substring (1);
1333                                         return ! pp_primary (ref s);
1334                                 } else
1335                                         return pp_primary (ref s);
1336                         } else {
1337                                 Error_InvalidDirective ();
1338                                 return false;
1339                         }
1340                 }
1341                 
1342                 bool pp_eq (ref string s)
1343                 {
1344                         bool va = pp_unary (ref s);
1345
1346                         s = s.Trim ();
1347                         int len = s.Length;
1348                         if (len > 0){
1349                                 if (s [0] == '='){
1350                                         if (len > 2 && s [1] == '='){
1351                                                 s = s.Substring (2);
1352                                                 return va == pp_unary (ref s);
1353                                         } else {
1354                                                 Error_InvalidDirective ();
1355                                                 return false;
1356                                         }
1357                                 } else if (s [0] == '!' && len > 1 && s [1] == '='){
1358                                         s = s.Substring (2);
1359
1360                                         return va != pp_unary (ref s);
1361
1362                                 } 
1363                         }
1364
1365                         return va;
1366                                 
1367                 }
1368                 
1369                 bool pp_and (ref string s)
1370                 {
1371                         bool va = pp_eq (ref s);
1372
1373                         s = s.Trim ();
1374                         int len = s.Length;
1375                         if (len > 0){
1376                                 if (s [0] == '&'){
1377                                         if (len > 2 && s [1] == '&'){
1378                                                 s = s.Substring (2);
1379                                                 return (va & pp_eq (ref s));
1380                                         } else {
1381                                                 Error_InvalidDirective ();
1382                                                 return false;
1383                                         }
1384                                 } 
1385                         }
1386                         return va;
1387                 }
1388                 
1389                 //
1390                 // Evaluates an expression for `#if' or `#elif'
1391                 //
1392                 bool pp_expr (ref string s)
1393                 {
1394                         bool va = pp_and (ref s);
1395                         s = s.Trim ();
1396                         int len = s.Length;
1397                         if (len > 0){
1398                                 char c = s [0];
1399                                 
1400                                 if (c == '|'){
1401                                         if (len > 2 && s [1] == '|'){
1402                                                 s = s.Substring (2);
1403                                                 return va | pp_expr (ref s);
1404                                         } else {
1405                                                 Error_InvalidDirective ();
1406                                                 return false;
1407                                         }
1408                                 } 
1409                         }
1410                         
1411                         return va;
1412                 }
1413
1414                 bool eval (string s)
1415                 {
1416                         bool v = pp_expr (ref s);
1417                         s = s.Trim ();
1418                         if (s.Length != 0){
1419                                 Error_InvalidDirective ();
1420                                 return false;
1421                         }
1422
1423                         return v;
1424                 }
1425                 
1426                 void Error_InvalidDirective ()
1427                 {
1428                         Report.Error (1517, Location, "Invalid pre-processor directive");
1429                 }
1430
1431                 void Error_UnexpectedDirective (string extra)
1432                 {
1433                         Report.Error (
1434                                 1028, Location,
1435                                 "Unexpected processor directive (" + extra + ")");
1436                 }
1437
1438                 void Error_TokensSeen ()
1439                 {
1440                         Report.Error (
1441                                 1032, Location,
1442                                 "Cannot define or undefine pre-processor symbols after a token in the file");
1443                 }
1444                 
1445                 //
1446                 // if true, then the code continues processing the code
1447                 // if false, the code stays in a loop until another directive is
1448                 // reached.
1449                 //
1450                 bool handle_preprocessing_directive (bool caller_is_taking)
1451                 {
1452                         //char [] blank = { ' ', '\t' };
1453                         string cmd, arg;
1454                         bool region_directive = false;
1455
1456                         get_cmd_arg (out cmd, out arg);
1457                         // Eat any trailing whitespaces and single-line comments
1458                         if (arg.IndexOf ("'") != -1)
1459                                 arg = arg.Substring (0, arg.IndexOf ("//"));
1460                         arg = arg.TrimEnd (' ', '\t');
1461
1462                         //
1463                         // The first group of pre-processing instructions is always processed
1464                         //
1465                         switch (cmd.ToLower()){
1466                         case "line":
1467                                 if (!PreProcessLine (arg))
1468                                         Report.Error (
1469                                                 1576, Location,
1470                                                 "Argument to #line directive is missing or invalid");
1471                                 return true;
1472
1473                         case "region":
1474                                 region_directive = true;
1475                                 arg = "true";
1476                                 goto case "if";
1477
1478                         case "end region":
1479                                 region_directive = true;
1480                                 goto case "end if";
1481                                 
1482                         case "if":
1483                                 if (arg == ""){
1484                                         Error_InvalidDirective ();
1485                                         return true;
1486                                 }
1487                                 bool taking = false;
1488                                 if (ifstack == null)
1489                                         ifstack = new Stack ();
1490
1491                                 if (ifstack.Count == 0){
1492                                         taking = true;
1493                                 } else {
1494                                         int state = (int) ifstack.Peek ();
1495                                         if ((state & TAKING) != 0)
1496                                                 taking = true;
1497                                 }
1498
1499                                 if (eval (arg) && taking){
1500                                         int push = TAKING | TAKEN_BEFORE | PARENT_TAKING;
1501                                         if (region_directive)
1502                                                 push |= REGION;
1503                                         ifstack.Push (push);
1504                                         return true;
1505                                 } else {
1506                                         int push = (taking ? PARENT_TAKING : 0);
1507                                         if (region_directive)
1508                                                 push |= REGION;
1509                                         ifstack.Push (push);
1510                                         return false;
1511                                 }
1512                                 
1513                         case "end if":
1514                                 if (ifstack == null || ifstack.Count == 0){
1515                                         Error_UnexpectedDirective ("no #if for this #end if");
1516                                         return true;
1517                                 } else {
1518                                         int pop = (int) ifstack.Pop ();
1519                                         
1520                                         if (region_directive && ((pop & REGION) == 0))
1521                                                 Report.Error (1027, Location, "#end if directive expected");
1522                                         else if (!region_directive && ((pop & REGION) != 0))
1523                                                 Report.Error (1038, Location, "#end region directive expected");
1524                                         
1525                                         if (ifstack.Count == 0)
1526                                                 return true;
1527                                         else {
1528                                                 int state = (int) ifstack.Peek ();
1529
1530                                                 if ((state & TAKING) != 0)
1531                                                         return true;
1532                                                 else
1533                                                         return false;
1534                                         }
1535                                 }
1536
1537                         case "elseif":
1538                                 if (ifstack == null || ifstack.Count == 0){
1539                                         Error_UnexpectedDirective ("no #if for this #elif");
1540                                         return true;
1541                                 } else {
1542                                         int state = (int) ifstack.Peek ();
1543
1544                                         if ((state & REGION) != 0) {
1545                                                 Report.Error (1038, Location, "#end region directive expected");
1546                                                 return true;
1547                                         }
1548
1549                                         if ((state & ELSE_SEEN) != 0){
1550                                                 Error_UnexpectedDirective ("#elif not valid after #else");
1551                                                 return true;
1552                                         }
1553
1554                                         if ((state & (TAKEN_BEFORE | TAKING)) != 0)
1555                                                 return false;
1556
1557                                         if (eval (arg) && ((state & PARENT_TAKING) != 0)){
1558                                                 state = (int) ifstack.Pop ();
1559                                                 ifstack.Push (state | TAKING | TAKEN_BEFORE);
1560                                                 return true;
1561                                         } else 
1562                                                 return false;
1563                                 }
1564
1565                         case "else":
1566                                 if (ifstack == null || ifstack.Count == 0){
1567                                         Report.Error (
1568                                                 1028, Location,
1569                                                 "Unexpected processor directive (no #if for this #else)");
1570                                         return true;
1571                                 } else {
1572                                         int state = (int) ifstack.Peek ();
1573
1574                                         if ((state & REGION) != 0) {
1575                                                 Report.Error (1038, Location, "#end region directive expected");
1576                                                 return true;
1577                                         }
1578
1579                                         if ((state & ELSE_SEEN) != 0){
1580                                                 Error_UnexpectedDirective ("#else within #else");
1581                                                 return true;
1582                                         }
1583
1584                                         ifstack.Pop ();
1585
1586                                         bool ret;
1587                                         if ((state & TAKEN_BEFORE) == 0){
1588                                                 ret = ((state & PARENT_TAKING) != 0);
1589                                         } else
1590                                                 ret = false;
1591                                         
1592                                         if (ret)
1593                                                 state |= TAKING;
1594                                         else
1595                                                 state &= ~TAKING;
1596                                         
1597                                         ifstack.Push (state | ELSE_SEEN);
1598                                         
1599                                         return ret;
1600                                 }
1601                         }
1602
1603                         //
1604                         // These are only processed if we are in a `taking' block
1605                         //
1606                         if (!caller_is_taking)
1607                                 return false;
1608                                         
1609                         switch (cmd.ToLower()){
1610                         case "define":
1611                                 /* if (any_token_seen){
1612                                         Error_TokensSeen ();
1613                                         return true;
1614                                 } */
1615                                 PreProcessDefinition (true, arg);
1616                                 return true;
1617
1618                         case "undef":
1619                                 /* if (any_token_seen){
1620                                         Error_TokensSeen ();
1621                                         return true;
1622                                 } */
1623                                 PreProcessDefinition (false, arg);
1624                                 return true;
1625
1626                         case "error":
1627                                 Report.Error (1029, Location, "#error: '" + arg + "'");
1628                                 return true;
1629
1630                         case "warning":
1631                                 Report.Warning (1030, Location, "#warning: '" + arg + "'");
1632                                 return true;
1633                         }
1634
1635                         Report.Error (1024, Location, "Preprocessor directive expected (got: '" + cmd + "')");
1636                         return true;
1637                 }
1638
1639         }
1640 }