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