**** Merged r41386-41393 from MCS ****
[mono.git] / mcs / gmcs / cs-tokenizer.cs
1 //
2 // cs-tokenizer.cs: The Tokenizer for the C# compiler
3 //                  This also implements the preprocessor
4 //
5 // Author: Miguel de Icaza (miguel@gnu.org)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)
10 // (C) 2004 Novell, Inc
11 //
12
13 /*
14  * TODO:
15  *   Make sure we accept the proper Unicode ranges, per the spec.
16  *   Report error 1032
17 */
18
19 using System;
20 using System.Text;
21 using System.Collections;
22 using System.IO;
23 using System.Globalization;
24 using System.Reflection;
25
26 namespace Mono.CSharp
27 {
28         /// <summary>
29         ///    Tokenizer for C# source code. 
30         /// </summary>
31
32         public class Tokenizer : yyParser.yyInput
33         {
34                 SeekableStreamReader reader;
35                 public SourceFile ref_name;
36                 public SourceFile file_name;
37                 public int ref_line = 1;
38                 public int line = 1;
39                 public int col = 1;
40                 public int current_token;
41                 bool handle_get_set = false;
42                 bool handle_remove_add = false;
43                 bool handle_assembly = false;
44                 bool handle_constraints = false;
45                 bool handle_typeof = false;
46
47                 //
48                 // XML documentation buffer. The save point is used to divide
49                 // comments on types and comments on members.
50                 //
51                 StringBuilder xml_comment_buffer;
52
53                 //
54                 // See comment on XmlCommentState enumeration.
55                 //
56                 XmlCommentState xmlDocState = XmlCommentState.Allowed;
57
58                 //
59                 // Whether tokens have been seen on this line
60                 //
61                 bool tokens_seen = false;
62
63                 //
64                 // Whether a token has been seen on the file
65                 // This is needed because `define' is not allowed to be used
66                 // after a token has been seen.
67                 //
68                 bool any_token_seen = false;
69
70                 static Hashtable tokenValues;
71                 
72                 private static Hashtable TokenValueName
73                 {
74                         get {
75                                 if (tokenValues == null)
76                                         tokenValues = GetTokenValueNameHash ();
77
78                                 return tokenValues;
79                         }
80                 }
81
82                 private static Hashtable GetTokenValueNameHash ()
83                 {
84                         Type t = typeof (Token);
85                         FieldInfo [] fields = t.GetFields ();
86                         Hashtable hash = new Hashtable ();
87                         foreach (FieldInfo field in fields) {
88                                 if (field.IsLiteral && field.IsStatic && field.FieldType == typeof (int))
89                                         hash.Add (field.GetValue (null), field.Name);
90                         }
91                         return hash;
92                 }
93                 
94                 //
95                 // Returns a verbose representation of the current location
96                 //
97                 public string location {
98                         get {
99                                 string det;
100
101                                 if (current_token == Token.ERROR)
102                                         det = "detail: " + error_details;
103                                 else
104                                         det = "";
105                                 
106                                 // return "Line:     "+line+" Col: "+col + "\n" +
107                                 //       "VirtLine: "+ref_line +
108                                 //       " Token: "+current_token + " " + det;
109                                 string current_token_name = TokenValueName [current_token] as string;
110                                 if (current_token_name == null)
111                                         current_token_name = current_token.ToString ();
112
113                                 return String.Format ("{0} ({1},{2}), Token: {3} {4}", ref_name.Name,
114                                                                                        ref_line,
115                                                                                        col,
116                                                                                        current_token_name,
117                                                                                        det);
118                         }
119                 }
120
121                 public bool PropertyParsing {
122                         get {
123                                 return handle_get_set;
124                         }
125
126                         set {
127                                 handle_get_set = value;
128                         }
129                 }
130
131                 public bool AssemblyTargetParsing {
132                         get {
133                                 return handle_assembly;
134                         }
135
136                         set {
137                                 handle_assembly = value;
138                         }
139                 }
140
141                 public bool EventParsing {
142                         get {
143                                 return handle_remove_add;
144                         }
145
146                         set {
147                                 handle_remove_add = value;
148                         }
149                 }
150
151                 public bool ConstraintsParsing {
152                         get {
153                                 return handle_constraints;
154                         }
155
156                         set {
157                                 handle_constraints = value;
158                         }
159                 }
160
161                 public bool TypeOfParsing {
162                         get {
163                                 return handle_typeof;
164                         }
165
166                         set {
167                                 handle_typeof = value;
168                         }
169                 }
170
171                 public XmlCommentState doc_state {
172                         get { return xmlDocState; }
173                         set {
174                                 if (value == XmlCommentState.Allowed) {
175                                         check_incorrect_doc_comment ();
176                                         consume_doc_comment ();
177                                 }
178                                 xmlDocState = value;
179                         }
180                 }
181
182                 //
183                 // Class variables
184                 // 
185                 static CharArrayHashtable[] keywords;
186                 static NumberStyles styles;
187                 static NumberFormatInfo csharp_format_info;
188                 
189                 //
190                 // Values for the associated token returned
191                 //
192                 int putback_char;
193                 Object val;
194
195                 //
196                 // Pre-processor
197                 //
198                 Hashtable defines;
199
200                 const int TAKING        = 1;
201                 const int TAKEN_BEFORE  = 2;
202                 const int ELSE_SEEN     = 4;
203                 const int PARENT_TAKING = 8;
204                 const int REGION        = 16;           
205
206                 //
207                 // pre-processor if stack state:
208                 //
209                 Stack ifstack;
210
211                 static System.Text.StringBuilder string_builder;
212
213                 const int max_id_size = 512;
214                 static char [] id_builder = new char [max_id_size];
215
216                 static CharArrayHashtable [] identifiers = new CharArrayHashtable [max_id_size + 1];
217
218                 const int max_number_size = 128;
219                 static char [] number_builder = new char [max_number_size];
220                 static int number_pos;
221                 
222                 //
223                 // Details about the error encoutered by the tokenizer
224                 //
225                 string error_details;
226                 
227                 public string error {
228                         get {
229                                 return error_details;
230                         }
231                 }
232                 
233                 public int Line {
234                         get {
235                                 return ref_line;
236                         }
237                 }
238
239                 public int Col {
240                         get {
241                                 return col;
242                         }
243                 }
244
245                 static void AddKeyword (string kw, int token) {
246                         if (keywords [kw.Length] == null) {
247                                 keywords [kw.Length] = new CharArrayHashtable (kw.Length);
248                         }
249                         keywords [kw.Length] [kw.ToCharArray ()] = token;
250                 }
251
252                 static void InitTokens ()
253                 {
254                         keywords = new CharArrayHashtable [64];
255
256                         AddKeyword ("__arglist", Token.ARGLIST);
257                         AddKeyword ("abstract", Token.ABSTRACT);
258                         AddKeyword ("as", Token.AS);
259                         AddKeyword ("add", Token.ADD);
260                         AddKeyword ("assembly", Token.ASSEMBLY);
261                         AddKeyword ("base", Token.BASE);
262                         AddKeyword ("bool", Token.BOOL);
263                         AddKeyword ("break", Token.BREAK);
264                         AddKeyword ("byte", Token.BYTE);
265                         AddKeyword ("case", Token.CASE);
266                         AddKeyword ("catch", Token.CATCH);
267                         AddKeyword ("char", Token.CHAR);
268                         AddKeyword ("checked", Token.CHECKED);
269                         AddKeyword ("class", Token.CLASS);
270                         AddKeyword ("const", Token.CONST);
271                         AddKeyword ("continue", Token.CONTINUE);
272                         AddKeyword ("decimal", Token.DECIMAL);
273                         AddKeyword ("default", Token.DEFAULT);
274                         AddKeyword ("delegate", Token.DELEGATE);
275                         AddKeyword ("do", Token.DO);
276                         AddKeyword ("double", Token.DOUBLE);
277                         AddKeyword ("else", Token.ELSE);
278                         AddKeyword ("enum", Token.ENUM);
279                         AddKeyword ("event", Token.EVENT);
280                         AddKeyword ("explicit", Token.EXPLICIT);
281                         AddKeyword ("extern", Token.EXTERN);
282                         AddKeyword ("false", Token.FALSE);
283                         AddKeyword ("finally", Token.FINALLY);
284                         AddKeyword ("fixed", Token.FIXED);
285                         AddKeyword ("float", Token.FLOAT);
286                         AddKeyword ("for", Token.FOR);
287                         AddKeyword ("foreach", Token.FOREACH);
288                         AddKeyword ("goto", Token.GOTO);
289                         AddKeyword ("get", Token.GET);
290                         AddKeyword ("if", Token.IF);
291                         AddKeyword ("implicit", Token.IMPLICIT);
292                         AddKeyword ("in", Token.IN);
293                         AddKeyword ("int", Token.INT);
294                         AddKeyword ("interface", Token.INTERFACE);
295                         AddKeyword ("internal", Token.INTERNAL);
296                         AddKeyword ("is", Token.IS);
297                         AddKeyword ("lock", Token.LOCK);
298                         AddKeyword ("long", Token.LONG);
299                         AddKeyword ("namespace", Token.NAMESPACE);
300                         AddKeyword ("new", Token.NEW);
301                         AddKeyword ("null", Token.NULL);
302                         AddKeyword ("object", Token.OBJECT);
303                         AddKeyword ("operator", Token.OPERATOR);
304                         AddKeyword ("out", Token.OUT);
305                         AddKeyword ("override", Token.OVERRIDE);
306                         AddKeyword ("params", Token.PARAMS);
307                         AddKeyword ("private", Token.PRIVATE);
308                         AddKeyword ("protected", Token.PROTECTED);
309                         AddKeyword ("public", Token.PUBLIC);
310                         AddKeyword ("readonly", Token.READONLY);
311                         AddKeyword ("ref", Token.REF);
312                         AddKeyword ("remove", Token.REMOVE);
313                         AddKeyword ("return", Token.RETURN);
314                         AddKeyword ("sbyte", Token.SBYTE);
315                         AddKeyword ("sealed", Token.SEALED);
316                         AddKeyword ("set", Token.SET);
317                         AddKeyword ("short", Token.SHORT);
318                         AddKeyword ("sizeof", Token.SIZEOF);
319                         AddKeyword ("stackalloc", Token.STACKALLOC);
320                         AddKeyword ("static", Token.STATIC);
321                         AddKeyword ("string", Token.STRING);
322                         AddKeyword ("struct", Token.STRUCT);
323                         AddKeyword ("switch", Token.SWITCH);
324                         AddKeyword ("this", Token.THIS);
325                         AddKeyword ("throw", Token.THROW);
326                         AddKeyword ("true", Token.TRUE);
327                         AddKeyword ("try", Token.TRY);
328                         AddKeyword ("typeof", Token.TYPEOF);
329                         AddKeyword ("uint", Token.UINT);
330                         AddKeyword ("ulong", Token.ULONG);
331                         AddKeyword ("unchecked", Token.UNCHECKED);
332                         AddKeyword ("unsafe", Token.UNSAFE);
333                         AddKeyword ("ushort", Token.USHORT);
334                         AddKeyword ("using", Token.USING);
335                         AddKeyword ("virtual", Token.VIRTUAL);
336                         AddKeyword ("void", Token.VOID);
337                         AddKeyword ("volatile", Token.VOLATILE);
338                         AddKeyword ("where", Token.WHERE);
339                         AddKeyword ("while", Token.WHILE);
340                         AddKeyword ("partial", Token.PARTIAL);
341                 }
342
343                 //
344                 // Class initializer
345                 // 
346                 static Tokenizer ()
347                 {
348                         InitTokens ();
349                         csharp_format_info = NumberFormatInfo.InvariantInfo;
350                         styles = NumberStyles.Float;
351                         
352                         string_builder = new System.Text.StringBuilder ();
353                 }
354
355                 int GetKeyword (char[] id, int id_len)
356                 {
357                         /*
358                          * Keywords are stored in an array of hashtables grouped by their
359                          * length.
360                          */
361
362                         if ((id_len >= keywords.Length) || (keywords [id_len] == null))
363                                 return -1;
364                         object o = keywords [id_len] [id];
365
366                         if (o == null)
367                                 return -1;
368                         
369                         int res = (int) o;
370
371                         if (handle_get_set == false && (res == Token.GET || res == Token.SET))
372                                 return -1;
373                         if (handle_remove_add == false && (res == Token.REMOVE || res == Token.ADD))
374                                 return -1;
375                         if (handle_assembly == false && res == Token.ASSEMBLY)
376                                 return -1;
377                         if (handle_constraints == false && res == Token.WHERE)
378                                 return -1;
379
380                         return res;
381                         
382                 }
383
384                 public Location Location {
385                         get {
386                                 return new Location (ref_line);
387                         }
388                 }
389
390                 void define (string def)
391                 {
392                         if (!RootContext.AllDefines.Contains (def)){
393                                 RootContext.AllDefines [def] = true;
394                         }
395                         if (defines.Contains (def))
396                                 return;
397                         defines [def] = true;
398                 }
399                 
400                 public Tokenizer (SeekableStreamReader input, SourceFile file, ArrayList defs)
401                 {
402                         this.ref_name = file;
403                         this.file_name = file;
404                         reader = input;
405                         
406                         putback_char = -1;
407
408                         if (defs != null){
409                                 defines = new Hashtable ();
410                                 foreach (string def in defs)
411                                         define (def);
412                         }
413
414                         xml_comment_buffer = new StringBuilder ();
415
416                         //
417                         // FIXME: This could be `Location.Push' but we have to
418                         // find out why the MS compiler allows this
419                         //
420                         Mono.CSharp.Location.Push (file);
421                 }
422
423                 public static void Cleanup () {
424                         identifiers = null;
425                 }
426
427                 static bool is_identifier_start_character (char c)
428                 {
429                         return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || Char.IsLetter (c);
430                 }
431
432                 static bool is_identifier_part_character (char c)
433                 {
434                         return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c);
435                 }
436                 
437                 public static bool IsValidIdentifier (string s)
438                 {
439                         if (s == null || s.Length == 0)
440                                 return false;
441                         
442                         if (!is_identifier_start_character (s [0]))
443                                 return false;
444                         
445                         for (int i = 1; i < s.Length; i ++)
446                                 if (! is_identifier_part_character (s [i]))
447                                         return false;
448                         
449                         return true;
450                 }
451
452                 bool parse_generic_dimension (out int dimension)
453                 {
454                         dimension = 1;
455
456                 again:
457                         int the_token = token ();
458                         if (the_token == Token.OP_GENERICS_GT)
459                                 return true;
460                         else if (the_token == Token.COMMA) {
461                                 dimension++;
462                                 goto again;
463                         }
464
465                         return false;
466                 }
467
468                 bool parse_less_than ()
469                 {
470                 start:
471                         int the_token = token ();
472                         switch (the_token) {
473                         case Token.IDENTIFIER:
474                         case Token.OBJECT:
475                         case Token.STRING:
476                         case Token.BOOL:
477                         case Token.DECIMAL:
478                         case Token.FLOAT:
479                         case Token.DOUBLE:
480                         case Token.SBYTE:
481                         case Token.BYTE:
482                         case Token.SHORT:
483                         case Token.USHORT:
484                         case Token.INT:
485                         case Token.UINT:
486                         case Token.LONG:
487                         case Token.ULONG:
488                         case Token.CHAR:
489                         case Token.VOID:
490                                 break;
491
492                         default:
493                                 return false;
494                         }
495                 again:
496                         the_token = token ();
497
498                         if (the_token == Token.OP_GENERICS_GT)
499                                 return true;
500                         else if ((the_token == Token.COMMA) || (the_token == Token.DOT))
501                                 goto start;
502                         else if (the_token == Token.INTERR)
503                                 goto again;
504                         else if (the_token == Token.OP_GENERICS_LT) {
505                                 if (!parse_less_than ())
506                                         return false;
507                                 goto again;
508                         } else if (the_token == Token.OPEN_BRACKET) {
509                         rank_specifiers:
510                                 the_token = token ();
511                                 if (the_token == Token.CLOSE_BRACKET)
512                                         goto again;
513                                 else if (the_token == Token.COMMA)
514                                         goto rank_specifiers;
515                                 return false;
516                         }
517
518                         return false;
519                 }
520
521                 bool parsing_less_than = false;
522                 int parsing_generic_less_than = 0;
523
524                 int is_punct (char c, ref bool doread)
525                 {
526                         int d;
527                         int t;
528
529                         doread = false;
530
531                         switch (c){
532                         case '{':
533                                 return Token.OPEN_BRACE;
534                         case '}':
535                                 return Token.CLOSE_BRACE;
536                         case '[':
537                                 // To block doccomment inside attribute declaration.
538                                 if (doc_state == XmlCommentState.Allowed)
539                                         doc_state = XmlCommentState.NotAllowed;
540                                 return Token.OPEN_BRACKET;
541                         case ']':
542                                 return Token.CLOSE_BRACKET;
543                         case '(':
544                                 return Token.OPEN_PARENS;
545                         case ')': {
546                                 if (deambiguate_close_parens == 0)
547                                         return Token.CLOSE_PARENS;
548
549                                 --deambiguate_close_parens;
550
551                                 // Save current position and parse next token.
552                                 int old = reader.Position;
553                                 int new_token = token ();
554                                 reader.Position = old;
555                                 putback_char = -1;
556
557                                 if (new_token == Token.OPEN_PARENS)
558                                         return Token.CLOSE_PARENS_OPEN_PARENS;
559                                 else if (new_token == Token.MINUS)
560                                         return Token.CLOSE_PARENS_MINUS;
561                                 else if (IsCastToken (new_token))
562                                         return Token.CLOSE_PARENS_CAST;
563                                 else
564                                         return Token.CLOSE_PARENS_NO_CAST;
565                         }
566
567                         case ',':
568                                 return Token.COMMA;
569                         case ':':
570                                 return Token.COLON;
571                         case ';':
572                                 return Token.SEMICOLON;
573                         case '~':
574                                 return Token.TILDE;
575                         case '?':
576                                 return Token.INTERR;
577                         }
578
579                         if (c == '<') {
580                                 if (parsing_generic_less_than++ > 0)
581                                         return Token.OP_GENERICS_LT;
582
583                                 int old = reader.Position;
584                                 if (handle_typeof) {
585                                         int dimension;
586                                         if (parse_generic_dimension (out dimension)) {
587                                                 val = dimension;
588                                                 return Token.GENERIC_DIMENSION;
589                                         }
590                                         reader.Position = old;
591                                         putback_char = -1;
592                                 }
593
594                                 // Save current position and parse next token.
595                                 old = reader.Position;
596                                 bool is_generic_lt = parse_less_than ();
597                                 reader.Position = old;
598                                 putback_char = -1;
599
600                                 if (is_generic_lt) {
601                                         parsing_generic_less_than++;
602                                         return Token.OP_GENERICS_LT;
603                                 } else
604                                         parsing_generic_less_than = 0;
605
606                                 d = peekChar ();
607                                 if (d == '<'){
608                                         getChar ();
609                                         d = peekChar ();
610
611                                         if (d == '='){
612                                                 doread = true;
613                                                 return Token.OP_SHIFT_LEFT_ASSIGN;
614                                         }
615                                         return Token.OP_SHIFT_LEFT;
616                                 } else if (d == '='){
617                                         doread = true;
618                                         return Token.OP_LE;
619                                 }
620                                 return Token.OP_LT;
621                         } else if (c == '>') {
622                                 if (parsing_generic_less_than > 0) {
623                                         parsing_generic_less_than--;
624                                         return Token.OP_GENERICS_GT;
625                                 }
626
627                                 d = peekChar ();
628                                 if (d == '>'){
629                                         getChar ();
630                                         d = peekChar ();
631
632                                         if (d == '='){
633                                                 doread = true;
634                                                 return Token.OP_SHIFT_RIGHT_ASSIGN;
635                                         }
636                                         return Token.OP_SHIFT_RIGHT;
637                                 } else if (d == '='){
638                                         doread = true;
639                                         return Token.OP_GE;
640                                 }
641                                 return Token.OP_GT;
642                         }
643
644                         d = peekChar ();
645                         if (c == '+'){
646                                 
647                                 if (d == '+')
648                                         t = Token.OP_INC;
649                                 else if (d == '=')
650                                         t = Token.OP_ADD_ASSIGN;
651                                 else
652                                         return Token.PLUS;
653                                 doread = true;
654                                 return t;
655                         }
656                         if (c == '-'){
657                                 if (d == '-')
658                                         t = Token.OP_DEC;
659                                 else if (d == '=')
660                                         t = Token.OP_SUB_ASSIGN;
661                                 else if (d == '>')
662                                         t = Token.OP_PTR;
663                                 else
664                                         return Token.MINUS;
665                                 doread = true;
666                                 return t;
667                         }
668
669                         if (c == '!'){
670                                 if (d == '='){
671                                         doread = true;
672                                         return Token.OP_NE;
673                                 }
674                                 return Token.BANG;
675                         }
676
677                         if (c == '='){
678                                 if (d == '='){
679                                         doread = true;
680                                         return Token.OP_EQ;
681                                 }
682                                 return Token.ASSIGN;
683                         }
684
685                         if (c == '&'){
686                                 if (d == '&'){
687                                         doread = true;
688                                         return Token.OP_AND;
689                                 } else if (d == '='){
690                                         doread = true;
691                                         return Token.OP_AND_ASSIGN;
692                                 }
693                                 return Token.BITWISE_AND;
694                         }
695
696                         if (c == '|'){
697                                 if (d == '|'){
698                                         doread = true;
699                                         return Token.OP_OR;
700                                 } else if (d == '='){
701                                         doread = true;
702                                         return Token.OP_OR_ASSIGN;
703                                 }
704                                 return Token.BITWISE_OR;
705                         }
706
707                         if (c == '*'){
708                                 if (d == '='){
709                                         doread = true;
710                                         return Token.OP_MULT_ASSIGN;
711                                 }
712                                 return Token.STAR;
713                         }
714
715                         if (c == '/'){
716                                 if (d == '='){
717                                         doread = true;
718                                         return Token.OP_DIV_ASSIGN;
719                                 }
720                                 return Token.DIV;
721                         }
722
723                         if (c == '%'){
724                                 if (d == '='){
725                                         doread = true;
726                                         return Token.OP_MOD_ASSIGN;
727                                 }
728                                 return Token.PERCENT;
729                         }
730
731                         if (c == '^'){
732                                 if (d == '='){
733                                         doread = true;
734                                         return Token.OP_XOR_ASSIGN;
735                                 }
736                                 return Token.CARRET;
737                         }
738
739                         return Token.ERROR;
740                 }
741
742                 int deambiguate_close_parens = 0;
743
744                 public void Deambiguate_CloseParens ()
745                 {
746                         putback (')');
747                         deambiguate_close_parens++;
748                 }
749
750                 public void PutbackNullable ()
751                 {
752                         if (nullable_pos < 0)
753                                 throw new Exception ();
754
755                         current_token = -1;
756                         val = null;
757                         reader.Position = nullable_pos;
758
759                         putback_char = '?';
760                 }
761
762                 public void PutbackCloseParens ()
763                 {
764                         putback_char = ')';
765                 }
766
767                 void Error_NumericConstantTooLong ()
768                 {
769                         Report.Error (1021, Location, "Numeric constant too long");                     
770                 }
771
772                 int nullable_pos = -1;
773
774                 public void CheckNullable (bool is_nullable)
775                 {
776                         if (is_nullable)
777                                 nullable_pos = reader.Position;
778                         else
779                                 nullable_pos = -1;
780                 }
781
782                 bool decimal_digits (int c)
783                 {
784                         int d;
785                         bool seen_digits = false;
786                         
787                         if (c != -1){
788                                 if (number_pos == max_number_size)
789                                         Error_NumericConstantTooLong ();
790                                 number_builder [number_pos++] = (char) c;
791                         }
792                         
793                         //
794                         // We use peekChar2, because decimal_digits needs to do a 
795                         // 2-character look-ahead (5.ToString for example).
796                         //
797                         while ((d = peekChar2 ()) != -1){
798                                 if (d >= '0' && d <= '9'){
799                                         if (number_pos == max_number_size)
800                                                 Error_NumericConstantTooLong ();
801                                         number_builder [number_pos++] = (char) d;
802                                         getChar ();
803                                         seen_digits = true;
804                                 } else
805                                         break;
806                         }
807                         
808                         return seen_digits;
809                 }
810
811                 bool is_hex (int e)
812                 {
813                         return (e >= '0' && e <= '9') || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
814                 }
815                 
816                 void hex_digits (int c)
817                 {
818                         if (c != -1)
819                                 number_builder [number_pos++] = (char) c;
820                         
821                 }
822                 
823                 int real_type_suffix (int c)
824                 {
825                         int t;
826
827                         switch (c){
828                         case 'F': case 'f':
829                                 t =  Token.LITERAL_FLOAT;
830                                 break;
831                         case 'D': case 'd':
832                                 t = Token.LITERAL_DOUBLE;
833                                 break;
834                         case 'M': case 'm':
835                                  t= Token.LITERAL_DECIMAL;
836                                 break;
837                         default:
838                                 return Token.NONE;
839                         }
840                         return t;
841                 }
842
843                 int integer_type_suffix (ulong ul, int c)
844                 {
845                         bool is_unsigned = false;
846                         bool is_long = false;
847
848                         if (c != -1){
849                                 bool scanning = true;
850                                 do {
851                                         switch (c){
852                                         case 'U': case 'u':
853                                                 if (is_unsigned)
854                                                         scanning = false;
855                                                 is_unsigned = true;
856                                                 getChar ();
857                                                 break;
858
859                                         case 'l':
860                                                 if (!is_unsigned && (RootContext.WarningLevel >= 4)){
861                                                         //
862                                                         // if we have not seen anything in between
863                                                         // report this error
864                                                         //
865                                                         Report.Warning (78, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");
866                                                 }
867                                                 //
868                                                 // This goto statement causes the MS CLR 2.0 beta 1 csc to report an error, so
869                                                 // work around that.
870                                                 //
871                                                 //goto case 'L';
872                                                 if (is_long)
873                                                         scanning = false;
874                                                 is_long = true;
875                                                 getChar ();
876                                                 break;
877
878                                         case 'L': 
879                                                 if (is_long)
880                                                         scanning = false;
881                                                 is_long = true;
882                                                 getChar ();
883                                                 break;
884                                                 
885                                         default:
886                                                 scanning = false;
887                                                 break;
888                                         }
889                                         c = peekChar ();
890                                 } while (scanning);
891                         }
892
893                         if (is_long && is_unsigned){
894                                 val = ul;
895                                 return Token.LITERAL_INTEGER;
896                         } else if (is_unsigned){
897                                 // uint if possible, or ulong else.
898
899                                 if ((ul & 0xffffffff00000000) == 0)
900                                         val = (uint) ul;
901                                 else
902                                         val = ul;
903                         } else if (is_long){
904                                 // long if possible, ulong otherwise
905                                 if ((ul & 0x8000000000000000) != 0)
906                                         val = ul;
907                                 else
908                                         val = (long) ul;
909                         } else {
910                                 // int, uint, long or ulong in that order
911                                 if ((ul & 0xffffffff00000000) == 0){
912                                         uint ui = (uint) ul;
913                                         
914                                         if ((ui & 0x80000000) != 0)
915                                                 val = ui;
916                                         else
917                                                 val = (int) ui;
918                                 } else {
919                                         if ((ul & 0x8000000000000000) != 0)
920                                                 val = ul;
921                                         else
922                                                 val = (long) ul;
923                                 }
924                         }
925                         return Token.LITERAL_INTEGER;
926                 }
927                                 
928                 //
929                 // given `c' as the next char in the input decide whether
930                 // we need to convert to a special type, and then choose
931                 // the best representation for the integer
932                 //
933                 int adjust_int (int c)
934                 {
935                         try {
936                                 if (number_pos > 9){
937                                         ulong ul = (uint) (number_builder [0] - '0');
938
939                                         for (int i = 1; i < number_pos; i++){
940                                                 ul = checked ((ul * 10) + ((uint)(number_builder [i] - '0')));
941                                         }
942                                         return integer_type_suffix (ul, c);
943                                 } else {
944                                         uint ui = (uint) (number_builder [0] - '0');
945
946                                         for (int i = 1; i < number_pos; i++){
947                                                 ui = checked ((ui * 10) + ((uint)(number_builder [i] - '0')));
948                                         }
949                                         return integer_type_suffix (ui, c);
950                                 }
951                         } catch (OverflowException) {
952                                 error_details = "Integral constant is too large";
953                                 Report.Error (1021, Location, error_details);
954                                 val = 0ul;
955                                 return Token.LITERAL_INTEGER;
956                         }
957                         catch (FormatException) {
958                                 Report.Error (1013, Location, "Invalid number");
959                                 val = 0ul;
960                                 return Token.LITERAL_INTEGER;
961                         }
962                 }
963                 
964                 int adjust_real (int t)
965                 {
966                         string s = new String (number_builder, 0, number_pos);
967
968                         switch (t){
969                         case Token.LITERAL_DECIMAL:
970                                 try {
971                                         val = System.Decimal.Parse (s, styles, csharp_format_info);
972                                 } catch (OverflowException) {
973                                         val = 0m;     
974                                         error_details = "Floating-point constant is outside the range of the type 'decimal'";
975                                         Report.Error (594, Location, error_details);
976                                 }
977                                 break;
978                         case Token.LITERAL_FLOAT:
979                                 try {
980                                         val = (float) System.Double.Parse (s, styles, csharp_format_info);
981                                 } catch (OverflowException) {
982                                         val = 0.0f;     
983                                         error_details = "Floating-point constant is outside the range of the type 'float'";
984                                         Report.Error (594, Location, error_details);
985                                 }
986                                 break;
987                                 
988                         case Token.LITERAL_DOUBLE:
989                         case Token.NONE:
990                                 t = Token.LITERAL_DOUBLE;
991                                 try {
992                                         val = System.Double.Parse (s, styles, csharp_format_info);
993                                 } catch (OverflowException) {
994                                         val = 0.0;     
995                                         error_details = "Floating-point constant is outside the range of the type 'double'";
996                                         Report.Error (594, Location, error_details);
997                                 }
998                                 break;
999                         }
1000                         return t;
1001                 }
1002
1003                 int handle_hex ()
1004                 {
1005                         int d;
1006                         ulong ul;
1007                         
1008                         getChar ();
1009                         while ((d = peekChar ()) != -1){
1010                                 if (is_hex (d)){
1011                                         number_builder [number_pos++] = (char) d;
1012                                         getChar ();
1013                                 } else
1014                                         break;
1015                         }
1016                         
1017                         string s = new String (number_builder, 0, number_pos);
1018                         try {
1019                                 if (number_pos <= 8)
1020                                         ul = System.UInt32.Parse (s, NumberStyles.HexNumber);
1021                                 else
1022                                         ul = System.UInt64.Parse (s, NumberStyles.HexNumber);
1023                         } catch (OverflowException){
1024                                 error_details = "Integral constant is too large";
1025                                 Report.Error (1021, Location, error_details);
1026                                 val = 0ul;
1027                                 return Token.LITERAL_INTEGER;
1028                         }
1029                         
1030                         return integer_type_suffix (ul, peekChar ());
1031                 }
1032
1033                 //
1034                 // Invoked if we know we have .digits or digits
1035                 //
1036                 int is_number (int c)
1037                 {
1038                         bool is_real = false;
1039                         int type;
1040
1041                         number_pos = 0;
1042
1043                         if (c >= '0' && c <= '9'){
1044                                 if (c == '0'){
1045                                         int peek = peekChar ();
1046
1047                                         if (peek == 'x' || peek == 'X')
1048                                                 return handle_hex ();
1049                                 }
1050                                 decimal_digits (c);
1051                                 c = getChar ();
1052                         }
1053
1054                         //
1055                         // We need to handle the case of
1056                         // "1.1" vs "1.string" (LITERAL_FLOAT vs NUMBER DOT IDENTIFIER)
1057                         //
1058                         if (c == '.'){
1059                                 if (decimal_digits ('.')){
1060                                         is_real = true;
1061                                         c = getChar ();
1062                                 } else {
1063                                         putback ('.');
1064                                         number_pos--;
1065                                         return adjust_int (-1);
1066                                 }
1067                         }
1068                         
1069                         if (c == 'e' || c == 'E'){
1070                                 is_real = true;
1071                                 if (number_pos == max_number_size)
1072                                         Error_NumericConstantTooLong ();
1073                                 number_builder [number_pos++] = 'e';
1074                                 c = getChar ();
1075                                 
1076                                 if (c == '+'){
1077                                         if (number_pos == max_number_size)
1078                                                 Error_NumericConstantTooLong ();
1079                                         number_builder [number_pos++] = '+';
1080                                         c = -1;
1081                                 } else if (c == '-') {
1082                                         if (number_pos == max_number_size)
1083                                                 Error_NumericConstantTooLong ();
1084                                         number_builder [number_pos++] = '-';
1085                                         c = -1;
1086                                 } else {
1087                                         if (number_pos == max_number_size)
1088                                                 Error_NumericConstantTooLong ();
1089                                         number_builder [number_pos++] = '+';
1090                                 }
1091                                         
1092                                 decimal_digits (c);
1093                                 c = getChar ();
1094                         }
1095
1096                         type = real_type_suffix (c);
1097                         if (type == Token.NONE && !is_real){
1098                                 putback (c);
1099                                 return adjust_int (c);
1100                         } else 
1101                                 is_real = true;
1102
1103                         if (type == Token.NONE){
1104                                 putback (c);
1105                         }
1106                         
1107                         if (is_real)
1108                                 return adjust_real (type);
1109
1110                         Console.WriteLine ("This should not be reached");
1111                         throw new Exception ("Is Number should never reach this point");
1112                 }
1113
1114                 //
1115                 // Accepts exactly count (4 or 8) hex, no more no less
1116                 //
1117                 int getHex (int count, out bool error)
1118                 {
1119                         int i;
1120                         int total = 0;
1121                         int c;
1122                         int top = count != -1 ? count : 4;
1123                         
1124                         getChar ();
1125                         error = false;
1126                         for (i = 0; i < top; i++){
1127                                 c = getChar ();
1128                                 
1129                                 if (c >= '0' && c <= '9')
1130                                         c = (int) c - (int) '0';
1131                                 else if (c >= 'A' && c <= 'F')
1132                                         c = (int) c - (int) 'A' + 10;
1133                                 else if (c >= 'a' && c <= 'f')
1134                                         c = (int) c - (int) 'a' + 10;
1135                                 else {
1136                                         error = true;
1137                                         return 0;
1138                                 }
1139                                 
1140                                 total = (total * 16) + c;
1141                                 if (count == -1){
1142                                         int p = peekChar ();
1143                                         if (p == -1)
1144                                                 break;
1145                                         if (!is_hex ((char)p))
1146                                                 break;
1147                                 }
1148                         }
1149                         return total;
1150                 }
1151
1152                 int escape (int c)
1153                 {
1154                         bool error;
1155                         int d;
1156                         int v;
1157
1158                         d = peekChar ();
1159                         if (c != '\\')
1160                                 return c;
1161                         
1162                         switch (d){
1163                         case 'a':
1164                                 v = '\a'; break;
1165                         case 'b':
1166                                 v = '\b'; break;
1167                         case 'n':
1168                                 v = '\n'; break;
1169                         case 't':
1170                                 v = '\t'; break;
1171                         case 'v':
1172                                 v = '\v'; break;
1173                         case 'r':
1174                                 v = '\r'; break;
1175                         case '\\':
1176                                 v = '\\'; break;
1177                         case 'f':
1178                                 v = '\f'; break;
1179                         case '0':
1180                                 v = 0; break;
1181                         case '"':
1182                                 v = '"'; break;
1183                         case '\'':
1184                                 v = '\''; break;
1185                         case 'x':
1186                                 v = getHex (-1, out error);
1187                                 if (error)
1188                                         goto default;
1189                                 return v;
1190                         case 'u':
1191                                 v = getHex (4, out error);
1192                                 if (error)
1193                                         goto default;
1194                                 return v;
1195                         case 'U':
1196                                 v = getHex (8, out error);
1197                                 if (error)
1198                                         goto default;
1199                                 return v;
1200                         default:
1201                                 Report.Error (1009, Location, "Unrecognized escape sequence in " + (char)d);
1202                                 return d;
1203                         }
1204                         getChar ();
1205                         return v;
1206                 }
1207
1208                 int getChar ()
1209                 {
1210                         if (putback_char != -1){
1211                                 int x = putback_char;
1212                                 putback_char = -1;
1213
1214                                 return x;
1215                         }
1216                         return reader.Read ();
1217                 }
1218
1219                 int peekChar ()
1220                 {
1221                         if (putback_char != -1)
1222                                 return putback_char;
1223                         putback_char = reader.Read ();
1224                         return putback_char;
1225                 }
1226
1227                 int peekChar2 ()
1228                 {
1229                         if (putback_char != -1)
1230                                 return putback_char;
1231                         return reader.Peek ();
1232                 }
1233                 
1234                 void putback (int c)
1235                 {
1236                         if (putback_char != -1){
1237                                 Console.WriteLine ("Col: " + col);
1238                                 Console.WriteLine ("Row: " + line);
1239                                 Console.WriteLine ("Name: " + ref_name.Name);
1240                                 Console.WriteLine ("Current [{0}] putting back [{1}]  ", putback_char, c);
1241                                 throw new Exception ("This should not happen putback on putback");
1242                         }
1243                         putback_char = c;
1244                 }
1245
1246                 public bool advance ()
1247                 {
1248                         return peekChar () != -1;
1249                 }
1250
1251                 public Object Value {
1252                         get {
1253                                 return val;
1254                         }
1255                 }
1256
1257                 public Object value ()
1258                 {
1259                         return val;
1260                 }
1261
1262                 bool IsCastToken (int token)
1263                 {
1264                         switch (token) {
1265                         case Token.BANG:
1266                         case Token.TILDE:
1267                         case Token.IDENTIFIER:
1268                         case Token.LITERAL_INTEGER:
1269                         case Token.LITERAL_FLOAT:
1270                         case Token.LITERAL_DOUBLE:
1271                         case Token.LITERAL_DECIMAL:
1272                         case Token.LITERAL_CHARACTER:
1273                         case Token.LITERAL_STRING:
1274                         case Token.BASE:
1275                         case Token.CHECKED:
1276                         case Token.FALSE:
1277                         case Token.FIXED:
1278                         case Token.NEW:
1279                         case Token.NULL:
1280                         case Token.SIZEOF:
1281                         case Token.THIS:
1282                         case Token.THROW:
1283                         case Token.TRUE:
1284                         case Token.TYPEOF:
1285                         case Token.UNCHECKED:
1286                         case Token.UNSAFE:
1287
1288                                 //
1289                                 // These can be part of a member access
1290                                 //
1291                         case Token.INT:
1292                         case Token.UINT:
1293                         case Token.SHORT:
1294                         case Token.USHORT:
1295                         case Token.LONG:
1296                         case Token.ULONG:
1297                         case Token.DOUBLE:
1298                         case Token.FLOAT:
1299                         case Token.CHAR:
1300                                 return true;
1301
1302                         default:
1303                                 return false;
1304                         }
1305                 }
1306
1307                 public int token ()
1308                 {
1309                         current_token = xtoken ();
1310
1311                         if (current_token != Token.DEFAULT)
1312                                 return current_token;
1313
1314                         int c = consume_whitespace ();
1315                         if (c == -1)
1316                                 current_token = Token.ERROR;
1317                         else if (c == '(')
1318                                 current_token = Token.DEFAULT_OPEN_PARENS;
1319                         else
1320                                 putback (c);
1321
1322                         return current_token;
1323                 }
1324
1325                 static StringBuilder static_cmd_arg = new System.Text.StringBuilder ();
1326                 
1327                 void get_cmd_arg (out string cmd, out string arg)
1328                 {
1329                         int c;
1330                         
1331                         tokens_seen = false;
1332                         arg = "";
1333                         static_cmd_arg.Length = 0;
1334
1335                         // skip over white space
1336                         while ((c = getChar ()) != -1 && (c != '\n') && ((c == '\r') || (c == ' ') || (c == '\t')))
1337                                 ;
1338                                 
1339                         while ((c != -1) && (c != '\n') && (c != ' ') && (c != '\t') && (c != '\r')){
1340                                 if (is_identifier_part_character ((char) c)){
1341                                         static_cmd_arg.Append ((char) c);
1342                                         c = getChar ();
1343                                 } else {
1344                                         putback (c);
1345                                         break;
1346                                 }
1347                         }
1348
1349                         cmd = static_cmd_arg.ToString ();
1350
1351                         if (c == '\n'){
1352                                 line++;
1353                                 ref_line++;
1354                                 return;
1355                         } else if (c == '\r')
1356                                 col = 0;
1357
1358                         // skip over white space
1359                         while ((c = getChar ()) != -1 && (c != '\n') && ((c == '\r') || (c == ' ') || (c == '\t')))
1360                                 ;
1361
1362                         if (c == '\n'){
1363                                 line++;
1364                                 ref_line++;
1365                                 return;
1366                         } else if (c == '\r'){
1367                                 col = 0;
1368                                 return;
1369                         }
1370                         
1371                         static_cmd_arg.Length = 0;
1372                         static_cmd_arg.Append ((char) c);
1373                         
1374                         while ((c = getChar ()) != -1 && (c != '\n') && (c != '\r')){
1375                                 static_cmd_arg.Append ((char) c);
1376                         }
1377
1378                         if (c == '\n'){
1379                                 line++;
1380                                 ref_line++;
1381                         } else if (c == '\r')
1382                                 col = 0;
1383                         arg = static_cmd_arg.ToString ().Trim ();
1384                 }
1385
1386                 //
1387                 // Handles the #line directive
1388                 //
1389                 bool PreProcessLine (string arg)
1390                 {
1391                         if (arg == "")
1392                                 return false;
1393
1394                         if (arg == "default"){
1395                                 ref_line = line;
1396                                 ref_name = file_name;
1397                                 Location.Push (ref_name);
1398                                 return true;
1399                         } else if (arg == "hidden"){
1400                                 //
1401                                 // We ignore #line hidden
1402                                 //
1403                                 return true;
1404                         }
1405                         
1406                         try {
1407                                 int pos;
1408
1409                                 if ((pos = arg.IndexOf (' ')) != -1 && pos != 0){
1410                                         ref_line = System.Int32.Parse (arg.Substring (0, pos));
1411                                         pos++;
1412                                         
1413                                         char [] quotes = { '\"' };
1414                                         
1415                                         string name = arg.Substring (pos). Trim (quotes);
1416                                         ref_name = Location.LookupFile (name);
1417                                         file_name.HasLineDirective = true;
1418                                         ref_name.HasLineDirective = true;
1419                                         Location.Push (ref_name);
1420                                 } else {
1421                                         ref_line = System.Int32.Parse (arg);
1422                                 }
1423                         } catch {
1424                                 return false;
1425                         }
1426                         
1427                         return true;
1428                 }
1429
1430                 //
1431                 // Handles #define and #undef
1432                 //
1433                 void PreProcessDefinition (bool is_define, string arg)
1434                 {
1435                         if (arg == "" || arg == "true" || arg == "false"){
1436                                 Report.Error (1001, Location, "Missing identifer to pre-processor directive");
1437                                 return;
1438                         }
1439
1440                         char[] whitespace = { ' ', '\t' };
1441                         if (arg.IndexOfAny (whitespace) != -1){
1442                                 Report.Error (1025, Location, "Single-line comment or end-of-line expected");
1443                                 return;
1444                         }
1445
1446                         if (!is_identifier_start_character (arg [0]))
1447                                 Report.Error (1001, Location, "Identifier expected: " + arg);
1448                         
1449                         foreach (char c in arg.Substring (1)){
1450                                 if (!is_identifier_part_character (c)){
1451                                         Report.Error (1001, Location, "Identifier expected: " + arg);
1452                                         return;
1453                                 }
1454                         }
1455
1456                         if (is_define){
1457                                 if (defines == null)
1458                                         defines = new Hashtable ();
1459                                 define (arg);
1460                         } else {
1461                                 if (defines == null)
1462                                         return;
1463                                 if (defines.Contains (arg))
1464                                         defines.Remove (arg);
1465                         }
1466                 }
1467
1468                 /// <summary>
1469                 /// Handles #pragma directive
1470                 /// </summary>
1471                 void PreProcessPragma (string arg)
1472                 {
1473                         const string warning = "warning";
1474                         const string w_disable = "warning disable";
1475                         const string w_restore = "warning restore";
1476
1477                         if (arg == w_disable) {
1478                                 Report.RegisterWarningRegion (Location).WarningDisable (line);
1479                                 return;
1480                         }
1481
1482                         if (arg == w_restore) {
1483                                 Report.RegisterWarningRegion (Location).WarningEnable (line);
1484                                 return;
1485                         }
1486
1487                         if (arg.StartsWith (w_disable)) {
1488                                 int[] codes = ParseNumbers (arg.Substring (w_disable.Length));
1489                                 foreach (int code in codes) {
1490                                         if (code != 0)
1491                                                 Report.RegisterWarningRegion (Location).WarningDisable (Location, code);
1492                                 }
1493                                 return;
1494                         }
1495
1496                         if (arg.StartsWith (w_restore)) {
1497                                 int[] codes = ParseNumbers (arg.Substring (w_restore.Length));
1498                                 foreach (int code in codes) {
1499                                         Report.RegisterWarningRegion (Location).WarningEnable (Location, code);
1500                                 }
1501                                 return;
1502                         }
1503
1504                         if (arg.StartsWith (warning)) {
1505                                 Report.Warning (1634, 1, Location, "Expected disable or restore");
1506                                 return;
1507                         }
1508                 }
1509
1510                 int[] ParseNumbers (string text)
1511                 {
1512                         string[] string_array = text.Split (',');
1513                         int[] values = new int [string_array.Length];
1514                         int index = 0;
1515                         foreach (string string_code in string_array) {
1516                                 try {
1517                                         values[index++] = int.Parse (string_code, System.Globalization.CultureInfo.InvariantCulture);
1518                                 }
1519                                 catch (FormatException) {
1520                                         Report.Warning (1692, Location, "Invalid number");
1521                                 }
1522                         }
1523                         return values;
1524                 }
1525
1526                 bool eval_val (string s)
1527                 {
1528                         if (s == "true")
1529                                 return true;
1530                         if (s == "false")
1531                                 return false;
1532                         
1533                         if (defines == null)
1534                                 return false;
1535                         if (defines.Contains (s))
1536                                 return true;
1537
1538                         return false;
1539                 }
1540
1541                 bool pp_primary (ref string s)
1542                 {
1543                         s = s.Trim ();
1544                         int len = s.Length;
1545
1546                         if (len > 0){
1547                                 char c = s [0];
1548                                 
1549                                 if (c == '('){
1550                                         s = s.Substring (1);
1551                                         bool val = pp_expr (ref s);
1552                                         if (s.Length > 0 && s [0] == ')'){
1553                                                 s = s.Substring (1);
1554                                                 return val;
1555                                         }
1556                                         Error_InvalidDirective ();
1557                                         return false;
1558                                 }
1559                                 
1560                                 if (is_identifier_start_character (c)){
1561                                         int j = 1;
1562
1563                                         while (j < len){
1564                                                 c = s [j];
1565                                                 
1566                                                 if (is_identifier_part_character (c)){
1567                                                         j++;
1568                                                         continue;
1569                                                 }
1570                                                 bool v = eval_val (s.Substring (0, j));
1571                                                 s = s.Substring (j);
1572                                                 return v;
1573                                         }
1574                                         bool vv = eval_val (s);
1575                                         s = "";
1576                                         return vv;
1577                                 }
1578                         }
1579                         Error_InvalidDirective ();
1580                         return false;
1581                 }
1582                 
1583                 bool pp_unary (ref string s)
1584                 {
1585                         s = s.Trim ();
1586                         int len = s.Length;
1587
1588                         if (len > 0){
1589                                 if (s [0] == '!'){
1590                                         if (len > 1 && s [1] == '='){
1591                                                 Error_InvalidDirective ();
1592                                                 return false;
1593                                         }
1594                                         s = s.Substring (1);
1595                                         return ! pp_primary (ref s);
1596                                 } else
1597                                         return pp_primary (ref s);
1598                         } else {
1599                                 Error_InvalidDirective ();
1600                                 return false;
1601                         }
1602                 }
1603                 
1604                 bool pp_eq (ref string s)
1605                 {
1606                         bool va = pp_unary (ref s);
1607
1608                         s = s.Trim ();
1609                         int len = s.Length;
1610                         if (len > 0){
1611                                 if (s [0] == '='){
1612                                         if (len > 2 && s [1] == '='){
1613                                                 s = s.Substring (2);
1614                                                 return va == pp_unary (ref s);
1615                                         } else {
1616                                                 Error_InvalidDirective ();
1617                                                 return false;
1618                                         }
1619                                 } else if (s [0] == '!' && len > 1 && s [1] == '='){
1620                                         s = s.Substring (2);
1621
1622                                         return va != pp_unary (ref s);
1623
1624                                 } 
1625                         }
1626
1627                         return va;
1628                                 
1629                 }
1630                 
1631                 bool pp_and (ref string s)
1632                 {
1633                         bool va = pp_eq (ref s);
1634
1635                         s = s.Trim ();
1636                         int len = s.Length;
1637                         if (len > 0){
1638                                 if (s [0] == '&'){
1639                                         if (len > 2 && s [1] == '&'){
1640                                                 s = s.Substring (2);
1641                                                 return (va & pp_and (ref s));
1642                                         } else {
1643                                                 Error_InvalidDirective ();
1644                                                 return false;
1645                                         }
1646                                 } 
1647                         }
1648                         return va;
1649                 }
1650                 
1651                 //
1652                 // Evaluates an expression for `#if' or `#elif'
1653                 //
1654                 bool pp_expr (ref string s)
1655                 {
1656                         bool va = pp_and (ref s);
1657                         s = s.Trim ();
1658                         int len = s.Length;
1659                         if (len > 0){
1660                                 char c = s [0];
1661                                 
1662                                 if (c == '|'){
1663                                         if (len > 2 && s [1] == '|'){
1664                                                 s = s.Substring (2);
1665                                                 return va | pp_expr (ref s);
1666                                         } else {
1667                                                 Error_InvalidDirective ();
1668                                                 return false;
1669                                         }
1670                                 } 
1671                         }
1672                         
1673                         return va;
1674                 }
1675
1676                 bool eval (string s)
1677                 {
1678                         bool v = pp_expr (ref s);
1679                         s = s.Trim ();
1680                         if (s.Length != 0){
1681                                 Error_InvalidDirective ();
1682                                 return false;
1683                         }
1684
1685                         return v;
1686                 }
1687                 
1688                 void Error_InvalidDirective ()
1689                 {
1690                         Report.Error (1517, Location, "Invalid pre-processor directive");
1691                 }
1692
1693                 void Error_UnexpectedDirective (string extra)
1694                 {
1695                         Report.Error (
1696                                 1028, Location,
1697                                 "Unexpected processor directive (" + extra + ")");
1698                 }
1699
1700                 void Error_TokensSeen ()
1701                 {
1702                         Report.Error (
1703                                 1032, Location,
1704                                 "Cannot define or undefine pre-processor symbols after a token in the file");
1705                 }
1706                 
1707                 //
1708                 // if true, then the code continues processing the code
1709                 // if false, the code stays in a loop until another directive is
1710                 // reached.
1711                 //
1712                 bool handle_preprocessing_directive (bool caller_is_taking)
1713                 {
1714                         string cmd, arg;
1715                         bool region_directive = false;
1716
1717                         get_cmd_arg (out cmd, out arg);
1718
1719                         // Eat any trailing whitespaces and single-line comments
1720                         if (arg.IndexOf ("//") != -1)
1721                                 arg = arg.Substring (0, arg.IndexOf ("//"));
1722                         arg = arg.TrimEnd (' ', '\t');
1723
1724                         //
1725                         // The first group of pre-processing instructions is always processed
1726                         //
1727                         switch (cmd){
1728                         case "pragma":
1729                                 if (RootContext.Version == LanguageVersion.ISO_1) {
1730                                         Report.FeatureIsNotStandardized (Location, "#pragma");
1731                                         return caller_is_taking;
1732                                 }
1733
1734                                 PreProcessPragma (arg);
1735                                 return caller_is_taking;
1736                                 
1737                         case "line":
1738                                 if (!PreProcessLine (arg))
1739                                         Report.Error (
1740                                                 1576, Location,
1741                                                 "Argument to #line directive is missing or invalid");
1742                                 return caller_is_taking;
1743
1744                         case "region":
1745                                 region_directive = true;
1746                                 arg = "true";
1747                                 goto case "if";
1748
1749                         case "endregion":
1750                                 region_directive = true;
1751                                 goto case "endif";
1752                                 
1753                         case "if":
1754                                 if (arg == ""){
1755                                         Error_InvalidDirective ();
1756                                         return true;
1757                                 }
1758                                 bool taking = false;
1759                                 if (ifstack == null)
1760                                         ifstack = new Stack ();
1761
1762                                 if (ifstack.Count == 0){
1763                                         taking = true;
1764                                 } else {
1765                                         int state = (int) ifstack.Peek ();
1766                                         if ((state & TAKING) != 0)
1767                                                 taking = true;
1768                                 }
1769
1770                                 if (eval (arg) && taking){
1771                                         int push = TAKING | TAKEN_BEFORE | PARENT_TAKING;
1772                                         if (region_directive)
1773                                                 push |= REGION;
1774                                         ifstack.Push (push);
1775                                         return true;
1776                                 } else {
1777                                         int push = (taking ? PARENT_TAKING : 0);
1778                                         if (region_directive)
1779                                                 push |= REGION;
1780                                         ifstack.Push (push);
1781                                         return false;
1782                                 }
1783                                 
1784                         case "endif":
1785                                 if (ifstack == null || ifstack.Count == 0){
1786                                         Error_UnexpectedDirective ("no #if for this #endif");
1787                                         return true;
1788                                 } else {
1789                                         int pop = (int) ifstack.Pop ();
1790                                         
1791                                         if (region_directive && ((pop & REGION) == 0))
1792                                                 Report.Error (1027, Location, "#endif directive expected");
1793                                         else if (!region_directive && ((pop & REGION) != 0))
1794                                                 Report.Error (1038, Location, "#endregion directive expected");
1795                                         
1796                                         if (ifstack.Count == 0)
1797                                                 return true;
1798                                         else {
1799                                                 int state = (int) ifstack.Peek ();
1800
1801                                                 if ((state & TAKING) != 0)
1802                                                         return true;
1803                                                 else
1804                                                         return false;
1805                                         }
1806                                 }
1807
1808                         case "elif":
1809                                 if (ifstack == null || ifstack.Count == 0){
1810                                         Error_UnexpectedDirective ("no #if for this #elif");
1811                                         return true;
1812                                 } else {
1813                                         int state = (int) ifstack.Peek ();
1814
1815                                         if ((state & REGION) != 0) {
1816                                                 Report.Error (1038, Location, "#endregion directive expected");
1817                                                 return true;
1818                                         }
1819
1820                                         if ((state & ELSE_SEEN) != 0){
1821                                                 Error_UnexpectedDirective ("#elif not valid after #else");
1822                                                 return true;
1823                                         }
1824
1825                                         if ((state & (TAKEN_BEFORE | TAKING)) != 0)
1826                                                 return false;
1827
1828                                         if (eval (arg) && ((state & PARENT_TAKING) != 0)){
1829                                                 state = (int) ifstack.Pop ();
1830                                                 ifstack.Push (state | TAKING | TAKEN_BEFORE);
1831                                                 return true;
1832                                         } else 
1833                                                 return false;
1834                                 }
1835
1836                         case "else":
1837                                 if (ifstack == null || ifstack.Count == 0){
1838                                         Report.Error (
1839                                                 1028, Location,
1840                                                 "Unexpected processor directive (no #if for this #else)");
1841                                         return true;
1842                                 } else {
1843                                         int state = (int) ifstack.Peek ();
1844
1845                                         if ((state & REGION) != 0) {
1846                                                 Report.Error (1038, Location, "#endregion directive expected");
1847                                                 return true;
1848                                         }
1849
1850                                         if ((state & ELSE_SEEN) != 0){
1851                                                 Error_UnexpectedDirective ("#else within #else");
1852                                                 return true;
1853                                         }
1854
1855                                         ifstack.Pop ();
1856
1857                                         bool ret;
1858                                         if ((state & TAKEN_BEFORE) == 0){
1859                                                 ret = ((state & PARENT_TAKING) != 0);
1860                                         } else
1861                                                 ret = false;
1862                                         
1863                                         if (ret)
1864                                                 state |= TAKING;
1865                                         else
1866                                                 state &= ~TAKING;
1867                                         
1868                                         ifstack.Push (state | ELSE_SEEN);
1869                                         
1870                                         return ret;
1871                                 }
1872                         }
1873
1874                         //
1875                         // These are only processed if we are in a `taking' block
1876                         //
1877                         if (!caller_is_taking)
1878                                 return false;
1879                                         
1880                         switch (cmd){
1881                         case "define":
1882                                 if (any_token_seen){
1883                                         Error_TokensSeen ();
1884                                         return true;
1885                                 }
1886                                 PreProcessDefinition (true, arg);
1887                                 return true;
1888
1889                         case "undef":
1890                                 if (any_token_seen){
1891                                         Error_TokensSeen ();
1892                                         return true;
1893                                 }
1894                                 PreProcessDefinition (false, arg);
1895                                 return true;
1896
1897                         case "error":
1898                                 Report.Error (1029, Location, "#error: '" + arg + "'");
1899                                 return true;
1900
1901                         case "warning":
1902                                 Report.Warning (1030, Location, "#warning: '{0}'", arg);
1903                                 return true;
1904                         }
1905
1906                         Report.Error (1024, Location, "Preprocessor directive expected (got: " + cmd + ")");
1907                         return true;
1908
1909                 }
1910
1911                 private int consume_string (bool quoted) 
1912                 {
1913                         int c;
1914                         string_builder.Length = 0;
1915                                                                 
1916                         while ((c = getChar ()) != -1){
1917                                 if (c == '"'){
1918                                         if (quoted && peekChar () == '"'){
1919                                                 string_builder.Append ((char) c);
1920                                                 getChar ();
1921                                                 continue;
1922                                         } else {
1923                                                 val = string_builder.ToString ();
1924                                                 return Token.LITERAL_STRING;
1925                                         }
1926                                 }
1927
1928                                 if (c == '\n'){
1929                                         if (!quoted)
1930                                                 Report.Error (1010, Location, "Newline in constant");
1931                                         line++;
1932                                         ref_line++;
1933                                         col = 0;
1934                                 } else
1935                                         col++;
1936
1937                                 if (!quoted){
1938                                         c = escape (c);
1939                                         if (c == -1)
1940                                                 return Token.ERROR;
1941                                 }
1942                                 string_builder.Append ((char) c);
1943                         }
1944
1945                         Report.Error (1039, Location, "Unterminated string literal");
1946                         return Token.EOF;
1947                 }
1948
1949                 private int consume_identifier (int s)
1950                 {
1951                         int res = consume_identifier (s, false);
1952
1953                         if (doc_state == XmlCommentState.Allowed)
1954                                 doc_state = XmlCommentState.NotAllowed;
1955                         switch (res) {
1956                         case Token.USING:
1957                         case Token.NAMESPACE:
1958                                 check_incorrect_doc_comment ();
1959                                 break;
1960                         }
1961
1962                         if (res == Token.PARTIAL) {
1963                                 // Save current position and parse next token.
1964                                 int old = reader.Position;
1965                                 int old_putback = putback_char;
1966
1967                                 putback_char = -1;
1968
1969                                 int next_token = token ();
1970                                 bool ok = (next_token == Token.CLASS) ||
1971                                         (next_token == Token.STRUCT) ||
1972                                         (next_token == Token.INTERFACE);
1973
1974                                 reader.Position = old;
1975                                 putback_char = old_putback;
1976
1977                                 if (ok)
1978                                         return res;
1979                                 else {
1980                                         val = "partial";
1981                                         return Token.IDENTIFIER;
1982                                 }
1983                         }
1984
1985                         return res;
1986                 }
1987
1988                 private int consume_identifier (int s, bool quoted) 
1989                 {
1990                         int pos = 1;
1991                         int c;
1992                         
1993                         id_builder [0] = (char) s;
1994                                         
1995                         while ((c = reader.Read ()) != -1) {
1996                                 if (is_identifier_part_character ((char) c)){
1997                                         if (pos == max_id_size){
1998                                                 Report.Error (645, Location, "Identifier too long (limit is 512 chars)");
1999                                                 return Token.ERROR;
2000                                         }
2001                                         
2002                                         id_builder [pos++] = (char) c;
2003                                         putback_char = -1;
2004                                         col++;
2005                                 } else {
2006                                         putback_char = c;
2007                                         break;
2008                                 }
2009                         }
2010
2011                         //
2012                         // Optimization: avoids doing the keyword lookup
2013                         // on uppercase letters and _
2014                         //
2015                         if (!quoted && (s >= 'a' || s == '_')){
2016                                 int keyword = GetKeyword (id_builder, pos);
2017                                 if (keyword != -1)
2018                                 return keyword;
2019                         }
2020
2021                         //
2022                         // Keep identifiers in an array of hashtables to avoid needless
2023                         // allocations
2024                         //
2025
2026                         if (identifiers [pos] != null) {
2027                                 val = identifiers [pos][id_builder];
2028                                 if (val != null) {
2029                                         return Token.IDENTIFIER;
2030                                 }
2031                         }
2032                         else
2033                                 identifiers [pos] = new CharArrayHashtable (pos);
2034
2035                         val = new String (id_builder, 0, pos);
2036
2037                         char [] chars = new char [pos];
2038                         Array.Copy (id_builder, chars, pos);
2039
2040                         identifiers [pos] [chars] = val;
2041
2042                         return Token.IDENTIFIER;
2043                 }
2044
2045                 int consume_whitespace ()
2046                 {
2047                         int c;
2048
2049                         // Whether we have seen comments on the current line
2050                         bool comments_seen = false;
2051                         
2052                         val = null;
2053                         // optimization: eliminate col and implement #directive semantic correctly.
2054                         for (;(c = getChar ()) != -1; col++) {
2055                                 if (c == ' ')
2056                                         continue;
2057                                 
2058                                 if (c == '\t') {
2059                                         col = (((col + 8) / 8) * 8) - 1;
2060                                         continue;
2061                                 }
2062                                 
2063                                 if (c == ' ' || c == '\f' || c == '\v' || c == 0xa0)
2064                                         continue;
2065
2066                                 if (c == '\r') {
2067                                         if (peekChar () == '\n')
2068                                                 getChar ();
2069
2070                                         line++;
2071                                         ref_line++;
2072                                         col = 0;
2073                                         any_token_seen |= tokens_seen;
2074                                         tokens_seen = false;
2075                                         comments_seen = false;
2076                                         continue;
2077                                 }
2078
2079                                 // Handle double-slash comments.
2080                                 if (c == '/'){
2081                                         int d = peekChar ();
2082                                 
2083                                         if (d == '/'){
2084                                                 getChar ();
2085                                                 if (RootContext.Documentation != null && peekChar () == '/') {
2086                                                         getChar ();
2087                                                         // Don't allow ////.
2088                                                         if ((d = peekChar ()) != '/') {
2089                                                                 if (doc_state == XmlCommentState.Allowed)
2090                                                                         handle_one_line_xml_comment ();
2091                                                                 else if (doc_state == XmlCommentState.NotAllowed)
2092                                                                         warn_incorrect_doc_comment ();
2093                                                         }
2094                                                 }
2095                                                 while ((d = getChar ()) != -1 && (d != '\n') && d != '\r')
2096                                                         col++;
2097                                                 if (d == '\n'){
2098                                                         line++;
2099                                                         ref_line++;
2100                                                         col = 0;
2101                                                 }
2102                                                 any_token_seen |= tokens_seen;
2103                                                 tokens_seen = false;
2104                                                 comments_seen = false;
2105                                                 continue;
2106                                         } else if (d == '*'){
2107                                                 getChar ();
2108                                                 bool docAppend = false;
2109                                                 if (RootContext.Documentation != null && peekChar () == '*') {
2110                                                         getChar ();
2111                                                         // But when it is /**/, just do nothing.
2112                                                         if (peekChar () == '/') {
2113                                                                 getChar ();
2114                                                                 continue;
2115                                                         }
2116                                                         if (doc_state == XmlCommentState.Allowed)
2117                                                                 docAppend = true;
2118                                                         else if (doc_state == XmlCommentState.NotAllowed)
2119                                                                 warn_incorrect_doc_comment ();
2120                                                 }
2121
2122                                                 int current_comment_start = 0;
2123                                                 if (docAppend) {
2124                                                         current_comment_start = xml_comment_buffer.Length;
2125                                                         xml_comment_buffer.Append (Environment.NewLine);
2126                                                 }
2127
2128                                                 while ((d = getChar ()) != -1){
2129                                                         if (d == '*' && peekChar () == '/'){
2130                                                                 getChar ();
2131                                                                 col++;
2132                                                                 comments_seen = true;
2133                                                                 break;
2134                                                         }
2135                                                         if (docAppend)
2136                                                                 xml_comment_buffer.Append ((char) d);
2137                                                         
2138                                                         if (d == '\n'){
2139                                                                 line++;
2140                                                                 ref_line++;
2141                                                                 col = 0;
2142                                                                 any_token_seen |= tokens_seen;
2143                                                                 tokens_seen = false;
2144                                                                 // 
2145                                                                 // Reset 'comments_seen' just to be consistent.
2146                                                                 // It doesn't matter either way, here.
2147                                                                 //
2148                                                                 comments_seen = false;
2149                                                         }
2150                                                 }
2151                                                 if (docAppend)
2152                                                         update_formatted_doc_comment (current_comment_start);
2153                                                 continue;
2154                                         }
2155                                         goto is_punct_label;
2156                                 }
2157
2158                         is_punct_label:
2159                                 // white space
2160                                 if (c == '\n'){
2161                                         line++;
2162                                         ref_line++;
2163                                         col = 0;
2164                                         any_token_seen |= tokens_seen;
2165                                         tokens_seen = false;
2166                                         comments_seen = false;
2167                                         continue;
2168                                 }
2169
2170                                 /* For now, ignore pre-processor commands */
2171                                 // FIXME: In C# the '#' is not limited to appear
2172                                 // on the first column.
2173                                 if (c == '#') {
2174                                         bool cont = true;
2175                                         
2176                                         if (tokens_seen || comments_seen) {
2177                                                error_details = "Preprocessor directives must appear as the first non-whitespace " +
2178                                                        "character on a line.";
2179
2180                                                Report.Error (1040, Location, error_details);
2181
2182                                                return Token.ERROR;
2183                                        }
2184                                         
2185                                 start_again:
2186                                         
2187                                         cont = handle_preprocessing_directive (cont);
2188
2189                                         if (cont){
2190                                                 col = 0;
2191                                                 continue;
2192                                         }
2193                                         col = 1;
2194
2195                                         bool skipping = false;
2196                                         for (;(c = getChar ()) != -1; col++){
2197                                                 if (c == '\n'){
2198                                                         col = 0;
2199                                                         line++;
2200                                                         ref_line++;
2201                                                         skipping = false;
2202                                                 } else if (c == ' ' || c == '\t' || c == '\v' || c == '\r' || c == 0xa0)
2203                                                         continue;
2204                                                 else if (c != '#')
2205                                                         skipping = true;
2206                                                 if (c == '#' && !skipping)
2207                                                         goto start_again;
2208                                         }
2209                                         any_token_seen |= tokens_seen;
2210                                         tokens_seen = false;
2211                                         if (c == -1)
2212                                                 Report.Error (1027, Location, "#endif/#endregion expected");
2213                                         continue;
2214                                 }
2215
2216                                 return c;
2217                         }
2218
2219                         return -1;
2220                 }
2221                 
2222                 public int xtoken ()
2223                 {
2224                         int t;
2225                         bool doread = false;
2226                         int c;
2227
2228                         val = null;
2229                         // optimization: eliminate col and implement #directive semantic correctly.
2230
2231                         c = consume_whitespace ();
2232                         if (c == -1)
2233                                 return Token.EOF;
2234
2235                         if (is_identifier_start_character ((char)c)){
2236                                 tokens_seen = true;
2237                                         return consume_identifier (c);
2238                         }
2239
2240                 is_punct_label:
2241                         if ((t = is_punct ((char)c, ref doread)) != Token.ERROR){
2242                                 tokens_seen = true;
2243                                 if (doread){
2244                                         getChar ();
2245                                         col++;
2246                                 }
2247                                 return t;
2248                         }
2249
2250                         if (c >= '0' && c <= '9'){
2251                                 tokens_seen = true;
2252                                 return is_number (c);
2253                         }
2254
2255                         if (c == '.'){
2256                                 tokens_seen = true;
2257                                 int peek = peekChar ();
2258                                 if (peek >= '0' && peek <= '9')
2259                                         return is_number (c);
2260                                 return Token.DOT;
2261                         }
2262
2263                         if (c == '"') 
2264                                 return consume_string (false);
2265
2266                         if (c == '\''){
2267                                 c = getChar ();
2268                                 tokens_seen = true;
2269                                 if (c == '\''){
2270                                         error_details = "Empty character literal";
2271                                         Report.Error (1011, Location, error_details);
2272                                         return Token.ERROR;
2273                                 }
2274                                 c = escape (c);
2275                                 if (c == -1)
2276                                         return Token.ERROR;
2277                                 val = new System.Char ();
2278                                 val = (char) c;
2279                                 c = getChar ();
2280
2281                                 if (c != '\''){
2282                                         error_details = "Too many characters in character literal";
2283                                         Report.Error (1012, Location, error_details);
2284
2285                                         // Try to recover, read until newline or next "'"
2286                                         while ((c = getChar ()) != -1){
2287                                                 if (c == '\n' || c == '\''){
2288                                                         line++;
2289                                                         ref_line++;
2290                                                         col = 0;
2291                                                         break;
2292                                                 } else
2293                                                         col++;
2294                                         }
2295                                         return Token.ERROR;
2296                                 }
2297                                 return Token.LITERAL_CHARACTER;
2298                         }
2299                                 
2300                         if (c == '@') {
2301                                 c = getChar ();
2302                                 if (c == '"') {
2303                                         tokens_seen = true;
2304                                         return consume_string (true);
2305                                 } else if (is_identifier_start_character ((char) c)){
2306                                         return consume_identifier (c, true);
2307                                 } else {
2308                                         Report.Error (1646, Location, "Keyword, identifier, or string expected after verbatim specifier: @");
2309                                 }
2310                         }
2311
2312                         if (c == '#') {
2313                                 error_details = "Preprocessor directives must appear as the first non-whitespace " +
2314                                         "character on a line.";
2315
2316                                 Report.Error (1040, Location, error_details);
2317
2318                                 return Token.ERROR;
2319                         }
2320
2321                         error_details = ((char)c).ToString ();
2322
2323                         return Token.ERROR;
2324                 }
2325
2326                 //
2327                 // Handles one line xml comment
2328                 //
2329                 private void handle_one_line_xml_comment ()
2330                 {
2331                         int c;
2332                         while ((c = peekChar ()) == ' ')
2333                                 getChar (); // skip heading whitespaces.
2334                         while ((c = peekChar ()) != -1 && c != '\n' && c != '\r') {
2335                                 col++;
2336                                 xml_comment_buffer.Append ((char) getChar ());
2337                         }
2338                         if (c == '\r' || c == '\n')
2339                                 xml_comment_buffer.Append (Environment.NewLine);
2340                 }
2341
2342                 //
2343                 // Remove heading "*" in Javadoc-like xml documentation.
2344                 //
2345                 private void update_formatted_doc_comment (int current_comment_start)
2346                 {
2347                         int length = xml_comment_buffer.Length - current_comment_start;
2348                         string [] lines = xml_comment_buffer.ToString (
2349                                 current_comment_start,
2350                                 length).Replace ("\r", "").Split ('\n');
2351                         
2352                         // The first line starts with /**, thus it is not target
2353                         // for the format check.
2354                         for (int i = 1; i < lines.Length; i++) {
2355                                 string s = lines [i];
2356                                 int idx = s.IndexOf ('*');
2357                                 string head = null;
2358                                 if (idx < 0) {
2359                                         if (i < lines.Length - 1)
2360                                                 return;
2361                                         head = s;
2362                                 } else
2363                                         head = s.Substring (0, idx);
2364                                 foreach (char c in head)
2365                                         if (c != ' ')
2366                                                 return;
2367                                 lines [i] = s.Substring (idx + 1);
2368                         }
2369                         xml_comment_buffer.Remove (current_comment_start, length);
2370                         xml_comment_buffer.Insert (current_comment_start, String.Join (Environment.NewLine, lines));
2371                 }
2372
2373                 //
2374                 // Checks if there was incorrect doc comments and raise
2375                 // warnings.
2376                 //
2377                 public void check_incorrect_doc_comment ()
2378                 {
2379                         if (xml_comment_buffer.Length > 0)
2380                                 warn_incorrect_doc_comment ();
2381                 }
2382
2383                 //
2384                 // Raises a warning when tokenizer found incorrect doccomment
2385                 // markup.
2386                 //
2387                 private void warn_incorrect_doc_comment ()
2388                 {
2389                         doc_state = XmlCommentState.Error;
2390                         // in csc, it is 'XML comment is not placed on a valid 
2391                         // language element'. But that does not make sense.
2392                         Report.Warning (1587, 2, Location, "XML comment is placed on an invalid language element which can not accept it.");
2393                 }
2394
2395                 //
2396                 // Consumes the saved xml comment lines (if any)
2397                 // as for current target member or type.
2398                 //
2399                 public string consume_doc_comment ()
2400                 {
2401                         if (xml_comment_buffer.Length > 0) {
2402                                 string ret = xml_comment_buffer.ToString ();
2403                                 xml_comment_buffer.Length = 0;
2404                                 return ret;
2405                         }
2406                         return null;
2407                 }
2408
2409                 public void cleanup ()
2410                 {
2411                         if (ifstack != null && ifstack.Count >= 1) {
2412                                 int state = (int) ifstack.Pop ();
2413                                 if ((state & REGION) != 0)
2414                                         Report.Error (1038, Location, "#endregion directive expected");
2415                                 else 
2416                                         Report.Error (1027, Location, "#endif directive expected");
2417                         }
2418                                 
2419                 }
2420         }
2421
2422         //
2423         // Indicates whether it accepts XML documentation or not.
2424         //
2425         public enum XmlCommentState {
2426                 // comment is allowed in this state.
2427                 Allowed,
2428                 // comment is not allowed in this state.
2429                 NotAllowed,
2430                 // once comments appeared when it is NotAllowed, then the
2431                 // state is changed to it, until the state is changed to
2432                 // .Allowed.
2433                 Error
2434         }
2435 }
2436