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