Merge pull request #498 from Unroll-Me/master
[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@gmail.com)
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 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 //
14
15 using System;
16 using System.Text;
17 using System.Collections.Generic;
18 using System.Globalization;
19 using System.Diagnostics;
20 using System.Collections;
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                 class KeywordEntry<T>
31                 {
32                         public readonly T Token;
33                         public KeywordEntry<T> Next;
34                         public readonly char[] Value;
35
36                         public KeywordEntry (string value, T token)
37                         {
38                                 this.Value = value.ToCharArray ();
39                                 this.Token = token;
40                         }
41                 }
42
43                 sealed class IdentifiersComparer : IEqualityComparer<char[]>
44                 {
45                         readonly int length;
46
47                         public IdentifiersComparer (int length)
48                         {
49                                 this.length = length;
50                         }
51
52                         public bool Equals (char[] x, char[] y)
53                         {
54                                 for (int i = 0; i < length; ++i)
55                                         if (x [i] != y [i])
56                                                 return false;
57
58                                 return true;
59                         }
60
61                         public int GetHashCode (char[] obj)
62                         {
63                                 int h = 0;
64                                 for (int i = 0; i < length; ++i)
65                                         h = (h << 5) - h + obj [i];
66
67                                 return h;
68                         }
69                 }
70
71                 //
72                 // This class has to be used by parser only, it reuses token
73                 // details after each file parse completion
74                 //
75                 public class LocatedToken
76                 {
77                         public int row, column;
78                         public string value;
79                         public SourceFile file;
80
81                         public LocatedToken ()
82                         {
83                         }
84
85                         public LocatedToken (string value, Location loc)
86                         {
87                                 this.value = value;
88                                 file = loc.SourceFile;
89                                 row = loc.Row;
90                                 column = loc.Column;
91                         }
92
93                         public override string ToString ()
94                         {
95                                 return string.Format ("Token '{0}' at {1},{2}", Value, row, column);
96                         }
97                         
98                         public Location Location {
99                                 get { return new Location (file, row, column); }
100                         }
101
102                         public string Value {
103                                 get { return value; }
104                         }
105                 }
106
107                 public class LocatedTokenBuffer
108                 {
109                         readonly LocatedToken[] buffer;
110                         public int pos;
111
112                         public LocatedTokenBuffer ()
113                         {
114                                 buffer = new LocatedToken[0];
115                         }
116
117                         public LocatedTokenBuffer (LocatedToken[] buffer)
118                         {
119                                 this.buffer = buffer ?? new LocatedToken[0];
120                         }
121
122                         public LocatedToken Create (SourceFile file, int row, int column)
123                         {
124                                 return Create (null, file, row, column);
125                         }
126
127                         public LocatedToken Create (string value, SourceFile file, int row, int column)
128                         {
129                                 //
130                                 // TODO: I am not very happy about the logic but it's the best
131                                 // what I could come up with for now.
132                                 // Ideally we should be using just tiny buffer (256 elements) which
133                                 // is enough to hold all details for currect stack and recycle elements
134                                 // poped from the stack but there is a trick needed to recycle
135                                 // them properly.
136                                 //
137                                 LocatedToken entry;
138                                 if (pos >= buffer.Length) {
139                                         entry = new LocatedToken ();
140                                 } else {
141                                         entry = buffer[pos];
142                                         if (entry == null) {
143                                                 entry = new LocatedToken ();
144                                                 buffer[pos] = entry;
145                                         }
146
147                                         ++pos;
148                                 }
149                                 entry.value = value;
150                                 entry.file = file;
151                                 entry.row = row;
152                                 entry.column = column;
153                                 return entry;
154                         }
155
156                         //
157                         // Used for token not required by expression evaluator
158                         //
159                         [Conditional ("FULL_AST")]
160                         public void CreateOptional (SourceFile file, int row, int col, ref object token)
161                         {
162                                 token = Create (file, row, col);
163                         }
164                 }
165
166                 public enum PreprocessorDirective
167                 {
168                         Invalid = 0,
169
170                         Region = 1,
171                         Endregion = 2,
172                         If = 3 | RequiresArgument,
173                         Endif = 4,
174                         Elif = 5 | RequiresArgument,
175                         Else = 6,
176                         Define = 7 | RequiresArgument,
177                         Undef = 8 | RequiresArgument,
178                         Error = 9,
179                         Warning = 10,
180                         Pragma = 11 | CustomArgumentsParsing,
181                         Line = 12 | CustomArgumentsParsing,
182
183                         CustomArgumentsParsing = 1 << 10,
184                         RequiresArgument = 1 << 11
185                 }
186
187                 readonly SeekableStreamReader reader;
188                 readonly CompilationSourceFile source_file;
189                 readonly CompilerContext context;
190
191                 SourceFile current_source;
192                 Location hidden_block_start;
193                 int ref_line = 1;
194                 int line = 1;
195                 int col = 0;
196                 int previous_col;
197                 int current_token;
198                 readonly int tab_size;
199                 bool handle_get_set = false;
200                 bool handle_remove_add = false;
201                 bool handle_where = false;
202                 bool handle_typeof = false;
203                 bool lambda_arguments_parsing;
204                 List<Location> escaped_identifiers;
205                 int parsing_generic_less_than;
206                 readonly bool doc_processing;
207                 readonly LocatedTokenBuffer ltb;
208                 
209                 //
210                 // Used mainly for parser optimizations. Some expressions for instance
211                 // can appear only in block (including initializer, base initializer)
212                 // scope only
213                 //
214                 public int parsing_block;
215                 internal bool query_parsing;
216                 
217                 // 
218                 // When parsing type only, useful for ambiguous nullable types
219                 //
220                 public int parsing_type;
221                 
222                 //
223                 // Set when parsing generic declaration (type or method header)
224                 //
225                 public bool parsing_generic_declaration;
226                 public bool parsing_generic_declaration_doc;
227                 
228                 //
229                 // The value indicates that we have not reach any declaration or
230                 // namespace yet
231                 //
232                 public int parsing_declaration;
233
234                 public bool parsing_attribute_section;
235
236                 public bool parsing_modifiers;
237
238                 //
239                 // The special characters to inject on streams to run the unit parser
240                 // in the special expression mode. Using private characters from
241                 // Plane Sixteen (U+100000 to U+10FFFD)
242                 //
243                 // This character is only tested just before the tokenizer is about to report
244                 // an error;   So on the regular operation mode, this addition will have no
245                 // impact on the tokenizer's performance.
246                 //
247                 
248                 public const int EvalStatementParserCharacter = 0x100000;
249                 public const int EvalCompilationUnitParserCharacter = 0x100001;
250                 public const int EvalUsingDeclarationsParserCharacter = 0x100002;
251                 public const int DocumentationXref = 0x100003;
252                 
253                 //
254                 // XML documentation buffer. The save point is used to divide
255                 // comments on types and comments on members.
256                 //
257                 StringBuilder xml_comment_buffer;
258
259                 //
260                 // See comment on XmlCommentState enumeration.
261                 //
262                 XmlCommentState xml_doc_state = XmlCommentState.Allowed;
263
264                 //
265                 // Whether tokens have been seen on this line
266                 //
267                 bool tokens_seen = false;
268
269                 //
270                 // Set to true once the GENERATE_COMPLETION token has bee
271                 // returned.   This helps produce one GENERATE_COMPLETION,
272                 // as many COMPLETE_COMPLETION as necessary to complete the
273                 // AST tree and one final EOF.
274                 //
275                 bool generated;
276                 
277                 //
278                 // Whether a token has been seen on the file
279                 // This is needed because `define' is not allowed to be used
280                 // after a token has been seen.
281                 //
282                 bool any_token_seen;
283
284                 //
285                 // Class variables
286                 // 
287                 static readonly KeywordEntry<int>[][] keywords;
288                 static readonly KeywordEntry<PreprocessorDirective>[][] keywords_preprocessor;
289                 static readonly HashSet<string> keyword_strings;
290                 static readonly NumberStyles styles;
291                 static readonly NumberFormatInfo csharp_format_info;
292
293                 // Pragma arguments
294                 static readonly char[] pragma_warning = "warning".ToCharArray ();
295                 static readonly char[] pragma_warning_disable = "disable".ToCharArray ();
296                 static readonly char[] pragma_warning_restore = "restore".ToCharArray ();
297                 static readonly char[] pragma_checksum = "checksum".ToCharArray ();
298                 static readonly char[] line_hidden = "hidden".ToCharArray ();
299                 static readonly char[] line_default = "default".ToCharArray ();
300
301                 static readonly char[] simple_whitespaces = new char[] { ' ', '\t' };
302
303                 public bool PropertyParsing {
304                         get { return handle_get_set; }
305                         set { handle_get_set = value; }
306                 }
307
308                 public bool EventParsing {
309                         get { return handle_remove_add; }
310                         set { handle_remove_add = value; }
311                 }
312
313                 public bool ConstraintsParsing {
314                         get { return handle_where; }
315                         set { handle_where = value; }
316                 }
317
318                 public bool TypeOfParsing {
319                         get { return handle_typeof; }
320                         set { handle_typeof = value; }
321                 }
322         
323                 public XmlCommentState doc_state {
324                         get { return xml_doc_state; }
325                         set {
326                                 if (value == XmlCommentState.Allowed) {
327                                         check_incorrect_doc_comment ();
328                                         reset_doc_comment ();
329                                 }
330                                 xml_doc_state = value;
331                         }
332                 }
333
334                 //
335                 // This is used to trigger completion generation on the parser
336                 public bool CompleteOnEOF;
337                 
338                 void AddEscapedIdentifier (Location loc)
339                 {
340                         if (escaped_identifiers == null)
341                                 escaped_identifiers = new List<Location> ();
342
343                         escaped_identifiers.Add (loc);
344                 }
345
346                 public bool IsEscapedIdentifier (ATypeNameExpression name)
347                 {
348                         return escaped_identifiers != null && escaped_identifiers.Contains (name.Location);
349                 }
350
351                 //
352                 // Values for the associated token returned
353                 //
354                 internal int putback_char;      // Used by repl only
355                 object val;
356
357                 //
358                 // Pre-processor
359                 //
360                 const int TAKING        = 1;
361                 const int ELSE_SEEN     = 4;
362                 const int PARENT_TAKING = 8;
363                 const int REGION        = 16;           
364
365                 //
366                 // pre-processor if stack state:
367                 //
368                 Stack<int> ifstack;
369
370                 public const int MaxIdentifierLength = 512;
371                 public const int MaxNumberLength = 512;
372
373                 readonly char[] id_builder;
374                 readonly Dictionary<char[], string>[] identifiers;
375                 readonly char[] number_builder;
376                 int number_pos;
377
378                 char[] value_builder = new char[64];
379
380                 public int Line {
381                         get {
382                                 return ref_line;
383                         }
384                 }
385
386                 //
387                 // This is used when the tokenizer needs to save
388                 // the current position as it needs to do some parsing
389                 // on its own to deamiguate a token in behalf of the
390                 // parser.
391                 //
392                 Stack<Position> position_stack = new Stack<Position> (2);
393
394                 class Position {
395                         public int position;
396                         public int line;
397                         public int ref_line;
398                         public int col;
399                         public Location hidden;
400                         public int putback_char;
401                         public int previous_col;
402                         public Stack<int> ifstack;
403                         public int parsing_generic_less_than;
404                         public int current_token;
405                         public object val;
406
407                         public Position (Tokenizer t)
408                         {
409                                 position = t.reader.Position;
410                                 line = t.line;
411                                 ref_line = t.ref_line;
412                                 col = t.col;
413                                 hidden = t.hidden_block_start;
414                                 putback_char = t.putback_char;
415                                 previous_col = t.previous_col;
416                                 if (t.ifstack != null && t.ifstack.Count != 0) {
417                                         // There is no simple way to clone Stack<T> all
418                                         // methods reverse the order
419                                         var clone = t.ifstack.ToArray ();
420                                         Array.Reverse (clone);
421                                         ifstack = new Stack<int> (clone);
422                                 }
423                                 parsing_generic_less_than = t.parsing_generic_less_than;
424                                 current_token = t.current_token;
425                                 val = t.val;
426                         }
427                 }
428
429                 public Tokenizer (SeekableStreamReader input, CompilationSourceFile file, ParserSession session)
430                 {
431                         this.source_file = file;
432                         this.context = file.Compiler;
433                         this.current_source = file.SourceFile;
434                         this.identifiers = session.Identifiers;
435                         this.id_builder = session.IDBuilder;
436                         this.number_builder = session.NumberBuilder;
437                         this.ltb = new LocatedTokenBuffer (session.LocatedTokens);
438
439                         reader = input;
440
441                         putback_char = -1;
442
443                         xml_comment_buffer = new StringBuilder ();
444                         doc_processing = context.Settings.DocumentationFile != null;
445
446                         tab_size = context.Settings.TabSize;
447                 }
448                 
449                 public void PushPosition ()
450                 {
451                         position_stack.Push (new Position (this));
452                 }
453
454                 public void PopPosition ()
455                 {
456                         Position p = position_stack.Pop ();
457
458                         reader.Position = p.position;
459                         ref_line = p.ref_line;
460                         line = p.line;
461                         col = p.col;
462                         hidden_block_start = p.hidden;
463                         putback_char = p.putback_char;
464                         previous_col = p.previous_col;
465                         ifstack = p.ifstack;
466                         parsing_generic_less_than = p.parsing_generic_less_than;
467                         current_token = p.current_token;
468                         val = p.val;
469                 }
470
471                 // Do not reset the position, ignore it.
472                 public void DiscardPosition ()
473                 {
474                         position_stack.Pop ();
475                 }
476                 
477                 static void AddKeyword (string kw, int token)
478                 {
479                         keyword_strings.Add (kw);
480
481                         AddKeyword (keywords, kw, token);
482                 }
483
484                 static void AddPreprocessorKeyword (string kw, PreprocessorDirective directive)
485                 {
486                         AddKeyword (keywords_preprocessor, kw, directive);
487                 }
488
489                 static void AddKeyword<T> (KeywordEntry<T>[][] keywords, string kw, T token)
490                 {
491                         int length = kw.Length;
492                         if (keywords[length] == null) {
493                                 keywords[length] = new KeywordEntry<T>['z' - '_' + 1];
494                         }
495
496                         int char_index = kw[0] - '_';
497                         var kwe = keywords[length][char_index];
498                         if (kwe == null) {
499                                 keywords[length][char_index] = new KeywordEntry<T> (kw, token);
500                                 return;
501                         }
502
503                         while (kwe.Next != null) {
504                                 kwe = kwe.Next;
505                         }
506
507                         kwe.Next = new KeywordEntry<T> (kw, token);
508                 }
509
510                 //
511                 // Class initializer
512                 // 
513                 static Tokenizer ()
514                 {
515                         keyword_strings = new HashSet<string> ();
516
517                         // 11 is the length of the longest keyword for now
518                         keywords = new KeywordEntry<int>[11][];
519
520                         AddKeyword ("__arglist", Token.ARGLIST);
521                         AddKeyword ("__makeref", Token.MAKEREF);
522                         AddKeyword ("__reftype", Token.REFTYPE);
523                         AddKeyword ("__refvalue", Token.REFVALUE);
524                         AddKeyword ("abstract", Token.ABSTRACT);
525                         AddKeyword ("as", Token.AS);
526                         AddKeyword ("add", Token.ADD);
527                         AddKeyword ("base", Token.BASE);
528                         AddKeyword ("bool", Token.BOOL);
529                         AddKeyword ("break", Token.BREAK);
530                         AddKeyword ("byte", Token.BYTE);
531                         AddKeyword ("case", Token.CASE);
532                         AddKeyword ("catch", Token.CATCH);
533                         AddKeyword ("char", Token.CHAR);
534                         AddKeyword ("checked", Token.CHECKED);
535                         AddKeyword ("class", Token.CLASS);
536                         AddKeyword ("const", Token.CONST);
537                         AddKeyword ("continue", Token.CONTINUE);
538                         AddKeyword ("decimal", Token.DECIMAL);
539                         AddKeyword ("default", Token.DEFAULT);
540                         AddKeyword ("delegate", Token.DELEGATE);
541                         AddKeyword ("do", Token.DO);
542                         AddKeyword ("double", Token.DOUBLE);
543                         AddKeyword ("else", Token.ELSE);
544                         AddKeyword ("enum", Token.ENUM);
545                         AddKeyword ("event", Token.EVENT);
546                         AddKeyword ("explicit", Token.EXPLICIT);
547                         AddKeyword ("extern", Token.EXTERN);
548                         AddKeyword ("false", Token.FALSE);
549                         AddKeyword ("finally", Token.FINALLY);
550                         AddKeyword ("fixed", Token.FIXED);
551                         AddKeyword ("float", Token.FLOAT);
552                         AddKeyword ("for", Token.FOR);
553                         AddKeyword ("foreach", Token.FOREACH);
554                         AddKeyword ("goto", Token.GOTO);
555                         AddKeyword ("get", Token.GET);
556                         AddKeyword ("if", Token.IF);
557                         AddKeyword ("implicit", Token.IMPLICIT);
558                         AddKeyword ("in", Token.IN);
559                         AddKeyword ("int", Token.INT);
560                         AddKeyword ("interface", Token.INTERFACE);
561                         AddKeyword ("internal", Token.INTERNAL);
562                         AddKeyword ("is", Token.IS);
563                         AddKeyword ("lock", Token.LOCK);
564                         AddKeyword ("long", Token.LONG);
565                         AddKeyword ("namespace", Token.NAMESPACE);
566                         AddKeyword ("new", Token.NEW);
567                         AddKeyword ("null", Token.NULL);
568                         AddKeyword ("object", Token.OBJECT);
569                         AddKeyword ("operator", Token.OPERATOR);
570                         AddKeyword ("out", Token.OUT);
571                         AddKeyword ("override", Token.OVERRIDE);
572                         AddKeyword ("params", Token.PARAMS);
573                         AddKeyword ("private", Token.PRIVATE);
574                         AddKeyword ("protected", Token.PROTECTED);
575                         AddKeyword ("public", Token.PUBLIC);
576                         AddKeyword ("readonly", Token.READONLY);
577                         AddKeyword ("ref", Token.REF);
578                         AddKeyword ("remove", Token.REMOVE);
579                         AddKeyword ("return", Token.RETURN);
580                         AddKeyword ("sbyte", Token.SBYTE);
581                         AddKeyword ("sealed", Token.SEALED);
582                         AddKeyword ("set", Token.SET);
583                         AddKeyword ("short", Token.SHORT);
584                         AddKeyword ("sizeof", Token.SIZEOF);
585                         AddKeyword ("stackalloc", Token.STACKALLOC);
586                         AddKeyword ("static", Token.STATIC);
587                         AddKeyword ("string", Token.STRING);
588                         AddKeyword ("struct", Token.STRUCT);
589                         AddKeyword ("switch", Token.SWITCH);
590                         AddKeyword ("this", Token.THIS);
591                         AddKeyword ("throw", Token.THROW);
592                         AddKeyword ("true", Token.TRUE);
593                         AddKeyword ("try", Token.TRY);
594                         AddKeyword ("typeof", Token.TYPEOF);
595                         AddKeyword ("uint", Token.UINT);
596                         AddKeyword ("ulong", Token.ULONG);
597                         AddKeyword ("unchecked", Token.UNCHECKED);
598                         AddKeyword ("unsafe", Token.UNSAFE);
599                         AddKeyword ("ushort", Token.USHORT);
600                         AddKeyword ("using", Token.USING);
601                         AddKeyword ("virtual", Token.VIRTUAL);
602                         AddKeyword ("void", Token.VOID);
603                         AddKeyword ("volatile", Token.VOLATILE);
604                         AddKeyword ("while", Token.WHILE);
605                         AddKeyword ("partial", Token.PARTIAL);
606                         AddKeyword ("where", Token.WHERE);
607
608                         // LINQ keywords
609                         AddKeyword ("from", Token.FROM);
610                         AddKeyword ("join", Token.JOIN);
611                         AddKeyword ("on", Token.ON);
612                         AddKeyword ("equals", Token.EQUALS);
613                         AddKeyword ("select", Token.SELECT);
614                         AddKeyword ("group", Token.GROUP);
615                         AddKeyword ("by", Token.BY);
616                         AddKeyword ("let", Token.LET);
617                         AddKeyword ("orderby", Token.ORDERBY);
618                         AddKeyword ("ascending", Token.ASCENDING);
619                         AddKeyword ("descending", Token.DESCENDING);
620                         AddKeyword ("into", Token.INTO);
621
622                         // Contextual async keywords
623                         AddKeyword ("async", Token.ASYNC);
624                         AddKeyword ("await", Token.AWAIT);
625
626                         keywords_preprocessor = new KeywordEntry<PreprocessorDirective>[10][];
627
628                         AddPreprocessorKeyword ("region", PreprocessorDirective.Region);
629                         AddPreprocessorKeyword ("endregion", PreprocessorDirective.Endregion);
630                         AddPreprocessorKeyword ("if", PreprocessorDirective.If);
631                         AddPreprocessorKeyword ("endif", PreprocessorDirective.Endif);
632                         AddPreprocessorKeyword ("elif", PreprocessorDirective.Elif);
633                         AddPreprocessorKeyword ("else", PreprocessorDirective.Else);
634                         AddPreprocessorKeyword ("define", PreprocessorDirective.Define);
635                         AddPreprocessorKeyword ("undef", PreprocessorDirective.Undef);
636                         AddPreprocessorKeyword ("error", PreprocessorDirective.Error);
637                         AddPreprocessorKeyword ("warning", PreprocessorDirective.Warning);
638                         AddPreprocessorKeyword ("pragma", PreprocessorDirective.Pragma);
639                         AddPreprocessorKeyword ("line", PreprocessorDirective.Line);
640
641                         csharp_format_info = NumberFormatInfo.InvariantInfo;
642                         styles = NumberStyles.Float;
643                 }
644
645                 int GetKeyword (char[] id, int id_len)
646                 {
647                         //
648                         // Keywords are stored in an array of arrays grouped by their
649                         // length and then by the first character
650                         //
651                         if (id_len >= keywords.Length || keywords [id_len] == null)
652                                 return -1;
653
654                         int first_index = id [0] - '_';
655                         if (first_index > 'z' - '_')
656                                 return -1;
657
658                         var kwe = keywords [id_len] [first_index];
659                         if (kwe == null)
660                                 return -1;
661
662                         int res;
663                         do {
664                                 res = kwe.Token;
665                                 for (int i = 1; i < id_len; ++i) {
666                                         if (id [i] != kwe.Value [i]) {
667                                                 res = 0;
668                                                 kwe = kwe.Next;
669                                                 break;
670                                         }
671                                 }
672                         } while (res == 0 && kwe != null);
673
674                         if (res == 0)
675                                 return -1;
676
677                         int next_token;
678                         switch (res) {
679                         case Token.GET:
680                         case Token.SET:
681                                 if (!handle_get_set)
682                                         res = -1;
683                                 break;
684                         case Token.REMOVE:
685                         case Token.ADD:
686                                 if (!handle_remove_add)
687                                         res = -1;
688                                 break;
689                         case Token.EXTERN:
690                                 if (parsing_declaration == 0)
691                                         res = Token.EXTERN_ALIAS;
692                                 break;
693                         case Token.DEFAULT:
694                                 if (peek_token () == Token.COLON) {
695                                         token ();
696                                         res = Token.DEFAULT_COLON;
697                                 }
698                                 break;
699                         case Token.WHERE:
700                                 if (!handle_where && !query_parsing)
701                                         res = -1;
702                                 break;
703                         case Token.FROM:
704                                 //
705                                 // A query expression is any expression that starts with `from identifier'
706                                 // followed by any token except ; , =
707                                 // 
708                                 if (!query_parsing) {
709                                         if (lambda_arguments_parsing) {
710                                                 res = -1;
711                                                 break;
712                                         }
713
714                                         PushPosition ();
715                                         // HACK: to disable generics micro-parser, because PushPosition does not
716                                         // store identifiers array
717                                         parsing_generic_less_than = 1;
718                                         switch (xtoken ()) {
719                                         case Token.IDENTIFIER:
720                                         case Token.INT:
721                                         case Token.BOOL:
722                                         case Token.BYTE:
723                                         case Token.CHAR:
724                                         case Token.DECIMAL:
725                                         case Token.FLOAT:
726                                         case Token.LONG:
727                                         case Token.OBJECT:
728                                         case Token.STRING:
729                                         case Token.UINT:
730                                         case Token.ULONG:
731                                                 next_token = xtoken ();
732                                                 if (next_token == Token.SEMICOLON || next_token == Token.COMMA || next_token == Token.EQUALS)
733                                                         goto default;
734                                                 
735                                                 res = Token.FROM_FIRST;
736                                                 query_parsing = true;
737                                                 if (context.Settings.Version <= LanguageVersion.ISO_2)
738                                                         Report.FeatureIsNotAvailable (context, Location, "query expressions");
739                                                 break;
740                                         case Token.VOID:
741                                                 Expression.Error_VoidInvalidInTheContext (Location, Report);
742                                                 break;
743                                         default:
744                                                 PopPosition ();
745                                                 // HACK: A token is not a keyword so we need to restore identifiers buffer
746                                                 // which has been overwritten before we grabbed the identifier
747                                                 id_builder [0] = 'f'; id_builder [1] = 'r'; id_builder [2] = 'o'; id_builder [3] = 'm';
748                                                 return -1;
749                                         }
750                                         PopPosition ();
751                                 }
752                                 break;
753                         case Token.JOIN:
754                         case Token.ON:
755                         case Token.EQUALS:
756                         case Token.SELECT:
757                         case Token.GROUP:
758                         case Token.BY:
759                         case Token.LET:
760                         case Token.ORDERBY:
761                         case Token.ASCENDING:
762                         case Token.DESCENDING:
763                         case Token.INTO:
764                                 if (!query_parsing)
765                                         res = -1;
766                                 break;
767                                 
768                         case Token.USING:
769                         case Token.NAMESPACE:
770                                 // TODO: some explanation needed
771                                 check_incorrect_doc_comment ();
772                                 break;
773                                 
774                         case Token.PARTIAL:
775                                 if (parsing_block > 0) {
776                                         res = -1;
777                                         break;
778                                 }
779
780                                 // Save current position and parse next token.
781                                 PushPosition ();
782
783                                 next_token = token ();
784                                 bool ok = (next_token == Token.CLASS) ||
785                                         (next_token == Token.STRUCT) ||
786                                         (next_token == Token.INTERFACE) ||
787                                         (next_token == Token.VOID);
788
789                                 PopPosition ();
790
791                                 if (ok) {
792                                         if (next_token == Token.VOID) {
793                                                 if (context.Settings.Version <= LanguageVersion.ISO_2)
794                                                         Report.FeatureIsNotAvailable (context, Location, "partial methods");
795                                         } else if (context.Settings.Version == LanguageVersion.ISO_1)
796                                                 Report.FeatureIsNotAvailable (context, Location, "partial types");
797
798                                         return res;
799                                 }
800
801                                 if (next_token < Token.LAST_KEYWORD) {
802                                         Report.Error (267, Location,
803                                                 "The `partial' modifier can be used only immediately before `class', `struct', `interface', or `void' keyword");
804                                         return token ();
805                                 }                                       
806
807                                 res = -1;
808                                 break;
809
810                         case Token.ASYNC:
811                                 if (parsing_modifiers) {
812                                         //
813                                         // Skip attributes section or constructor called async
814                                         //
815                                         if (parsing_attribute_section || peek_token () == Token.OPEN_PARENS) {
816                                                 res = -1;
817                                         } else {
818                                                 // async is keyword
819                                         }
820                                 } else if (parsing_block > 0) {
821                                         switch (peek_token ()) {
822                                         case Token.DELEGATE:
823                                         case Token.OPEN_PARENS_LAMBDA:
824                                                 // async is keyword
825                                                 break;
826                                         case Token.IDENTIFIER:
827                                                 PushPosition ();
828                                                 xtoken ();
829                                                 if (xtoken () != Token.ARROW)
830                                                         goto default;
831
832                                                 PopPosition ();
833                                                 break;
834                                         default:
835                                                 // peek_token could overwrite id_buffer
836                                                 id_builder [0] = 'a'; id_builder [1] = 's'; id_builder [2] = 'y'; id_builder [3] = 'n'; id_builder [4] = 'c';
837                                                 res = -1;
838                                                 break;
839                                         }
840                                 } else {
841                                         res = -1;
842                                 }
843
844                                 if (res == Token.ASYNC && context.Settings.Version <= LanguageVersion.V_4) {
845                                         Report.FeatureIsNotAvailable (context, Location, "asynchronous functions");
846                                 }
847                                 
848                                 break;
849
850                         case Token.AWAIT:
851                                 if (parsing_block == 0)
852                                         res = -1;
853
854                                 break;
855                         }
856
857
858                         return res;
859                 }
860
861                 static PreprocessorDirective GetPreprocessorDirective (char[] id, int id_len)
862                 {
863                         //
864                         // Keywords are stored in an array of arrays grouped by their
865                         // length and then by the first character
866                         //
867                         if (id_len >= keywords_preprocessor.Length || keywords_preprocessor[id_len] == null)
868                                 return PreprocessorDirective.Invalid;
869
870                         int first_index = id[0] - '_';
871                         if (first_index > 'z' - '_')
872                                 return PreprocessorDirective.Invalid;
873
874                         var kwe = keywords_preprocessor[id_len][first_index];
875                         if (kwe == null)
876                                 return PreprocessorDirective.Invalid;
877
878                         PreprocessorDirective res = PreprocessorDirective.Invalid;
879                         do {
880                                 res = kwe.Token;
881                                 for (int i = 1; i < id_len; ++i) {
882                                         if (id[i] != kwe.Value[i]) {
883                                                 res = 0;
884                                                 kwe = kwe.Next;
885                                                 break;
886                                         }
887                                 }
888                         } while (res == PreprocessorDirective.Invalid && kwe != null);
889
890                         return res;
891                 }
892
893                 public Location Location {
894                         get {
895                                 return new Location (current_source, ref_line, col);
896                         }
897                 }
898
899                 static bool is_identifier_start_character (int c)
900                 {
901                         return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || Char.IsLetter ((char)c);
902                 }
903
904                 static bool is_identifier_part_character (char c)
905                 {
906                         if (c >= 'a' && c <= 'z')
907                                 return true;
908
909                         if (c >= 'A' && c <= 'Z')
910                                 return true;
911
912                         if (c == '_' || (c >= '0' && c <= '9'))
913                                 return true;
914
915                         if (c < 0x80)
916                                 return false;
917
918                         return Char.IsLetter (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation;
919                 }
920
921                 public static bool IsKeyword (string s)
922                 {
923                         return keyword_strings.Contains (s);
924                 }
925
926                 //
927                 // Open parens micro parser. Detects both lambda and cast ambiguity.
928                 //      
929                 int TokenizeOpenParens ()
930                 {
931                         int ptoken;
932                         current_token = -1;
933
934                         int bracket_level = 0;
935                         bool is_type = false;
936                         bool can_be_type = false;
937                         
938                         while (true) {
939                                 ptoken = current_token;
940                                 token ();
941
942                                 switch (current_token) {
943                                 case Token.CLOSE_PARENS:
944                                         token ();
945                                         
946                                         //
947                                         // Expression inside parens is lambda, (int i) => 
948                                         //
949                                         if (current_token == Token.ARROW)
950                                                 return Token.OPEN_PARENS_LAMBDA;
951
952                                         //
953                                         // Expression inside parens is single type, (int[])
954                                         //
955                                         if (is_type)
956                                                 return Token.OPEN_PARENS_CAST;
957
958                                         //
959                                         // Expression is possible cast, look at next token, (T)null
960                                         //
961                                         if (can_be_type) {
962                                                 switch (current_token) {
963                                                 case Token.OPEN_PARENS:
964                                                 case Token.BANG:
965                                                 case Token.TILDE:
966                                                 case Token.IDENTIFIER:
967                                                 case Token.LITERAL:
968                                                 case Token.BASE:
969                                                 case Token.CHECKED:
970                                                 case Token.DELEGATE:
971                                                 case Token.FALSE:
972                                                 case Token.FIXED:
973                                                 case Token.NEW:
974                                                 case Token.NULL:
975                                                 case Token.SIZEOF:
976                                                 case Token.THIS:
977                                                 case Token.THROW:
978                                                 case Token.TRUE:
979                                                 case Token.TYPEOF:
980                                                 case Token.UNCHECKED:
981                                                 case Token.UNSAFE:
982                                                 case Token.DEFAULT:
983                                                 case Token.AWAIT:
984
985                                                 //
986                                                 // These can be part of a member access
987                                                 //
988                                                 case Token.INT:
989                                                 case Token.UINT:
990                                                 case Token.SHORT:
991                                                 case Token.USHORT:
992                                                 case Token.LONG:
993                                                 case Token.ULONG:
994                                                 case Token.DOUBLE:
995                                                 case Token.FLOAT:
996                                                 case Token.CHAR:
997                                                 case Token.BYTE:
998                                                 case Token.DECIMAL:
999                                                 case Token.BOOL:
1000                                                         return Token.OPEN_PARENS_CAST;
1001                                                 }
1002                                         }
1003                                         return Token.OPEN_PARENS;
1004                                         
1005                                 case Token.DOT:
1006                                 case Token.DOUBLE_COLON:
1007                                         if (ptoken != Token.IDENTIFIER && ptoken != Token.OP_GENERICS_GT)
1008                                                 goto default;
1009
1010                                         continue;
1011
1012                                 case Token.IDENTIFIER:
1013                                         switch (ptoken) {
1014                                         case Token.DOT:
1015                                                 if (bracket_level == 0) {
1016                                                         is_type = false;
1017                                                         can_be_type = true;
1018                                                 }
1019
1020                                                 continue;
1021                                         case Token.OP_GENERICS_LT:
1022                                         case Token.COMMA:
1023                                         case Token.DOUBLE_COLON:
1024                                         case -1:
1025                                                 if (bracket_level == 0)
1026                                                         can_be_type = true;
1027                                                 continue;
1028                                         default:
1029                                                 can_be_type = is_type = false;
1030                                                 continue;
1031                                         }
1032
1033                                 case Token.OBJECT:
1034                                 case Token.STRING:
1035                                 case Token.BOOL:
1036                                 case Token.DECIMAL:
1037                                 case Token.FLOAT:
1038                                 case Token.DOUBLE:
1039                                 case Token.SBYTE:
1040                                 case Token.BYTE:
1041                                 case Token.SHORT:
1042                                 case Token.USHORT:
1043                                 case Token.INT:
1044                                 case Token.UINT:
1045                                 case Token.LONG:
1046                                 case Token.ULONG:
1047                                 case Token.CHAR:
1048                                 case Token.VOID:
1049                                         if (bracket_level == 0)
1050                                                 is_type = true;
1051                                         continue;
1052
1053                                 case Token.COMMA:
1054                                         if (bracket_level == 0) {
1055                                                 bracket_level = 100;
1056                                                 can_be_type = is_type = false;
1057                                         }
1058                                         continue;
1059
1060                                 case Token.OP_GENERICS_LT:
1061                                 case Token.OPEN_BRACKET:
1062                                         if (bracket_level++ == 0)
1063                                                 is_type = true;
1064                                         continue;
1065
1066                                 case Token.OP_GENERICS_GT:
1067                                 case Token.CLOSE_BRACKET:
1068                                         --bracket_level;
1069                                         continue;
1070
1071                                 case Token.INTERR_NULLABLE:
1072                                 case Token.STAR:
1073                                         if (bracket_level == 0)
1074                                                 is_type = true;
1075                                         continue;
1076
1077                                 case Token.REF:
1078                                 case Token.OUT:
1079                                         can_be_type = is_type = false;
1080                                         continue;
1081
1082                                 default:
1083                                         return Token.OPEN_PARENS;
1084                                 }
1085                         }
1086                 }
1087
1088                 public static bool IsValidIdentifier (string s)
1089                 {
1090                         if (s == null || s.Length == 0)
1091                                 return false;
1092
1093                         if (!is_identifier_start_character (s [0]))
1094                                 return false;
1095                         
1096                         for (int i = 1; i < s.Length; i ++)
1097                                 if (! is_identifier_part_character (s [i]))
1098                                         return false;
1099                         
1100                         return true;
1101                 }
1102
1103                 bool parse_less_than ()
1104                 {
1105                 start:
1106                         int the_token = token ();
1107                         if (the_token == Token.OPEN_BRACKET) {
1108                                 while (true) {
1109                                         the_token = token ();
1110                                         if (the_token == Token.EOF)
1111                                                 return true;
1112
1113                                         if (the_token == Token.CLOSE_BRACKET)
1114                                                 break;
1115                                 }
1116                                 the_token = token ();
1117                         } else if (the_token == Token.IN || the_token == Token.OUT) {
1118                                 the_token = token ();
1119                         }
1120                         switch (the_token) {
1121                         case Token.IDENTIFIER:
1122                         case Token.OBJECT:
1123                         case Token.STRING:
1124                         case Token.BOOL:
1125                         case Token.DECIMAL:
1126                         case Token.FLOAT:
1127                         case Token.DOUBLE:
1128                         case Token.SBYTE:
1129                         case Token.BYTE:
1130                         case Token.SHORT:
1131                         case Token.USHORT:
1132                         case Token.INT:
1133                         case Token.UINT:
1134                         case Token.LONG:
1135                         case Token.ULONG:
1136                         case Token.CHAR:
1137                         case Token.VOID:
1138                                 break;
1139                         case Token.OP_GENERICS_GT:
1140                         case Token.IN:
1141                         case Token.OUT:
1142                                 return true;
1143
1144                         default:
1145                                 return false;
1146                         }
1147                 again:
1148                         the_token = token ();
1149
1150                         if (the_token == Token.OP_GENERICS_GT)
1151                                 return true;
1152                         else if (the_token == Token.COMMA || the_token == Token.DOT || the_token == Token.DOUBLE_COLON)
1153                                 goto start;
1154                         else if (the_token == Token.INTERR_NULLABLE || the_token == Token.STAR)
1155                                 goto again;
1156                         else if (the_token == Token.OP_GENERICS_LT) {
1157                                 if (!parse_less_than ())
1158                                         return false;
1159                                 goto again;
1160                         } else if (the_token == Token.OPEN_BRACKET) {
1161                         rank_specifiers:
1162                                 the_token = token ();
1163                                 if (the_token == Token.CLOSE_BRACKET)
1164                                         goto again;
1165                                 else if (the_token == Token.COMMA)
1166                                         goto rank_specifiers;
1167                                 return false;
1168                         }
1169
1170                         return false;
1171                 }
1172
1173                 bool parse_generic_dimension (out int dimension)
1174                 {
1175                         dimension = 1;
1176
1177                 again:
1178                         int the_token = token ();
1179                         if (the_token == Token.OP_GENERICS_GT)
1180                                 return true;
1181                         else if (the_token == Token.COMMA) {
1182                                 dimension++;
1183                                 goto again;
1184                         }
1185
1186                         return false;
1187                 }
1188                 
1189                 public int peek_token ()
1190                 {
1191                         int the_token;
1192
1193                         PushPosition ();
1194                         the_token = token ();
1195                         PopPosition ();
1196                         
1197                         return the_token;
1198                 }
1199                                         
1200                 //
1201                 // Tonizes `?' using custom disambiguous rules to return one
1202                 // of following tokens: INTERR_NULLABLE, OP_COALESCING, INTERR
1203                 //
1204                 // Tricky expression look like:
1205                 //
1206                 // Foo ? a = x ? b : c;
1207                 //
1208                 int TokenizePossibleNullableType ()
1209                 {
1210                         if (parsing_block == 0 || parsing_type > 0)
1211                                 return Token.INTERR_NULLABLE;
1212
1213                         int d = peek_char ();
1214                         if (d == '?') {
1215                                 get_char ();
1216                                 return Token.OP_COALESCING;
1217                         }
1218
1219                         switch (current_token) {
1220                         case Token.CLOSE_PARENS:
1221                         case Token.TRUE:
1222                         case Token.FALSE:
1223                         case Token.NULL:
1224                         case Token.LITERAL:
1225                                 return Token.INTERR;
1226                         }
1227
1228                         if (d != ' ') {
1229                                 if (d == ',' || d == ';' || d == '>')
1230                                         return Token.INTERR_NULLABLE;
1231                                 if (d == '*' || (d >= '0' && d <= '9'))
1232                                         return Token.INTERR;
1233                         }
1234
1235                         PushPosition ();
1236                         current_token = Token.NONE;
1237                         int next_token;
1238                         switch (xtoken ()) {
1239                         case Token.LITERAL:
1240                         case Token.TRUE:
1241                         case Token.FALSE:
1242                         case Token.NULL:
1243                         case Token.THIS:
1244                         case Token.NEW:
1245                                 next_token = Token.INTERR;
1246                                 break;
1247                                 
1248                         case Token.SEMICOLON:
1249                         case Token.COMMA:
1250                         case Token.CLOSE_PARENS:
1251                         case Token.OPEN_BRACKET:
1252                         case Token.OP_GENERICS_GT:
1253                         case Token.INTERR:
1254                         case Token.OP_COALESCING:
1255                                 next_token = Token.INTERR_NULLABLE;
1256                                 break;
1257                                 
1258                         default:
1259                                 next_token = -1;
1260                                 break;
1261                         }
1262
1263                         if (next_token == -1) {
1264                                 switch (xtoken ()) {
1265                                 case Token.COMMA:
1266                                 case Token.SEMICOLON:
1267                                 case Token.OPEN_BRACE:
1268                                 case Token.CLOSE_PARENS:
1269                                 case Token.IN:
1270                                         next_token = Token.INTERR_NULLABLE;
1271                                         break;
1272                                         
1273                                 case Token.COLON:
1274                                         next_token = Token.INTERR;
1275                                         break;                                                  
1276                                         
1277                                 default:
1278                                         int ntoken;
1279                                         int interrs = 1;
1280                                         int colons = 0;
1281                                         int braces = 0;
1282                                         //
1283                                         // All shorcuts failed, do it hard way
1284                                         //
1285                                         while ((ntoken = xtoken ()) != Token.EOF) {
1286                                                 if (ntoken == Token.OPEN_BRACE) {
1287                                                         ++braces;
1288                                                         continue;
1289                                                 }
1290
1291                                                 if (ntoken == Token.CLOSE_BRACE) {
1292                                                         --braces;
1293                                                         continue;
1294                                                 }
1295
1296                                                 if (braces != 0)
1297                                                         continue;
1298
1299                                                 if (ntoken == Token.SEMICOLON)
1300                                                         break;
1301                                                 
1302                                                 if (ntoken == Token.COLON) {
1303                                                         if (++colons == interrs)
1304                                                                 break;
1305                                                         continue;
1306                                                 }
1307                                                 
1308                                                 if (ntoken == Token.INTERR) {
1309                                                         ++interrs;
1310                                                         continue;
1311                                                 }
1312                                         }
1313                                         
1314                                         next_token = colons != interrs && braces == 0 ? Token.INTERR_NULLABLE : Token.INTERR;
1315                                         break;
1316                                 }
1317                         }
1318                         
1319                         PopPosition ();
1320                         return next_token;
1321                 }
1322
1323                 bool decimal_digits (int c)
1324                 {
1325                         int d;
1326                         bool seen_digits = false;
1327                         
1328                         if (c != -1){
1329                                 if (number_pos == MaxNumberLength)
1330                                         Error_NumericConstantTooLong ();
1331                                 number_builder [number_pos++] = (char) c;
1332                         }
1333                         
1334                         //
1335                         // We use peek_char2, because decimal_digits needs to do a 
1336                         // 2-character look-ahead (5.ToString for example).
1337                         //
1338                         while ((d = peek_char2 ()) != -1){
1339                                 if (d >= '0' && d <= '9'){
1340                                         if (number_pos == MaxNumberLength)
1341                                                 Error_NumericConstantTooLong ();
1342                                         number_builder [number_pos++] = (char) d;
1343                                         get_char ();
1344                                         seen_digits = true;
1345                                 } else
1346                                         break;
1347                         }
1348                         
1349                         return seen_digits;
1350                 }
1351
1352                 static bool is_hex (int e)
1353                 {
1354                         return (e >= '0' && e <= '9') || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
1355                 }
1356
1357                 static TypeCode real_type_suffix (int c)
1358                 {
1359                         switch (c){
1360                         case 'F': case 'f':
1361                                 return TypeCode.Single;
1362                         case 'D': case 'd':
1363                                 return TypeCode.Double;
1364                         case 'M': case 'm':
1365                                 return TypeCode.Decimal;
1366                         default:
1367                                 return TypeCode.Empty;
1368                         }
1369                 }
1370
1371                 ILiteralConstant integer_type_suffix (ulong ul, int c, Location loc)
1372                 {
1373                         bool is_unsigned = false;
1374                         bool is_long = false;
1375
1376                         if (c != -1){
1377                                 bool scanning = true;
1378                                 do {
1379                                         switch (c){
1380                                         case 'U': case 'u':
1381                                                 if (is_unsigned)
1382                                                         scanning = false;
1383                                                 is_unsigned = true;
1384                                                 get_char ();
1385                                                 break;
1386
1387                                         case 'l':
1388                                                 if (!is_unsigned){
1389                                                         //
1390                                                         // if we have not seen anything in between
1391                                                         // report this error
1392                                                         //
1393                                                         Report.Warning (78, 4, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");
1394                                                 }
1395
1396                                                 goto case 'L';
1397
1398                                         case 'L': 
1399                                                 if (is_long)
1400                                                         scanning = false;
1401                                                 is_long = true;
1402                                                 get_char ();
1403                                                 break;
1404                                                 
1405                                         default:
1406                                                 scanning = false;
1407                                                 break;
1408                                         }
1409                                         c = peek_char ();
1410                                 } while (scanning);
1411                         }
1412
1413                         if (is_long && is_unsigned){
1414                                 return new ULongLiteral (context.BuiltinTypes, ul, loc);
1415                         }
1416                         
1417                         if (is_unsigned){
1418                                 // uint if possible, or ulong else.
1419
1420                                 if ((ul & 0xffffffff00000000) == 0)
1421                                         return new UIntLiteral (context.BuiltinTypes, (uint) ul, loc);
1422                                 else
1423                                         return new ULongLiteral (context.BuiltinTypes, ul, loc);
1424                         } else if (is_long){
1425                                 // long if possible, ulong otherwise
1426                                 if ((ul & 0x8000000000000000) != 0)
1427                                         return new ULongLiteral (context.BuiltinTypes, ul, loc);
1428                                 else
1429                                         return new LongLiteral (context.BuiltinTypes, (long) ul, loc);
1430                         } else {
1431                                 // int, uint, long or ulong in that order
1432                                 if ((ul & 0xffffffff00000000) == 0){
1433                                         uint ui = (uint) ul;
1434                                         
1435                                         if ((ui & 0x80000000) != 0)
1436                                                 return new UIntLiteral (context.BuiltinTypes, ui, loc);
1437                                         else
1438                                                 return new IntLiteral (context.BuiltinTypes, (int) ui, loc);
1439                                 } else {
1440                                         if ((ul & 0x8000000000000000) != 0)
1441                                                 return new ULongLiteral (context.BuiltinTypes, ul, loc);
1442                                         else
1443                                                 return new LongLiteral (context.BuiltinTypes, (long) ul, loc);
1444                                 }
1445                         }
1446                 }
1447                                 
1448                 //
1449                 // given `c' as the next char in the input decide whether
1450                 // we need to convert to a special type, and then choose
1451                 // the best representation for the integer
1452                 //
1453                 ILiteralConstant adjust_int (int c, Location loc)
1454                 {
1455                         try {
1456                                 if (number_pos > 9){
1457                                         ulong ul = (uint) (number_builder [0] - '0');
1458
1459                                         for (int i = 1; i < number_pos; i++){
1460                                                 ul = checked ((ul * 10) + ((uint)(number_builder [i] - '0')));
1461                                         }
1462
1463                                         return integer_type_suffix (ul, c, loc);
1464                                 } else {
1465                                         uint ui = (uint) (number_builder [0] - '0');
1466
1467                                         for (int i = 1; i < number_pos; i++){
1468                                                 ui = checked ((ui * 10) + ((uint)(number_builder [i] - '0')));
1469                                         }
1470
1471                                         return integer_type_suffix (ui, c, loc);
1472                                 }
1473                         } catch (OverflowException) {
1474                                 Error_NumericConstantTooLong ();
1475                                 return new IntLiteral (context.BuiltinTypes, 0, loc);
1476                         }
1477                         catch (FormatException) {
1478                                 Report.Error (1013, Location, "Invalid number");
1479                                 return new IntLiteral (context.BuiltinTypes, 0, loc);
1480                         }
1481                 }
1482                 
1483                 ILiteralConstant adjust_real (TypeCode t, Location loc)
1484                 {
1485                         string s = new string (number_builder, 0, number_pos);
1486                         const string error_details = "Floating-point constant is outside the range of type `{0}'";
1487
1488                         switch (t){
1489                         case TypeCode.Decimal:
1490                                 try {
1491                                         return new DecimalLiteral (context.BuiltinTypes, decimal.Parse (s, styles, csharp_format_info), loc);
1492                                 } catch (OverflowException) {
1493                                         Report.Error (594, Location, error_details, "decimal");
1494                                         return new DecimalLiteral (context.BuiltinTypes, 0, loc);
1495                                 }
1496                         case TypeCode.Single:
1497                                 try {
1498                                         return new FloatLiteral (context.BuiltinTypes, float.Parse (s, styles, csharp_format_info), loc);
1499                                 } catch (OverflowException) {
1500                                         Report.Error (594, Location, error_details, "float");
1501                                         return new FloatLiteral (context.BuiltinTypes, 0, loc);
1502                                 }
1503                         default:
1504                                 try {
1505                                         return new DoubleLiteral (context.BuiltinTypes, double.Parse (s, styles, csharp_format_info), loc);
1506                                 } catch (OverflowException) {
1507                                         Report.Error (594, loc, error_details, "double");
1508                                         return new DoubleLiteral (context.BuiltinTypes, 0, loc);
1509                                 }
1510                         }
1511                 }
1512
1513                 ILiteralConstant handle_hex (Location loc)
1514                 {
1515                         int d;
1516                         ulong ul;
1517                         
1518                         get_char ();
1519                         while ((d = peek_char ()) != -1){
1520                                 if (is_hex (d)){
1521                                         number_builder [number_pos++] = (char) d;
1522                                         get_char ();
1523                                 } else
1524                                         break;
1525                         }
1526                         
1527                         string s = new String (number_builder, 0, number_pos);
1528
1529                         try {
1530                                 if (number_pos <= 8)
1531                                         ul = System.UInt32.Parse (s, NumberStyles.HexNumber);
1532                                 else
1533                                         ul = System.UInt64.Parse (s, NumberStyles.HexNumber);
1534
1535                                 return integer_type_suffix (ul, peek_char (), loc);
1536                         } catch (OverflowException){
1537                                 Error_NumericConstantTooLong ();
1538                                 return new IntLiteral (context.BuiltinTypes, 0, loc);
1539                         }
1540                         catch (FormatException) {
1541                                 Report.Error (1013, Location, "Invalid number");
1542                                 return new IntLiteral (context.BuiltinTypes, 0, loc);
1543                         }
1544                 }
1545
1546                 //
1547                 // Invoked if we know we have .digits or digits
1548                 //
1549                 int is_number (int c)
1550                 {
1551                         ILiteralConstant res;
1552
1553 #if FULL_AST
1554                         int read_start = reader.Position - 1;
1555                         if (c == '.') {
1556                                 //
1557                                 // Caller did peek_char
1558                                 //
1559                                 --read_start;
1560                         }
1561 #endif
1562                         number_pos = 0;
1563                         var loc = Location;
1564
1565                         if (c >= '0' && c <= '9'){
1566                                 if (c == '0'){
1567                                         int peek = peek_char ();
1568
1569                                         if (peek == 'x' || peek == 'X') {
1570                                                 val = res = handle_hex (loc);
1571 #if FULL_AST
1572                                                 res.ParsedValue = reader.ReadChars (read_start, reader.Position - 1);
1573 #endif
1574
1575                                                 return Token.LITERAL;
1576                                         }
1577                                 }
1578                                 decimal_digits (c);
1579                                 c = get_char ();
1580                         }
1581
1582                         //
1583                         // We need to handle the case of
1584                         // "1.1" vs "1.string" (LITERAL_FLOAT vs NUMBER DOT IDENTIFIER)
1585                         //
1586                         bool is_real = false;
1587                         if (c == '.'){
1588                                 if (decimal_digits ('.')){
1589                                         is_real = true;
1590                                         c = get_char ();
1591                                 } else {
1592                                         putback ('.');
1593                                         number_pos--;
1594                                         val = res = adjust_int (-1, loc);
1595
1596 #if FULL_AST
1597                                         res.ParsedValue = reader.ReadChars (read_start, reader.Position - 1);
1598 #endif
1599                                         return Token.LITERAL;
1600                                 }
1601                         }
1602                         
1603                         if (c == 'e' || c == 'E'){
1604                                 is_real = true;
1605                                 if (number_pos == MaxNumberLength)
1606                                         Error_NumericConstantTooLong ();
1607                                 number_builder [number_pos++] = (char) c;
1608                                 c = get_char ();
1609                                 
1610                                 if (c == '+'){
1611                                         if (number_pos == MaxNumberLength)
1612                                                 Error_NumericConstantTooLong ();
1613                                         number_builder [number_pos++] = '+';
1614                                         c = -1;
1615                                 } else if (c == '-') {
1616                                         if (number_pos == MaxNumberLength)
1617                                                 Error_NumericConstantTooLong ();
1618                                         number_builder [number_pos++] = '-';
1619                                         c = -1;
1620                                 } else {
1621                                         if (number_pos == MaxNumberLength)
1622                                                 Error_NumericConstantTooLong ();
1623                                         number_builder [number_pos++] = '+';
1624                                 }
1625                                         
1626                                 decimal_digits (c);
1627                                 c = get_char ();
1628                         }
1629
1630                         var type = real_type_suffix (c);
1631                         if (type == TypeCode.Empty && !is_real) {
1632                                 putback (c);
1633                                 res = adjust_int (c, loc);
1634                         } else {
1635                                 is_real = true;
1636
1637                                 if (type == TypeCode.Empty) {
1638                                         putback (c);
1639                                 }
1640
1641                                 res = adjust_real (type, loc);
1642                         }
1643
1644                         val = res;
1645
1646 #if FULL_AST
1647                         var chars = reader.ReadChars (read_start, reader.Position - (type == TypeCode.Empty && c > 0 ? 1 : 0));
1648                         if (chars[chars.Length - 1] == '\r')
1649                                 Array.Resize (ref chars, chars.Length - 1);
1650                         res.ParsedValue = chars;
1651 #endif
1652
1653                         return Token.LITERAL;
1654                 }
1655
1656                 //
1657                 // Accepts exactly count (4 or 8) hex, no more no less
1658                 //
1659                 int getHex (int count, out int surrogate, out bool error)
1660                 {
1661                         int i;
1662                         int total = 0;
1663                         int c;
1664                         int top = count != -1 ? count : 4;
1665                         
1666                         get_char ();
1667                         error = false;
1668                         surrogate = 0;
1669                         for (i = 0; i < top; i++){
1670                                 c = get_char ();
1671
1672                                 if (c >= '0' && c <= '9')
1673                                         c = (int) c - (int) '0';
1674                                 else if (c >= 'A' && c <= 'F')
1675                                         c = (int) c - (int) 'A' + 10;
1676                                 else if (c >= 'a' && c <= 'f')
1677                                         c = (int) c - (int) 'a' + 10;
1678                                 else {
1679                                         error = true;
1680                                         return 0;
1681                                 }
1682                                 
1683                                 total = (total * 16) + c;
1684                                 if (count == -1){
1685                                         int p = peek_char ();
1686                                         if (p == -1)
1687                                                 break;
1688                                         if (!is_hex ((char)p))
1689                                                 break;
1690                                 }
1691                         }
1692
1693                         if (top == 8) {
1694                                 if (total > 0x0010FFFF) {
1695                                         error = true;
1696                                         return 0;
1697                                 }
1698
1699                                 if (total >= 0x00010000) {
1700                                         surrogate = ((total - 0x00010000) % 0x0400 + 0xDC00);                                   
1701                                         total = ((total - 0x00010000) / 0x0400 + 0xD800);
1702                                 }
1703                         }
1704
1705                         return total;
1706                 }
1707
1708                 int escape (int c, out int surrogate)
1709                 {
1710                         bool error;
1711                         int d;
1712                         int v;
1713
1714                         d = peek_char ();
1715                         if (c != '\\') {
1716                                 surrogate = 0;
1717                                 return c;
1718                         }
1719                         
1720                         switch (d){
1721                         case 'a':
1722                                 v = '\a'; break;
1723                         case 'b':
1724                                 v = '\b'; break;
1725                         case 'n':
1726                                 v = '\n'; break;
1727                         case 't':
1728                                 v = '\t'; break;
1729                         case 'v':
1730                                 v = '\v'; break;
1731                         case 'r':
1732                                 v = '\r'; break;
1733                         case '\\':
1734                                 v = '\\'; break;
1735                         case 'f':
1736                                 v = '\f'; break;
1737                         case '0':
1738                                 v = 0; break;
1739                         case '"':
1740                                 v = '"'; break;
1741                         case '\'':
1742                                 v = '\''; break;
1743                         case 'x':
1744                                 v = getHex (-1, out surrogate, out error);
1745                                 if (error)
1746                                         goto default;
1747                                 return v;
1748                         case 'u':
1749                         case 'U':
1750                                 return EscapeUnicode (d, out surrogate);
1751                         default:
1752                                 surrogate = 0;
1753                                 Report.Error (1009, Location, "Unrecognized escape sequence `\\{0}'", ((char)d).ToString ());
1754                                 return d;
1755                         }
1756
1757                         get_char ();
1758                         surrogate = 0;
1759                         return v;
1760                 }
1761
1762                 int EscapeUnicode (int ch, out int surrogate)
1763                 {
1764                         bool error;
1765                         if (ch == 'U') {
1766                                 ch = getHex (8, out surrogate, out error);
1767                         } else {
1768                                 ch = getHex (4, out surrogate, out error);
1769                         }
1770
1771                         if (error)
1772                                 Report.Error (1009, Location, "Unrecognized escape sequence");
1773
1774                         return ch;
1775                 }
1776
1777                 int get_char ()
1778                 {
1779                         int x;
1780                         if (putback_char != -1) {
1781                                 x = putback_char;
1782                                 putback_char = -1;
1783                         } else {
1784                                 x = reader.Read ();
1785                         }
1786                         
1787                         if (x == '\r') {
1788                                 if (peek_char () == '\n') {
1789                                         putback_char = -1;
1790                                 }
1791
1792                                 x = '\n';
1793                                 advance_line ();
1794                         } else if (x == '\n') {
1795                                 advance_line ();
1796                         } else {
1797                                 col++;
1798                         }
1799                         return x;
1800                 }
1801
1802                 void advance_line ()
1803                 {
1804                         line++;
1805                         ref_line++;
1806                         previous_col = col;
1807                         col = 0;
1808                 }
1809
1810                 int peek_char ()
1811                 {
1812                         if (putback_char == -1)
1813                                 putback_char = reader.Read ();
1814                         return putback_char;
1815                 }
1816
1817                 int peek_char2 ()
1818                 {
1819                         if (putback_char != -1)
1820                                 return putback_char;
1821                         return reader.Peek ();
1822                 }
1823                 
1824                 public void putback (int c)
1825                 {
1826                         if (putback_char != -1) {
1827                                 throw new InternalErrorException (string.Format ("Secondary putback [{0}] putting back [{1}] is not allowed", (char)putback_char, (char) c), Location);
1828                         }
1829
1830                         if (c == '\n' || col == 0) {
1831                                 // It won't happen though.
1832                                 line--;
1833                                 ref_line--;
1834                                 col = previous_col;
1835                         }
1836                         else
1837                                 col--;
1838                         putback_char = c;
1839                 }
1840
1841                 public bool advance ()
1842                 {
1843                         return peek_char () != -1 || CompleteOnEOF;
1844                 }
1845
1846                 public Object Value {
1847                         get {
1848                                 return val;
1849                         }
1850                 }
1851
1852                 public Object value ()
1853                 {
1854                         return val;
1855                 }
1856
1857                 public int token ()
1858                 {
1859                         current_token = xtoken ();
1860                         return current_token;
1861                 }
1862
1863                 int TokenizePreprocessorIdentifier (out int c)
1864                 {
1865                         // skip over white space
1866                         do {
1867                                 c = get_char ();
1868                         } while (c == ' ' || c == '\t');
1869
1870
1871                         int pos = 0;
1872                         while (c != -1 && c >= 'a' && c <= 'z') {
1873                                 id_builder[pos++] = (char) c;
1874                                 c = get_char ();
1875                                 if (c == '\\') {
1876                                         int peek = peek_char ();
1877                                         if (peek == 'U' || peek == 'u') {
1878                                                 int surrogate;
1879                                                 c = EscapeUnicode (c, out surrogate);
1880                                                 if (surrogate != 0) {
1881                                                         if (is_identifier_part_character ((char) c)) {
1882                                                                 id_builder[pos++] = (char) c;
1883                                                         }
1884                                                         c = surrogate;
1885                                                 }
1886                                         }
1887                                 }
1888                         }
1889
1890                         return pos;
1891                 }
1892
1893                 PreprocessorDirective get_cmd_arg (out string arg)
1894                 {
1895                         int c;          
1896
1897                         tokens_seen = false;
1898                         arg = "";
1899
1900                         var cmd = GetPreprocessorDirective (id_builder, TokenizePreprocessorIdentifier (out c));
1901
1902                         if ((cmd & PreprocessorDirective.CustomArgumentsParsing) != 0)
1903                                 return cmd;
1904
1905                         // skip over white space
1906                         while (c == ' ' || c == '\t')
1907                                 c = get_char ();
1908
1909                         int has_identifier_argument = (int)(cmd & PreprocessorDirective.RequiresArgument);
1910                         int pos = 0;
1911
1912                         while (c != -1 && c != '\n') {
1913                                 if (c == '\\' && has_identifier_argument >= 0) {
1914                                         if (has_identifier_argument != 0) {
1915                                                 has_identifier_argument = 1;
1916
1917                                                 int peek = peek_char ();
1918                                                 if (peek == 'U' || peek == 'u') {
1919                                                         int surrogate;
1920                                                         c = EscapeUnicode (c, out surrogate);
1921                                                         if (surrogate != 0) {
1922                                                                 if (is_identifier_part_character ((char) c)) {
1923                                                                         if (pos == value_builder.Length)
1924                                                                                 Array.Resize (ref value_builder, pos * 2);
1925
1926                                                                         value_builder[pos++] = (char) c;
1927                                                                 }
1928                                                                 c = surrogate;
1929                                                         }
1930                                                 }
1931                                         } else {
1932                                                 has_identifier_argument = -1;
1933                                         }
1934                                 } else if (c == '/' && peek_char () == '/') {
1935                                         //
1936                                         // Eat single-line comments
1937                                         //
1938                                         get_char ();
1939                                         do {
1940                                                 c = get_char ();
1941                                         } while (c != -1 && c != '\n');
1942
1943                                         break;
1944                                 }
1945
1946                                 if (pos == value_builder.Length)
1947                                         Array.Resize (ref value_builder, pos * 2);
1948
1949                                 value_builder[pos++] = (char) c;
1950                                 c = get_char ();
1951                         }
1952
1953                         if (pos != 0) {
1954                                 if (pos > MaxIdentifierLength)
1955                                         arg = new string (value_builder, 0, pos);
1956                                 else
1957                                         arg = InternIdentifier (value_builder, pos);
1958
1959                                 // Eat any trailing whitespaces
1960                                 arg = arg.Trim (simple_whitespaces);
1961                         }
1962
1963                         return cmd;
1964                 }
1965
1966                 //
1967                 // Handles the #line directive
1968                 //
1969                 bool PreProcessLine ()
1970                 {
1971                         Location loc = Location;
1972
1973                         int c;
1974
1975                         int length = TokenizePreprocessorIdentifier (out c);
1976                         if (length == line_default.Length) {
1977                                 if (!IsTokenIdentifierEqual (line_default))
1978                                         return false;
1979
1980                                 current_source = source_file.SourceFile;
1981                                 if (!hidden_block_start.IsNull) {
1982                                         current_source.RegisterHiddenScope (hidden_block_start, loc);
1983                                         hidden_block_start = Location.Null;
1984                                 }
1985
1986                                 ref_line = line;
1987                                 return true;
1988                         }
1989
1990                         if (length == line_hidden.Length) {
1991                                 if (!IsTokenIdentifierEqual (line_hidden))
1992                                         return false;
1993
1994                                 if (hidden_block_start.IsNull)
1995                                         hidden_block_start = loc;
1996
1997                                 return true;
1998                         }
1999
2000                         if (length != 0 || c < '0' || c > '9') {
2001                                 //
2002                                 // Eat any remaining characters to continue parsing on next line
2003                                 //
2004                                 while (c != -1 && c != '\n') {
2005                                         c = get_char ();
2006                                 }
2007
2008                                 return false;
2009                         }
2010
2011                         int new_line = TokenizeNumber (c);
2012                         if (new_line < 1) {
2013                                 //
2014                                 // Eat any remaining characters to continue parsing on next line
2015                                 //
2016                                 while (c != -1 && c != '\n') {
2017                                         c = get_char ();
2018                                 }
2019
2020                                 return new_line != 0;
2021                         }
2022
2023                         c = get_char ();
2024                         if (c == ' ') {
2025                                 // skip over white space
2026                                 do {
2027                                         c = get_char ();
2028                                 } while (c == ' ' || c == '\t');
2029                         } else if (c == '"') {
2030                                 c = 0;
2031                         }
2032
2033                         if (c != '\n' && c != '/' && c != '"') {
2034                                 //
2035                                 // Eat any remaining characters to continue parsing on next line
2036                                 //
2037                                 while (c != -1 && c != '\n') {
2038                                         c = get_char ();
2039                                 }
2040
2041                                 Report.Error (1578, loc, "Filename, single-line comment or end-of-line expected");
2042                                 return true;
2043                         }
2044
2045                         string new_file_name = null;
2046                         if (c == '"') {
2047                                 new_file_name = TokenizeFileName (ref c);
2048
2049                                 // skip over white space
2050                                 while (c == ' ' || c == '\t') {
2051                                         c = get_char ();
2052                                 }
2053                         }
2054
2055                         if (c == '\n') {
2056                         } else if (c == '/') {
2057                                 ReadSingleLineComment ();
2058                         } else {
2059                                 //
2060                                 // Eat any remaining characters to continue parsing on next line
2061                                 //
2062                                 while (c != -1 && c != '\n') {
2063                                         c = get_char ();
2064                                 }
2065
2066                                 Error_EndLineExpected ();
2067                                 return true;
2068                         }
2069
2070                         if (new_file_name != null) {
2071                                 current_source = context.LookupFile (source_file, new_file_name);
2072                                 source_file.AddIncludeFile (current_source);
2073                         }
2074
2075                         if (!hidden_block_start.IsNull) {
2076                                 current_source.RegisterHiddenScope (hidden_block_start, loc);
2077                                 hidden_block_start = Location.Null;
2078                         }
2079
2080                         ref_line = new_line;
2081                         return true;
2082                 }
2083
2084                 //
2085                 // Handles #define and #undef
2086                 //
2087                 void PreProcessDefinition (bool is_define, string ident, bool caller_is_taking)
2088                 {
2089                         if (ident.Length == 0 || ident == "true" || ident == "false"){
2090                                 Report.Error (1001, Location, "Missing identifier to pre-processor directive");
2091                                 return;
2092                         }
2093
2094                         if (ident.IndexOfAny (simple_whitespaces) != -1){
2095                                 Error_EndLineExpected ();
2096                                 return;
2097                         }
2098
2099                         if (!is_identifier_start_character (ident [0]))
2100                                 Report.Error (1001, Location, "Identifier expected: {0}", ident);
2101                         
2102                         foreach (char c in ident.Substring (1)){
2103                                 if (!is_identifier_part_character (c)){
2104                                         Report.Error (1001, Location, "Identifier expected: {0}",  ident);
2105                                         return;
2106                                 }
2107                         }
2108
2109                         if (!caller_is_taking)
2110                                 return;
2111
2112                         if (is_define) {
2113                                 //
2114                                 // #define ident
2115                                 //
2116                                 if (context.Settings.IsConditionalSymbolDefined (ident))
2117                                         return;
2118
2119                                 source_file.AddDefine (ident);
2120                         } else {
2121                                 //
2122                                 // #undef ident
2123                                 //
2124                                 source_file.AddUndefine (ident);
2125                         }
2126                 }
2127
2128                 byte read_hex (out bool error)
2129                 {
2130                         int total;
2131                         int c = get_char ();
2132
2133                         if ((c >= '0') && (c <= '9'))
2134                                 total = (int) c - (int) '0';
2135                         else if ((c >= 'A') && (c <= 'F'))
2136                                 total = (int) c - (int) 'A' + 10;
2137                         else if ((c >= 'a') && (c <= 'f'))
2138                                 total = (int) c - (int) 'a' + 10;
2139                         else {
2140                                 error = true;
2141                                 return 0;
2142                         }
2143
2144                         total *= 16;
2145                         c = get_char ();
2146
2147                         if ((c >= '0') && (c <= '9'))
2148                                 total += (int) c - (int) '0';
2149                         else if ((c >= 'A') && (c <= 'F'))
2150                                 total += (int) c - (int) 'A' + 10;
2151                         else if ((c >= 'a') && (c <= 'f'))
2152                                 total += (int) c - (int) 'a' + 10;
2153                         else {
2154                                 error = true;
2155                                 return 0;
2156                         }
2157
2158                         error = false;
2159                         return (byte) total;
2160                 }
2161
2162                 //
2163                 // Parses #pragma checksum
2164                 //
2165                 bool ParsePragmaChecksum ()
2166                 {
2167                         //
2168                         // The syntax is ` "foo.txt" "{guid}" "hash"'
2169                         //
2170                         // guid is predefined hash algorithm guid {406ea660-64cf-4c82-b6f0-42d48172a799} for md5
2171                         //
2172                         int c = get_char ();
2173
2174                         if (c != '"')
2175                                 return false;
2176
2177                         string file_name = TokenizeFileName (ref c);
2178
2179                         // TODO: Any white-spaces count
2180                         if (c != ' ')
2181                                 return false;
2182
2183                         SourceFile file = context.LookupFile (source_file, file_name);
2184
2185                         if (get_char () != '"' || get_char () != '{')
2186                                 return false;
2187
2188                         bool error;
2189                         byte[] guid_bytes = new byte [16];
2190                         int i = 0;
2191
2192                         for (; i < 4; i++) {
2193                                 guid_bytes [i] = read_hex (out error);
2194                                 if (error)
2195                                         return false;
2196                         }
2197
2198                         if (get_char () != '-')
2199                                 return false;
2200
2201                         for (; i < 10; i++) {
2202                                 guid_bytes [i] = read_hex (out error);
2203                                 if (error)
2204                                         return false;
2205
2206                                 guid_bytes [i++] = read_hex (out error);
2207                                 if (error)
2208                                         return false;
2209
2210                                 if (get_char () != '-')
2211                                         return false;
2212                         }
2213
2214                         for (; i < 16; i++) {
2215                                 guid_bytes [i] = read_hex (out error);
2216                                 if (error)
2217                                         return false;
2218                         }
2219
2220                         if (get_char () != '}' || get_char () != '"')
2221                                 return false;
2222
2223                         // TODO: Any white-spaces count
2224                         c = get_char ();
2225                         if (c != ' ')
2226                                 return false;
2227
2228                         if (get_char () != '"')
2229                                 return false;
2230
2231                         // Any length of checksum
2232                         List<byte> checksum_bytes = new List<byte> (16);
2233
2234                         var checksum_location = Location;
2235                         c = peek_char ();
2236                         while (c != '"' && c != -1) {
2237                                 checksum_bytes.Add (read_hex (out error));
2238                                 if (error)
2239                                         return false;
2240
2241                                 c = peek_char ();
2242                         }
2243
2244                         if (c == '/') {
2245                                 ReadSingleLineComment ();
2246                         } else if (get_char () != '"') {
2247                                 return false;
2248                         }
2249
2250                         if (context.Settings.GenerateDebugInfo) {
2251                                 var chsum = checksum_bytes.ToArray ();
2252
2253                                 if (file.HasChecksum) {
2254                                         if (!ArrayComparer.IsEqual (file.Checksum, chsum)) {
2255                                                 // TODO: Report.SymbolRelatedToPreviousError
2256                                                 Report.Warning (1697, 1, checksum_location, "Different checksum values specified for file `{0}'", file.Name);
2257                                         }
2258                                 }
2259
2260                                 file.SetChecksum (guid_bytes, chsum);
2261                                 current_source.AutoGenerated = true;
2262                         }
2263
2264                         return true;
2265                 }
2266
2267                 bool IsTokenIdentifierEqual (char[] identifier)
2268                 {
2269                         for (int i = 0; i < identifier.Length; ++i) {
2270                                 if (identifier[i] != id_builder[i])
2271                                         return false;
2272                         }
2273
2274                         return true;
2275                 }
2276
2277                 int TokenizeNumber (int value)
2278                 {
2279                         number_pos = 0;
2280
2281                         decimal_digits (value);
2282                         uint ui = (uint) (number_builder[0] - '0');
2283
2284                         try {
2285                                 for (int i = 1; i < number_pos; i++) {
2286                                         ui = checked ((ui * 10) + ((uint) (number_builder[i] - '0')));
2287                                 }
2288
2289                                 return (int) ui;
2290                         } catch (OverflowException) {
2291                                 Error_NumericConstantTooLong ();
2292                                 return -1;
2293                         }
2294                 }
2295
2296                 string TokenizeFileName (ref int c)
2297                 {
2298                         var string_builder = new StringBuilder ();
2299                         while (c != -1 && c != '\n') {
2300                                 c = get_char ();
2301                                 if (c == '"') {
2302                                         c = get_char ();
2303                                         break;
2304                                 }
2305
2306                                 string_builder.Append ((char) c);
2307                         }
2308
2309                         if (string_builder.Length == 0) {
2310                                 Report.Warning (1709, 1, Location, "Filename specified for preprocessor directive is empty");
2311                         }
2312
2313                 
2314                         return string_builder.ToString ();
2315                 }
2316
2317                 int TokenizePragmaNumber (ref int c)
2318                 {
2319                         number_pos = 0;
2320
2321                         int number;
2322
2323                         if (c >= '0' && c <= '9') {
2324                                 number = TokenizeNumber (c);
2325
2326                                 c = get_char ();
2327
2328                                 // skip over white space
2329                                 while (c == ' ' || c == '\t')
2330                                         c = get_char ();
2331
2332                                 if (c == ',') {
2333                                         c = get_char ();
2334                                 }
2335
2336                                 // skip over white space
2337                                 while (c == ' ' || c == '\t')
2338                                         c = get_char ();
2339                         } else {
2340                                 number = -1;
2341                                 if (c == '/') {
2342                                         ReadSingleLineComment ();
2343                                 } else {
2344                                         Report.Warning (1692, 1, Location, "Invalid number");
2345
2346                                         // Read everything till the end of the line or file
2347                                         do {
2348                                                 c = get_char ();
2349                                         } while (c != -1 && c != '\n');
2350                                 }
2351                         }
2352
2353                         return number;
2354                 }
2355
2356                 void ReadSingleLineComment ()
2357                 {
2358                         if (peek_char () != '/')
2359                                 Report.Warning (1696, 1, Location, "Single-line comment or end-of-line expected");
2360
2361                         // Read everything till the end of the line or file
2362                         int c;
2363                         do {
2364                                 c = get_char ();
2365                         } while (c != -1 && c != '\n');
2366                 }
2367
2368                 /// <summary>
2369                 /// Handles #pragma directive
2370                 /// </summary>
2371                 void ParsePragmaDirective (string arg)
2372                 {
2373                         int c;
2374                         int length = TokenizePreprocessorIdentifier (out c);
2375                         if (length == pragma_warning.Length && IsTokenIdentifierEqual (pragma_warning)) {
2376                                 length = TokenizePreprocessorIdentifier (out c);
2377
2378                                 //
2379                                 // #pragma warning disable
2380                                 // #pragma warning restore
2381                                 //
2382                                 if (length == pragma_warning_disable.Length) {
2383                                         bool disable = IsTokenIdentifierEqual (pragma_warning_disable);
2384                                         if (disable || IsTokenIdentifierEqual (pragma_warning_restore)) {
2385                                                 // skip over white space
2386                                                 while (c == ' ' || c == '\t')
2387                                                         c = get_char ();
2388
2389                                                 var loc = Location;
2390
2391                                                 if (c == '\n' || c == '/') {
2392                                                         if (c == '/')
2393                                                                 ReadSingleLineComment ();
2394
2395                                                         //
2396                                                         // Disable/Restore all warnings
2397                                                         //
2398                                                         if (disable) {
2399                                                                 Report.RegisterWarningRegion (loc).WarningDisable (loc.Row);
2400                                                         } else {
2401                                                                 Report.RegisterWarningRegion (loc).WarningEnable (loc.Row);
2402                                                         }
2403                                                 } else {
2404                                                         //
2405                                                         // Disable/Restore a warning or group of warnings
2406                                                         //
2407                                                         int code;
2408                                                         do {
2409                                                                 code = TokenizePragmaNumber (ref c);
2410                                                                 if (code > 0) {
2411                                                                         if (disable) {
2412                                                                                 Report.RegisterWarningRegion (loc).WarningDisable (loc, code, context.Report);
2413                                                                         } else {
2414                                                                                 Report.RegisterWarningRegion (loc).WarningEnable (loc, code, context);
2415                                                                         }
2416                                                                 }
2417                                                         } while (code >= 0 && c != '\n' && c != -1);
2418                                                 }
2419
2420                                                 return;
2421                                         }
2422                                 }
2423
2424                                 Report.Warning (1634, 1, Location, "Expected disable or restore");
2425
2426                                 // Eat any remaining characters on the line
2427                                 while (c != '\n' && c != -1)
2428                                         c = get_char ();
2429
2430                                 return;
2431                         }
2432
2433                         //
2434                         // #pragma checksum
2435                         //
2436                         if (length == pragma_checksum.Length && IsTokenIdentifierEqual (pragma_checksum)) {
2437                                 if (c != ' ' || !ParsePragmaChecksum ()) {
2438                                         Report.Warning (1695, 1, Location,
2439                                                 "Invalid #pragma checksum syntax. Expected \"filename\" \"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\" \"XXXX...\"");
2440                                 }
2441
2442                                 return;
2443                         }
2444
2445                         Report.Warning (1633, 1, Location, "Unrecognized #pragma directive");
2446                 }
2447
2448                 bool eval_val (string s)
2449                 {
2450                         if (s == "true")
2451                                 return true;
2452                         if (s == "false")
2453                                 return false;
2454
2455                         return source_file.IsConditionalDefined (s);
2456                 }
2457
2458                 bool pp_primary (ref string s)
2459                 {
2460                         s = s.Trim ();
2461                         int len = s.Length;
2462
2463                         if (len > 0){
2464                                 char c = s [0];
2465                                 
2466                                 if (c == '('){
2467                                         s = s.Substring (1);
2468                                         bool val = pp_expr (ref s, false);
2469                                         if (s.Length > 0 && s [0] == ')'){
2470                                                 s = s.Substring (1);
2471                                                 return val;
2472                                         }
2473                                         Error_InvalidDirective ();
2474                                         return false;
2475                                 }
2476                                 
2477                                 if (is_identifier_start_character (c)){
2478                                         int j = 1;
2479
2480                                         while (j < len){
2481                                                 c = s [j];
2482                                                 
2483                                                 if (is_identifier_part_character (c)){
2484                                                         j++;
2485                                                         continue;
2486                                                 }
2487                                                 bool v = eval_val (s.Substring (0, j));
2488                                                 s = s.Substring (j);
2489                                                 return v;
2490                                         }
2491                                         bool vv = eval_val (s);
2492                                         s = "";
2493                                         return vv;
2494                                 }
2495                         }
2496                         Error_InvalidDirective ();
2497                         return false;
2498                 }
2499                 
2500                 bool pp_unary (ref string s)
2501                 {
2502                         s = s.Trim ();
2503                         int len = s.Length;
2504
2505                         if (len > 0){
2506                                 if (s [0] == '!'){
2507                                         if (len > 1 && s [1] == '='){
2508                                                 Error_InvalidDirective ();
2509                                                 return false;
2510                                         }
2511                                         s = s.Substring (1);
2512                                         return ! pp_primary (ref s);
2513                                 } else
2514                                         return pp_primary (ref s);
2515                         } else {
2516                                 Error_InvalidDirective ();
2517                                 return false;
2518                         }
2519                 }
2520                 
2521                 bool pp_eq (ref string s)
2522                 {
2523                         bool va = pp_unary (ref s);
2524
2525                         s = s.Trim ();
2526                         int len = s.Length;
2527                         if (len > 0){
2528                                 if (s [0] == '='){
2529                                         if (len > 2 && s [1] == '='){
2530                                                 s = s.Substring (2);
2531                                                 return va == pp_unary (ref s);
2532                                         } else {
2533                                                 Error_InvalidDirective ();
2534                                                 return false;
2535                                         }
2536                                 } else if (s [0] == '!' && len > 1 && s [1] == '='){
2537                                         s = s.Substring (2);
2538
2539                                         return va != pp_unary (ref s);
2540
2541                                 } 
2542                         }
2543
2544                         return va;
2545                                 
2546                 }
2547                 
2548                 bool pp_and (ref string s)
2549                 {
2550                         bool va = pp_eq (ref s);
2551
2552                         s = s.Trim ();
2553                         int len = s.Length;
2554                         if (len > 0){
2555                                 if (s [0] == '&'){
2556                                         if (len > 2 && s [1] == '&'){
2557                                                 s = s.Substring (2);
2558                                                 return (va & pp_and (ref s));
2559                                         } else {
2560                                                 Error_InvalidDirective ();
2561                                                 return false;
2562                                         }
2563                                 } 
2564                         }
2565                         return va;
2566                 }
2567                 
2568                 //
2569                 // Evaluates an expression for `#if' or `#elif'
2570                 //
2571                 bool pp_expr (ref string s, bool isTerm)
2572                 {
2573                         bool va = pp_and (ref s);
2574                         s = s.Trim ();
2575                         int len = s.Length;
2576                         if (len > 0){
2577                                 char c = s [0];
2578                                 
2579                                 if (c == '|'){
2580                                         if (len > 2 && s [1] == '|'){
2581                                                 s = s.Substring (2);
2582                                                 return va | pp_expr (ref s, isTerm);
2583                                         } else {
2584                                                 Error_InvalidDirective ();
2585                                                 return false;
2586                                         }
2587                                 }
2588                                 if (isTerm) {
2589                                         Error_EndLineExpected ();
2590                                         return false;
2591                                 }
2592                         }
2593                         
2594                         return va;
2595                 }
2596
2597                 bool eval (string s)
2598                 {
2599                         bool v = pp_expr (ref s, true);
2600                         s = s.Trim ();
2601                         if (s.Length != 0){
2602                                 return false;
2603                         }
2604
2605                         return v;
2606                 }
2607
2608                 void Error_NumericConstantTooLong ()
2609                 {
2610                         Report.Error (1021, Location, "Integral constant is too large");                        
2611                 }
2612                 
2613                 void Error_InvalidDirective ()
2614                 {
2615                         Report.Error (1517, Location, "Invalid preprocessor directive");
2616                 }
2617
2618                 void Error_UnexpectedDirective (string extra)
2619                 {
2620                         Report.Error (
2621                                 1028, Location,
2622                                 "Unexpected processor directive ({0})", extra);
2623                 }
2624
2625                 void Error_TokensSeen ()
2626                 {
2627                         Report.Error (1032, Location,
2628                                 "Cannot define or undefine preprocessor symbols after first token in file");
2629                 }
2630
2631                 void Eror_WrongPreprocessorLocation ()
2632                 {
2633                         Report.Error (1040, Location,
2634                                 "Preprocessor directives must appear as the first non-whitespace character on a line");
2635                 }
2636
2637                 void Error_EndLineExpected ()
2638                 {
2639                         Report.Error (1025, Location, "Single-line comment or end-of-line expected");
2640                 }
2641
2642                 //
2643                 // Raises a warning when tokenizer found documentation comment
2644                 // on unexpected place
2645                 //
2646                 void WarningMisplacedComment (Location loc)
2647                 {
2648                         if (doc_state != XmlCommentState.Error) {
2649                                 doc_state = XmlCommentState.Error;
2650                                 Report.Warning (1587, 2, loc, "XML comment is not placed on a valid language element");
2651                         }
2652                 }
2653                 
2654                 //
2655                 // if true, then the code continues processing the code
2656                 // if false, the code stays in a loop until another directive is
2657                 // reached.
2658                 // When caller_is_taking is false we ignore all directives except the ones
2659                 // which can help us to identify where the #if block ends
2660                 bool ParsePreprocessingDirective (bool caller_is_taking)
2661                 {
2662                         string arg;
2663                         bool region_directive = false;
2664
2665                         var directive = get_cmd_arg (out arg);
2666
2667                         //
2668                         // The first group of pre-processing instructions is always processed
2669                         //
2670                         switch (directive) {
2671                         case PreprocessorDirective.Region:
2672                                 region_directive = true;
2673                                 arg = "true";
2674                                 goto case PreprocessorDirective.If;
2675
2676                         case PreprocessorDirective.Endregion:
2677                                 if (ifstack == null || ifstack.Count == 0){
2678                                         Error_UnexpectedDirective ("no #region for this #endregion");
2679                                         return true;
2680                                 }
2681                                 int pop = ifstack.Pop ();
2682                                         
2683                                 if ((pop & REGION) == 0)
2684                                         Report.Error (1027, Location, "Expected `#endif' directive");
2685                                         
2686                                 return caller_is_taking;
2687                                 
2688                         case PreprocessorDirective.If:
2689                                 if (ifstack == null)
2690                                         ifstack = new Stack<int> (2);
2691
2692                                 int flags = region_directive ? REGION : 0;
2693                                 if (ifstack.Count == 0){
2694                                         flags |= PARENT_TAKING;
2695                                 } else {
2696                                         int state = ifstack.Peek ();
2697                                         if ((state & TAKING) != 0) {
2698                                                 flags |= PARENT_TAKING;
2699                                         }
2700                                 }
2701
2702                                 if (eval (arg) && caller_is_taking) {
2703                                         ifstack.Push (flags | TAKING);
2704                                         return true;
2705                                 }
2706                                 ifstack.Push (flags);
2707                                 return false;
2708
2709                         case PreprocessorDirective.Endif:
2710                                 if (ifstack == null || ifstack.Count == 0){
2711                                         Error_UnexpectedDirective ("no #if for this #endif");
2712                                         return true;
2713                                 } else {
2714                                         pop = ifstack.Pop ();
2715                                         
2716                                         if ((pop & REGION) != 0)
2717                                                 Report.Error (1038, Location, "#endregion directive expected");
2718                                         
2719                                         if (arg.Length != 0) {
2720                                                 Error_EndLineExpected ();
2721                                         }
2722                                         
2723                                         if (ifstack.Count == 0)
2724                                                 return true;
2725
2726                                         int state = ifstack.Peek ();
2727                                         return (state & TAKING) != 0;
2728                                 }
2729
2730                         case PreprocessorDirective.Elif:
2731                                 if (ifstack == null || ifstack.Count == 0){
2732                                         Error_UnexpectedDirective ("no #if for this #elif");
2733                                         return true;
2734                                 } else {
2735                                         int state = ifstack.Pop ();
2736
2737                                         if ((state & REGION) != 0) {
2738                                                 Report.Error (1038, Location, "#endregion directive expected");
2739                                                 return true;
2740                                         }
2741
2742                                         if ((state & ELSE_SEEN) != 0){
2743                                                 Error_UnexpectedDirective ("#elif not valid after #else");
2744                                                 return true;
2745                                         }
2746
2747                                         if ((state & TAKING) != 0) {
2748                                                 ifstack.Push (0);
2749                                                 return false;
2750                                         }
2751
2752                                         if (eval (arg) && ((state & PARENT_TAKING) != 0)){
2753                                                 ifstack.Push (state | TAKING);
2754                                                 return true;
2755                                         }
2756
2757                                         ifstack.Push (state);
2758                                         return false;
2759                                 }
2760
2761                         case PreprocessorDirective.Else:
2762                                 if (ifstack == null || ifstack.Count == 0){
2763                                         Error_UnexpectedDirective ("no #if for this #else");
2764                                         return true;
2765                                 } else {
2766                                         int state = ifstack.Peek ();
2767
2768                                         if ((state & REGION) != 0) {
2769                                                 Report.Error (1038, Location, "#endregion directive expected");
2770                                                 return true;
2771                                         }
2772
2773                                         if ((state & ELSE_SEEN) != 0){
2774                                                 Error_UnexpectedDirective ("#else within #else");
2775                                                 return true;
2776                                         }
2777
2778                                         ifstack.Pop ();
2779
2780                                         if (arg.Length != 0) {
2781                                                 Error_EndLineExpected ();
2782                                                 return true;
2783                                         }
2784
2785                                         bool ret = false;
2786                                         if ((state & PARENT_TAKING) != 0) {
2787                                                 ret = (state & TAKING) == 0;
2788                                         
2789                                                 if (ret)
2790                                                         state |= TAKING;
2791                                                 else
2792                                                         state &= ~TAKING;
2793                                         }
2794         
2795                                         ifstack.Push (state | ELSE_SEEN);
2796                                         
2797                                         return ret;
2798                                 }
2799                         case PreprocessorDirective.Define:
2800                                 if (any_token_seen){
2801                                         Error_TokensSeen ();
2802                                         return caller_is_taking;
2803                                 }
2804                                 PreProcessDefinition (true, arg, caller_is_taking);
2805                                 return caller_is_taking;
2806
2807                         case PreprocessorDirective.Undef:
2808                                 if (any_token_seen){
2809                                         Error_TokensSeen ();
2810                                         return caller_is_taking;
2811                                 }
2812                                 PreProcessDefinition (false, arg, caller_is_taking);
2813                                 return caller_is_taking;
2814
2815                         case PreprocessorDirective.Invalid:
2816                                 Report.Error (1024, Location, "Wrong preprocessor directive");
2817                                 return true;
2818                         }
2819
2820                         //
2821                         // These are only processed if we are in a `taking' block
2822                         //
2823                         if (!caller_is_taking)
2824                                 return false;
2825                                         
2826                         switch (directive){
2827                         case PreprocessorDirective.Error:
2828                                 Report.Error (1029, Location, "#error: '{0}'", arg);
2829                                 return true;
2830
2831                         case PreprocessorDirective.Warning:
2832                                 Report.Warning (1030, 1, Location, "#warning: `{0}'", arg);
2833                                 return true;
2834
2835                         case PreprocessorDirective.Pragma:
2836                                 if (context.Settings.Version == LanguageVersion.ISO_1) {
2837                                         Report.FeatureIsNotAvailable (context, Location, "#pragma");
2838                                 }
2839
2840                                 ParsePragmaDirective (arg);
2841                                 return true;
2842
2843                         case PreprocessorDirective.Line:
2844                                 Location loc = Location;
2845                                 if (!PreProcessLine ())
2846                                         Report.Error (1576, loc, "The line number specified for #line directive is missing or invalid");
2847
2848                                 return caller_is_taking;
2849                         }
2850
2851                         throw new NotImplementedException (directive.ToString ());
2852                 }
2853
2854                 private int consume_string (bool quoted)
2855                 {
2856                         int c;
2857                         int pos = 0;
2858                         Location start_location = Location;
2859                         if (quoted)
2860                                 start_location = start_location - 1;
2861
2862 #if FULL_AST
2863                         int reader_pos = reader.Position;
2864 #endif
2865
2866                         while (true){
2867                                 // Cannot use get_char because of \r in quoted strings
2868                                 if (putback_char != -1) {
2869                                         c = putback_char;
2870                                         putback_char = -1;
2871                                 } else {
2872                                         c = reader.Read ();
2873                                 }
2874
2875                                 if (c == '"') {
2876                                         ++col;
2877
2878                                         if (quoted && peek_char () == '"') {
2879                                                 if (pos == value_builder.Length)
2880                                                         Array.Resize (ref value_builder, pos * 2);
2881
2882                                                 value_builder[pos++] = (char) c;
2883                                                 get_char ();
2884                                                 continue;
2885                                         }
2886
2887                                         string s;
2888                                         if (pos == 0)
2889                                                 s = string.Empty;
2890                                         else if (pos <= 4)
2891                                                 s = InternIdentifier (value_builder, pos);
2892                                         else
2893                                                 s = new string (value_builder, 0, pos);
2894
2895                                         ILiteralConstant res = new StringLiteral (context.BuiltinTypes, s, start_location);
2896                                         val = res;
2897 #if FULL_AST
2898                                         res.ParsedValue = quoted ?
2899                                                 reader.ReadChars (reader_pos - 2, reader.Position - 1) :
2900                                                 reader.ReadChars (reader_pos - 1, reader.Position);
2901 #endif
2902
2903                                         return Token.LITERAL;
2904                                 }
2905
2906                                 if (c == '\n') {
2907                                         if (!quoted) {
2908                                                 Report.Error (1010, Location, "Newline in constant");
2909
2910                                                 advance_line ();
2911
2912                                                 // Don't add \r to string literal
2913                                                 if (pos > 1 && value_builder [pos - 1] == '\r')
2914                                                         --pos;
2915
2916                                                 val = new StringLiteral (context.BuiltinTypes, new string (value_builder, 0, pos), start_location);
2917                                                 return Token.LITERAL;
2918                                         }
2919
2920                                         advance_line ();
2921                                 } else if (c == '\\' && !quoted) {
2922                                         int surrogate;
2923                                         c = escape (c, out surrogate);
2924                                         if (c == -1)
2925                                                 return Token.ERROR;
2926                                         if (surrogate != 0) {
2927                                                 if (pos == value_builder.Length)
2928                                                         Array.Resize (ref value_builder, pos * 2);
2929
2930                                                 value_builder[pos++] = (char) c;
2931                                                 c = surrogate;
2932                                         }
2933                                 } else if (c == -1) {
2934                                         Report.Error (1039, Location, "Unterminated string literal");
2935                                         return Token.EOF;
2936                                 } else {
2937                                         ++col;
2938                                 }
2939
2940                                 if (pos == value_builder.Length)
2941                                         Array.Resize (ref value_builder, pos * 2);
2942
2943                                 value_builder[pos++] = (char) c;
2944                         }
2945                 }
2946
2947                 private int consume_identifier (int s)
2948                 {
2949                         int res = consume_identifier (s, false);
2950
2951                         if (doc_state == XmlCommentState.Allowed)
2952                                 doc_state = XmlCommentState.NotAllowed;
2953
2954                         return res;
2955                 }
2956
2957                 int consume_identifier (int c, bool quoted) 
2958                 {
2959                         //
2960                         // This method is very performance sensitive. It accounts
2961                         // for approximately 25% of all parser time
2962                         //
2963
2964                         int pos = 0;
2965                         int column = col;
2966                         if (quoted)
2967                                 --column;
2968
2969                         if (c == '\\') {
2970                                 int surrogate;
2971                                 c = escape (c, out surrogate);
2972                                 if (surrogate != 0) {
2973                                         id_builder [pos++] = (char) c;
2974                                         c = surrogate;
2975                                 }
2976                         }
2977
2978                         id_builder [pos++] = (char) c;
2979
2980                         try {
2981                                 while (true) {
2982                                         c = reader.Read ();
2983
2984                                         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9')) {
2985                                                 id_builder [pos++] = (char) c;
2986                                                 continue;
2987                                         }
2988
2989                                         if (c < 0x80) {
2990                                                 if (c == '\\') {
2991                                                         int surrogate;
2992                                                         c = escape (c, out surrogate);
2993                                                         if (is_identifier_part_character ((char) c))
2994                                                                 id_builder[pos++] = (char) c;
2995
2996                                                         if (surrogate != 0) {
2997                                                                 c = surrogate;
2998                                                         }
2999
3000                                                         continue;
3001                                                 }
3002                                         } else if (Char.IsLetter ((char) c) || Char.GetUnicodeCategory ((char) c) == UnicodeCategory.ConnectorPunctuation) {
3003                                                 id_builder [pos++] = (char) c;
3004                                                 continue;
3005                                         }
3006
3007                                         putback_char = c;
3008                                         break;
3009                                 }
3010                         } catch (IndexOutOfRangeException) {
3011                                 Report.Error (645, Location, "Identifier too long (limit is 512 chars)");
3012                                 --pos;
3013                                 col += pos;
3014                         }
3015
3016                         col += pos - 1;
3017
3018                         //
3019                         // Optimization: avoids doing the keyword lookup
3020                         // on uppercase letters
3021                         //
3022                         if (id_builder [0] >= '_' && !quoted) {
3023                                 int keyword = GetKeyword (id_builder, pos);
3024                                 if (keyword != -1) {
3025                                         val = ltb.Create (keyword == Token.AWAIT ? "await" : null, current_source, ref_line, column);
3026                                         return keyword;
3027                                 }
3028                         }
3029
3030                         string s = InternIdentifier (id_builder, pos);
3031                         val = ltb.Create (s, current_source, ref_line, column);
3032                         if (quoted && parsing_attribute_section)
3033                                 AddEscapedIdentifier (((LocatedToken) val).Location);
3034
3035                         return Token.IDENTIFIER;
3036                 }
3037
3038                 string InternIdentifier (char[] charBuffer, int length)
3039                 {
3040                         //
3041                         // Keep identifiers in an array of hashtables to avoid needless
3042                         // allocations
3043                         //
3044                         var identifiers_group = identifiers[length];
3045                         string s;
3046                         if (identifiers_group != null) {
3047                                 if (identifiers_group.TryGetValue (charBuffer, out s)) {
3048                                         return s;
3049                                 }
3050                         } else {
3051                                 // TODO: this should be number of files dependant
3052                                 // corlib compilation peaks at 1000 and System.Core at 150
3053                                 int capacity = length > 20 ? 10 : 100;
3054                                 identifiers_group = new Dictionary<char[], string> (capacity, new IdentifiersComparer (length));
3055                                 identifiers[length] = identifiers_group;
3056                         }
3057
3058                         char[] chars = new char[length];
3059                         Array.Copy (charBuffer, chars, length);
3060
3061                         s = new string (charBuffer, 0, length);
3062                         identifiers_group.Add (chars, s);
3063                         return s;
3064                 }
3065                 
3066                 public int xtoken ()
3067                 {
3068                         int d, c;
3069
3070                         // Whether we have seen comments on the current line
3071                         bool comments_seen = false;
3072                         while ((c = get_char ()) != -1) {
3073                                 switch (c) {
3074                                 case '\t':
3075                                         col = ((col - 1 + tab_size) / tab_size) * tab_size;
3076                                         continue;
3077
3078                                 case ' ':
3079                                 case '\f':
3080                                 case '\v':
3081                                 case 0xa0:
3082                                 case 0:
3083                                 case 0xFEFF:    // Ignore BOM anywhere in the file
3084                                         continue;
3085
3086 /*                              This is required for compatibility with .NET
3087                                 case 0xEF:
3088                                         if (peek_char () == 0xBB) {
3089                                                 PushPosition ();
3090                                                 get_char ();
3091                                                 if (get_char () == 0xBF)
3092                                                         continue;
3093                                                 PopPosition ();
3094                                         }
3095                                         break;
3096 */
3097                                 case '\\':
3098                                         tokens_seen = true;
3099                                         return consume_identifier (c);
3100
3101                                 case '{':
3102                                         val = ltb.Create (current_source, ref_line, col);
3103                                         return Token.OPEN_BRACE;
3104                                 case '}':
3105                                         val = ltb.Create (current_source, ref_line, col);
3106                                         return Token.CLOSE_BRACE;
3107                                 case '[':
3108                                         // To block doccomment inside attribute declaration.
3109                                         if (doc_state == XmlCommentState.Allowed)
3110                                                 doc_state = XmlCommentState.NotAllowed;
3111
3112                                         val = ltb.Create (current_source, ref_line, col);
3113
3114                                         if (parsing_block == 0 || lambda_arguments_parsing)
3115                                                 return Token.OPEN_BRACKET;
3116
3117                                         int next = peek_char ();
3118                                         switch (next) {
3119                                         case ']':
3120                                         case ',':
3121                                                 return Token.OPEN_BRACKET;
3122
3123                                         case ' ':
3124                                         case '\f':
3125                                         case '\v':
3126                                         case '\r':
3127                                         case '\n':
3128                                         case '/':
3129                                                 next = peek_token ();
3130                                                 if (next == Token.COMMA || next == Token.CLOSE_BRACKET)
3131                                                         return Token.OPEN_BRACKET;
3132
3133                                                 return Token.OPEN_BRACKET_EXPR;
3134                                         default:
3135                                                 return Token.OPEN_BRACKET_EXPR;
3136                                         }
3137                                 case ']':
3138                                         ltb.CreateOptional (current_source, ref_line, col, ref val);
3139                                         return Token.CLOSE_BRACKET;
3140                                 case '(':
3141                                         val = ltb.Create (current_source, ref_line, col);
3142                                         //
3143                                         // An expression versions of parens can appear in block context only
3144                                         //
3145                                         if (parsing_block != 0 && !lambda_arguments_parsing) {
3146                                                 
3147                                                 //
3148                                                 // Optmize most common case where we know that parens
3149                                                 // is not special
3150                                                 //
3151                                                 switch (current_token) {
3152                                                 case Token.IDENTIFIER:
3153                                                 case Token.IF:
3154                                                 case Token.FOR:
3155                                                 case Token.FOREACH:
3156                                                 case Token.TYPEOF:
3157                                                 case Token.WHILE:
3158                                                 case Token.USING:
3159                                                 case Token.DEFAULT:
3160                                                 case Token.DELEGATE:
3161                                                 case Token.OP_GENERICS_GT:
3162                                                         return Token.OPEN_PARENS;
3163                                                 }
3164
3165                                                 // Optimize using peek
3166                                                 int xx = peek_char ();
3167                                                 switch (xx) {
3168                                                 case '(':
3169                                                 case '\'':
3170                                                 case '"':
3171                                                 case '0':
3172                                                 case '1':
3173                                                         return Token.OPEN_PARENS;
3174                                                 }
3175
3176                                                 lambda_arguments_parsing = true;
3177                                                 PushPosition ();
3178                                                 d = TokenizeOpenParens ();
3179                                                 PopPosition ();
3180                                                 lambda_arguments_parsing = false;
3181                                                 return d;
3182                                         }
3183
3184                                         return Token.OPEN_PARENS;
3185                                 case ')':
3186                                         ltb.CreateOptional (current_source, ref_line, col, ref val);
3187                                         return Token.CLOSE_PARENS;
3188                                 case ',':
3189                                         ltb.CreateOptional (current_source, ref_line, col, ref val);
3190                                         return Token.COMMA;
3191                                 case ';':
3192                                         ltb.CreateOptional (current_source, ref_line, col, ref val);
3193                                         return Token.SEMICOLON;
3194                                 case '~':
3195                                         val = ltb.Create (current_source, ref_line, col);
3196                                         return Token.TILDE;
3197                                 case '?':
3198                                         val = ltb.Create (current_source, ref_line, col);
3199                                         return TokenizePossibleNullableType ();
3200                                 case '<':
3201                                         val = ltb.Create (current_source, ref_line, col);
3202                                         if (parsing_generic_less_than++ > 0)
3203                                                 return Token.OP_GENERICS_LT;
3204
3205                                         return TokenizeLessThan ();
3206
3207                                 case '>':
3208                                         val = ltb.Create (current_source, ref_line, col);
3209                                         d = peek_char ();
3210
3211                                         if (d == '='){
3212                                                 get_char ();
3213                                                 return Token.OP_GE;
3214                                         }
3215
3216                                         if (parsing_generic_less_than > 1 || (parsing_generic_less_than == 1 && d != '>')) {
3217                                                 parsing_generic_less_than--;
3218                                                 return Token.OP_GENERICS_GT;
3219                                         }
3220
3221                                         if (d == '>') {
3222                                                 get_char ();
3223                                                 d = peek_char ();
3224
3225                                                 if (d == '=') {
3226                                                         get_char ();
3227                                                         return Token.OP_SHIFT_RIGHT_ASSIGN;
3228                                                 }
3229                                                 return Token.OP_SHIFT_RIGHT;
3230                                         }
3231
3232                                         return Token.OP_GT;
3233
3234                                 case '+':
3235                                         val = ltb.Create (current_source, ref_line, col);
3236                                         d = peek_char ();
3237                                         if (d == '+') {
3238                                                 d = Token.OP_INC;
3239                                         } else if (d == '=') {
3240                                                 d = Token.OP_ADD_ASSIGN;
3241                                         } else {
3242                                                 return Token.PLUS;
3243                                         }
3244                                         get_char ();
3245                                         return d;
3246
3247                                 case '-':
3248                                         val = ltb.Create (current_source, ref_line, col);
3249                                         d = peek_char ();
3250                                         if (d == '-') {
3251                                                 d = Token.OP_DEC;
3252                                         } else if (d == '=')
3253                                                 d = Token.OP_SUB_ASSIGN;
3254                                         else if (d == '>')
3255                                                 d = Token.OP_PTR;
3256                                         else {
3257                                                 return Token.MINUS;
3258                                         }
3259                                         get_char ();
3260                                         return d;
3261
3262                                 case '!':
3263                                         val = ltb.Create (current_source, ref_line, col);
3264                                         if (peek_char () == '='){
3265                                                 get_char ();
3266                                                 return Token.OP_NE;
3267                                         }
3268                                         return Token.BANG;
3269
3270                                 case '=':
3271                                         val = ltb.Create (current_source, ref_line, col);
3272                                         d = peek_char ();
3273                                         if (d == '='){
3274                                                 get_char ();
3275                                                 return Token.OP_EQ;
3276                                         }
3277                                         if (d == '>'){
3278                                                 get_char ();
3279                                                 return Token.ARROW;
3280                                         }
3281
3282                                         return Token.ASSIGN;
3283
3284                                 case '&':
3285                                         val = ltb.Create (current_source, ref_line, col);
3286                                         d = peek_char ();
3287                                         if (d == '&'){
3288                                                 get_char ();
3289                                                 return Token.OP_AND;
3290                                         }
3291                                         if (d == '='){
3292                                                 get_char ();
3293                                                 return Token.OP_AND_ASSIGN;
3294                                         }
3295                                         return Token.BITWISE_AND;
3296
3297                                 case '|':
3298                                         val = ltb.Create (current_source, ref_line, col);
3299                                         d = peek_char ();
3300                                         if (d == '|'){
3301                                                 get_char ();
3302                                                 return Token.OP_OR;
3303                                         }
3304                                         if (d == '='){
3305                                                 get_char ();
3306                                                 return Token.OP_OR_ASSIGN;
3307                                         }
3308                                         return Token.BITWISE_OR;
3309
3310                                 case '*':
3311                                         val = ltb.Create (current_source, ref_line, col);
3312                                         if (peek_char () == '='){
3313                                                 get_char ();
3314                                                 return Token.OP_MULT_ASSIGN;
3315                                         }
3316                                         return Token.STAR;
3317
3318                                 case '/':
3319                                         d = peek_char ();
3320                                         if (d == '='){
3321                                                 val = ltb.Create (current_source, ref_line, col);
3322                                                 get_char ();
3323                                                 return Token.OP_DIV_ASSIGN;
3324                                         }
3325
3326                                         // Handle double-slash comments.
3327                                         if (d == '/'){
3328                                                 get_char ();
3329                                                 if (doc_processing) {
3330                                                         if (peek_char () == '/') {
3331                                                                 get_char ();
3332                                                                 // Don't allow ////.
3333                                                                 if ((d = peek_char ()) != '/') {
3334                                                                         if (doc_state == XmlCommentState.Allowed)
3335                                                                                 handle_one_line_xml_comment ();
3336                                                                         else if (doc_state == XmlCommentState.NotAllowed)
3337                                                                                 WarningMisplacedComment (Location - 3);
3338                                                                 }
3339                                                         } else {
3340                                                                 if (xml_comment_buffer.Length > 0)
3341                                                                         doc_state = XmlCommentState.NotAllowed;
3342                                                         }
3343                                                 }
3344
3345                                                 while ((d = get_char ()) != -1 && d != '\n');
3346
3347                                                 any_token_seen |= tokens_seen;
3348                                                 tokens_seen = false;
3349                                                 comments_seen = false;
3350                                                 continue;
3351                                         } else if (d == '*'){
3352                                                 get_char ();
3353                                                 bool docAppend = false;
3354                                                 if (doc_processing && peek_char () == '*') {
3355                                                         get_char ();
3356                                                         // But when it is /**/, just do nothing.
3357                                                         if (peek_char () == '/') {
3358                                                                 get_char ();
3359                                                                 continue;
3360                                                         }
3361                                                         if (doc_state == XmlCommentState.Allowed)
3362                                                                 docAppend = true;
3363                                                         else if (doc_state == XmlCommentState.NotAllowed) {
3364                                                                 WarningMisplacedComment (Location - 2);
3365                                                         }
3366                                                 }
3367
3368                                                 int current_comment_start = 0;
3369                                                 if (docAppend) {
3370                                                         current_comment_start = xml_comment_buffer.Length;
3371                                                         xml_comment_buffer.Append (Environment.NewLine);
3372                                                 }
3373
3374                                                 while ((d = get_char ()) != -1){
3375                                                         if (d == '*' && peek_char () == '/'){
3376                                                                 get_char ();
3377                                                                 comments_seen = true;
3378                                                                 break;
3379                                                         }
3380                                                         if (docAppend)
3381                                                                 xml_comment_buffer.Append ((char) d);
3382                                                         
3383                                                         if (d == '\n'){
3384                                                                 any_token_seen |= tokens_seen;
3385                                                                 tokens_seen = false;
3386                                                                 // 
3387                                                                 // Reset 'comments_seen' just to be consistent.
3388                                                                 // It doesn't matter either way, here.
3389                                                                 //
3390                                                                 comments_seen = false;
3391                                                         }
3392                                                 }
3393                                                 if (!comments_seen)
3394                                                         Report.Error (1035, Location, "End-of-file found, '*/' expected");
3395
3396                                                 if (docAppend)
3397                                                         update_formatted_doc_comment (current_comment_start);
3398                                                 continue;
3399                                         }
3400                                         val = ltb.Create (current_source, ref_line, col);
3401                                         return Token.DIV;
3402
3403                                 case '%':
3404                                         val = ltb.Create (current_source, ref_line, col);
3405                                         if (peek_char () == '='){
3406                                                 get_char ();
3407                                                 return Token.OP_MOD_ASSIGN;
3408                                         }
3409                                         return Token.PERCENT;
3410
3411                                 case '^':
3412                                         val = ltb.Create (current_source, ref_line, col);
3413                                         if (peek_char () == '='){
3414                                                 get_char ();
3415                                                 return Token.OP_XOR_ASSIGN;
3416                                         }
3417                                         return Token.CARRET;
3418
3419                                 case ':':
3420                                         val = ltb.Create (current_source, ref_line, col);
3421                                         if (peek_char () == ':') {
3422                                                 get_char ();
3423                                                 return Token.DOUBLE_COLON;
3424                                         }
3425                                         return Token.COLON;
3426
3427                                 case '0': case '1': case '2': case '3': case '4':
3428                                 case '5': case '6': case '7': case '8': case '9':
3429                                         tokens_seen = true;
3430                                         return is_number (c);
3431
3432                                 case '\n': // white space
3433                                         any_token_seen |= tokens_seen;
3434                                         tokens_seen = false;
3435                                         comments_seen = false;
3436                                         continue;
3437
3438                                 case '.':
3439                                         tokens_seen = true;
3440                                         d = peek_char ();
3441                                         if (d >= '0' && d <= '9')
3442                                                 return is_number (c);
3443
3444                                         ltb.CreateOptional (current_source, ref_line, col, ref val);
3445                                         return Token.DOT;
3446                                 
3447                                 case '#':
3448                                         if (tokens_seen || comments_seen) {
3449                                                 Eror_WrongPreprocessorLocation ();
3450                                                 return Token.ERROR;
3451                                         }
3452                                         
3453                                         if (ParsePreprocessingDirective (true))
3454                                                 continue;
3455
3456                                         bool directive_expected = false;
3457                                         while ((c = get_char ()) != -1) {
3458                                                 if (col == 1) {
3459                                                         directive_expected = true;
3460                                                 } else if (!directive_expected) {
3461                                                         // TODO: Implement comment support for disabled code and uncomment this code
3462 //                                                      if (c == '#') {
3463 //                                                              Eror_WrongPreprocessorLocation ();
3464 //                                                              return Token.ERROR;
3465 //                                                      }
3466                                                         continue;
3467                                                 }
3468
3469                                                 if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' )
3470                                                         continue;
3471
3472                                                 if (c == '#') {
3473                                                         if (ParsePreprocessingDirective (false))
3474                                                                 break;
3475                                                 }
3476                                                 directive_expected = false;
3477                                         }
3478
3479                                         if (c != -1) {
3480                                                 tokens_seen = false;
3481                                                 continue;
3482                                         }
3483
3484                                         return Token.EOF;
3485                                 
3486                                 case '"':
3487                                         return consume_string (false);
3488
3489                                 case '\'':
3490                                         return TokenizeBackslash ();
3491                                 
3492                                 case '@':
3493                                         c = get_char ();
3494                                         if (c == '"') {
3495                                                 tokens_seen = true;
3496                                                 return consume_string (true);
3497                                         }
3498
3499                                         if (is_identifier_start_character (c)){
3500                                                 return consume_identifier (c, true);
3501                                         }
3502
3503                                         Report.Error (1646, Location, "Keyword, identifier, or string expected after verbatim specifier: @");
3504                                         return Token.ERROR;
3505
3506                                 case EvalStatementParserCharacter:
3507                                         return Token.EVAL_STATEMENT_PARSER;
3508                                 case EvalCompilationUnitParserCharacter:
3509                                         return Token.EVAL_COMPILATION_UNIT_PARSER;
3510                                 case EvalUsingDeclarationsParserCharacter:
3511                                         return Token.EVAL_USING_DECLARATIONS_UNIT_PARSER;
3512                                 case DocumentationXref:
3513                                         return Token.DOC_SEE;
3514                                 }
3515
3516                                 if (is_identifier_start_character (c)) {
3517                                         tokens_seen = true;
3518                                         return consume_identifier (c);
3519                                 }
3520
3521                                 if (char.IsWhiteSpace ((char) c))
3522                                         continue;
3523
3524                                 Report.Error (1056, Location, "Unexpected character `{0}'", ((char) c).ToString ());
3525                         }
3526
3527                         if (CompleteOnEOF){
3528                                 if (generated)
3529                                         return Token.COMPLETE_COMPLETION;
3530                                 
3531                                 generated = true;
3532                                 return Token.GENERATE_COMPLETION;
3533                         }
3534                         
3535
3536                         return Token.EOF;
3537                 }
3538
3539                 int TokenizeBackslash ()
3540                 {
3541 #if FULL_AST
3542                         int read_start = reader.Position;
3543 #endif
3544                         Location start_location = Location;
3545                         int c = get_char ();
3546                         tokens_seen = true;
3547                         if (c == '\'') {
3548                                 val = new CharLiteral (context.BuiltinTypes, (char) c, start_location);
3549                                 Report.Error (1011, start_location, "Empty character literal");
3550                                 return Token.LITERAL;
3551                         }
3552
3553                         if (c == '\n') {
3554                                 Report.Error (1010, start_location, "Newline in constant");
3555                                 return Token.ERROR;
3556                         }
3557
3558                         int d;
3559                         c = escape (c, out d);
3560                         if (c == -1)
3561                                 return Token.ERROR;
3562                         if (d != 0)
3563                                 throw new NotImplementedException ();
3564
3565                         ILiteralConstant res = new CharLiteral (context.BuiltinTypes, (char) c, start_location);
3566                         val = res;
3567                         c = get_char ();
3568
3569                         if (c != '\'') {
3570                                 Report.Error (1012, start_location, "Too many characters in character literal");
3571
3572                                 // Try to recover, read until newline or next "'"
3573                                 while ((c = get_char ()) != -1) {
3574                                         if (c == '\n' || c == '\'')
3575                                                 break;
3576                                 }
3577                         }
3578
3579 #if FULL_AST
3580                         res.ParsedValue = reader.ReadChars (read_start - 1, reader.Position);
3581 #endif
3582
3583                         return Token.LITERAL;
3584                 }
3585
3586                 int TokenizeLessThan ()
3587                 {
3588                         int d;
3589                         if (handle_typeof) {
3590                                 PushPosition ();
3591                                 if (parse_generic_dimension (out d)) {
3592                                         val = d;
3593                                         DiscardPosition ();
3594                                         return Token.GENERIC_DIMENSION;
3595                                 }
3596                                 PopPosition ();
3597                         }
3598
3599                         // Save current position and parse next token.
3600                         PushPosition ();
3601                         if (parse_less_than ()) {
3602                                 if (parsing_generic_declaration && (parsing_generic_declaration_doc || token () != Token.DOT)) {
3603                                         d = Token.OP_GENERICS_LT_DECL;
3604                                 } else {
3605                                         d = Token.OP_GENERICS_LT;
3606                                 }
3607                                 PopPosition ();
3608                                 return d;
3609                         }
3610
3611                         PopPosition ();
3612                         parsing_generic_less_than = 0;
3613
3614                         d = peek_char ();
3615                         if (d == '<') {
3616                                 get_char ();
3617                                 d = peek_char ();
3618
3619                                 if (d == '=') {
3620                                         get_char ();
3621                                         return Token.OP_SHIFT_LEFT_ASSIGN;
3622                                 }
3623                                 return Token.OP_SHIFT_LEFT;
3624                         }
3625
3626                         if (d == '=') {
3627                                 get_char ();
3628                                 return Token.OP_LE;
3629                         }
3630                         return Token.OP_LT;
3631                 }
3632
3633                 //
3634                 // Handles one line xml comment
3635                 //
3636                 private void handle_one_line_xml_comment ()
3637                 {
3638                         int c;
3639                         while ((c = peek_char ()) == ' ')
3640                                 get_char (); // skip heading whitespaces.
3641                         while ((c = peek_char ()) != -1 && c != '\n' && c != '\r') {
3642                                 xml_comment_buffer.Append ((char) get_char ());
3643                         }
3644                         if (c == '\r' || c == '\n')
3645                                 xml_comment_buffer.Append (Environment.NewLine);
3646                 }
3647
3648                 //
3649                 // Remove heading "*" in Javadoc-like xml documentation.
3650                 //
3651                 private void update_formatted_doc_comment (int current_comment_start)
3652                 {
3653                         int length = xml_comment_buffer.Length - current_comment_start;
3654                         string [] lines = xml_comment_buffer.ToString (
3655                                 current_comment_start,
3656                                 length).Replace ("\r", "").Split ('\n');
3657                         
3658                         // The first line starts with /**, thus it is not target
3659                         // for the format check.
3660                         for (int i = 1; i < lines.Length; i++) {
3661                                 string s = lines [i];
3662                                 int idx = s.IndexOf ('*');
3663                                 string head = null;
3664                                 if (idx < 0) {
3665                                         if (i < lines.Length - 1)
3666                                                 return;
3667                                         head = s;
3668                                 } else
3669                                         head = s.Substring (0, idx);
3670                                 foreach (char c in head)
3671                                         if (c != ' ')
3672                                                 return;
3673                                 lines [i] = s.Substring (idx + 1);
3674                         }
3675                         xml_comment_buffer.Remove (current_comment_start, length);
3676                         xml_comment_buffer.Insert (current_comment_start, String.Join (Environment.NewLine, lines));
3677                 }
3678
3679                 //
3680                 // Checks if there was incorrect doc comments and raise
3681                 // warnings.
3682                 //
3683                 public void check_incorrect_doc_comment ()
3684                 {
3685                         if (xml_comment_buffer.Length > 0)
3686                                 WarningMisplacedComment (Location);
3687                 }
3688
3689                 //
3690                 // Consumes the saved xml comment lines (if any)
3691                 // as for current target member or type.
3692                 //
3693                 public string consume_doc_comment ()
3694                 {
3695                         if (xml_comment_buffer.Length > 0) {
3696                                 string ret = xml_comment_buffer.ToString ();
3697                                 reset_doc_comment ();
3698                                 return ret;
3699                         }
3700                         return null;
3701                 }
3702
3703                 Report Report {
3704                         get { return context.Report; }
3705                 }
3706
3707                 void reset_doc_comment ()
3708                 {
3709                         xml_comment_buffer.Length = 0;
3710                 }
3711
3712                 public void cleanup ()
3713                 {
3714                         if (ifstack != null && ifstack.Count >= 1) {
3715                                 int state = ifstack.Pop ();
3716                                 if ((state & REGION) != 0)
3717                                         Report.Error (1038, Location, "#endregion directive expected");
3718                                 else 
3719                                         Report.Error (1027, Location, "Expected `#endif' directive");
3720                         }
3721                 }
3722         }
3723
3724         //
3725         // Indicates whether it accepts XML documentation or not.
3726         //
3727         public enum XmlCommentState {
3728                 // comment is allowed in this state.
3729                 Allowed,
3730                 // comment is not allowed in this state.
3731                 NotAllowed,
3732                 // once comments appeared when it is NotAllowed, then the
3733                 // state is changed to it, until the state is changed to
3734                 // .Allowed.
3735                 Error
3736         }
3737 }
3738