summaryrefslogtreecommitdiff
path: root/src/rtt/rttmain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtt/rttmain.c')
-rw-r--r--src/rtt/rttmain.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/src/rtt/rttmain.c b/src/rtt/rttmain.c
new file mode 100644
index 0000000..2099c2f
--- /dev/null
+++ b/src/rtt/rttmain.c
@@ -0,0 +1,402 @@
+#include "rtt.h"
+
+/*
+ * prototypes for static functions.
+ */
+static void add_tdef (char *name);
+
+/*
+ * refpath is used to locate the standard include files for the Icon
+ * run-time system. If patchpath has been patched in the binary of rtt,
+ * the string that was patched in is used for refpath.
+ */
+char *refpath;
+char patchpath[MaxPath+18] = "%PatchStringHere->";
+
+static char *ostr = "+ECPD:I:U:d:cir:st:x";
+
+static char *options =
+ "[-E] [-C] [-P] [-Dname[=[text]]] [-Uname] [-Ipath] [-dfile]\n \
+[-rpath] [-tname] [-x] [files]";
+
+/*
+ * The relative path to grttin.h and rt.h depends on whether they are
+ * interpreted as relative to where rtt.exe is or where rtt.exe is
+ * invoked.
+ */
+ char *grttin_path = "../src/h/grttin.h";
+ char *rt_path = "../src/h/rt.h";
+
+/*
+ * Note: rtt presently does not process system include files. If this
+ * is needed, it may be necessary to add other options that set
+ * manifest constants in such include files. See pmain.c for the
+ * stand-alone preprocessor for examples of what's needed.
+ */
+
+char *progname = "rtt";
+char *compiler_def;
+FILE *out_file;
+char *inclname;
+int def_fnd;
+char *largeints = NULL;
+
+int iconx_flg = 0;
+int enable_out = 0;
+
+static char *curlst_nm = "rttcur.lst";
+static FILE *curlst;
+static char *cur_src;
+
+extern int line_cntrl;
+
+/*
+ * tdefnm is used to construct a list of identifiers that
+ * must be treated by rtt as typedef names.
+ */
+struct tdefnm {
+ char *name;
+ struct tdefnm *next;
+ };
+
+static char *dbname = "rt.db";
+static int pp_only = 0;
+static char *opt_lst;
+static char **opt_args;
+static char *in_header;
+static struct tdefnm *tdefnm_lst = NULL;
+
+/*
+ * getopt() variables
+ */
+extern int optind; /* index into parent argv vector */
+extern int optopt; /* character checked for validity */
+extern char *optarg; /* argument associated with option */
+
+int main(argc, argv)
+int argc;
+char **argv;
+ {
+ int c;
+ int nopts;
+ char buf[MaxPath]; /* file name construction buffer */
+ struct fileparts *fp;
+
+ /*
+ * See if the location of include files has been patched into the
+ * rtt executable.
+ */
+ if ((int)strlen(patchpath) > 18)
+ refpath = patchpath+18;
+ else
+ refpath = relfile(argv[0], "/../");
+
+ /*
+ * Initialize the string table and indicate that File must be treated
+ * as a typedef name.
+ */
+ init_str();
+ add_tdef("FILE");
+
+ /*
+ * By default, the spelling of white space in unimportant (it can
+ * only be significant with the -E option) and #line directives
+ * are required in the output.
+ */
+ whsp_image = NoSpelling;
+ line_cntrl = 1;
+
+ /*
+ * opt_lst and opt_args are the options and corresponding arguments
+ * that are passed along to the preprocessor initialization routine.
+ * Their number is at most the number of arguments to rtt.
+ */
+ opt_lst = alloc(argc);
+ opt_args = alloc(argc * sizeof (char *));
+ nopts = 0;
+
+ /*
+ * Process options.
+ */
+ while ((c = getopt(argc, argv, ostr)) != EOF)
+ switch (c) {
+ case 'E': /* run preprocessor only */
+ pp_only = 1;
+ if (whsp_image == NoSpelling)
+ whsp_image = NoComment;
+ break;
+ case 'C': /* retain spelling of white space, only effective with -E */
+ whsp_image = FullImage;
+ break;
+ case 'P': /* do not produce #line directives in output */
+ line_cntrl = 0;
+ break;
+ case 'd': /* -d name: name of data base */
+ dbname = optarg;
+ break;
+ case 'r': /* -r path: location of include files */
+ refpath = optarg;
+ break;
+ case 't': /* -t ident : treat ident as a typedef name */
+ add_tdef(optarg);
+ break;
+ case 'x': /* produce code for interpreter rather than compiler */
+ iconx_flg = 1;
+ break;
+
+ case 'D': /* define preprocessor symbol */
+ case 'I': /* path to search for preprocessor includes */
+ case 'U': /* undefine preprocessor symbol */
+ /*
+ * Save these options for the preprocessor initialization routine.
+ */
+ opt_lst[nopts] = c;
+ opt_args[nopts] = optarg;
+ ++nopts;
+ break;
+ default:
+ show_usage();
+ }
+
+ #ifdef Rttx
+ if (!iconx_flg) {
+ fprintf(stdout,
+ "rtt was compiled to only support the intepreter, use -x\n");
+ exit(EXIT_FAILURE);
+ }
+ #endif /* Rttx */
+
+ if (iconx_flg)
+ compiler_def = "#define COMPILER 0\n";
+ else
+ compiler_def = "#define COMPILER 1\n";
+ in_header = alloc(strlen(refpath) + strlen(grttin_path) + 1);
+ strcpy(in_header, refpath);
+ strcat(in_header, grttin_path);
+ inclname = alloc(strlen(refpath) + strlen(rt_path) + 1);
+ strcpy(inclname, refpath);
+ strcat(inclname, rt_path);
+
+ opt_lst[nopts] = '\0';
+
+ /*
+ * At least one file name must be given on the command line.
+ */
+ if (optind == argc)
+ show_usage();
+
+ /*
+ * When creating the compiler run-time system, rtt outputs a list
+ * of names of C files created, because most of the file names are
+ * not derived from the names of the input files.
+ */
+ if (!iconx_flg) {
+ curlst = fopen(curlst_nm, "w");
+ if (curlst == NULL)
+ err2("cannot open ", curlst_nm);
+ }
+
+ /*
+ * Unless the input is only being preprocessed, set up the in-memory data
+ * base (possibly loading it from a file).
+ */
+ if (!pp_only) {
+ fp = fparse(dbname);
+ if (*fp->ext == '\0')
+ dbname = salloc(makename(buf, SourceDir, dbname, DBSuffix));
+ else if (!smatch(fp->ext, DBSuffix))
+ err2("bad data base name:", dbname);
+ loaddb(dbname);
+ }
+
+ /*
+ * Scan file name arguments, and translate the files.
+ */
+ while (optind < argc) {
+ trans(argv[optind]);
+ optind++;
+ }
+
+ #ifndef Rttx
+ /*
+ * Unless the user just requested the preprocessor be run, we
+ * have created C files and updated the in-memory data base.
+ * If this is the compiler's run-time system, we must dump
+ * to data base to a file and create a list of all output files
+ * produced in all runs of rtt that created the data base.
+ */
+ if (!(pp_only || iconx_flg)) {
+ if (fclose(curlst) != 0)
+ err2("cannot close ", curlst_nm);
+ dumpdb(dbname);
+ full_lst("rttfull.lst");
+ }
+ #endif /* Rttx */
+
+ return EXIT_SUCCESS;
+ }
+
+/*
+ * trans - translate a source file.
+ */
+void trans(src_file)
+char *src_file;
+ {
+ char *cname;
+ char buf[MaxPath]; /* file name construction buffer */
+ char *buf_ptr;
+ char *s;
+ struct fileparts *fp;
+ struct tdefnm *td;
+ struct token *t;
+ static char *test_largeints = "#ifdef LargeInts\nyes\n#endif\n";
+ static int first_time = 1;
+
+ cur_src = src_file;
+
+ /*
+ * Read standard header file for preprocessor directives and
+ * typedefs, but don't write anything to output.
+ */
+ enable_out = 0;
+ init_preproc(in_header, opt_lst, opt_args);
+ str_src("<rtt initialization>", compiler_def, (int)strlen(compiler_def));
+ init_sym();
+ for (td = tdefnm_lst; td != NULL; td = td->next)
+ sym_add(TypeDefName, td->name, OtherDcl, 1);
+ init_lex();
+ yyparse();
+ if (first_time) {
+ first_time = 0;
+ /*
+ * Now that the standard include files have been processed, see if
+ * Largeints is defined and make sure it matches what's in the data base.
+ */
+ s = "NoLargeInts";
+ str_src("<rtt initialization>", test_largeints,
+ (int)strlen(test_largeints));
+ while ((t = preproc()) != NULL)
+ if (strcmp(t->image, "yes"))
+ s = "LargeInts";
+ if (largeints == NULL)
+ largeints = s;
+ else if (strcmp(largeints, s) != 0)
+ err2("header file definition of LargeInts/NoLargeInts does not match ",
+ dbname);
+ }
+ enable_out = 1;
+
+ /*
+ * Make sure we have a .r file or standard input.
+ */
+ if (strcmp(cur_src, "-") == 0) {
+ source("-"); /* tell preprocessor to read standard input */
+ cname = salloc(makename(buf, TargetDir, "stdin", CSuffix));
+ }
+ else {
+ fp = fparse(cur_src);
+ if (*fp->ext == '\0')
+ cur_src = salloc(makename(buf, SourceDir, cur_src, RttSuffix));
+ else if (!smatch(fp->ext, RttSuffix))
+ err2("unknown file suffix ", cur_src);
+ cur_src = spec_str(cur_src);
+
+ /*
+ * For the compiler, remove from the data base the list of
+ * files produced from this input file.
+ */
+ if (!iconx_flg)
+ clr_dpnd(cur_src);
+ source(cur_src); /* tell preprocessor to read source file */
+
+ /*
+ * For the interpreter prepend "x" to the file name for the .c file.
+ */
+ buf_ptr = buf;
+ if (iconx_flg)
+ *buf_ptr++ = 'x';
+ makename(buf_ptr, TargetDir, cur_src, CSuffix);
+ cname = salloc(buf);
+ }
+
+ if (pp_only)
+ output(stdout); /* invoke standard preprocessor output routine */
+ else {
+ /*
+ * For the compiler, non-RTL code is put in a file whose name
+ * is derived from input file name. The flag def_fnd indicates
+ * if anything interesting is put in the file.
+ */
+ def_fnd = 0;
+ if ((out_file = fopen(cname, "w")) == NULL)
+ err2("cannot open output file ", cname);
+ else
+ addrmlst(cname, out_file);
+ prologue(); /* output standard comments and preprocessor directives */
+ yyparse(); /* translate the input */
+ fprintf(out_file, "\n");
+ if (fclose(out_file) != 0)
+ err2("cannot close ", cname);
+
+ /*
+ * For the Compiler, note the name of the "primary" output file
+ * in the data base and list of created files.
+ */
+ if (!iconx_flg)
+ put_c_fl(cname, def_fnd);
+ }
+ }
+
+/*
+ * add_tdef - add identifier to list of typedef names.
+ */
+static void add_tdef(name)
+char *name;
+ {
+ struct tdefnm *td;
+
+ td = NewStruct(tdefnm);
+ td->name = spec_str(name);
+ td->next = tdefnm_lst;
+ tdefnm_lst = td;
+ }
+
+/*
+ * Add name of file to the output list, and if it contains "interesting"
+ * code, add it to the dependency list in the data base.
+ */
+void put_c_fl(fname, keep)
+char *fname;
+int keep;
+ {
+ struct fileparts *fp;
+
+ fp = fparse(fname);
+ fprintf(curlst, "%s\n", fp->name);
+ if (keep)
+ add_dpnd(src_lkup(cur_src), fname);
+ }
+
+/*
+ * Print an error message if called incorrectly.
+ */
+void show_usage()
+ {
+ fprintf(stderr, "usage: %s %s\n", progname, options);
+ exit(EXIT_FAILURE);
+ }
+
+/*
+ * yyerror - error routine called by yacc.
+ */
+void yyerror(s)
+char *s;
+ {
+ struct token *t;
+
+ t = yylval.t;
+ if (t == NULL)
+ err2(s, " at end of file");
+ else
+ errt1(t, s);
+ }