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