Merged from mcs.
[mono.git] / mcs / gmcs / 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 //
10
11 namespace Mono.CSharp
12 {
13         using System;
14         using System.Reflection;
15         using System.Reflection.Emit;
16         using System.Collections;
17         using System.IO;
18         using System.Text;
19         using System.Globalization;
20
21         enum Target {
22                 Library, Exe, Module, WinExe
23         };
24         
25         /// <summary>
26         ///    The compiler driver.
27         /// </summary>
28         public class Driver
29         {
30                 
31                 //
32                 // Assemblies references to be linked.   Initialized with
33                 // mscorlib.dll here.
34                 static ArrayList references;
35
36                 //
37                 // If any of these fail, we ignore the problem.  This is so
38                 // that we can list all the assemblies in Windows and not fail
39                 // if they are missing on Linux.
40                 //
41                 static ArrayList soft_references;
42
43                 // Lookup paths
44                 static ArrayList link_paths;
45
46                 // Whether we want Yacc to output its progress
47                 static bool yacc_verbose = false;
48
49                 // Whether we want to only run the tokenizer
50                 static bool tokenize = false;
51                 
52                 static string first_source;
53
54                 static Target target = Target.Exe;
55                 static string target_ext = ".exe";
56
57                 static bool want_debugging_support = false;
58
59                 static bool parse_only = false;
60                 static bool timestamps = false;
61                 static bool pause = false;
62                 static bool show_counters = false;
63                 public static bool parser_verbose = false;
64                 
65                 //
66                 // Whether to load the initial config file (what CSC.RSP has by default)
67                 // 
68                 static bool load_default_config = true;
69
70                 static Hashtable response_file_list;
71
72                 //
73                 // A list of resource files
74                 //
75                 static ArrayList resources;
76                 static ArrayList embedded_resources;
77                 
78                 //
79                 // An array of the defines from the command line
80                 //
81                 static ArrayList defines;
82
83                 //
84                 // Output file
85                 //
86                 static string output_file = null;
87
88                 //
89                 // Last time we took the time
90                 //
91                 static DateTime last_time, first_time;
92
93                 //
94                 // Encoding: ISO-Latin1 is 28591
95                 //
96                 static Encoding encoding;
97
98                 //
99                 // Whether the user has specified a different encoder manually
100                 //
101                 static bool using_default_encoder = true;
102                 
103                 public static void ShowTime (string msg)
104                 {
105                         if (!timestamps)
106                                 return;
107
108                         DateTime now = DateTime.Now;
109                         TimeSpan span = now - last_time;
110                         last_time = now;
111
112                         Console.WriteLine (
113                                 "[{0:00}:{1:000}] {2}",
114                                 (int) span.TotalSeconds, span.Milliseconds, msg);
115                 }
116
117                 public static void ShowTotalTime (string msg)
118                 {
119                         if (!timestamps)
120                                 return;
121
122                         DateTime now = DateTime.Now;
123                         TimeSpan span = now - first_time;
124                         last_time = now;
125
126                         Console.WriteLine (
127                                 "[{0:00}:{1:000}] {2}",
128                                 (int) span.TotalSeconds, span.Milliseconds, msg);
129                 }              
130                
131                 static void tokenize_file (SourceFile file)
132                 {
133                         Stream input;
134
135                         try {
136                                 input = File.OpenRead (file.Name);
137                         } catch {
138                                 Report.Error (2001, "Source file '" + file.Name + "' could not be opened");
139                                 return;
140                         }
141
142                         using (input){
143                                 SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder);
144                                 Tokenizer lexer = new Tokenizer (reader, file, defines);
145                                 int token, tokens = 0, errors = 0;
146
147                                 while ((token = lexer.token ()) != Token.EOF){
148                                         Location l = lexer.Location;
149                                         tokens++;
150                                         if (token == Token.ERROR)
151                                                 errors++;
152                                 }
153                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
154                         }
155                         
156                         return;
157                 }
158
159                 // MonoTODO("Change error code for aborted compilation to something reasonable")]               
160                 static void parse (SourceFile file)
161                 {
162                         CSharpParser parser;
163                         Stream input;
164
165                         try {
166                                 input = File.OpenRead (file.Name);
167                         } catch {
168                                 Report.Error (2001, "Source file '" + file.Name + "' could not be opened");
169                                 return;
170                         }
171
172                         SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder);
173                                 
174                         parser = new CSharpParser (reader, file, defines);
175                         parser.yacc_verbose_flag = yacc_verbose;
176                         try {
177                                 parser.parse ();
178                         } catch (Exception ex) {
179                                 Report.Error(666, "Compilation aborted: " + ex);
180                         } finally {
181                                 input.Close ();
182                         }
183                 }
184                 
185                 static void Usage ()
186                 {
187                         Console.WriteLine (
188                                 "Mono C# compiler, (C) 2001 - 2003 Ximian, Inc.\n" +
189                                 "mcs [options] source-files\n" +
190                                 "   --about            About the Mono C# compiler\n" +
191                                 "   -checked[+|-]      Set default context to checked\n" +
192                                 "   -codepage:ID       Sets code page to the one in ID\n" +
193                                 "                      (number, `utf8' or `reset')\n" +
194                                 "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
195                                 "   -debug[+-]         Generate debugging information\n" + 
196                                 "   -doc:FILE          XML Documentation file to generate\n" + 
197                                 "   -g                 Generate debugging information\n" +
198                                 "   --fatal            Makes errors fatal\n" +
199                                 "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
200                                 "   -main:class        Specified the class that contains the entry point\n" +
201                                 "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
202                                 "   -nostdlib[+|-]     Does not load core libraries\n" +
203                                 "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
204                                 "   -out:FNAME         Specifies output file\n" +
205                                 "   --parse            Only parses the source file\n" +
206                                 "   --expect-error X   Expect that error X will be encountered\n" +
207                                 "   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
208                                 "   -reference:ASS     References the specified assembly (-r:ASS)\n" +
209                                 "   --stacktrace       Shows stack trace at error location\n" +
210                                 "   -target:KIND       Specifies the target (KIND is one of: exe, winexe,\n" +
211                                 "                      library, module), (short: /t:)\n" +
212                                 "   --timestamp        Displays time stamps of various compiler events\n" +
213                                 "   -unsafe[+|-]       Allows unsafe code\n" +
214                                 "   -warnaserror[+|-]  Treat warnings as errors\n" +
215                                 "   -warn:LEVEL        Sets warning level (the highest is 4, the default)\n" +
216                                 "   -v                 Verbose parsing (for debugging the parser)\n" +
217                                 "   -2                 Enables experimental C# features\n" +
218                                 "\n" +
219                                 "Resources:\n" +
220                                 "   -linkresource:FILE[,ID] Links FILE as a resource\n" +
221                                 "   -resource:FILE[,ID]     Embed FILE as a resource\n" +
222                                 "   --mcs-debug X      Sets MCS debugging level to X\n" +
223                                 "   @file              Read response file for more options\n\n" +
224                                 "Options can be of the form -option or /option");
225                 }
226
227                 static void TargetUsage ()
228                 {
229                         Report.Error (2019, "Valid options for -target: are exe, winexe, library or module");
230                 }
231                 
232                 static void About ()
233                 {
234                         Console.WriteLine (
235                                 "The Mono C# compiler is (C) 2001, 2002, 2003 Ximian, Inc.\n\n" +
236                                 "The compiler source code is released under the terms of the GNU GPL\n\n" +
237
238                                 "For more information on Mono, visit the project Web site\n" +
239                                 "   http://www.go-mono.com\n\n" +
240
241                                 "The compiler was written by Miguel de Icaza, Ravi Pratap and Martin Baulig");
242                         Environment.Exit (0);
243                 }
244
245                 public static int counter1, counter2;
246                 
247                 public static int Main (string[] args)
248                 {
249                         RootContext.V2 = true;
250                         bool ok = MainDriver (args);
251                         
252                         if (ok && Report.Errors == 0) {
253                                 Console.Write("Compilation succeeded");
254                                 if (Report.Warnings > 0) {
255                                         Console.Write(" - {0} warning(s)", Report.Warnings);
256                                 }
257                                 Console.WriteLine();
258                                 if (show_counters){
259                                         Console.WriteLine ("Counter1: " + counter1);
260                                         Console.WriteLine ("Counter2: " + counter2);
261                                 }
262                                 if (pause)
263                                         Console.ReadLine ();
264                                 return 0;
265                         } else {
266                                 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
267                                         Report.Errors, Report.Warnings);
268                                 return 1;
269                         }
270                 }
271
272                 static public void LoadAssembly (string assembly, bool soft)
273                 {
274                         Assembly a;
275                         string total_log = "";
276
277                         try {
278                                 char[] path_chars = { '/', '\\', '.' };
279
280                                 if (assembly.IndexOfAny (path_chars) != -1) {
281                                         a = Assembly.LoadFrom (assembly);
282                                 } else {
283                                         a = Assembly.Load (assembly);
284                                 }
285                                 TypeManager.AddAssembly (a);
286
287                         } catch (FileNotFoundException){
288                                 foreach (string dir in link_paths){
289                                         string full_path = Path.Combine (dir, assembly);
290                                         if (!assembly.EndsWith (".dll"))
291                                                 full_path += ".dll";
292
293                                         try {
294                                                 a = Assembly.LoadFrom (full_path);
295                                                 TypeManager.AddAssembly (a);
296                                                 return;
297                                         } catch (FileNotFoundException ff) {
298                                                 total_log += ff.FusionLog;
299                                                 continue;
300                                         }
301                                 }
302                                 if (!soft) {
303                                         Report.Error (6, "Cannot find assembly `" + assembly + "'" );
304                                         Console.WriteLine ("Log: \n" + total_log);
305                                 }
306                         } catch (BadImageFormatException f) {
307                                 Report.Error(6, "Cannot load assembly (bad file format)" + f.FusionLog);
308                         } catch (FileLoadException f){
309                                 Report.Error(6, "Cannot load assembly " + f.FusionLog);
310                         } catch (ArgumentNullException){
311                                 Report.Error(6, "Cannot load assembly (null argument)");
312                         }
313                 }
314
315                 /// <summary>
316                 ///   Loads all assemblies referenced on the command line
317                 /// </summary>
318                 static public void LoadReferences ()
319                 {
320                         foreach (string r in references)
321                                 LoadAssembly (r, false);
322
323                         foreach (string r in soft_references)
324                                 LoadAssembly (r, true);
325                         
326                         return;
327                 }
328
329                 static void SetupDefaultDefines ()
330                 {
331                         defines = new ArrayList ();
332                         defines.Add ("__MonoCS__");
333                 }
334
335                 static string [] LoadArgs (string file)
336                 {
337                         StreamReader f;
338                         ArrayList args = new ArrayList ();
339                         string line;
340                         try {
341                                 f = new StreamReader (file);
342                         } catch {
343                                 return null;
344                         }
345
346                         StringBuilder sb = new StringBuilder ();
347                         
348                         while ((line = f.ReadLine ()) != null){
349                                 int t = line.Length;
350
351                                 for (int i = 0; i < t; i++){
352                                         char c = line [i];
353                                         
354                                         if (c == '"' || c == '\''){
355                                                 char end = c;
356                                                 
357                                                 for (i++; i < t; i++){
358                                                         c = line [i];
359
360                                                         if (c == end)
361                                                                 break;
362                                                         sb.Append (c);
363                                                 }
364                                         } else if (c == ' '){
365                                                 if (sb.Length > 0){
366                                                         args.Add (sb.ToString ());
367                                                         sb.Length = 0;
368                                                 }
369                                         } else
370                                                 sb.Append (c);
371                                 }
372                                 if (sb.Length > 0){
373                                         args.Add (sb.ToString ());
374                                         sb.Length = 0;
375                                 }
376                         }
377
378                         string [] ret_value = new string [args.Count];
379                         args.CopyTo (ret_value, 0);
380
381                         return ret_value;
382                 }
383
384                 //
385                 // Returns the directory where the system assemblies are installed
386                 //
387                 static string GetSystemDir ()
388                 {
389                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
390
391                         foreach (Assembly a in assemblies){
392                                 string codebase = a.Location;
393                                 if (codebase.EndsWith ("corlib.dll")){
394                                         return codebase.Substring (0, codebase.LastIndexOf (System.IO.Path.DirectorySeparatorChar));
395                                 }
396                         }
397
398                         Report.Error (-15, "Can not compute my system path");
399                         return "";
400                 }
401
402                 //
403                 // Given a path specification, splits the path from the file/pattern
404                 //
405                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
406                 {
407                         int p = spec.LastIndexOf ("/");
408                         if (p != -1){
409                                 //
410                                 // Windows does not like /file.cs, switch that to:
411                                 // "\", "file.cs"
412                                 //
413                                 if (p == 0){
414                                         path = "\\";
415                                         pattern = spec.Substring (1);
416                                 } else {
417                                         path = spec.Substring (0, p);
418                                         pattern = spec.Substring (p + 1);
419                                 }
420                                 return;
421                         }
422
423                         p = spec.LastIndexOf ("\\");
424                         if (p != -1){
425                                 path = spec.Substring (0, p);
426                                 pattern = spec.Substring (p + 1);
427                                 return;
428                         }
429
430                         path = ".";
431                         pattern = spec;
432                 }
433
434                 static void ProcessFile (string f)
435                 {
436                         if (first_source == null)
437                                 first_source = f;
438
439                         Location.AddFile (f);
440                 }
441
442                 static void ProcessFiles ()
443                 {
444                         Location.Initialize ();
445
446                         foreach (SourceFile file in Location.SourceFiles) {
447                                 if (tokenize) {
448                                         tokenize_file (file);
449                                 } else {
450                                         parse (file);
451                                 }
452                         }
453                 }
454
455                 static void CompileFiles (string spec, bool recurse)
456                 {
457                         string path, pattern;
458
459                         SplitPathAndPattern (spec, out path, out pattern);
460                         if (pattern.IndexOf ("*") == -1){
461                                 ProcessFile (spec);
462                                 return;
463                         }
464
465                         string [] files = null;
466                         try {
467                                 files = Directory.GetFiles (path, pattern);
468                         } catch (System.IO.DirectoryNotFoundException) {
469                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
470                                 return;
471                         } catch (System.IO.IOException){
472                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
473                                 return;
474                         }
475                         foreach (string f in files) {
476                                 ProcessFile (f);
477                         }
478
479                         if (!recurse)
480                                 return;
481                         
482                         string [] dirs = null;
483
484                         try {
485                                 dirs = Directory.GetDirectories (path);
486                         } catch {
487                         }
488                         
489                         foreach (string d in dirs) {
490                                         
491                                 // Don't include path in this string, as each
492                                 // directory entry already does
493                                 CompileFiles (d + "/" + pattern, true);
494                         }
495                 }
496
497                 static void DefineDefaultConfig ()
498                 {
499                         //
500                         // For now the "default config" is harcoded into the compiler
501                         // we can move this outside later
502                         //
503                         string [] default_config = {
504                                 "System",
505                                 "System.Xml",
506 #if false
507                                 //
508                                 // Is it worth pre-loading all this stuff?
509                                 //
510                                 "Accessibility",
511                                 "System.Configuration.Install",
512                                 "System.Data",
513                                 "System.Design",
514                                 "System.DirectoryServices",
515                                 "System.Drawing.Design",
516                                 "System.Drawing",
517                                 "System.EnterpriseServices",
518                                 "System.Management",
519                                 "System.Messaging",
520                                 "System.Runtime.Remoting",
521                                 "System.Runtime.Serialization.Formatters.Soap",
522                                 "System.Security",
523                                 "System.ServiceProcess",
524                                 "System.Web",
525                                 "System.Web.RegularExpressions",
526                                 "System.Web.Services",
527                                 "System.Windows.Forms"
528 #endif
529                         };
530                         
531                         int p = 0;
532                         foreach (string def in default_config)
533                                 soft_references.Insert (p++, def);
534                 }
535
536                 static void SetOutputFile (string name)
537                 {
538                         output_file = name;
539                 }
540
541                 static void SetWarningLevel (string s)
542                 {
543                         int level = 0;
544
545                         try {
546                                 level = Int32.Parse (s);
547                         } catch {
548                                 Report.Error (
549                                         1900,
550                                         "--wlevel requires a value from 0 to 4");
551                                 Environment.Exit (1);
552                         }
553                         if (level < 0 || level > 4){
554                                 Report.Error (1900, "Warning level must be 0 to 4");
555                                 Environment.Exit (1);
556                         } else
557                                 RootContext.WarningLevel = level;
558                 }
559
560                 static void SetupV2 ()
561                 {
562                         RootContext.V2 = true;
563                         defines.Add ("__V2__");
564                 }
565                 
566                 static void Version ()
567                 {
568                         string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
569                         Console.WriteLine ("Mono C# compiler version {0}", version);
570                         Environment.Exit (0);
571                 }
572                 
573                 //
574                 // Currently handles the Unix-like command line options, but will be
575                 // deprecated in favor of the CSCParseOption, which will also handle the
576                 // options that start with a dash in the future.
577                 //
578                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
579                 {
580                         switch (arg){
581                         case "-vv":
582                                 parser_verbose = true;
583                                 return true;
584                                 
585                         case "-v":
586                                 yacc_verbose = true;
587                                 return true;
588
589                         case "--version":
590                                 Version ();
591                                 return true;
592                                 
593                         case "--parse":
594                                 parse_only = true;
595                                 return true;
596                                 
597                         case "--main": case "-m":
598                                 if ((i + 1) >= args.Length){
599                                         Usage ();
600                                         Environment.Exit (1);
601                                 }
602                                 RootContext.MainClass = args [++i];
603                                 return true;
604                                 
605                         case "--unsafe":
606                                 RootContext.Unsafe = true;
607                                 return true;
608                                 
609                         case "/?": case "/h": case "/help":
610                         case "--help":
611                                 Usage ();
612                                 Environment.Exit (0);
613                                 return true;
614                                 
615                         case "--define":
616                                 if ((i + 1) >= args.Length){
617                                         Usage ();
618                                         Environment.Exit (1);
619                                 }
620                                 defines.Add (args [++i]);
621                                 return true;
622
623                         case "--show-counters":
624                                 show_counters = true;
625                                 return true;
626                                 
627                         case "--expect-error": {
628                                 int code = 0;
629                                 
630                                 try {
631                                         code = Int32.Parse (
632                                                 args [++i], NumberStyles.AllowLeadingSign);
633                                         Report.ExpectedError = code;
634                                 } catch {
635                                         Report.Error (-14, "Invalid number specified");
636                                 } 
637                                 return true;
638                         }
639                                 
640                         case "--tokenize": 
641                                 tokenize = true;
642                                 return true;
643                                 
644                         case "-o": 
645                         case "--output":
646                                 if ((i + 1) >= args.Length){
647                                         Usage ();
648                                         Environment.Exit (1);
649                                 }
650                                 SetOutputFile (args [++i]);
651                                 return true;
652                                 
653                         case "--checked":
654                                 RootContext.Checked = true;
655                                 return true;
656                                 
657                         case "--stacktrace":
658                                 Report.Stacktrace = true;
659                                 return true;
660                                 
661                         case "--linkresource":
662                         case "--linkres":
663                                 if ((i + 1) >= args.Length){
664                                         Usage ();
665                                         Report.Error (5, "Missing argument to --linkres"); 
666                                         Environment.Exit (1);
667                                 }
668                                 if (resources == null)
669                                         resources = new ArrayList ();
670                                 
671                                 resources.Add (args [++i]);
672                                 return true;
673                                 
674                         case "--resource":
675                         case "--res":
676                                 if ((i + 1) >= args.Length){
677                                         Usage ();
678                                         Report.Error (5, "Missing argument to --resource"); 
679                                         Environment.Exit (1);
680                                 }
681                                 if (embedded_resources == null)
682                                         embedded_resources = new ArrayList ();
683                                 
684                                 embedded_resources.Add (args [++i]);
685                                 return true;
686                                 
687                         case "--target":
688                                 if ((i + 1) >= args.Length){
689                                         Environment.Exit (1);
690                                         return true;
691                                 }
692                                 
693                                 string type = args [++i];
694                                 switch (type){
695                                 case "library":
696                                         target = Target.Library;
697                                         target_ext = ".dll";
698                                         break;
699                                         
700                                 case "exe":
701                                         target = Target.Exe;
702                                         break;
703                                         
704                                 case "winexe":
705                                         target = Target.WinExe;
706                                         break;
707                                         
708                                 case "module":
709                                         target = Target.Module;
710                                         target_ext = ".dll";
711                                         break;
712                                 default:
713                                         TargetUsage ();
714                                         Environment.Exit (1);
715                                         break;
716                                 }
717                                 return true;
718                                 
719                         case "-r":
720                                 if ((i + 1) >= args.Length){
721                                         Usage ();
722                                         Environment.Exit (1);
723                                 }
724                                 
725                                 references.Add (args [++i]);
726                                 return true;
727                                 
728                         case "-L":
729                                 if ((i + 1) >= args.Length){
730                                         Usage ();       
731                                         Environment.Exit (1);
732                                 }
733                                 link_paths.Add (args [++i]);
734                                 return true;
735                                 
736                         case "--nostdlib":
737                                 RootContext.StdLib = false;
738                                 return true;
739                                 
740                         case "--fatal":
741                                 Report.Fatal = true;
742                                 return true;
743                                 
744                         case "--werror":
745                                 Report.WarningsAreErrors = true;
746                                 return true;
747                                 
748                         case "--nowarn":
749                                 if ((i + 1) >= args.Length){
750                                         Usage ();
751                                         Environment.Exit (1);
752                                 }
753                                 int warn = 0;
754                                 
755                                 try {
756                                         warn = Int32.Parse (args [++i]);
757                                 } catch {
758                                         Usage ();
759                                         Environment.Exit (1);
760                                 }
761                                 Report.SetIgnoreWarning (warn);
762                                 return true;
763                                 
764                         case "--wlevel":
765                                 if ((i + 1) >= args.Length){
766                                         Report.Error (
767                                                 1900,
768                                                 "--wlevel requires a value from 0 to 4");
769                                         Environment.Exit (1);
770                                 }
771
772                                 SetWarningLevel (args [++i]);
773                                 return true;
774
775                         case "--mcs-debug":
776                                 if ((i + 1) >= args.Length){
777                                         Report.Error (5, "--mcs-debug requires an argument");
778                                         Environment.Exit (1);
779                                 }
780
781                                 try {
782                                         Report.DebugFlags = Int32.Parse (args [++i]);
783                                 } catch {
784                                         Report.Error (5, "Invalid argument to --mcs-debug");
785                                         Environment.Exit (1);
786                                 }
787                                 return true;
788                                 
789                         case "--about":
790                                 About ();
791                                 return true;
792                                 
793                         case "--recurse":
794                                 if ((i + 1) >= args.Length){
795                                         Report.Error (5, "--recurse requires an argument");
796                                         Environment.Exit (1);
797                                 }
798                                 CompileFiles (args [++i], true); 
799                                 return true;
800                                 
801                         case "--timestamp":
802                                 timestamps = true;
803                                 last_time = first_time = DateTime.Now;
804                                 return true;
805
806                         case "--pause":
807                                 pause = true;
808                                 return true;
809                                 
810                         case "--debug": case "-g":
811                                 want_debugging_support = true;
812                                 return true;
813                                 
814                         case "--noconfig":
815                                 load_default_config = false;
816                                 return true;
817                         }
818
819                         return false;
820                 }
821
822                 //
823                 // Currently it is very basic option parsing, but eventually, this will
824                 // be the complete option parser
825                 //
826                 static bool CSCParseOption (string option, ref string [] args, ref int i)
827                 {
828                         int idx = option.IndexOf (":");
829                         string arg, value;
830
831                         if (idx == -1){
832                                 arg = option;
833                                 value = "";
834                         } else {
835                                 arg = option.Substring (0, idx);
836
837                                 value = option.Substring (idx + 1);
838                         }
839
840                         switch (arg){
841                         case "/nologo":
842                                 return true;
843
844                         case "/t":
845                         case "/target":
846                                 switch (value){
847                                 case "exe":
848                                         target = Target.Exe;
849                                         break;
850
851                                 case "winexe":
852                                         target = Target.WinExe;
853                                         break;
854
855                                 case "library":
856                                         target = Target.Library;
857                                         target_ext = ".dll";
858                                         break;
859
860                                 case "module":
861                                         target = Target.Module;
862                                         target_ext = ".netmodule";
863                                         break;
864
865                                 default:
866                                         TargetUsage ();
867                                         Environment.Exit (1);
868                                         break;
869                                 }
870                                 return true;
871
872                         case "/out":
873                                 if (value == ""){
874                                         Usage ();
875                                         Environment.Exit (1);
876                                 }
877                                 SetOutputFile (value);
878                                 return true;
879
880                         case "/optimize":
881                         case "/optimize+":
882                         case "/optimize-":
883                         case "/incremental":
884                         case "/incremental+":
885                         case "/incremental-":
886                                 // nothing.
887                                 return true;
888
889                         case "/d":
890                         case "/define": {
891                                 string [] defs;
892
893                                 if (value == ""){
894                                         Usage ();
895                                         Environment.Exit (1);
896                                 }
897
898                                 defs = value.Split (new Char [] {';', ','});
899                                 foreach (string d in defs){
900                                         defines.Add (d);
901                                 }
902                                 return true;
903                         }
904
905                         case "/linkres":
906                         case "/linkresource":
907                                 if (value == ""){
908                                         Report.Error (5, arg + " requires an argument");
909                                         Environment.Exit (1);
910                                 }
911                                 if (resources == null)
912                                         resources = new ArrayList ();
913                                 
914                                 resources.Add (value);
915                                 return true;
916                                 
917                         case "/res":
918                         case "/resource":
919                                 if (value == ""){
920                                         Report.Error (5, arg + " requires an argument");
921                                         Environment.Exit (1);
922                                 }
923                                 if (embedded_resources == null)
924                                         embedded_resources = new ArrayList ();
925                                 
926                                 embedded_resources.Add (value);
927                                 return true;
928                                 
929                         case "/recurse":
930                                 if (value == ""){
931                                         Report.Error (5, "/recurse requires an argument");
932                                         Environment.Exit (1);
933                                 }
934                                 CompileFiles (value, true); 
935                                 return true;
936
937                         case "/r":
938                         case "/reference": {
939                                 if (value == ""){
940                                         Report.Error (5, arg + " requires an argument");
941                                         Environment.Exit (1);
942                                 }
943
944                                 string [] refs = value.Split (new char [] { ';', ',' });
945                                 foreach (string r in refs){
946                                         references.Add (r);
947                                 }
948                                 return true;
949                         }
950                         case "/doc": {
951                                 if (value == ""){
952                                         Report.Error (5, arg + " requires an argument");
953                                         Environment.Exit (1);
954                                 }
955                                 // TODO handle the /doc argument to generate xml doc
956                                 return true;
957                         }
958                         case "/lib": {
959                                 string [] libdirs;
960                                 
961                                 if (value == ""){
962                                         Report.Error (5, "/lib requires an argument");
963                                         Environment.Exit (1);
964                                 }
965
966                                 libdirs = value.Split (new Char [] { ',' });
967                                 foreach (string dir in libdirs)
968                                         link_paths.Add (dir);
969                                 return true;
970                         }
971                                 
972                         case "/debug":
973                         case "/debug+":
974                                 want_debugging_support = true;
975                                 return true;
976
977                         case "/checked":
978                         case "/checked+":
979                                 RootContext.Checked = true;
980                                 return true;
981
982                         case "/checked-":
983                                 RootContext.Checked = false;
984                                 return true;
985
986                         case "/unsafe":
987                         case "/unsafe+":
988                                 RootContext.Unsafe = true;
989                                 return true;
990
991                         case "/unsafe-":
992                                 RootContext.Unsafe = false;
993                                 return true;
994
995                         case "/warnaserror":
996                         case "/warnaserror+":
997                                 Report.WarningsAreErrors = true;
998                                 return true;
999
1000                         case "/warnaserror-":
1001                                 Report.WarningsAreErrors = false;
1002                                 return true;
1003
1004                         case "/warn":
1005                                 SetWarningLevel (value);
1006                                 return true;
1007
1008                         case "/nowarn": {
1009                                 string [] warns;
1010
1011                                 if (value == ""){
1012                                         Report.Error (5, "/nowarn requires an argument");
1013                                         Environment.Exit (1);
1014                                 }
1015                                 
1016                                 warns = value.Split (new Char [] {','});
1017                                 foreach (string wc in warns){
1018                                         int warn = 0;
1019                                         
1020                                         try {
1021                                                 warn = Int32.Parse (wc);
1022                                         } catch {
1023                                                 Usage ();
1024                                                 Environment.Exit (1);
1025                                         }
1026                                         Report.SetIgnoreWarning (warn);
1027                                 }
1028                                 return true;
1029                         }
1030
1031                         case "/noconfig-":
1032                                 load_default_config = true;
1033                                 return true;
1034                                 
1035                         case "/noconfig":
1036                         case "/noconfig+":
1037                                 load_default_config = false;
1038                                 return true;
1039
1040                         case "/help":
1041                         case "/?":
1042                                 Usage ();
1043                                 Environment.Exit (0);
1044                                 return true;
1045
1046                         case "/main":
1047                         case "/m":
1048                                 if (value == ""){
1049                                         Report.Error (5, arg + " requires an argument");                                        
1050                                         Environment.Exit (1);
1051                                 }
1052                                 RootContext.MainClass = value;
1053                                 return true;
1054
1055                         case "/nostdlib":
1056                         case "/nostdlib+":
1057                                 RootContext.StdLib = false;
1058                                 return true;
1059
1060                         case "/nostdlib-":
1061                                 RootContext.StdLib = true;
1062                                 return true;
1063
1064                         case "/fullpaths":
1065                                 return true;
1066
1067                         case "/win32icon":
1068                                 Report.Error (5, "/win32icon is currently not supported");
1069                                 return true;
1070                                 
1071                         case "/v2":
1072                         case "/2":
1073                                 SetupV2 ();
1074                                 return true;
1075                                 
1076                         case "/codepage":
1077                                 int cp = -1;
1078
1079                                 if (value == "utf8"){
1080                                         encoding = new UTF8Encoding();
1081                                         using_default_encoder = false;
1082                                         return true;
1083                                 }
1084                                 if (value == "reset"){
1085                                         //
1086                                         // 28591 is the code page for ISO-8859-1 encoding.
1087                                         //
1088                                         cp = 28591;
1089                                         using_default_encoder = true;
1090                                 }
1091                                 
1092                                 try {
1093                                         cp = Int32.Parse (value);
1094                                 } catch { }
1095                                 
1096                                 if (cp == -1){
1097                                         Console.WriteLine ("Invalid code-page requested");
1098                                         Usage ();
1099                                 }
1100
1101                                 try {
1102                                         encoding = Encoding.GetEncoding (cp);
1103                                         using_default_encoder = false;
1104                                 } catch {
1105                                         Console.WriteLine ("Code page: {0} not supported", cp);
1106                                 }
1107                                 return true;
1108
1109                         }
1110                         return false;
1111                 }
1112                 
1113                 /// <summary>
1114                 ///    Parses the arguments, and drives the compilation
1115                 ///    process.
1116                 /// </summary>
1117                 ///
1118                 /// <remarks>
1119                 ///    TODO: Mostly structured to debug the compiler
1120                 ///    now, needs to be turned into a real driver soon.
1121                 /// </remarks>
1122                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1123                 static bool MainDriver (string [] args)
1124                 {
1125                         int i;
1126                         bool parsing_options = true;
1127
1128                         Console.WriteLine ("Mono C# Compiler {0} for Generics",
1129                                            Assembly.GetExecutingAssembly ().GetName ().Version.ToString ());
1130                         try {
1131                                 encoding = Encoding.GetEncoding (28591);
1132                         } catch {
1133                                 Console.WriteLine ("Error: could not load encoding 28591, trying 1252");
1134                                 encoding = Encoding.GetEncoding (1252);
1135                         }
1136                         
1137                         references = new ArrayList ();
1138                         soft_references = new ArrayList ();
1139                         link_paths = new ArrayList ();
1140
1141                         SetupDefaultDefines ();
1142                         
1143                         //
1144                         // Setup defaults
1145                         //
1146                         // This is not required because Assembly.Load knows about this
1147                         // path.
1148                         //
1149
1150                         int argc = args.Length;
1151                         for (i = 0; i < argc; i++){
1152                                 string arg = args [i];
1153
1154                                 if (arg.StartsWith ("@")){
1155                                         string [] new_args, extra_args;
1156                                         string response_file = arg.Substring (1);
1157
1158                                         if (response_file_list == null)
1159                                                 response_file_list = new Hashtable ();
1160                                         
1161                                         if (response_file_list.Contains (response_file)){
1162                                                 Report.Error (
1163                                                         1515, "Response file `" + response_file +
1164                                                         "' specified multiple times");
1165                                                 Environment.Exit (1);
1166                                         }
1167                                         
1168                                         response_file_list.Add (response_file, response_file);
1169                                                     
1170                                         extra_args = LoadArgs (response_file);
1171                                         if (extra_args == null){
1172                                                 Report.Error (2011, "Unable to open response file: " +
1173                                                               response_file);
1174                                                 return false;
1175                                         }
1176
1177                                         new_args = new string [extra_args.Length + argc];
1178                                         args.CopyTo (new_args, 0);
1179                                         extra_args.CopyTo (new_args, argc);
1180                                         args = new_args;
1181                                         argc = new_args.Length;
1182                                         continue;
1183                                 }
1184
1185                                 if (parsing_options){
1186                                         if (arg == "--"){
1187                                                 parsing_options = false;
1188                                                 continue;
1189                                         }
1190                                         
1191                                         if (arg.StartsWith ("-")){
1192                                                 if (UnixParseOption (arg, ref args, ref i))
1193                                                         continue;
1194
1195                                                 // Try a -CSCOPTION
1196                                                 string csc_opt = "/" + arg.Substring (1);
1197                                                 if (CSCParseOption (csc_opt, ref args, ref i))
1198                                                         continue;
1199                                         } else {
1200                                                 if (arg.StartsWith ("/")){
1201                                                         if (CSCParseOption (arg, ref args, ref i))
1202                                                                 continue;
1203                                                 }
1204                                         }
1205                                 }
1206
1207                                 CompileFiles (arg, false); 
1208                         }
1209
1210                         ProcessFiles ();
1211
1212                         if (tokenize)
1213                                 return true;
1214                         
1215                         if (first_source == null){
1216                                 Report.Error (2008, "No files to compile were specified");
1217                                 return false;
1218                         }
1219
1220                         if (Report.Errors > 0)
1221                                 return false;
1222                         
1223                         if (parse_only)
1224                                 return true;
1225                         
1226                         //
1227                         // Load Core Library for default compilation
1228                         //
1229                         if (RootContext.StdLib)
1230                                 references.Insert (0, "mscorlib");
1231
1232                         if (load_default_config)
1233                                 DefineDefaultConfig ();
1234
1235                         if (Report.Errors > 0){
1236                                 return false;
1237                         }
1238
1239                         //
1240                         // Load assemblies required
1241                         //
1242                         if (timestamps)
1243                                 ShowTime ("Loading references");
1244                         link_paths.Add (GetSystemDir ());
1245                         LoadReferences ();
1246                         
1247                         if (timestamps)
1248                                 ShowTime ("   References loaded");
1249                         
1250                         if (Report.Errors > 0){
1251                                 return false;
1252                         }
1253
1254                         //
1255                         // Quick hack
1256                         //
1257                         if (output_file == null){
1258                                 int pos = first_source.LastIndexOf (".");
1259
1260                                 if (pos > 0)
1261                                         output_file = first_source.Substring (0, pos) + target_ext;
1262                                 else
1263                                         output_file = first_source + target_ext;
1264                         }
1265
1266                         CodeGen.Init (output_file, output_file, want_debugging_support);
1267
1268                         TypeManager.AddModule (CodeGen.ModuleBuilder);
1269
1270                         DateTime start = DateTime.Now;
1271                         TypeManager.ComputeNamespaces ();
1272                         DateTime end = DateTime.Now;
1273                         
1274                         //
1275                         // Before emitting, we need to get the core
1276                         // types emitted from the user defined types
1277                         // or from the system ones.
1278                         //
1279                         if (timestamps)
1280                                 ShowTime ("Initializing Core Types");
1281                         if (!RootContext.StdLib){
1282                                 RootContext.ResolveCore ();
1283                                 if (Report.Errors > 0)
1284                                         return false;
1285                         }
1286                         
1287                         TypeManager.InitCoreTypes ();
1288                         if (timestamps)
1289                                 ShowTime ("   Core Types done");
1290
1291                         //
1292                         // The second pass of the compiler
1293                         //
1294                         if (timestamps)
1295                                 ShowTime ("Resolving tree");
1296                         RootContext.ResolveTree ();
1297                         if (Report.Errors > 0)
1298                                 return false;
1299                         if (timestamps)
1300                                 ShowTime ("Populate tree");
1301                         if (!RootContext.StdLib)
1302                                 RootContext.BootCorlib_PopulateCoreTypes ();
1303                         RootContext.PopulateTypes ();
1304                         RootContext.DefineTypes ();
1305                         
1306                         TypeManager.InitCodeHelpers ();
1307
1308                         //
1309                         // Verify using aliases now
1310                         //
1311                         Namespace.VerifyUsing ();
1312                         
1313                         if (Report.Errors > 0){
1314                                 return false;
1315                         }
1316                         
1317                         //
1318                         // The code generator
1319                         //
1320                         if (timestamps)
1321                                 ShowTime ("Emitting code");
1322                         ShowTotalTime ("Total so far");
1323                         RootContext.EmitCode ();
1324                         if (timestamps)
1325                                 ShowTime ("   done");
1326
1327                         if (Report.Errors > 0){
1328                                 return false;
1329                         }
1330
1331                         if (timestamps)
1332                                 ShowTime ("Closing types");
1333
1334                         RootContext.CloseTypes ();
1335
1336                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1337                                 
1338                         if (target == Target.Library || target == Target.Module){
1339                                 k = PEFileKinds.Dll;
1340
1341                                 if (RootContext.MainClass != null)
1342                                         Report.Error (2017, "Can not specify -main: when building module or library");
1343                         } else if (target == Target.Exe)
1344                                 k = PEFileKinds.ConsoleApplication;
1345                         else if (target == Target.WinExe)
1346                                 k = PEFileKinds.WindowApplication;
1347
1348                         if (target == Target.Exe || target == Target.WinExe){
1349                                 MethodInfo ep = RootContext.EntryPoint;
1350
1351                                 if (ep == null){
1352                                         if (Report.Errors == 0)
1353                                                 Report.Error (5001, "Program " + output_file +
1354                                                               " does not have an entry point defined");
1355                                         return false;
1356                                 }
1357                                 
1358                                 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
1359                         }
1360
1361                         //
1362                         // Add the resources
1363                         //
1364                         if (resources != null){
1365                                 foreach (string spec in resources){
1366                                         string file, res;
1367                                         int cp;
1368                                         
1369                                         cp = spec.IndexOf (',');
1370                                         if (cp != -1){
1371                                                 file = spec.Substring (0, cp);
1372                                                 res = spec.Substring (cp + 1);
1373                                         } else
1374                                                 file = res = spec;
1375
1376                                         CodeGen.AssemblyBuilder.AddResourceFile (res, file);
1377                                 }
1378                         }
1379                         
1380                         if (embedded_resources != null){
1381                                 object[] margs = new object [2];
1382                                 Type[] argst = new Type [2];
1383                                 argst [0] = argst [1] = typeof (string);
1384                                 MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", argst);
1385                                 if (embed_res == null) {
1386                                         Report.Warning (0, new Location (-1), "Cannot embed resources on this runtime: try the Mono runtime instead.");
1387                                 } else {
1388                                         foreach (string spec in embedded_resources) {
1389                                                 int cp;
1390
1391                                                 cp = spec.IndexOf (',');
1392                                                 if (cp != -1){
1393                                                         margs [0] = spec.Substring (cp + 1);
1394                                                         margs [1] = spec.Substring (0, cp);
1395                                                 } else
1396                                                         margs [0] = margs [1] = spec;
1397
1398                                                 if (File.Exists ((string) margs [1]))
1399                                                         embed_res.Invoke (CodeGen.AssemblyBuilder, margs);
1400                                                 else {
1401                                                         Report.Error (1566, "Can not find the resource " + margs [1]);
1402                                                 }
1403                                         }
1404                                 }
1405                         }
1406
1407                         if (Report.Errors > 0)
1408                                 return false;
1409                         
1410                         CodeGen.Save (output_file);
1411                         if (timestamps) {
1412                                 ShowTime ("Saved output");
1413                                 ShowTotalTime ("Total");
1414                         }
1415
1416                         Timer.ShowTimers ();
1417                         
1418                         if (Report.ExpectedError != 0){
1419                                 Console.WriteLine("Failed to report expected error " + Report.ExpectedError);
1420                                 Environment.Exit (1);
1421                                 return false;
1422                         }
1423
1424 #if DEBUGME
1425                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1426                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1427 #endif
1428                         return (Report.Errors == 0);
1429                 }
1430
1431         }
1432 }