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