Detect when the input ends in .dlt and use DltParser
[delight/core.git] / dmd / mars.c
blob39e633911faaa4da3e6ebdf9ad78b5e7c16b3d5c
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include <assert.h>
15 #include <limits.h>
17 #ifndef IN_GCC
18 #if _WIN32
19 #include <windows.h>
20 long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep);
21 #endif
23 #if __DMC__
24 #include <dos.h>
25 #endif
27 #if linux
28 #include <errno.h>
29 #endif
30 #endif
32 #include "mem.h"
33 #include "root.h"
35 #include "mars.h"
36 #include "module.h"
37 #include "mtype.h"
38 #include "id.h"
39 #include "cond.h"
40 #include "expression.h"
41 #include "lexer.h"
42 #include "lib.h"
44 void browse(const char *url);
45 void getenv_setargv(const char *envvar, int *pargc, char** *pargv);
47 void obj_start(char *srcfile);
48 void obj_end(Library *library, File *objfile);
50 Global global;
52 Global::Global()
54 mars_ext = "d";
55 sym_ext = "d";
56 hdr_ext = "di";
57 doc_ext = "html";
58 ddoc_ext = "ddoc";
59 dlt_ext = "dlt";
61 #ifndef IN_GCC
62 #if _WIN32
63 obj_ext = "obj";
64 #elif linux
65 obj_ext = "o";
66 #else
67 #error "fix this"
68 #endif
69 #else
70 obj_ext = "o";
71 #endif
73 #ifndef IN_GCC
74 #if _WIN32
75 lib_ext = "lib";
76 #elif linux
77 lib_ext = "a";
78 #else
79 #error "fix this"
80 #endif
81 #else
82 lib_ext = "a";
83 #endif
85 copyright = "Copyright (c) 1999-2008 by Digital Mars";
86 written = "written by Walter Bright";
87 version = "v1.030";
88 global.structalign = 8;
90 memset(&params, 0, sizeof(Param));
93 char *Loc::toChars()
95 OutBuffer buf;
96 char *p;
98 if (filename)
100 buf.printf("%s", filename);
103 if (linnum)
104 #ifndef IN_GCC
105 buf.printf("(%d)", linnum);
106 #else
107 buf.printf(":%u", linnum);
108 #endif
109 buf.writeByte(0);
110 return (char *)buf.extractData();
113 Loc::Loc(Module *mod, unsigned linnum)
115 this->linnum = linnum;
116 this->filename = mod ? mod->srcfile->toChars() : NULL;
119 /**************************************
120 * Print error message and exit.
123 void error(Loc loc, const char *format, ...)
125 va_list ap;
126 va_start(ap, format);
127 verror(loc, format, ap);
128 va_end( ap );
131 void verror(Loc loc, const char *format, va_list ap)
133 if (!global.gag)
135 char *p = loc.toChars();
137 if (*p)
138 fprintf(stdmsg, "%s: ", p);
139 mem.free(p);
141 fprintf(stdmsg, "Error: ");
142 vfprintf(stdmsg, format, ap);
143 fprintf(stdmsg, "\n");
144 fflush(stdmsg);
146 global.errors++;
149 /***************************************
150 * Call this after printing out fatal error messages to clean up and exit
151 * the compiler.
154 void fatal()
156 #if 0
157 halt();
158 #endif
159 exit(EXIT_FAILURE);
162 /**************************************
163 * Try to stop forgetting to remove the breakpoints from
164 * release builds.
166 void halt()
168 #ifdef DEBUG
169 *(char*)0=0;
170 #endif
173 #ifndef IN_GCC
175 extern void backend_init();
176 extern void backend_term();
178 void usage()
180 printf("Digital Mars D Compiler %s\n%s %s\n",
181 global.version, global.copyright, global.written);
182 printf("\
183 Documentation: http://www.digitalmars.com/d/1.0/index.html\n\
184 Usage:\n\
185 dmd files.d ... { -switch }\n\
187 files.d D source files\n%s\
188 -c do not link\n\
189 -cov do code coverage analysis\n\
190 -D generate documentation\n\
191 -Dddocdir write documentation file to docdir directory\n\
192 -Dffilename write documentation file to filename\n\
193 -d allow deprecated features\n\
194 -debug compile in debug code\n\
195 -debug=level compile in debug code <= level\n\
196 -debug=ident compile in debug code identified by ident\n\
197 -debuglib=name set symbolic debug library to name\n\
198 -defaultlib=name set default library to name\n\
199 -g add symbolic debug info\n\
200 -gc add symbolic debug info, pretend to be C\n\
201 -H generate 'header' file\n\
202 -Hdhdrdir write 'header' file to hdrdir directory\n\
203 -Hffilename write 'header' file to filename\n\
204 --help print help\n\
205 -Ipath where to look for imports\n\
206 -ignore ignore unsupported pragmas\n\
207 -inline do function inlining\n\
208 -Jpath where to look for string imports\n\
209 -Llinkerflag pass linkerflag to link\n\
210 -lib generate library rather than object files\n\
211 -man open web browser on manual page\n\
212 -nofloat do not emit reference to floating point\n\
213 -O optimize\n\
214 -o- do not write object file\n\
215 -odobjdir write object & library files to directory objdir\n\
216 -offilename name output file to filename\n\
217 -op do not strip paths from source file\n\
218 -profile profile runtime performance of generated code\n\
219 -quiet suppress unnecessary messages\n\
220 -release compile release version\n\
221 -run srcfile args... run resulting program, passing args\n\
222 -unittest compile in unit tests\n\
223 -v verbose\n\
224 -v1 D language version 1\n\
225 -version=level compile in version code >= level\n\
226 -version=ident compile in version code identified by ident\n\
227 -w enable warnings\n\
229 #if WIN32
230 " @cmdfile read arguments from cmdfile\n"
231 #else
233 #endif
237 int main(int argc, char *argv[])
239 int i;
240 Array files;
241 Array libmodules;
242 char *p;
243 Module *m;
244 int status = EXIT_SUCCESS;
245 int argcstart = argc;
247 // Check for malformed input
248 if (argc < 1 || !argv)
250 Largs:
251 error("missing or null command line arguments");
252 fatal();
254 for (i = 0; i < argc; i++)
256 if (!argv[i])
257 goto Largs;
260 #if __DMC__ // DMC unique support for response files
261 if (response_expand(&argc,&argv)) // expand response files
262 error("can't open response file");
263 #endif
265 files.reserve(argc - 1);
267 // Set default values
268 global.params.argv0 = argv[0];
269 global.params.link = 1;
270 global.params.useAssert = 1;
271 global.params.useInvariants = 1;
272 global.params.useIn = 1;
273 global.params.useOut = 1;
274 global.params.useArrayBounds = 1;
275 global.params.useSwitchError = 1;
276 global.params.useInline = 0;
277 global.params.obj = 1;
278 global.params.Dversion = 2;
279 global.params.quiet = 1;
281 global.params.linkswitches = new Array();
282 global.params.libfiles = new Array();
283 global.params.objfiles = new Array();
284 global.params.ddocfiles = new Array();
286 #if _WIN32
287 global.params.defaultlibname = "phobos";
288 #elif linux
289 global.params.defaultlibname = "phobos";
290 #endif
291 global.params.debuglibname = global.params.defaultlibname;
293 // Predefine version identifiers
294 VersionCondition::addPredefinedGlobalIdent("DigitalMars");
295 #if _WIN32
296 VersionCondition::addPredefinedGlobalIdent("Windows");
297 VersionCondition::addPredefinedGlobalIdent("Win32");
298 global.params.isWindows = 1;
299 #endif
300 #if linux
301 VersionCondition::addPredefinedGlobalIdent("linux");
302 global.params.isLinux = 1;
303 #endif /* linux */
304 VersionCondition::addPredefinedGlobalIdent("X86");
305 VersionCondition::addPredefinedGlobalIdent("LittleEndian");
306 //VersionCondition::addPredefinedGlobalIdent("D_Bits");
307 VersionCondition::addPredefinedGlobalIdent("D_InlineAsm");
308 VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
309 #if V2
310 VersionCondition::addPredefinedGlobalIdent("D_Version2");
311 #endif
312 VersionCondition::addPredefinedGlobalIdent("all");
314 #if _WIN32
315 inifile(argv[0], "sc.ini");
316 #endif
317 #if linux
318 inifile(argv[0], "dmd.conf");
319 #endif
320 getenv_setargv("DFLAGS", &argc, &argv);
322 #if 0
323 for (i = 0; i < argc; i++)
325 printf("argv[%d] = '%s'\n", i, argv[i]);
327 #endif
329 for (i = 1; i < argc; i++)
331 p = argv[i];
332 if (*p == '-')
334 if (strcmp(p + 1, "d") == 0)
335 global.params.useDeprecated = 1;
336 else if (strcmp(p + 1, "c") == 0)
337 global.params.link = 0;
338 else if (strcmp(p + 1, "cov") == 0)
339 global.params.cov = 1;
340 else if (strcmp(p + 1, "fPIC") == 0)
341 global.params.pic = 1;
342 else if (strcmp(p + 1, "multiobj") == 0)
343 global.params.multiobj = 1;
344 else if (strcmp(p + 1, "g") == 0)
345 global.params.symdebug = 1;
346 else if (strcmp(p + 1, "gc") == 0)
347 global.params.symdebug = 2;
348 else if (strcmp(p + 1, "gt") == 0)
349 { error("use -profile instead of -gt\n");
350 global.params.trace = 1;
352 else if (strcmp(p + 1, "profile") == 0)
353 global.params.trace = 1;
354 else if (strcmp(p + 1, "v") == 0)
355 global.params.verbose = 1;
356 else if (strcmp(p + 1, "v1") == 0)
358 #if V1
359 global.params.Dversion = 1;
360 #else
361 error("use DMD 1.0 series compilers for -v1 switch");
362 break;
363 #endif
365 else if (strcmp(p + 1, "w") == 0)
366 global.params.warnings = 1;
367 else if (strcmp(p + 1, "O") == 0)
368 global.params.optimize = 1;
369 else if (p[1] == 'o')
371 switch (p[2])
373 case '-':
374 global.params.obj = 0;
375 break;
377 case 'd':
378 if (!p[3])
379 goto Lnoarg;
380 global.params.objdir = p + 3;
381 break;
383 case 'f':
384 if (!p[3])
385 goto Lnoarg;
386 global.params.objname = p + 3;
387 break;
389 case 'p':
390 if (p[3])
391 goto Lerror;
392 global.params.preservePaths = 1;
393 break;
395 case 0:
396 error("-o no longer supported, use -of or -od");
397 break;
399 default:
400 goto Lerror;
403 else if (p[1] == 'D')
404 { global.params.doDocComments = 1;
405 switch (p[2])
407 case 'd':
408 if (!p[3])
409 goto Lnoarg;
410 global.params.docdir = p + 3;
411 break;
412 case 'f':
413 if (!p[3])
414 goto Lnoarg;
415 global.params.docname = p + 3;
416 break;
418 case 0:
419 break;
421 default:
422 goto Lerror;
425 #ifdef _DH
426 else if (p[1] == 'H')
427 { global.params.doHdrGeneration = 1;
428 switch (p[2])
430 case 'd':
431 if (!p[3])
432 goto Lnoarg;
433 global.params.hdrdir = p + 3;
434 break;
436 case 'f':
437 if (!p[3])
438 goto Lnoarg;
439 global.params.hdrname = p + 3;
440 break;
442 case 0:
443 break;
445 default:
446 goto Lerror;
449 #endif
450 else if (strcmp(p + 1, "ignore") == 0)
451 global.params.ignoreUnsupportedPragmas = 1;
452 else if (strcmp(p + 1, "inline") == 0)
453 global.params.useInline = 1;
454 else if (strcmp(p + 1, "lib") == 0)
455 global.params.lib = 1;
456 else if (strcmp(p + 1, "nofloat") == 0)
457 global.params.nofloat = 1;
458 else if (strcmp(p + 1, "quiet") == 0)
459 global.params.quiet = 1;
460 else if (strcmp(p + 1, "release") == 0)
461 global.params.release = 1;
462 else if (strcmp(p + 1, "unittest") == 0)
463 global.params.useUnitTests = 1;
464 else if (p[1] == 'I')
466 if (!global.params.imppath)
467 global.params.imppath = new Array();
468 global.params.imppath->push(p + 2);
470 else if (p[1] == 'J')
472 if (!global.params.fileImppath)
473 global.params.fileImppath = new Array();
474 global.params.fileImppath->push(p + 2);
476 else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l')
478 // Parse:
479 // -debug
480 // -debug=number
481 // -debug=identifier
482 if (p[6] == '=')
484 if (isdigit(p[7]))
485 { long level;
487 errno = 0;
488 level = strtol(p + 7, &p, 10);
489 if (*p || errno || level > INT_MAX)
490 goto Lerror;
491 DebugCondition::setGlobalLevel((int)level);
493 else if (Lexer::isValidIdentifier(p + 7))
494 DebugCondition::addGlobalIdent(p + 7);
495 else
496 goto Lerror;
498 else if (p[6])
499 goto Lerror;
500 else
501 global.params.debuglevel = 1;
503 else if (memcmp(p + 1, "version", 5) == 0)
505 // Parse:
506 // -version=number
507 // -version=identifier
508 if (p[8] == '=')
510 if (isdigit(p[9]))
511 { long level;
513 errno = 0;
514 level = strtol(p + 9, &p, 10);
515 if (*p || errno || level > INT_MAX)
516 goto Lerror;
517 VersionCondition::setGlobalLevel((int)level);
519 else if (Lexer::isValidIdentifier(p + 9))
520 VersionCondition::addGlobalIdent(p + 9);
521 else
522 goto Lerror;
524 else
525 goto Lerror;
527 else if (strcmp(p + 1, "-b") == 0)
528 global.params.debugb = 1;
529 else if (strcmp(p + 1, "-c") == 0)
530 global.params.debugc = 1;
531 else if (strcmp(p + 1, "-f") == 0)
532 global.params.debugf = 1;
533 else if (strcmp(p + 1, "-help") == 0)
534 { usage();
535 exit(EXIT_SUCCESS);
537 else if (strcmp(p + 1, "-r") == 0)
538 global.params.debugr = 1;
539 else if (strcmp(p + 1, "-x") == 0)
540 global.params.debugx = 1;
541 else if (strcmp(p + 1, "-y") == 0)
542 global.params.debugy = 1;
543 else if (p[1] == 'L')
545 global.params.linkswitches->push(p + 2);
547 else if (memcmp(p + 1, "defaultlib=", 11) == 0)
549 global.params.defaultlibname = p + 1 + 11;
551 else if (memcmp(p + 1, "debuglib=", 9) == 0)
553 global.params.debuglibname = p + 1 + 9;
555 else if (memcmp(p + 1, "man", 3) == 0)
557 #if _WIN32
558 #if V1
559 browse("http://www.digitalmars.com/d/1.0/dmd-windows.html");
560 #else
561 browse("http://www.digitalmars.com/d/2.0/dmd-windows.html");
562 #endif
563 #endif
564 #if linux
565 #if V1
566 browse("http://www.digitalmars.com/d/1.0/dmd-linux.html");
567 #else
568 browse("http://www.digitalmars.com/d/2.0/dmd-linux.html");
569 #endif
570 #endif
571 exit(EXIT_SUCCESS);
573 else if (strcmp(p + 1, "run") == 0)
574 { global.params.run = 1;
575 global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1;
576 if (global.params.runargs_length)
578 files.push(argv[i + 1]);
579 global.params.runargs = &argv[i + 2];
580 i += global.params.runargs_length;
581 global.params.runargs_length--;
583 else
584 { global.params.run = 0;
585 goto Lnoarg;
588 else
590 Lerror:
591 error("unrecognized switch '%s'", argv[i]);
592 continue;
594 Lnoarg:
595 error("argument expected for switch '%s'", argv[i]);
596 continue;
599 else
601 #if !TARGET_LINUX
602 char *ext = FileName::ext(p);
603 if (ext && stricmp(ext, "exe") == 0)
605 global.params.objname = p;
606 continue;
608 #endif
609 files.push(p);
612 if (global.errors)
614 fatal();
616 if (files.dim == 0)
617 { usage();
618 return EXIT_FAILURE;
621 if (global.params.release)
622 { global.params.useInvariants = 0;
623 global.params.useIn = 0;
624 global.params.useOut = 0;
625 global.params.useAssert = 0;
626 global.params.useArrayBounds = 0;
627 global.params.useSwitchError = 0;
630 if (global.params.run)
631 global.params.quiet = 1;
633 if (global.params.useUnitTests)
634 global.params.useAssert = 1;
636 if (!global.params.obj || global.params.lib)
637 global.params.link = 0;
639 if (global.params.link)
641 global.params.exefile = global.params.objname;
642 global.params.oneobj = 1;
643 if (global.params.objname)
645 /* Use this to name the one object file with the same
646 * name as the exe file.
648 global.params.objname = FileName::forceExt(global.params.objname, global.obj_ext)->toChars();
650 /* If output directory is given, use that path rather than
651 * the exe file path.
653 if (global.params.objdir)
654 { char *name = FileName::name(global.params.objname);
655 global.params.objname = FileName::combine(global.params.objdir, name);
659 else if (global.params.lib)
661 global.params.libname = global.params.objname;
662 global.params.objname = NULL;
664 // Haven't investigated handling these options with multiobj
665 if (!global.params.cov && !global.params.trace)
666 global.params.multiobj = 1;
668 else if (global.params.run)
670 error("flags conflict with -run");
671 fatal();
673 else
675 if (global.params.objname && files.dim > 1)
677 global.params.oneobj = 1;
678 //error("multiple source files, but only one .obj name");
679 //fatal();
682 if (global.params.cov)
683 VersionCondition::addPredefinedGlobalIdent("D_Coverage");
684 #if V2
685 if (global.params.useUnitTests)
686 VersionCondition::addPredefinedGlobalIdent("unittest");
687 #endif
689 // Initialization
690 Type::init();
691 Id::initialize();
692 Module::init();
693 initPrecedence();
695 backend_init();
697 //printf("%d source files\n",files.dim);
699 // Build import search path
700 if (global.params.imppath)
702 for (i = 0; i < global.params.imppath->dim; i++)
704 char *path = (char *)global.params.imppath->data[i];
705 Array *a = FileName::splitPath(path);
707 if (a)
709 if (!global.path)
710 global.path = new Array();
711 global.path->append(a);
716 // Build string import search path
717 if (global.params.fileImppath)
719 for (i = 0; i < global.params.fileImppath->dim; i++)
721 char *path = (char *)global.params.fileImppath->data[i];
722 Array *a = FileName::splitPath(path);
724 if (a)
726 if (!global.filePath)
727 global.filePath = new Array();
728 global.filePath->append(a);
733 // Create Modules
734 Array modules;
735 modules.reserve(files.dim);
736 int firstmodule = 1;
737 for (i = 0; i < files.dim; i++)
739 char *ext;
740 char *name;
741 bool isDltFile = 0;
743 p = (char *) files.data[i];
745 #if _WIN32
746 // Convert / to \ so linker will work
747 for (int i = 0; p[i]; i++)
749 if (p[i] == '/')
750 p[i] = '\\';
752 #endif
754 p = FileName::name(p); // strip path
755 ext = FileName::ext(p);
756 if (ext)
757 { /* Deduce what to do with a file based on its extension
759 #if TARGET_LINUX
760 if (strcmp(ext, global.obj_ext) == 0)
761 #else
762 if (stricmp(ext, global.obj_ext) == 0)
763 #endif
765 global.params.objfiles->push(files.data[i]);
766 libmodules.push(files.data[i]);
767 continue;
770 #if TARGET_LINUX
771 if (strcmp(ext, global.lib_ext) == 0)
772 #else
773 if (stricmp(ext, global.lib_ext) == 0)
774 #endif
776 global.params.libfiles->push(files.data[i]);
777 libmodules.push(files.data[i]);
778 continue;
781 if (strcmp(ext, global.ddoc_ext) == 0)
783 global.params.ddocfiles->push(files.data[i]);
784 continue;
787 #if !TARGET_LINUX
788 if (stricmp(ext, "res") == 0)
790 global.params.resfile = (char *)files.data[i];
791 continue;
794 if (stricmp(ext, "def") == 0)
796 global.params.deffile = (char *)files.data[i];
797 continue;
800 if (stricmp(ext, "exe") == 0)
802 assert(0); // should have already been handled
804 #endif
806 /* Examine extension to see if it is a valid
807 * D source file extension
809 isDltFile = (stricmp(ext, global.dlt_ext) == 0);
810 if (stricmp(ext, global.mars_ext) == 0 ||
811 stricmp(ext, global.dlt_ext) == 0 ||
812 stricmp(ext, "dd") == 0 ||
813 stricmp(ext, "htm") == 0 ||
814 stricmp(ext, "html") == 0 ||
815 stricmp(ext, "xhtml") == 0)
818 ext--; // skip onto '.'
819 assert(*ext == '.');
820 name = (char *)mem.malloc((ext - p) + 1);
821 memcpy(name, p, ext - p);
822 name[ext - p] = 0; // strip extension
824 if (name[0] == 0 ||
825 strcmp(name, "..") == 0 ||
826 strcmp(name, ".") == 0)
828 Linvalid:
829 error("invalid file name '%s'", (char *)files.data[i]);
830 fatal();
833 else
834 { error("unrecognized file extension %s\n", ext);
835 fatal();
838 else
839 { name = p;
840 if (!*name)
841 goto Linvalid;
844 /* At this point, name is the D source file name stripped of
845 * its path and extension.
848 Identifier *id = new Identifier(name, 0);
849 m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration, isDltFile);
850 modules.push(m);
852 if (firstmodule)
853 { global.params.objfiles->push(m->objfile->name->str);
854 firstmodule = 0;
858 #if _WIN32
859 __try
861 #endif
862 // Read files, parse them
863 int anydocfiles = 0;
864 for (i = 0; i < modules.dim; i++)
866 m = (Module *)modules.data[i];
867 if (global.params.verbose)
868 printf("parse %s\n", m->toChars());
869 if (!Module::rootModule)
870 Module::rootModule = m;
871 m->importedFrom = m;
872 if (!global.params.oneobj || i == 0 || m->isDocFile)
873 m->deleteObjFile();
874 m->read(0);
875 m->parse();
876 if (m->isDocFile)
878 anydocfiles = 1;
879 m->gendocfile();
881 // Remove m from list of modules
882 modules.remove(i);
883 i--;
885 // Remove m's object file from list of object files
886 for (int j = 0; j < global.params.objfiles->dim; j++)
888 if (m->objfile->name->str == global.params.objfiles->data[j])
890 global.params.objfiles->remove(j);
891 break;
895 if (global.params.objfiles->dim == 0)
896 global.params.link = 0;
899 if (anydocfiles && modules.dim &&
900 (global.params.oneobj || global.params.objname))
902 error("conflicting Ddoc and obj generation options");
903 fatal();
905 if (global.errors)
906 fatal();
907 #ifdef _DH
908 if (global.params.doHdrGeneration)
910 /* Generate 'header' import files.
911 * Since 'header' import files must be independent of command
912 * line switches and what else is imported, they are generated
913 * before any semantic analysis.
915 for (i = 0; i < modules.dim; i++)
917 m = (Module *)modules.data[i];
918 if (global.params.verbose)
919 printf("import %s\n", m->toChars());
920 m->genhdrfile();
923 if (global.errors)
924 fatal();
925 #endif
927 // Do semantic analysis
928 for (i = 0; i < modules.dim; i++)
930 m = (Module *)modules.data[i];
931 if (global.params.verbose)
932 printf("semantic %s\n", m->toChars());
933 m->semantic();
935 if (global.errors)
936 fatal();
938 // Do pass 2 semantic analysis
939 for (i = 0; i < modules.dim; i++)
941 m = (Module *)modules.data[i];
942 if (global.params.verbose)
943 printf("semantic2 %s\n", m->toChars());
944 m->semantic2();
946 if (global.errors)
947 fatal();
949 // Do pass 3 semantic analysis
950 for (i = 0; i < modules.dim; i++)
952 m = (Module *)modules.data[i];
953 if (global.params.verbose)
954 printf("semantic3 %s\n", m->toChars());
955 m->semantic3();
957 if (global.errors)
958 fatal();
960 // Scan for functions to inline
961 if (global.params.useInline)
963 /* The problem with useArrayBounds and useAssert is that the
964 * module being linked to may not have generated them, so if
965 * we inline functions from those modules, the symbols for them will
966 * not be found at link time.
968 if (!global.params.useArrayBounds && !global.params.useAssert)
970 // Do pass 3 semantic analysis on all imported modules,
971 // since otherwise functions in them cannot be inlined
972 for (i = 0; i < Module::amodules.dim; i++)
974 m = (Module *)Module::amodules.data[i];
975 if (global.params.verbose)
976 printf("semantic3 %s\n", m->toChars());
977 m->semantic3();
979 if (global.errors)
980 fatal();
983 for (i = 0; i < modules.dim; i++)
985 m = (Module *)modules.data[i];
986 if (global.params.verbose)
987 printf("inline scan %s\n", m->toChars());
988 m->inlineScan();
991 if (global.errors)
992 fatal();
994 Library *library = NULL;
995 if (global.params.lib)
997 library = new Library();
998 library->setFilename(global.params.objdir, global.params.libname);
1000 // Add input object and input library files to output library
1001 for (int i = 0; i < libmodules.dim; i++)
1003 char *p = (char *)libmodules.data[i];
1004 library->addObject(p, NULL, 0);
1008 // Generate output files
1009 if (global.params.oneobj)
1011 for (i = 0; i < modules.dim; i++)
1013 m = (Module *)modules.data[i];
1014 if (global.params.verbose)
1015 printf("code %s\n", m->toChars());
1016 if (i == 0)
1017 obj_start(m->srcfile->toChars());
1018 m->genobjfile(0);
1019 if (!global.errors && global.params.doDocComments)
1020 m->gendocfile();
1022 if (!global.errors && modules.dim)
1024 obj_end(library, ((Module *)modules.data[0])->objfile);
1027 else
1029 for (i = 0; i < modules.dim; i++)
1031 m = (Module *)modules.data[i];
1032 if (global.params.verbose)
1033 printf("code %s\n", m->toChars());
1034 if (global.params.obj)
1035 { obj_start(m->srcfile->toChars());
1036 m->genobjfile(global.params.multiobj);
1037 obj_end(library, m->objfile);
1038 obj_write_deferred(library);
1040 if (global.errors)
1042 if (!global.params.lib)
1043 m->deleteObjFile();
1045 else
1047 if (global.params.doDocComments)
1048 m->gendocfile();
1053 if (global.params.lib && !global.errors)
1054 library->write();
1056 #if _WIN32
1058 __except (__ehfilter(GetExceptionInformation()))
1060 printf("Stack overflow\n");
1061 fatal();
1063 #endif
1064 backend_term();
1065 if (global.errors)
1066 fatal();
1068 if (!global.params.objfiles->dim)
1070 if (global.params.link)
1071 error("no object files to link");
1073 else
1075 if (global.params.link)
1076 status = runLINK();
1078 if (global.params.run)
1080 if (!status)
1082 status = runProgram();
1084 /* Delete .obj files and .exe file
1086 for (i = 0; i < modules.dim; i++)
1088 Module *m = (Module *)modules.data[i];
1089 m->deleteObjFile();
1090 if (global.params.oneobj)
1091 break;
1093 deleteExeFile();
1098 return status;
1103 /***********************************
1104 * Parse and append contents of environment variable envvar
1105 * to argc and argv[].
1106 * The string is separated into arguments, processing \ and ".
1109 void getenv_setargv(const char *envvar, int *pargc, char** *pargv)
1111 char *env;
1112 char *p;
1113 Array *argv;
1114 int argc;
1116 int wildcard; // do wildcard expansion
1117 int instring;
1118 int slash;
1119 char c;
1120 int j;
1122 env = getenv(envvar);
1123 if (!env)
1124 return;
1126 env = mem.strdup(env); // create our own writable copy
1128 argc = *pargc;
1129 argv = new Array();
1130 argv->setDim(argc);
1132 for (int i = 0; i < argc; i++)
1133 argv->data[i] = (void *)(*pargv)[i];
1135 j = 1; // leave argv[0] alone
1136 while (1)
1138 wildcard = 1;
1139 switch (*env)
1141 case ' ':
1142 case '\t':
1143 env++;
1144 break;
1146 case 0:
1147 goto Ldone;
1149 case '"':
1150 wildcard = 0;
1151 default:
1152 argv->push(env); // append
1153 //argv->insert(j, env); // insert at position j
1154 j++;
1155 argc++;
1156 p = env;
1157 slash = 0;
1158 instring = 0;
1159 c = 0;
1161 while (1)
1163 c = *env++;
1164 switch (c)
1166 case '"':
1167 p -= (slash >> 1);
1168 if (slash & 1)
1169 { p--;
1170 goto Laddc;
1172 instring ^= 1;
1173 slash = 0;
1174 continue;
1176 case ' ':
1177 case '\t':
1178 if (instring)
1179 goto Laddc;
1180 *p = 0;
1181 //if (wildcard)
1182 //wildcardexpand(); // not implemented
1183 break;
1185 case '\\':
1186 slash++;
1187 *p++ = c;
1188 continue;
1190 case 0:
1191 *p = 0;
1192 //if (wildcard)
1193 //wildcardexpand(); // not implemented
1194 goto Ldone;
1196 default:
1197 Laddc:
1198 slash = 0;
1199 *p++ = c;
1200 continue;
1202 break;
1207 Ldone:
1208 *pargc = argc;
1209 *pargv = (char **)argv->data;
1212 #if _WIN32
1214 long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep)
1216 //printf("%x\n", ep->ExceptionRecord->ExceptionCode);
1217 if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
1219 #ifndef DEBUG
1220 return EXCEPTION_EXECUTE_HANDLER;
1221 #endif
1223 return EXCEPTION_CONTINUE_SEARCH;
1226 #endif
1228 #endif