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