2007-06-06 Amit Biswas <amit@amitbiswas.com>
[mono.git] / mcs / mcs / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
9 // (C) 2004, 2005 Novell, Inc
10 //
11
12 namespace Mono.CSharp
13 {
14         using System;
15         using System.Reflection;
16         using System.Reflection.Emit;
17         using System.Collections;
18         using System.Collections.Specialized;
19         using System.IO;
20         using System.Text;
21         using System.Globalization;
22         using System.Diagnostics;
23
24         public enum Target {
25                 Library, Exe, Module, WinExe
26         };
27         
28         /// <summary>
29         ///    The compiler driver.
30         /// </summary>
31         public class Driver
32         {
33                 
34                 //
35                 // Assemblies references to be linked.   Initialized with
36                 // mscorlib.dll here.
37                 static ArrayList references;
38
39                 //
40                 // If any of these fail, we ignore the problem.  This is so
41                 // that we can list all the assemblies in Windows and not fail
42                 // if they are missing on Linux.
43                 //
44                 static ArrayList soft_references;
45
46                 // 
47                 // External aliases for assemblies.
48                 //
49                 static Hashtable external_aliases;
50
51                 //
52                 // Modules to be linked
53                 //
54                 static ArrayList modules;
55
56                 // Lookup paths
57                 static ArrayList link_paths;
58
59                 // Whether we want to only run the tokenizer
60                 static bool tokenize = false;
61                 
62                 static string first_source;
63
64                 static bool want_debugging_support = false;
65
66                 static bool parse_only = false;
67                 static bool timestamps = false;
68                 static bool pause = false;
69                 static bool show_counters = false;
70                 
71                 //
72                 // Whether to load the initial config file (what CSC.RSP has by default)
73                 // 
74                 static bool load_default_config = true;
75
76                 //
77                 // A list of resource files
78                 //
79                 static Resources embedded_resources;
80                 static string win32ResourceFile;
81                 static string win32IconFile;
82
83                 //
84                 // An array of the defines from the command line
85                 //
86                 static ArrayList defines;
87
88                 //
89                 // Output file
90                 //
91                 static string output_file = null;
92
93                 //
94                 // Last time we took the time
95                 //
96                 static DateTime last_time, first_time;
97
98                 //
99                 // Encoding.
100                 //
101                 static Encoding encoding;
102
103                 static public void Reset ()
104                 {
105                         want_debugging_support = false;
106                         parse_only = false;
107                         timestamps = false;
108                         pause = false;
109                         show_counters = false;
110                         load_default_config = true;
111                         embedded_resources = null;
112                         win32ResourceFile = win32IconFile = null;
113                         defines = null;
114                         output_file = null;
115                         encoding = null;
116                         first_source = null;
117                 }
118
119                 public static void ShowTime (string msg)
120                 {
121                         if (!timestamps)
122                                 return;
123
124                         DateTime now = DateTime.Now;
125                         TimeSpan span = now - last_time;
126                         last_time = now;
127
128                         Console.WriteLine (
129                                 "[{0:00}:{1:000}] {2}",
130                                 (int) span.TotalSeconds, span.Milliseconds, msg);
131                 }
132
133                 public static void ShowTotalTime (string msg)
134                 {
135                         if (!timestamps)
136                                 return;
137
138                         DateTime now = DateTime.Now;
139                         TimeSpan span = now - first_time;
140                         last_time = now;
141
142                         Console.WriteLine (
143                                 "[{0:00}:{1:000}] {2}",
144                                 (int) span.TotalSeconds, span.Milliseconds, msg);
145                 }              
146                
147                 static void tokenize_file (SourceFile file)
148                 {
149                         Stream input;
150
151                         try {
152                                 input = File.OpenRead (file.Name);
153                         } catch {
154                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
155                                 return;
156                         }
157
158                         using (input){
159                                 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
160                                 Tokenizer lexer = new Tokenizer (reader, file, defines);
161                                 int token, tokens = 0, errors = 0;
162
163                                 while ((token = lexer.token ()) != Token.EOF){
164                                         tokens++;
165                                         if (token == Token.ERROR)
166                                                 errors++;
167                                 }
168                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
169                         }
170                         
171                         return;
172                 }
173
174                 // MonoTODO("Change error code for aborted compilation to something reasonable")]               
175                 static void parse (SourceFile file)
176                 {
177                         CSharpParser parser;
178                         Stream input;
179
180                         try {
181                                 input = File.OpenRead (file.Name);
182                         } catch {
183                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
184                                 return;
185                         }
186
187                         SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
188
189                         // Check 'MZ' header
190                         if (reader.Read () == 77 && reader.Read () == 90) {
191                                 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
192                                 input.Close ();
193                                 return;
194                         }
195
196                         reader.Position = 0;
197                         parser = new CSharpParser (reader, file, defines);
198                         parser.ErrorOutput = Report.Stderr;
199                         try {
200                                 parser.parse ();
201                         } catch (Exception ex) {
202                                 Report.Error(
203                                         666, String.Format ("Compilation aborted in file {0}, parser at {1}: {2}",
204                                                             file.Name, parser.Lexer.Location, ex));
205                         } finally {
206                                 input.Close ();
207                         }
208                 }
209
210                 static void OtherFlags ()
211                 {
212                         Console.WriteLine (
213                                 "Other flags in the compiler\n" +
214                                 "   --fatal            Makes errors fatal\n" +
215                                 "   --parse            Only parses the source file\n" +
216                                 "   --typetest         Tests the tokenizer's built-in type parser\n" +
217                                 "   --stacktrace       Shows stack trace at error location\n" +
218                                 "   --timestamp        Displays time stamps of various compiler events\n" +
219                                 "   --expect-error X   Expect that error X will be encountered\n" +
220                                 "   -2                 Enables experimental C# features\n" +
221                                 "   -v                 Verbose parsing (for debugging the parser)\n" + 
222                                 "   --mcs-debug X      Sets MCS debugging level to X\n");
223                 }
224                 
225                 static void Usage ()
226                 {
227                         Console.WriteLine (
228                                 "Mono C# compiler, (C) 2001 - 2005 Novell, Inc.\n" +
229                                 "mcs [options] source-files\n" +
230                                 "   --about            About the Mono C# compiler\n" +
231                                 "   -addmodule:MODULE  Adds the module to the generated assembly\n" + 
232                                 "   -checked[+|-]      Set default context to checked\n" +
233                                 "   -codepage:ID       Sets code page to the one in ID (number, utf8, reset)\n" +
234                                 "   -clscheck[+|-]     Disables CLS Compliance verifications" + Environment.NewLine +
235                                 "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
236                                 "   -debug[+|-], -g    Generate debugging information\n" + 
237                                 "   -delaysign[+|-]    Only insert the public key into the assembly (no signing)\n" +
238                                 "   -doc:FILE          XML Documentation file to generate\n" + 
239                                 "   -keycontainer:NAME The key pair container used to strongname the assembly\n" +
240                                 "   -keyfile:FILE      The strongname key file used to strongname the assembly\n" +
241                                 "   -langversion:TEXT  Specifies language version modes: ISO-1 or Default\n" + 
242                                 "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
243                                 "   -main:class        Specified the class that contains the entry point\n" +
244                                 "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
245                                 "   -nostdlib[+|-]     Does not load core libraries\n" +
246                                 "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
247                                 "   -optimize[+|-]     Enables code optimalizations\n" + 
248                                 "   -out:FNAME         Specifies output file\n" +
249                                 "   -pkg:P1[,Pn]       References packages P1..Pn\n" + 
250                                 "   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
251                                 "   -reference:ASS     References the specified assembly (-r:ASS)\n" +
252                                 "   -target:KIND       Specifies the target (KIND is one of: exe, winexe,\n" +
253                                 "                      library, module), (short: /t:)\n" +
254                                 "   -unsafe[+|-]       Allows unsafe code\n" +
255                                 "   -warnaserror[+|-]  Treat warnings as errors\n" +
256                                 "   -warn:LEVEL        Sets warning level (the highest is 4, the default is 2)\n" +
257                                 "   -help2             Show other help flags\n" + 
258                                 "\n" +
259                                 "Resources:\n" +
260                                 "   -linkresource:FILE[,ID] Links FILE as a resource\n" +
261                                 "   -resource:FILE[,ID]     Embed FILE as a resource\n" +
262                                 "   -win32res:FILE          Specifies Win32 resource file (.res)\n" +
263                                 "   -win32icon:FILE         Use this icon for the output\n" +
264                                 "   @file                   Read response file for more options\n\n" +
265                                 "Options can be of the form -option or /option");
266                 }
267
268                 static void TargetUsage ()
269                 {
270                         Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
271                 }
272                 
273                 static void About ()
274                 {
275                         Console.WriteLine (
276                                 "The Mono C# compiler is (C) 2001-2005, Novell, Inc.\n\n" +
277                                 "The compiler source code is released under the terms of the GNU GPL\n\n" +
278
279                                 "For more information on Mono, visit the project Web site\n" +
280                                 "   http://www.go-mono.com\n\n" +
281
282                                 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath, Atushi Enomoto");
283                         Environment.Exit (0);
284                 }
285
286                 public static int counter1, counter2;
287                 
288                 public static int Main (string[] args)
289                 {
290                         RootContext.Version = LanguageVersion.Default;
291                         Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
292
293                         bool ok = MainDriver (args);
294                         
295                         if (ok && Report.Errors == 0) {
296                                 if (Report.Warnings > 0) {
297                                         Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
298                                 }
299                                 if (show_counters){
300                                         Console.WriteLine ("Counter1: " + counter1);
301                                         Console.WriteLine ("Counter2: " + counter2);
302                                 }
303                                 if (pause)
304                                         Console.ReadLine ();
305                                 return 0;
306                         } else {
307                                 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
308                                         Report.Errors, Report.Warnings);
309                                 return 1;
310                         }
311                 }
312
313                 static public void LoadAssembly (string assembly, bool soft)
314                 {
315                         LoadAssembly (assembly, null, soft);
316                 }
317
318                 static void Error6 (string name, string log)
319                 {
320                         if (log != null && log.Length > 0)
321                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
322                         Report.Error (6, "cannot find metadata file `{0}'", name);
323                 }
324
325                 static void Error9 (string type, string filename, string log)
326                 {
327                         if (log != null && log.Length > 0)
328                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
329                         Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
330                 }
331
332                 static void BadAssembly (string filename, string log)
333                 {
334                         MethodInfo adder_method = AssemblyClass.AddModule_Method;
335
336                         if (adder_method != null) {
337                                 AssemblyName an = new AssemblyName ();
338                                 an.Name = ".temp";
339                                 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
340                                 try {
341                                         object m = null;
342                                         try {
343                                                 m = adder_method.Invoke (ab, new object [] { filename });
344                                         } catch (TargetInvocationException ex) {
345                                                 throw ex.InnerException;
346                                         }
347
348                                         if (m != null) {
349                                                 Report.Error (1509, "referenced file `{0}' is not an assembly; try using the '-addmodule' option", filename);
350                                                 return;
351                                         }
352                                 } catch (FileNotFoundException) {
353                                         // did the file get deleted during compilation? who cares? swallow the exception
354                                 } catch (BadImageFormatException) {
355                                         // swallow exception
356                                 } catch (FileLoadException) {
357                                         // swallow exception
358                                 }
359                         }
360                         Error9 ("assembly", filename, log);
361                 }
362
363                 static public void LoadAssembly (string assembly, string alias, bool soft)
364                 {
365                         Assembly a = null;
366                         string total_log = "";
367
368                         try {
369                                 try {
370                                         char[] path_chars = { '/', '\\' };
371
372                                         if (assembly.IndexOfAny (path_chars) != -1) {
373                                                 a = Assembly.LoadFrom (assembly);
374                                         } else {
375                                                 string ass = assembly;
376                                                 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
377                                                         ass = assembly.Substring (0, assembly.Length - 4);
378                                                 a = Assembly.Load (ass);
379                                         }
380                                 } catch (FileNotFoundException) {
381                                         bool err = !soft;
382                                         foreach (string dir in link_paths) {
383                                                 string full_path = Path.Combine (dir, assembly);
384                                                 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
385                                                         full_path += ".dll";
386
387                                                 try {
388                                                         a = Assembly.LoadFrom (full_path);
389                                                         err = false;
390                                                         break;
391                                                 } catch (FileNotFoundException ff) {
392                                                         if (soft)
393                                                                 return;
394                                                         total_log += ff.FusionLog;
395                                                 }
396                                         }
397                                         if (err) {
398                                                 Error6 (assembly, total_log);
399                                                 return;
400                                         }
401                                 }
402
403                                 // Extern aliased refs require special handling
404                                 if (alias == null)
405                                         RootNamespace.Global.AddAssemblyReference (a);
406                                 else
407                                         RootNamespace.DefineRootNamespace (alias, a);
408
409                         } catch (BadImageFormatException f) {
410                                 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
411                                 BadAssembly (f.FileName, f.FusionLog);
412                         } catch (FileLoadException f) {
413                                 // ... while .NET 1.1 throws this
414                                 BadAssembly (f.FileName, f.FusionLog);
415                         }
416                 }
417
418                 static public void LoadModule (string module)
419                 {
420                         Module m = null;
421                         string total_log = "";
422
423                         try {
424                                 try {
425                                         m = CodeGen.Assembly.AddModule (module);
426                                 } catch (FileNotFoundException) {
427                                         bool err = true;
428                                         foreach (string dir in link_paths) {
429                                                 string full_path = Path.Combine (dir, module);
430                                                 if (!module.EndsWith (".netmodule"))
431                                                         full_path += ".netmodule";
432
433                                                 try {
434                                                         m = CodeGen.Assembly.AddModule (full_path);
435                                                         err = false;
436                                                         break;
437                                                 } catch (FileNotFoundException ff) {
438                                                         total_log += ff.FusionLog;
439                                                 }
440                                         }
441                                         if (err) {
442                                                 Error6 (module, total_log);
443                                                 return;
444                                         }
445                                 }
446
447                                 RootNamespace.Global.AddModuleReference (m);
448
449                         } catch (BadImageFormatException f) {
450                                 Error9 ("module", f.FileName, f.FusionLog);
451                         } catch (FileLoadException f) {
452                                 Error9 ("module", f.FileName, f.FusionLog);
453                         }
454                 }
455
456                 /// <summary>
457                 ///   Loads all assemblies referenced on the command line
458                 /// </summary>
459                 static public void LoadReferences ()
460                 {
461                         //
462                         // Load Core Library for default compilation
463                         //
464                         if (RootContext.StdLib)
465                                 LoadAssembly ("mscorlib", false);
466
467                         foreach (string r in soft_references)
468                                 LoadAssembly (r, true);
469
470                         foreach (string r in references)
471                                 LoadAssembly (r, false);
472
473                         foreach (DictionaryEntry entry in external_aliases)
474                                 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
475                         
476                         return;
477                 }
478
479                 static void SetupDefaultDefines ()
480                 {
481                         defines = new ArrayList ();
482                         defines.Add ("__MonoCS__");
483                 }
484
485                 static string [] LoadArgs (string file)
486                 {
487                         StreamReader f;
488                         ArrayList args = new ArrayList ();
489                         string line;
490                         try {
491                                 f = new StreamReader (file);
492                         } catch {
493                                 return null;
494                         }
495
496                         StringBuilder sb = new StringBuilder ();
497                         
498                         while ((line = f.ReadLine ()) != null){
499                                 int t = line.Length;
500
501                                 for (int i = 0; i < t; i++){
502                                         char c = line [i];
503                                         
504                                         if (c == '"' || c == '\''){
505                                                 char end = c;
506                                                 
507                                                 for (i++; i < t; i++){
508                                                         c = line [i];
509
510                                                         if (c == end)
511                                                                 break;
512                                                         sb.Append (c);
513                                                 }
514                                         } else if (c == ' '){
515                                                 if (sb.Length > 0){
516                                                         args.Add (sb.ToString ());
517                                                         sb.Length = 0;
518                                                 }
519                                         } else
520                                                 sb.Append (c);
521                                 }
522                                 if (sb.Length > 0){
523                                         args.Add (sb.ToString ());
524                                         sb.Length = 0;
525                                 }
526                         }
527
528                         string [] ret_value = new string [args.Count];
529                         args.CopyTo (ret_value, 0);
530
531                         return ret_value;
532                 }
533
534                 //
535                 // Returns the directory where the system assemblies are installed
536                 //
537                 static string GetSystemDir ()
538                 {
539                         return Path.GetDirectoryName (typeof (object).Assembly.Location);
540                 }
541
542                 //
543                 // Given a path specification, splits the path from the file/pattern
544                 //
545                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
546                 {
547                         int p = spec.LastIndexOf ('/');
548                         if (p != -1){
549                                 //
550                                 // Windows does not like /file.cs, switch that to:
551                                 // "\", "file.cs"
552                                 //
553                                 if (p == 0){
554                                         path = "\\";
555                                         pattern = spec.Substring (1);
556                                 } else {
557                                         path = spec.Substring (0, p);
558                                         pattern = spec.Substring (p + 1);
559                                 }
560                                 return;
561                         }
562
563                         p = spec.LastIndexOf ('\\');
564                         if (p != -1){
565                                 path = spec.Substring (0, p);
566                                 pattern = spec.Substring (p + 1);
567                                 return;
568                         }
569
570                         path = ".";
571                         pattern = spec;
572                 }
573
574                 static void ProcessFile (string f)
575                 {
576                         if (first_source == null)
577                                 first_source = f;
578
579                         Location.AddFile (f);
580                 }
581
582                 static void ProcessFiles ()
583                 {
584                         Location.Initialize ();
585
586                         foreach (SourceFile file in Location.SourceFiles) {
587                                 if (tokenize) {
588                                         tokenize_file (file);
589                                 } else {
590                                         parse (file);
591                                 }
592                         }
593                 }
594
595                 static void CompileFiles (string spec, bool recurse)
596                 {
597                         string path, pattern;
598
599                         SplitPathAndPattern (spec, out path, out pattern);
600                         if (pattern.IndexOf ('*') == -1){
601                                 ProcessFile (spec);
602                                 return;
603                         }
604
605                         string [] files = null;
606                         try {
607                                 files = Directory.GetFiles (path, pattern);
608                         } catch (System.IO.DirectoryNotFoundException) {
609                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
610                                 return;
611                         } catch (System.IO.IOException){
612                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
613                                 return;
614                         }
615                         foreach (string f in files) {
616                                 ProcessFile (f);
617                         }
618
619                         if (!recurse)
620                                 return;
621                         
622                         string [] dirs = null;
623
624                         try {
625                                 dirs = Directory.GetDirectories (path);
626                         } catch {
627                         }
628                         
629                         foreach (string d in dirs) {
630                                         
631                                 // Don't include path in this string, as each
632                                 // directory entry already does
633                                 CompileFiles (d + "/" + pattern, true);
634                         }
635                 }
636
637                 static void DefineDefaultConfig ()
638                 {
639                         //
640                         // For now the "default config" is harcoded into the compiler
641                         // we can move this outside later
642                         //
643                         string [] default_config = {
644                                 "System",
645                                 "System.Xml"
646 #if false
647                                 //
648                                 // Is it worth pre-loading all this stuff?
649                                 //
650                                 "Accessibility",
651                                 "System.Configuration.Install",
652                                 "System.Data",
653                                 "System.Design",
654                                 "System.DirectoryServices",
655                                 "System.Drawing.Design",
656                                 "System.Drawing",
657                                 "System.EnterpriseServices",
658                                 "System.Management",
659                                 "System.Messaging",
660                                 "System.Runtime.Remoting",
661                                 "System.Runtime.Serialization.Formatters.Soap",
662                                 "System.Security",
663                                 "System.ServiceProcess",
664                                 "System.Web",
665                                 "System.Web.RegularExpressions",
666                                 "System.Web.Services",
667                                 "System.Windows.Forms"
668 #endif
669                         };
670                         
671                         if (RootContext.Version == LanguageVersion.LINQ)
672                                 soft_references.Add ("System.Core");
673
674                         soft_references.AddRange (default_config);
675                 }
676
677                 public static string OutputFile
678                 {
679                         set {
680                                 output_file = value;
681                         }
682                         get {
683                                 return Path.GetFileName (output_file);
684                         }
685                 }
686
687                 static void SetWarningLevel (string s)
688                 {
689                         int level = -1;
690
691                         try {
692                                 level = Int32.Parse (s);
693                         } catch {
694                         }
695                         if (level < 0 || level > 4){
696                                 Report.Error (1900, "Warning level must be in the range 0-4");
697                                 return;
698                         }
699                         RootContext.WarningLevel = level;
700                 }
701
702                 static void SetupV2 ()
703                 {
704                         RootContext.Version = LanguageVersion.Default;
705                         defines.Add ("__V2__");
706                 }
707                 
708                 static void Version ()
709                 {
710                         string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
711                         Console.WriteLine ("Mono C# compiler version {0}", version);
712                         Environment.Exit (0);
713                 }
714
715                 //
716                 // This is to test the tokenizer internal parser that is used to deambiguate
717                 // '(' type identifier from '(' type others so that we are able to parse
718                 // without introducing reduce/reduce conflicts in the grammar.
719                 // 
720                 static void LambdaTypeParseTest (string fname)
721                 {
722                         bool fail = false;
723
724                         using (FileStream fs = File.OpenRead (fname)){
725                                 StreamReader r = new StreamReader (fs, encoding);
726                                 string line;
727                                 
728                                 while ((line = r.ReadLine ())!= null){
729                                         if (line [0] == '!')
730                                                 continue;
731                                         bool must_pass = line [0] == '+';
732                                         StringReader test = new StringReader (line.Substring (1));
733                                         SeekableStreamReader reader = new SeekableStreamReader (test);
734                                         SourceFile file = new SourceFile (fname, fname, 0);
735                                         
736                                         Tokenizer lexer = new Tokenizer (reader, file, defines);
737                                         bool res = lexer.parse_lambda_parameters ();
738                                         
739                                         Console.WriteLine ("{3} ({1}=={2}): {0}", line.Substring (1), res, must_pass, res == must_pass);
740                                         if (res != must_pass)
741                                                 fail = true;
742                                 }
743                         }
744                         Console.WriteLine ("fail={0}", fail);
745                         Environment.Exit (fail ? 1 : 0);
746                 }
747                 
748                 //
749                 // Currently handles the Unix-like command line options, but will be
750                 // deprecated in favor of the CSCParseOption, which will also handle the
751                 // options that start with a dash in the future.
752                 //
753                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
754                 {
755                         switch (arg){
756                         case "-v":
757                                 CSharpParser.yacc_verbose_flag++;
758                                 return true;
759
760                         case "--version":
761                                 Version ();
762                                 return true;
763                                 
764                         case "--parse":
765                                 parse_only = true;
766                                 return true;
767                                 
768                         case "--main": case "-m":
769                                 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
770                                 if ((i + 1) >= args.Length){
771                                         Usage ();
772                                         Environment.Exit (1);
773                                 }
774                                 RootContext.MainClass = args [++i];
775                                 return true;
776                                 
777                         case "--unsafe":
778                                 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
779                                 RootContext.Unsafe = true;
780                                 return true;
781                                 
782                         case "/?": case "/h": case "/help":
783                         case "--help":
784                                 Usage ();
785                                 Environment.Exit (0);
786                                 return true;
787
788                         case "--define":
789                                 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
790                                 if ((i + 1) >= args.Length){
791                                         Usage ();
792                                         Environment.Exit (1);
793                                 }
794                                 defines.Add (args [++i]);
795                                 return true;
796
797                         case "--show-counters":
798                                 show_counters = true;
799                                 return true;
800                                 
801                         case "--expect-error": {
802                                 int code = 0;
803                                 
804                                 try {
805                                         code = Int32.Parse (
806                                                 args [++i], NumberStyles.AllowLeadingSign);
807                                         Report.ExpectedError = code;
808                                 } catch {
809                                         Report.Error (-14, "Invalid number specified");
810                                 } 
811                                 return true;
812                         }
813                                 
814                         case "--tokenize": 
815                                 tokenize = true;
816                                 return true;
817                                 
818                         case "-o": 
819                         case "--output":
820                                 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
821                                 if ((i + 1) >= args.Length){
822                                         Usage ();
823                                         Environment.Exit (1);
824                                 }
825                                 OutputFile = args [++i];
826                                 return true;
827
828                         case "--checked":
829                                 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
830                                 RootContext.Checked = true;
831                                 return true;
832                                 
833                         case "--stacktrace":
834                                 Report.Stacktrace = true;
835                                 return true;
836                                 
837                         case "--linkresource":
838                         case "--linkres":
839                                 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
840                                 if ((i + 1) >= args.Length){
841                                         Usage ();
842                                         Report.Error (5, "Missing argument to --linkres"); 
843                                         Environment.Exit (1);
844                                 }
845                                 if (embedded_resources == null)
846                                         embedded_resources = new Resources ();
847                                 
848                                 embedded_resources.Add (false, args [++i], args [i]);
849                                 return true;
850                                 
851                         case "--resource":
852                         case "--res":
853                                 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
854                                 if ((i + 1) >= args.Length){
855                                         Usage ();
856                                         Report.Error (5, "Missing argument to --resource"); 
857                                         Environment.Exit (1);
858                                 }
859                                 if (embedded_resources == null)
860                                         embedded_resources = new Resources ();
861                                 
862                                 embedded_resources.Add (true, args [++i], args [i]);
863                                 return true;
864                                 
865                         case "--target":
866                                 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
867                                 if ((i + 1) >= args.Length){
868                                         Environment.Exit (1);
869                                         return true;
870                                 }
871                                 
872                                 string type = args [++i];
873                                 switch (type){
874                                 case "library":
875                                         RootContext.Target = Target.Library;
876                                         RootContext.TargetExt = ".dll";
877                                         break;
878                                         
879                                 case "exe":
880                                         RootContext.Target = Target.Exe;
881                                         break;
882                                         
883                                 case "winexe":
884                                         RootContext.Target = Target.WinExe;
885                                         break;
886                                         
887                                 case "module":
888                                         RootContext.Target = Target.Module;
889                                         RootContext.TargetExt = ".dll";
890                                         break;
891                                 default:
892                                         TargetUsage ();
893                                         break;
894                                 }
895                                 return true;
896                                 
897                         case "-r":
898                                 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
899                                 if ((i + 1) >= args.Length){
900                                         Usage ();
901                                         Environment.Exit (1);
902                                 }
903                                 
904                                 string val = args [++i];
905                                 int idx = val.IndexOf ('=');
906                                 if (idx > -1) {
907                                         string alias = val.Substring (0, idx);
908                                         string assembly = val.Substring (idx + 1);
909                                         AddExternAlias (alias, assembly);
910                                         return true;
911                                 }
912
913                                 references.Add (val);
914                                 return true;
915                                 
916                         case "-L":
917                                 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
918                                 if ((i + 1) >= args.Length){
919                                         Usage ();       
920                                         Environment.Exit (1);
921                                 }
922                                 link_paths.Add (args [++i]);
923                                 return true;
924                                 
925                         case "--nostdlib":
926                                 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
927                                 RootContext.StdLib = false;
928                                 return true;
929                                 
930                         case "--fatal":
931                                 Report.Fatal = true;
932                                 return true;
933                                 
934                         case "--werror":
935                                 Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror");
936                                 Report.WarningsAreErrors = true;
937                                 return true;
938
939                         case "--nowarn":
940                                 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
941                                 if ((i + 1) >= args.Length){
942                                         Usage ();
943                                         Environment.Exit (1);
944                                 }
945                                 int warn = 0;
946                                 
947                                 try {
948                                         warn = Int32.Parse (args [++i]);
949                                 } catch {
950                                         Usage ();
951                                         Environment.Exit (1);
952                                 }
953                                 Report.SetIgnoreWarning (warn);
954                                 return true;
955                                 
956                         case "--wlevel":
957                                 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
958                                 if ((i + 1) >= args.Length){
959                                         Report.Error (
960                                                 1900,
961                                                 "--wlevel requires a value from 0 to 4");
962                                         Environment.Exit (1);
963                                 }
964
965                                 SetWarningLevel (args [++i]);
966                                 return true;
967
968                         case "--mcs-debug":
969                                 if ((i + 1) >= args.Length){
970                                         Report.Error (5, "--mcs-debug requires an argument");
971                                         Environment.Exit (1);
972                                 }
973
974                                 try {
975                                         Report.DebugFlags = Int32.Parse (args [++i]);
976                                 } catch {
977                                         Report.Error (5, "Invalid argument to --mcs-debug");
978                                         Environment.Exit (1);
979                                 }
980                                 return true;
981                                 
982                         case "--about":
983                                 About ();
984                                 return true;
985                                 
986                         case "--recurse":
987                                 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
988                                 if ((i + 1) >= args.Length){
989                                         Report.Error (5, "--recurse requires an argument");
990                                         Environment.Exit (1);
991                                 }
992                                 CompileFiles (args [++i], true); 
993                                 return true;
994                                 
995                         case "--timestamp":
996                                 timestamps = true;
997                                 last_time = first_time = DateTime.Now;
998                                 return true;
999
1000                         case "--pause":
1001                                 pause = true;
1002                                 return true;
1003                                 
1004                         case "--debug": case "-g":
1005                                 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
1006                                 want_debugging_support = true;
1007                                 return true;
1008                                 
1009                         case "--noconfig":
1010                                 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1011                                 load_default_config = false;
1012                                 return true;
1013
1014                         case "--typetest":
1015                                 if ((i + 1) >= args.Length){
1016                                         Report.Error (5, "--typetest requires a filename argument");
1017                                         Environment.Exit (1);
1018                                 }
1019                                 LambdaTypeParseTest (args [++i]);
1020                                 return true;
1021                         }
1022
1023                         return false;
1024                 }
1025
1026                 //
1027                 // This parses the -arg and /arg options to the compiler, even if the strings
1028                 // in the following text use "/arg" on the strings.
1029                 //
1030                 static bool CSCParseOption (string option, ref string [] args, ref int i)
1031                 {
1032                         int idx = option.IndexOf (':');
1033                         string arg, value;
1034
1035                         if (idx == -1){
1036                                 arg = option;
1037                                 value = "";
1038                         } else {
1039                                 arg = option.Substring (0, idx);
1040
1041                                 value = option.Substring (idx + 1);
1042                         }
1043
1044                         switch (arg){
1045                         case "/nologo":
1046                                 return true;
1047
1048                         case "/t":
1049                         case "/target":
1050                                 switch (value){
1051                                 case "exe":
1052                                         RootContext.Target = Target.Exe;
1053                                         break;
1054
1055                                 case "winexe":
1056                                         RootContext.Target = Target.WinExe;
1057                                         break;
1058
1059                                 case "library":
1060                                         RootContext.Target = Target.Library;
1061                                         RootContext.TargetExt = ".dll";
1062                                         break;
1063
1064                                 case "module":
1065                                         RootContext.Target = Target.Module;
1066                                         RootContext.TargetExt = ".netmodule";
1067                                         break;
1068
1069                                 default:
1070                                         TargetUsage ();
1071                                         break;
1072                                 }
1073                                 return true;
1074
1075                         case "/out":
1076                                 if (value.Length == 0){
1077                                         Usage ();
1078                                         Environment.Exit (1);
1079                                 }
1080                                 OutputFile = value;
1081                                 return true;
1082
1083                         case "/o":
1084                         case "/o+":
1085                         case "/optimize":
1086                         case "/optimize+":
1087                                 RootContext.Optimize = true;
1088                                 return true;
1089
1090                         case "/o-":
1091                         case "/optimize-":
1092                                 RootContext.Optimize = false;
1093                                 return true;
1094
1095                         case "/incremental":
1096                         case "/incremental+":
1097                         case "/incremental-":
1098                                 // nothing.
1099                                 return true;
1100
1101                         case "/d":
1102                         case "/define": {
1103                                 if (value.Length == 0){
1104                                         Usage ();
1105                                         Environment.Exit (1);
1106                                 }
1107
1108                                 foreach (string d in value.Split (';', ',')){
1109                                         if (!Tokenizer.IsValidIdentifier (d)) {
1110                                                 Report.Warning (2029, 1, "Invalid conditional define symbol `{0}'", d);
1111                                                 continue;
1112                                         }
1113                                         defines.Add (d);
1114                                 }
1115                                 return true;
1116                         }
1117
1118                         case "/bugreport":
1119                                 //
1120                                 // We should collect data, runtime, etc and store in the file specified
1121                                 //
1122                                 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1123                                 return true;
1124
1125                         case "/pkg": {
1126                                 string packages;
1127
1128                                 if (value.Length == 0){
1129                                         Usage ();
1130                                         Environment.Exit (1);
1131                                 }
1132                                 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1133                                 
1134                                 ProcessStartInfo pi = new ProcessStartInfo ();
1135                                 pi.FileName = "pkg-config";
1136                                 pi.RedirectStandardOutput = true;
1137                                 pi.UseShellExecute = false;
1138                                 pi.Arguments = "--libs " + packages;
1139                                 Process p = null;
1140                                 try {
1141                                         p = Process.Start (pi);
1142                                 } catch (Exception e) {
1143                                         Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1144                                         Environment.Exit (1);
1145                                 }
1146
1147                                 if (p.StandardOutput == null){
1148                                         Report.Warning (-27, 1, "Specified package did not return any information");
1149                                         return true;
1150                                 }
1151                                 string pkgout = p.StandardOutput.ReadToEnd ();
1152                                 p.WaitForExit ();
1153                                 if (p.ExitCode != 0) {
1154                                         Report.Error (-27, "Error running pkg-config. Check the above output.");
1155                                         Environment.Exit (1);
1156                                 }
1157
1158                                 if (pkgout != null){
1159                                         string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1160                                                 Split (new Char [] { ' ', '\t'});
1161                                         args = AddArgs (args, xargs);
1162                                 }
1163                                 
1164                                 p.Close ();
1165                                 return true;
1166                         }
1167                                 
1168                         case "/linkres":
1169                         case "/linkresource":
1170                         case "/res":
1171                         case "/resource":
1172                                 if (embedded_resources == null)
1173                                         embedded_resources = new Resources ();
1174
1175                                 bool embeded = arg.StartsWith ("/r");
1176                                 string[] s = value.Split (',');
1177                                 switch (s.Length) {
1178                                         case 1:
1179                                                 if (s[0].Length == 0)
1180                                                         goto default;
1181                                                 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1182                                                 break;
1183                                         case 2:
1184                                                 embedded_resources.Add (embeded, s [0], s [1]);
1185                                                 break;
1186                                         case 3:
1187                                                 if (s [2] != "public" && s [2] != "private") {
1188                                                         Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1189                                                         return true;
1190                                                 }
1191                                                 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1192                                                 break;
1193                                         default:
1194                                                 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1195                                                 break;
1196                                 }
1197
1198                                 return true;
1199                                 
1200                         case "/recurse":
1201                                 if (value.Length == 0){
1202                                         Report.Error (5, "-recurse requires an argument");
1203                                         Environment.Exit (1);
1204                                 }
1205                                 CompileFiles (value, true); 
1206                                 return true;
1207
1208                         case "/r":
1209                         case "/reference": {
1210                                 if (value.Length == 0){
1211                                         Report.Error (5, "-reference requires an argument");
1212                                         Environment.Exit (1);
1213                                 }
1214
1215                                 string [] refs = value.Split (new char [] { ';', ',' });
1216                                 foreach (string r in refs){
1217                                         string val = r;
1218                                         int index = val.IndexOf ('=');
1219                                         if (index > -1) {
1220                                                 string alias = r.Substring (0, index);
1221                                                 string assembly = r.Substring (index + 1);
1222                                                 AddExternAlias (alias, assembly);
1223                                                 return true;
1224                                         }
1225                                         
1226                                         references.Add (val);
1227                                 }
1228                                 return true;
1229                         }
1230                         case "/addmodule": {
1231                                 if (value.Length == 0){
1232                                         Report.Error (5, arg + " requires an argument");
1233                                         Environment.Exit (1);
1234                                 }
1235
1236                                 string [] refs = value.Split (new char [] { ';', ',' });
1237                                 foreach (string r in refs){
1238                                         modules.Add (r);
1239                                 }
1240                                 return true;
1241                         }
1242                         case "/win32res": {
1243                                 if (value.Length == 0) {
1244                                         Report.Error (5, arg + " requires an argument");
1245                                         Environment.Exit (1);
1246                                 }
1247
1248                                 win32ResourceFile = value;
1249                                 return true;
1250                         }
1251                         case "/win32icon": {
1252                                 if (value.Length == 0) {
1253                                         Report.Error (5, arg + " requires an argument");
1254                                         Environment.Exit (1);
1255                                 }
1256
1257                                 win32IconFile = value;
1258                                 return true;
1259                         }
1260                         case "/doc": {
1261                                 if (value.Length == 0){
1262                                         Report.Error (2006, arg + " requires an argument");
1263                                         Environment.Exit (1);
1264                                 }
1265                                 RootContext.Documentation = new Documentation (value);
1266                                 return true;
1267                         }
1268                         case "/lib": {
1269                                 string [] libdirs;
1270                                 
1271                                 if (value.Length == 0){
1272                                         Report.Error (5, "/lib requires an argument");
1273                                         Environment.Exit (1);
1274                                 }
1275
1276                                 libdirs = value.Split (new Char [] { ',' });
1277                                 foreach (string dir in libdirs)
1278                                         link_paths.Add (dir);
1279                                 return true;
1280                         }
1281
1282                         case "/debug-":
1283                                 want_debugging_support = false;
1284                                 return true;
1285                                 
1286                         case "/debug":
1287                         case "/debug+":
1288                                 want_debugging_support = true;
1289                                 return true;
1290
1291                         case "/checked":
1292                         case "/checked+":
1293                                 RootContext.Checked = true;
1294                                 return true;
1295
1296                         case "/checked-":
1297                                 RootContext.Checked = false;
1298                                 return true;
1299
1300                         case "/clscheck":
1301                         case "/clscheck+":
1302                                 return true;
1303
1304                         case "/clscheck-":
1305                                 RootContext.VerifyClsCompliance = false;
1306                                 return true;
1307
1308                         case "/unsafe":
1309                         case "/unsafe+":
1310                                 RootContext.Unsafe = true;
1311                                 return true;
1312
1313                         case "/unsafe-":
1314                                 RootContext.Unsafe = false;
1315                                 return true;
1316
1317                         case "/warnaserror":
1318                         case "/warnaserror+":
1319                                 Report.WarningsAreErrors = true;
1320                                 return true;
1321
1322                         case "/warnaserror-":
1323                                 Report.WarningsAreErrors = false;
1324                                 return true;
1325
1326                         case "/warn":
1327                                 SetWarningLevel (value);
1328                                 return true;
1329
1330                         case "/nowarn": {
1331                                 string [] warns;
1332
1333                                 if (value.Length == 0){
1334                                         Report.Error (5, "/nowarn requires an argument");
1335                                         Environment.Exit (1);
1336                                 }
1337                                 
1338                                 warns = value.Split (new Char [] {','});
1339                                 foreach (string wc in warns){
1340                                         try {
1341                                                 int warn = Int32.Parse (wc);
1342                                                 if (warn < 1) {
1343                                                         throw new ArgumentOutOfRangeException("warn");
1344                                                 }
1345                                                 Report.SetIgnoreWarning (warn);
1346                                         } catch {
1347                                                 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1348                                         }
1349                                 }
1350                                 return true;
1351                         }
1352
1353                         case "/noconfig-":
1354                                 load_default_config = true;
1355                                 return true;
1356                                 
1357                         case "/noconfig":
1358                         case "/noconfig+":
1359                                 load_default_config = false;
1360                                 return true;
1361
1362                         case "/help2":
1363                                 OtherFlags ();
1364                                 Environment.Exit(0);
1365                                 return true;
1366                                 
1367                         case "/help":
1368                         case "/?":
1369                                 Usage ();
1370                                 Environment.Exit (0);
1371                                 return true;
1372
1373                         case "/main":
1374                         case "/m":
1375                                 if (value.Length == 0){
1376                                         Report.Error (5, arg + " requires an argument");                                        
1377                                         Environment.Exit (1);
1378                                 }
1379                                 RootContext.MainClass = value;
1380                                 return true;
1381
1382                         case "/nostdlib":
1383                         case "/nostdlib+":
1384                                 RootContext.StdLib = false;
1385                                 return true;
1386
1387                         case "/nostdlib-":
1388                                 RootContext.StdLib = true;
1389                                 return true;
1390
1391                         case "/fullpaths":
1392                                 return true;
1393
1394                         case "/keyfile":
1395                                 if (value == String.Empty) {
1396                                         Report.Error (5, arg + " requires an argument");
1397                                         Environment.Exit (1);
1398                                 }
1399                                 RootContext.StrongNameKeyFile = value;
1400                                 return true;
1401                         case "/keycontainer":
1402                                 if (value == String.Empty) {
1403                                         Report.Error (5, arg + " requires an argument");
1404                                         Environment.Exit (1);
1405                                 }
1406                                 RootContext.StrongNameKeyContainer = value;
1407                                 return true;
1408                         case "/delaysign+":
1409                                 RootContext.StrongNameDelaySign = true;
1410                                 return true;
1411                         case "/delaysign-":
1412                                 RootContext.StrongNameDelaySign = false;
1413                                 return true;
1414
1415                         case "/v2":
1416                         case "/2":
1417                                 Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
1418                                 SetupV2 ();
1419                                 return true;
1420                                 
1421                         case "/langversion":
1422                                 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1423                                         case "iso-1":
1424                                                 RootContext.Version = LanguageVersion.ISO_1;
1425                                                 return true;
1426
1427                                         case "default":
1428                                                 SetupV2 ();
1429                                                 return true;
1430 #if GMCS_SOURCE
1431                                         case "linq":
1432                                                 RootContext.Version = LanguageVersion.LINQ;
1433                                                 Tokenizer.InitializeLinqKeywords ();
1434                                                 return true;
1435 #endif
1436                                 }
1437                                 Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1' or `Default'", value);
1438                                 return true;
1439
1440                         case "/codepage":
1441                                 switch (value) {
1442                                 case "utf8":
1443                                         encoding = new UTF8Encoding();
1444                                         break;
1445                                 case "reset":
1446                                         encoding = Encoding.Default;
1447                                         break;
1448                                 default:
1449                                         try {
1450                                                 encoding = Encoding.GetEncoding (
1451                                                 Int32.Parse (value));
1452                                         } catch {
1453                                                 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1454                                         }
1455                                         break;
1456                                 }
1457                                 return true;
1458                         }
1459
1460                         return false;
1461                 }
1462
1463                 static void Error_WrongOption (string option)
1464                 {
1465                         Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1466                 }
1467
1468                 static string [] AddArgs (string [] args, string [] extra_args)
1469                 {
1470                         string [] new_args;
1471                         new_args = new string [extra_args.Length + args.Length];
1472
1473                         // if args contains '--' we have to take that into account
1474                         // split args into first half and second half based on '--'
1475                         // and add the extra_args before --
1476                         int split_position = Array.IndexOf (args, "--");
1477                         if (split_position != -1)
1478                         {
1479                                 Array.Copy (args, new_args, split_position);
1480                                 extra_args.CopyTo (new_args, split_position);
1481                                 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1482                         }
1483                         else
1484                         {
1485                                 args.CopyTo (new_args, 0);
1486                                 extra_args.CopyTo (new_args, args.Length);
1487                         }
1488
1489                         return new_args;
1490                 }
1491
1492                 static void AddExternAlias (string identifier, string assembly)
1493                 {
1494                         if (assembly.Length == 0) {
1495                                 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1496                                 return;
1497                         }
1498
1499                         if (!IsExternAliasValid (identifier)) {
1500                                 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1501                                 return;
1502                         }
1503                         
1504                         // Could here hashtable throw an exception?
1505                         external_aliases [identifier] = assembly;
1506                 }
1507                 
1508                 static bool IsExternAliasValid (string identifier)
1509                 {
1510                         if (identifier.Length == 0)
1511                                 return false;
1512                         if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1513                                 return false;
1514
1515                         for (int i = 1; i < identifier.Length; i++) {
1516                                 char c = identifier [i];
1517                                 if (Char.IsLetter (c) || Char.IsDigit (c))
1518                                         continue;
1519
1520                                 UnicodeCategory category = Char.GetUnicodeCategory (c);
1521                                 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1522                                                 category != UnicodeCategory.SpacingCombiningMark ||
1523                                                 category != UnicodeCategory.ConnectorPunctuation)
1524                                         return false;
1525                         }
1526                         
1527                         return true;
1528                 }
1529                 
1530                 /// <summary>
1531                 ///    Parses the arguments, and drives the compilation
1532                 ///    process.
1533                 /// </summary>
1534                 ///
1535                 /// <remarks>
1536                 ///    TODO: Mostly structured to debug the compiler
1537                 ///    now, needs to be turned into a real driver soon.
1538                 /// </remarks>
1539                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1540                 internal static bool MainDriver (string [] args)
1541                 {
1542                         int i;
1543                         bool parsing_options = true;
1544
1545                         encoding = Encoding.Default;
1546
1547                         references = new ArrayList ();
1548                         external_aliases = new Hashtable ();
1549                         soft_references = new ArrayList ();
1550                         modules = new ArrayList ();
1551                         link_paths = new ArrayList ();
1552
1553                         SetupDefaultDefines ();
1554                         
1555                         //
1556                         // Setup defaults
1557                         //
1558                         // This is not required because Assembly.Load knows about this
1559                         // path.
1560                         //
1561
1562                         Hashtable response_file_list = null;
1563
1564                         for (i = 0; i < args.Length; i++){
1565                                 string arg = args [i];
1566                                 if (arg.Length == 0)
1567                                         continue;
1568
1569                                 if (arg.StartsWith ("@")){
1570                                         string [] extra_args;
1571                                         string response_file = arg.Substring (1);
1572
1573                                         if (response_file_list == null)
1574                                                 response_file_list = new Hashtable ();
1575                                         
1576                                         if (response_file_list.Contains (response_file)){
1577                                                 Report.Error (
1578                                                         1515, "Response file `" + response_file +
1579                                                         "' specified multiple times");
1580                                                 Environment.Exit (1);
1581                                         }
1582                                         
1583                                         response_file_list.Add (response_file, response_file);
1584                                                     
1585                                         extra_args = LoadArgs (response_file);
1586                                         if (extra_args == null){
1587                                                 Report.Error (2011, "Unable to open response file: " +
1588                                                               response_file);
1589                                                 return false;
1590                                         }
1591
1592                                         args = AddArgs (args, extra_args);
1593                                         continue;
1594                                 }
1595
1596                                 if (parsing_options){
1597                                         if (arg == "--"){
1598                                                 parsing_options = false;
1599                                                 continue;
1600                                         }
1601                                         
1602                                         if (arg.StartsWith ("-")){
1603                                                 if (UnixParseOption (arg, ref args, ref i))
1604                                                         continue;
1605
1606                                                 // Try a -CSCOPTION
1607                                                 string csc_opt = "/" + arg.Substring (1);
1608                                                 if (CSCParseOption (csc_opt, ref args, ref i))
1609                                                         continue;
1610
1611                                                 Error_WrongOption (arg);
1612                                                 return false;
1613                                         } else {
1614                                                 if (arg [0] == '/'){
1615                                                         if (CSCParseOption (arg, ref args, ref i))
1616                                                                 continue;
1617
1618                                                         // Need to skip `/home/test.cs' however /test.cs is considered as error
1619                                                         if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
1620                                                                 Error_WrongOption (arg);
1621                                                                 return false;
1622                                                         }
1623                                                 }
1624                                         }
1625                                 }
1626
1627                                 CompileFiles (arg, false); 
1628                         }
1629
1630                         ProcessFiles ();
1631
1632                         if (tokenize)
1633                                 return true;
1634
1635                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
1636                                 throw new InternalErrorException ("who set it?");
1637
1638                         //
1639                         // If we are an exe, require a source file for the entry point
1640                         //
1641                         if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module){
1642                                 if (first_source == null){
1643                                         Report.Error (2008, "No files to compile were specified");
1644                                         return false;
1645                                 }
1646
1647                         }
1648
1649                         //
1650                         // If there is nothing to put in the assembly, and we are not a library
1651                         //
1652                         if (first_source == null && embedded_resources == null){
1653                                 Report.Error (2008, "No files to compile were specified");
1654                                 return false;
1655                         }
1656
1657                         if (Report.Errors > 0)
1658                                 return false;
1659                         
1660                         if (parse_only)
1661                                 return true;
1662
1663                         if (load_default_config)
1664                                 DefineDefaultConfig ();
1665
1666                         if (Report.Errors > 0){
1667                                 return false;
1668                         }
1669
1670                         //
1671                         // Load assemblies required
1672                         //
1673                         if (timestamps)
1674                                 ShowTime ("Loading references");
1675                         link_paths.Add (GetSystemDir ());
1676                         link_paths.Add (Directory.GetCurrentDirectory ());
1677                         LoadReferences ();
1678                         
1679                         if (timestamps)
1680                                 ShowTime ("   References loaded");
1681                         
1682                         if (Report.Errors > 0){
1683                                 return false;
1684                         }
1685
1686                         //
1687                         // Quick hack
1688                         //
1689                         if (output_file == null){
1690                                 if (first_source == null){
1691                                         Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1692                                         return false;
1693                                 }
1694                                         
1695                                 int pos = first_source.LastIndexOf ('.');
1696
1697                                 if (pos > 0)
1698                                         output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1699                                 else
1700                                         output_file = first_source + RootContext.TargetExt;
1701                         }
1702
1703                         if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1704                                 return false;
1705
1706                         if (RootContext.Target == Target.Module) {
1707                                 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1708                                 if (module_only == null) {
1709                                         Report.RuntimeMissingSupport (Location.Null, "/target:module");
1710                                         Environment.Exit (1);
1711                                 }
1712
1713                                 MethodInfo set_method = module_only.GetSetMethod (true);
1714                                 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1715                         }
1716
1717                         RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder);
1718
1719                         if (modules.Count > 0) {
1720                                 foreach (string module in modules)
1721                                         LoadModule (module);
1722                         }
1723                         
1724                         //
1725                         // Before emitting, we need to get the core
1726                         // types emitted from the user defined types
1727                         // or from the system ones.
1728                         //
1729                         if (timestamps)
1730                                 ShowTime ("Initializing Core Types");
1731                         if (!RootContext.StdLib){
1732                                 RootContext.ResolveCore ();
1733                                 if (Report.Errors > 0)
1734                                         return false;
1735                         }
1736                         
1737                         TypeManager.InitCoreTypes ();
1738                         if (timestamps)
1739                                 ShowTime ("   Core Types done");
1740
1741                         CodeGen.Module.Resolve ();
1742
1743                         //
1744                         // The second pass of the compiler
1745                         //
1746                         if (timestamps)
1747                                 ShowTime ("Resolving tree");
1748                         RootContext.ResolveTree ();
1749
1750                         if (Report.Errors > 0)
1751                                 return false;
1752                         if (timestamps)
1753                                 ShowTime ("Populate tree");
1754                         if (!RootContext.StdLib)
1755                                 RootContext.BootCorlib_PopulateCoreTypes ();
1756                         RootContext.PopulateTypes ();
1757
1758                         TypeManager.InitCodeHelpers ();
1759
1760                         RootContext.DefineTypes ();
1761                         
1762                         if (Report.Errors == 0 &&
1763                                 RootContext.Documentation != null &&
1764                                 !RootContext.Documentation.OutputDocComment (
1765                                         output_file))
1766                                 return false;
1767
1768                         //
1769                         // Verify using aliases now
1770                         //
1771                         NamespaceEntry.VerifyAllUsing ();
1772                         
1773                         if (Report.Errors > 0){
1774                                 return false;
1775                         }
1776
1777                         CodeGen.Assembly.Resolve ();
1778                         
1779                         if (RootContext.VerifyClsCompliance) {
1780                                 if (CodeGen.Assembly.IsClsCompliant) {
1781                                         AttributeTester.VerifyModulesClsCompliance ();
1782                                         TypeManager.LoadAllImportedTypes ();
1783                                 }
1784                         }
1785                         if (Report.Errors > 0)
1786                                 return false;
1787                         
1788                         //
1789                         // The code generator
1790                         //
1791                         if (timestamps)
1792                                 ShowTime ("Emitting code");
1793                         ShowTotalTime ("Total so far");
1794                         RootContext.EmitCode ();
1795                         if (timestamps)
1796                                 ShowTime ("   done");
1797
1798                         if (Report.Errors > 0){
1799                                 return false;
1800                         }
1801
1802                         if (timestamps)
1803                                 ShowTime ("Closing types");
1804
1805                         RootContext.CloseTypes ();
1806
1807                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1808
1809                         switch (RootContext.Target) {
1810                         case Target.Library:
1811                         case Target.Module:
1812                                 k = PEFileKinds.Dll; break;
1813                         case Target.Exe:
1814                                 k = PEFileKinds.ConsoleApplication; break;
1815                         case Target.WinExe:
1816                                 k = PEFileKinds.WindowApplication; break;
1817                         }
1818
1819                         if (RootContext.NeedsEntryPoint) {
1820                                 MethodInfo ep = RootContext.EntryPoint;
1821
1822                                 if (ep == null) {
1823                                         if (RootContext.MainClass != null) {
1824                                                 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1825                                                 if (main_cont == null) {
1826                                                         Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass); 
1827                                                         return false;
1828                                                 }
1829
1830                                                 if (!(main_cont is ClassOrStruct)) {
1831                                                         Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1832                                                         return false;
1833                                                 }
1834
1835                                                 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1836                                                 return false;
1837                                         }
1838
1839                                         if (Report.Errors == 0)
1840                                                 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1841                                                         output_file);
1842                                         return false;
1843                                 }
1844
1845                                 CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
1846                         } else if (RootContext.MainClass != null) {
1847                                 Report.Error (2017, "Cannot specify -main if building a module or library");
1848                         }
1849
1850                         if (embedded_resources != null){
1851                                 if (RootContext.Target == Target.Module) {
1852                                         Report.Error (1507, "Cannot link resource file when building a module");
1853                                         return false;
1854                                 }
1855
1856                                 embedded_resources.Emit ();
1857                         }
1858
1859                         //
1860                         // Add Win32 resources
1861                         //
1862
1863                         CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1864
1865                         if (win32ResourceFile != null) {
1866                                 try {
1867                                         CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1868                                 }
1869                                 catch (ArgumentException) {
1870                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1871                                 }
1872                         }
1873
1874                         if (win32IconFile != null) {
1875                                 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1876                                 if (define_icon == null) {
1877                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1878                                 }
1879                                 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1880                         }
1881
1882                         if (Report.Errors > 0)
1883                                 return false;
1884                         
1885                         CodeGen.Save (output_file);
1886                         if (timestamps) {
1887                                 ShowTime ("Saved output");
1888                                 ShowTotalTime ("Total");
1889                         }
1890
1891                         Timer.ShowTimers ();
1892                         
1893                         if (Report.ExpectedError != 0) {
1894                                 if (Report.Errors == 0) {
1895                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1896                                                 "No other errors reported.");
1897                                         
1898                                         Environment.Exit (2);
1899                                 } else {
1900                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1901                                                 "However, other errors were reported.");
1902                                         
1903                                         Environment.Exit (1);
1904                                 }
1905                                 
1906                                 
1907                                 return false;
1908                         }
1909
1910 #if DEBUGME
1911                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1912                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1913 #endif
1914                         return (Report.Errors == 0);
1915                 }
1916         }
1917
1918         class Resources
1919         {
1920                 interface IResource
1921                 {
1922                         void Emit ();
1923                         string FileName { get; }
1924                 }
1925
1926                 class EmbededResource : IResource
1927                 {
1928                         static MethodInfo embed_res;
1929
1930                         static EmbededResource () {
1931                                 Type[] argst = new Type [] { 
1932                                                                                            typeof (string), typeof (string), typeof (ResourceAttributes)
1933                                                                                    };
1934
1935                                 embed_res = typeof (AssemblyBuilder).GetMethod (
1936                                         "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1937                                         null, CallingConventions.Any, argst, null);
1938                                 
1939                                 if (embed_res == null) {
1940                                         Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1941                                 }
1942                         }
1943
1944                         readonly object[] args;
1945
1946                         public EmbededResource (string name, string file, bool isPrivate)
1947                         {
1948                                 args = new object [3];
1949                                 args [0] = name;
1950                                 args [1] = file;
1951                                 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1952                         }
1953
1954                         public void Emit()
1955                         {
1956                                 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1957                         }
1958
1959                         public string FileName {
1960                                 get {
1961                                         return (string)args [1];
1962                                 }
1963                         }
1964                 }
1965
1966                 class LinkedResource : IResource
1967                 {
1968                         readonly string file;
1969                         readonly string name;
1970                         readonly ResourceAttributes attribute;
1971
1972                         public LinkedResource (string name, string file, bool isPrivate)
1973                         {
1974                                 this.name = name;
1975                                 this.file = file;
1976                                 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1977                         }
1978
1979                         public void Emit ()
1980                         {
1981                                 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1982                         }
1983
1984                         public string FileName {
1985                                 get {
1986                                         return file;
1987                                 }
1988                         }
1989                 }
1990
1991
1992                 IDictionary embedded_resources = new HybridDictionary ();
1993
1994                 public void Add (bool embeded, string file, string name)
1995                 {
1996                         Add (embeded, file, name, false);
1997                 }
1998
1999                 public void Add (bool embeded, string file, string name, bool isPrivate)
2000                 {
2001                         if (embedded_resources.Contains (name)) {
2002                                 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
2003                                 return;
2004                         }
2005                         IResource r = embeded ? 
2006                                 (IResource) new EmbededResource (name, file, isPrivate) : 
2007                                 new LinkedResource (name, file, isPrivate);
2008
2009                         embedded_resources.Add (name, r);
2010                 }
2011
2012                 public void Emit ()
2013                 {
2014                         foreach (IResource r in embedded_resources.Values) {
2015                                 if (!File.Exists (r.FileName)) {
2016                                         Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
2017                                         continue;
2018                                 }
2019                                 
2020                                 r.Emit ();
2021                         }
2022                 }
2023         }
2024
2025         //
2026         // This is the only public entry point
2027         //
2028         public class CompilerCallableEntryPoint : MarshalByRefObject {
2029                 public static bool InvokeCompiler (string [] args, TextWriter error)
2030                 {
2031                         Report.Stderr = error;
2032                         try {
2033                                 return Driver.MainDriver (args) && Report.Errors == 0;
2034                         }
2035                         finally {
2036                                 Report.Stderr = Console.Error;
2037                                 Reset ();
2038                         }
2039                 }
2040
2041                 public static int[] AllWarningNumbers {
2042                         get {
2043                                 return Report.AllWarnings;
2044                         }
2045                 }
2046                 
2047                 static void Reset ()
2048                 {
2049                         Driver.Reset ();
2050                         RootContext.Reset ();
2051                         Tokenizer.Reset ();
2052                         Location.Reset ();
2053                         Report.Reset ();
2054                         TypeManager.Reset ();
2055                         TypeHandle.Reset ();
2056                         RootNamespace.Reset ();
2057                         NamespaceEntry.Reset ();
2058                         CodeGen.Reset ();
2059                         Attribute.Reset ();
2060                         AttributeTester.Reset ();
2061                 }
2062         }
2063 }