diff options
Diffstat (limited to 'src/iconc/cmain.c')
-rw-r--r-- | src/iconc/cmain.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/src/iconc/cmain.c b/src/iconc/cmain.c new file mode 100644 index 0000000..6daf5c4 --- /dev/null +++ b/src/iconc/cmain.c @@ -0,0 +1,424 @@ +/* + * cmain.c - main program icon compiler. + */ +#include "../h/gsupport.h" +#include "ctrans.h" +#include "ctree.h" +#include "ccode.h" +#include "csym.h" +#include "cproto.h" + +/* + * Prototypes. + */ +static void execute (char *ofile, char **args); +static FILE *open_out (char *fname); +static void rmfile (char *fname); +static void report (char *s); +static void usage (void); + +char *refpath; + +char patchpath[MaxPath+18] = "%PatchStringHere->"; + +/* + * Define global variables. + */ + +#define Global +#define Init(v) = v +#include "cglobals.h" + +/* + * getopt() variables + */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern char *optarg; /* argument associated with option */ + +/* + * main program + */ +int main(argc,argv) +int argc; +char **argv; + { + int no_c_comp = 0; /* suppress C compile and link? */ + int errors = 0; /* compilation errors */ + char *cfile = NULL; /* name of C file - primary */ + char *hfile = NULL; /* name of C file - include */ + char *ofile = NULL; /* name of executable result */ + + char *db_name = "rt.db"; /* data base name */ + char *incl_file = "rt.h"; /* header file name */ + + char *db_path; /* path to data base */ + char *db_lst; /* list of private data bases */ + char *incl_path; /* path to header file */ + char *s, c1; + char buf[MaxPath]; /* file name construction buffer */ + int c; + int ret_code; + struct fileparts *fp; + + if ((int)strlen(patchpath) > 18) + refpath = patchpath+18; + else + refpath = relfile(argv[0], "/../"); + + /* + * Process options. + */ + while ((c = getopt(argc,argv,"+C:ELS:Tcf:mn:o:p:r:stuv:x")) != EOF) + switch (c) { + case 'C': /* -C C-comp: C compiler*/ + c_comp = optarg; + break; + case 'E': /* -E: preprocess only */ + pponly = 1; + no_c_comp = 1; + break; + case 'L': /* Ignore: interpreter only */ + break; + case 'S': /* Ignore: interpreter only */ + break; + case 'T': + just_type_trace = 1; + break; + case 'c': /* -c: produce C file only */ + no_c_comp = 1; + break; + case 'f': /* -f: enable features */ + for (s = optarg; *s != '\0'; ++s) { + switch (*s) { + case 'a': /* -fa: enable all features */ + line_info = 1; + debug_info = 1; + err_conv = 1; + largeints = 1; + str_inv = 1; + break; + case 'd': /* -fd: enable debugging features */ + line_info = 1; + debug_info = 1; + break; + case 'e': /* -fe: enable error conversion */ + err_conv = 1; + break; + case 'l': /* -fl: support large integers */ + largeints = 1; + break; + case 'n': /* -fn: enable line numbers */ + line_info = 1; + break; + case 's': /* -fs: enable full string invocation */ + str_inv = 1; + break; + default: + quitf("-f option must be a, d, e, l, n, or s. found: %s", + optarg); + } + } + break; + case 'm': /* -m: preprocess using m4(1) */ + m4pre = 1; + break; + case 'n': /* -n: disable optimizations */ + for (s = optarg; *s != '\0'; ++s) { + switch (*s) { + case 'a': /* -na: disable all optimizations */ + opt_cntrl = 0; + allow_inline = 0; + opt_sgnl = 0; + do_typinfer = 0; + break; + case 'c': /* -nc: disable control flow opts */ + opt_cntrl = 0; + break; + case 'e': /* -ne: disable expanding in-line */ + allow_inline = 0; + break; + case 's': /* -ns: disable switch optimizations */ + opt_sgnl = 0; + break; + case 't': /* -nt: disable type inference */ + do_typinfer = 0; + break; + default: + usage(); + } + } + break; + case 'o': /* -o file: name output file */ + ofile = optarg; + break; + case 'p': /* -p C-opts: options for C comp */ + if (*optarg == '\0') /* if empty string, clear options */ + c_opts = optarg; + else { /* else append to current set */ + s = (char *)alloc(strlen(c_opts) + 1 + strlen(optarg) + 1); + sprintf(s, "%s %s", c_opts, optarg); + c_opts = s; + } + break; + case 'r': /* -r path: primary runtime system */ + refpath = optarg; + break; + case 's': /* -s: suppress informative messages */ + verbose = 0; + break; + case 't': /* -t: &trace = -1 */ + line_info = 1; + debug_info = 1; + trace = 1; + break; + case 'u': /* -u: warn about undeclared ids */ + uwarn = 1; + break; + case 'v': /* -v: set level of verbosity */ + if (sscanf(optarg, "%d%c", &verbose, &c1) != 1) + quitf("bad operand to -v option: %s",optarg); + break; + default: + case 'x': /* -x illegal until after file list */ + usage(); + } + + init(); /* initialize memory for translation */ + + /* + * Load the data bases of information about run-time routines and + * determine what libraries are needed for linking (these libraries + * go before any specified on the command line). + */ + db_lst = getenv("DBLIST"); + if (db_lst != NULL) + db_lst = salloc(db_lst); + s = db_lst; + while (s != NULL) { + db_lst = s; + while (isspace(*db_lst)) + ++db_lst; + if (*db_lst == '\0') + break; + for (s = db_lst; !isspace(*s) && *s != '\0'; ++s) + ; + if (*s == '\0') + s = NULL; + else + *s++ = '\0'; + readdb(db_lst); + addlib(salloc(makename(buf,SourceDir, db_lst, LibSuffix))); + } + db_path = (char *)alloc((unsigned int)strlen(refpath) + strlen(db_name) + 1); + strcpy(db_path, refpath); + strcat(db_path, db_name); + readdb(db_path); + addlib(salloc(makename(buf,SourceDir, db_path, LibSuffix))); + + /* + * Scan the rest of the command line for file name arguments. + */ + while (optind < argc) { + if (strcmp(argv[optind],"-x") == 0) /* stop at -x */ + break; + else if (strcmp(argv[optind],"-") == 0) + src_file("-"); /* "-" means standard input */ + else if (argv[optind][0] == '-') + addlib(argv[optind]); /* assume linker option */ + else { + fp = fparse(argv[optind]); /* parse file name */ + if (*fp->ext == '\0' || smatch(fp->ext, SourceSuffix)) { + makename(buf,SourceDir,argv[optind], SourceSuffix); + src_file(buf); + } + else + /* + * Assume all files that are not Icon source go to linker. + */ + addlib(argv[optind]); + } + optind++; + } + + if (srclst == NULL) + usage(); /* error -- no files named */ + + if (pponly) { + if (trans() == 0) + exit (EXIT_FAILURE); + else + exit (EXIT_SUCCESS); + } + + if (ofile == NULL) { /* if no -o file, synthesize a name */ + if (strcmp(srclst->name,"-") == 0) + ofile = salloc(makename(buf,TargetDir,"stdin",ExecSuffix)); + else + ofile = salloc(makename(buf,TargetDir,srclst->name,ExecSuffix)); + } else { /* add extension if necessary */ + fp = fparse(ofile); + if (*fp->ext == '\0' && *ExecSuffix != '\0') + ofile = salloc(makename(buf,NULL,ofile,ExecSuffix)); + } + + /* + * Make name of intermediate C files. + */ + cfile = salloc(makename(buf,TargetDir,ofile,CSuffix)); + hfile = salloc(makename(buf,TargetDir,ofile,HSuffix)); + + codefile = open_out(cfile); + fprintf(codefile, "#include \"%s\"\n", hfile); + + inclfile = open_out(hfile); + fprintf(inclfile, "#define COMPILER 1\n"); + + incl_path = (char *)alloc((unsigned int)(strlen(refpath) + + strlen(incl_file) + 1)); + strcpy(incl_path, refpath); + strcat(incl_path, incl_file); + fprintf(inclfile,"#include \"%s\"\n", incl_path); + + /* + * Translate .icn files to make C file. + */ + if ((verbose > 0) && !just_type_trace) + report("Translating to C"); + + errors = trans(); + if ((errors > 0) || just_type_trace) { /* exit if errors seen */ + rmfile(cfile); + rmfile(hfile); + if (errors > 0) + exit(EXIT_FAILURE); + else exit(EXIT_SUCCESS); + } + + fclose(codefile); + fclose(inclfile); + + /* + * Compile and link C file. + */ + if (no_c_comp) /* exit if no C compile wanted */ + exit(EXIT_SUCCESS); + + if (verbose > 0) + report("Compiling and linking C code"); + + ret_code = ccomp(cfile, ofile); + if (ret_code == EXIT_FAILURE) { + fprintf(stderr, "*** C compile and link failed ***\n"); + rmfile(ofile); + } + + /* + * Finish by removing C files. + */ + rmfile(cfile); + rmfile(hfile); + rmfile(makename(buf,TargetDir,cfile,ObjSuffix)); + + if (ret_code == EXIT_SUCCESS && optind < argc) { + if (verbose > 0) + report("Executing"); + execute (ofile, argv+optind+1); + } + + return ret_code; + } + +/* + * execute - execute compiled Icon program + */ +static void execute(ofile,args) +char *ofile, **args; + { + + int n; + char **argv, **p; + char buf[MaxPath]; /* file name construction buffer */ + + ofile = salloc(makename(buf,"./",ofile,ExecSuffix)); + + for (n = 0; args[n] != NULL; n++) /* count arguments */ + ; + p = argv = (char **)alloc((unsigned int)((n + 2) * sizeof(char *))); + + *p++ = ofile; /* set executable file */ + + while (*p++ = *args++) /* copy args into argument vector */ + ; + *p = NULL; + + execvp(ofile,argv); + quitf("could not run %s",ofile); + } + +/* + * Report phase. + */ +static void report(s) +char *s; + { + fprintf(stderr,"%s:\n",s); + } + +/* + * rmfile - remove a file + */ + +static void rmfile(fname) +char *fname; + { + remove(fname); + } + +/* + * open_out - open a C output file and write identifying information + * to the front. + */ +static FILE *open_out(fname) +char *fname; + { + FILE *f; + static char *ident = "/*ICONC*/"; + int c; + int i; + + /* + * If the file already exists, make sure it is old output from iconc + * before overwriting it. Note, this test doesn't work if the file + * is writable but not readable. + */ + f = fopen(fname, "r"); + if (f != NULL) { + for (i = 0; i < (int)strlen(ident); ++i) { + c = getc(f); + if (c == EOF) + break; + if ((char)c != ident[i]) + quitf("%s not in iconc format; rename or delete, and rerun", fname); + } + fclose(f); + } + + f = fopen(fname, "w"); + if (f == NULL) + quitf("cannot create %s", fname); + fprintf(f, "%s\n", ident); /* write "belongs to iconc" comment */ + id_comment(f); /* write detailed comment for human readers */ + fflush(f); + return f; + } + +/* + * Print an error message if called incorrectly. The message depends + * on the legal options for this system. + */ +static void usage() + { + fprintf(stderr,"usage: %s %s file ... [-x args]\n", progname, CUsage); + exit(EXIT_FAILURE); + } |