home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
language
/
sozobon2
/
cc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-23
|
15KB
|
749 lines
/* Copyright (c) 1988 by Sozobon, Limited. Author: Tony Andrews
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*/
static char Version[] =
"cc: version 1.01 Copyright (c) 1988 by Sozobon, Limited.";
/*
* cc - C compiler driver program
*
* Parses command line for options and file names. Then calls the
* various passes of the compiler as needed.
*/
#include <stdio.h>
#include <fcntl.h>
#include <osbind.h>
/*
* This is the amount of space to grab from TOS at a time for
* malloc(). The default is 64K which wastes space if you don't
* need much. Since we spawn sub-programs from cc, it's important
* to leave as much memory for them as possible.
*/
long _BLKSIZ = 4096;
#ifndef TRUE
#define FALSE (0)
#define TRUE !FALSE
#endif
#define MAXOPT 16 /* max. number of options to any one pass */
/*
* Standard filename extensions
*/
#define EXSUF ".ttp,.tos,.prg" /* suffixes for executables */
#define LIBSUF ".a,.lib" /* libraries */
/*
* Compiler pass information
*/
#define CC "hcc"
char *hccopt[MAXOPT];
int hcc_cnt = 0; /* number of options to hcc */
/*
* Optimizer information
*/
#define OPT "top"
#define OTMP "top_tmp.s"
/*
* Assembler information
*/
#define ASM "jas" /* default assembler */
#define ASMD "as68symb.dat" /* assembler data file (as68 only) */
/*
* Loader information
*/
#define LD "ld"
#define LTMP "ldfile.tmp" /* loader command file */
#define CSU "dstart.o" /* C startup code */
#define PCSU "pdstart.o" /* profiling startup code */
#define LIBC "dlibs" /* C runtime library */
#define PLIBC "pdlibs" /* profiled runtime library */
#define LIBM "libm" /* math library */
#define PLIBM "plibm" /* profiled math library */
/*
* Path information
*/
char *path; /* where to find executables */
char *lib; /* where to find library stuff */
char *tmp; /* where to put temporary files */
/*
* Default paths for executables and libraries
*
* Always check the root of the current drive first.
*/
#define DEFPATH "\\bin,\\sozobon\\bin"
#define DEFLIB "\\lib,\\sozobon\\lib"
#define DEFTMP ""
/*
* Boolean options
*/
int mflag = 0; /* generate a load map */
int vflag = 0; /* show what we're doing w/ version numbers */
int nflag = 0; /* ...but don't really do it */
int Sflag = 0; /* generate assembly files */
int cflag = 0; /* generate ".s" files only */
int Oflag = 0; /* run the optimizer */
int tflag = 0; /* generate a symbol table in executables */
int pflag = 0; /* enable execution profiling */
int fflag = 0; /* enable floating point */
/*
* We build lists of the various file types we're given. Within each
* type, MAXF says how many we can deal with.
*/
#define MAXF 30
int ncfiles = 0; /* .c files */
char *cfiles[MAXF];
int nsfiles = 0; /* .s files */
char *sfiles[MAXF];
int nofiles = 0; /* .o files */
char *ofiles[MAXF];
int nlfiles = 0; /* .a or .lib files (or files with no suffix) */
char *lfiles[MAXF];
char *output = NULL; /* output file */
char cmdln[512];
usage()
{
fprintf(stderr,
"Sozobon C Compiler Options:\n");
fprintf(stderr,
"-c compile, but don't link\n");
fprintf(stderr,
"-O run the assembly code optimizer\n");
fprintf(stderr,
"-S don't assemble, leave .s files around\n");
fprintf(stderr,
"-v (or -V) show the passes and versions as they run\n");
fprintf(stderr,
"-n like -v, but don't really run anything\n");
fprintf(stderr,
"-m tell the loader to generate a load map\n");
fprintf(stderr,
"-t tell the loader to generate a symbol table\n");
fprintf(stderr,
"-f link the floating point library\n");
fprintf(stderr,
"-p enable execution profiling\n");
fprintf(stderr,
"-o f use the file 'f' for the loader output\n");
fprintf(stderr,
"-Ilib add dir. 'lib' to the header search list\n");
fprintf(stderr,
"-Dsym define the pre-processor symbol 'sym' as 1\n");
fprintf(stderr,
"-Dsym=val or as 'val'\n");
fprintf(stderr,
"-Usym un-define the built-in symbol 'sym'\n");
exit(1);
}
main(argc, argv)
int argc;
char *argv[];
{
extern char *chsuf();
register int i;
register char *s;
register int endopt;
int domsg = FALSE;
if (argc == 1)
usage();
for (i=1; i < argc ;i++) {
if (argv[i][0] == '-') { /* option */
endopt = FALSE;
for (s = &argv[i][1]; *s && !endopt ;s++) {
switch (*s) {
case 'c':
cflag = TRUE; break;
case 'O':
Oflag = TRUE; break;
case 'S':
Sflag = TRUE; break;
case 'v':
case 'V':
vflag = TRUE; break;
case 'n':
nflag = TRUE; break;
case 'm':
mflag = TRUE; break;
case 't':
tflag = TRUE; break;
case 'f':
fflag = TRUE; break;
case 'p':
pflag = TRUE; break;
case 'o':
output = argv[++i];
endopt = TRUE;
break;
/*
* Options for other passes.
*/
case 'I': /* compiler options */
case 'D':
case 'U':
hccopt[hcc_cnt++] = argv[i];
endopt = TRUE;
break;
default:
usage();
}
}
} else { /* input file */
if (output == NULL)
output = chsuf(argv[i], ".ttp");
keepfile(argv[i]);
}
}
if ((ncfiles + nsfiles) > 1)
domsg = TRUE;
doinit();
if (vflag)
printf("%s\n", Version);
for (i = 0; i < ncfiles ;i++) {
if (domsg)
printf("%s:\n", cfiles[i]);
docomp(cfiles[i]);
doopt(cfiles[i]);
doasm(cfiles[i], TRUE);
}
for (i = 0; i < nsfiles ;i++) {
if (domsg)
printf("%s:\n", sfiles[i]);
doasm(sfiles[i], FALSE);
}
dold(); /* run the loader */
exit(0);
}
/*
* doinit() - set up some variables before getting started
*/
doinit()
{
char *getenv();
if ((path = getenv("PATH")) == NULL)
path = DEFPATH;
if ((lib = getenv("LIB")) == NULL)
lib = DEFLIB;
if ((tmp = getenv("TMP")) == NULL)
tmp = DEFTMP;
}
/*
* keepfile(f) - remember the filename 'f' in the appropriate place
*/
keepfile(f)
char *f;
{
char *p, *strchr();
if ((p = strchr(f, '.')) == NULL) { /* no suffix */
lfiles[nlfiles++] = f;
return;
}
if (strcmp(p, ".c") == 0) {
cfiles[ncfiles++] = f;
return;
}
if (strcmp(p, ".s") == 0) {
sfiles[nsfiles++] = f;
return;
}
if (strcmp(p, ".o") == 0) {
ofiles[nofiles++] = f;
return;
}
if (strcmp(p, ".a") == 0) {
lfiles[nlfiles++] = f;
return;
}
if (strcmp(p, ".lib") == 0) {
lfiles[nlfiles++] = f;
return;
}
fprintf(stderr, "cc: unknown file suffix '%s'\n", f);
exit(1);
}
/*
* chsuf(f, suf) - change the suffix of file 'f' to 'suf'.
*
* Space for the new string is obtained using malloc().
*/
char *
chsuf(f, suf)
char *f;
char *suf;
{
char *malloc();
char *s, *p;
p = s = malloc(strlen(f) + strlen(suf) + 1);
strcpy(p, f);
for (; *p ; p++) {
if (*p == '.')
break;
}
while (*suf)
*p++ = *suf++;
*suf = '\0';
return s;
}
/*
* isfile(f) - return true if the given file exists
*/
int
isfile(f)
char *f;
{
int fd;
if ((fd = open(f, O_RDONLY)) < 0)
return FALSE;
close(fd);
return TRUE;
}
/*
* findfile(e, b, s, chknul)
*
* Finds a file in one of the directories given in the environment
* variable whose value is pointed to by 'e'. Looks for the file
* given by 'b' with one of the suffixes listed in 's'. The suffix
* string should contain suffixes delimited by commas.
*
* e.g. findfile("env stuff", "hcc", ".tos,.ttp,.prg")
*
* Returns a pointer to a static area containing the pathname of the
* file, if found, NULL otherwise.
*
* If 'chknul' is set, try the base name without any suffix as well.
*/
char *
findfile(e, b, s, chknul)
char *e;
char *b;
char *s;
int chknul;
{
static char file[256];
char env[256];
char suf[128];
char *eptr, *sptr;
char *p;
/*
* Make a copy of the value of the env. variable. Convert all
* delimiters to nulls.
*/
if (e != NULL) {
strcpy(env, e);
for (p = env; *p ;p++) {
if (*p == ';' || *p == ',')
*p = '\0';
}
p[1] = '\0'; /* double null terminator */
} else
env[1] = env[0] = '\0';
strcpy(suf, s);
for (p = suf; *p ;p++) {
if (*p == ',')
*p = '\0';
}
p[1] = '\0'; /* double null terminator */
/*
* Always check the root of the current drive and the
* current directory first. If that doesn't work, then
* start looking in the usual places...
*/
for (sptr = suf; *sptr ;) {
sprintf(file, "%s%s", b, sptr);
if (isfile(file))
return file;
sprintf(file, "\\%s%s", b, sptr);
if (isfile(file))
return file;
while (*sptr++ != '\0')
;
}
for (eptr = env; *eptr ;) {
if (chknul) {
sprintf(file, "%s\\%s", eptr, b);
if (isfile(file))
return file;
}
for (sptr = suf; *sptr ;) {
sprintf(file, "%s\\%s%s", eptr, b, sptr);
if (isfile(file))
return file;
while (*sptr++ != '\0')
;
}
while (*eptr++ != '\0')
;
}
return NULL; /* give up */
}
/*
* docmd(path, cmdline) - run a command
*/
int
docmd(path, cmdline)
char *path;
char *cmdline;
{
int i;
char cmd[150];
strcpy(&cmd[1], cmdline);
cmd[0] = strlen(cmdline);
i = Pexec(0, path, cmd, 0L);
return i;
}
/*
* docomp(f) - run the compiler on the given .c file
*/
docomp(f)
char *f;
{
int i;
char *cpath, *sf;
if ((cpath = findfile(path, CC, EXSUF, FALSE)) == NULL) {
fprintf(stderr, "cc: can't find compiler program '%s'\n", CC);
exit(1);
}
strcpy(cmdln, pflag ? "-P " : "");
for (i=0; i < hcc_cnt ;i++) {
strcat(cmdln, hccopt[i]);
strcat(cmdln, " ");
}
strcat(cmdln, f);
if (nflag || vflag)
fprintf(stderr, "%s %s\n", cpath, cmdln);
if (!nflag) {
if (docmd(cpath, cmdln)) {
sf = chsuf(f, ".s");
unlink(sf);
free(sf);
fprintf(stderr, "cc: compiler failed\n");
exit(1);
}
}
}
/*
* doopt(f) - run the optimizer
*
* Only optimize files that were produced by the compiler.
*/
doopt(f)
char *f;
{
int i;
char *opath;
char *sf;
if (!Oflag)
return;
if ((opath = findfile(path, OPT, EXSUF, FALSE)) == NULL) {
fprintf(stderr, "cc: can't find optimizer program '%s'\n", OPT);
exit(1);
}
sf = chsuf(f, ".s");
if (nflag || vflag)
fprintf(stderr, "%s %s %s\n",
opath, sf, OTMP);
if (!nflag) {
sprintf(cmdln, "%s %s", sf, OTMP);
if (docmd(opath, cmdln)) {
unlink(OTMP);
fprintf(stderr, "cc: optimizer failed (continuing)\n");
unlink(OTMP);
} else {
unlink(sf);
rename(OTMP, sf);
}
}
free(sf);
}
/*
* doasm() - run the assembler
*
* If 'istmp' is TRUE, the file we were given is a temporary
*/
doasm(f, istmp)
char *f;
int istmp;
{
char *strrchr(), *getenv();
int i;
char apath[128], *dpath;
char *s;
char *aname; /* assembler to use */
char *sf;
if (Sflag)
return;
if ((aname = getenv("ASM")) == NULL)
aname = ASM;
if ((dpath = findfile(path, aname, EXSUF, FALSE)) == NULL) {
fprintf(stderr, "cc: can't find assembler program '%s'\n", aname);
exit(1);
}
strcpy(apath, dpath);
if (strcmp(aname, "as68") == 0) {
if ((dpath = findfile(lib, ASMD, "", TRUE)) == NULL) {
fprintf(stderr, "cc: can't find assembler data file\n");
exit(1);
}
if ((s = strrchr(dpath, '\\')) == NULL) {
fprintf(stderr, "cc: can't find assembler data file\n");
exit(1);
}
s[1] = '\0';
} else
dpath = NULL;
sf = chsuf(f, ".s");
if (nflag || vflag)
fprintf(stderr, "%s -l -u%s%s %s\n",
apath,
(dpath != NULL) ? " -s " : "",
(dpath != NULL) ? dpath : "",
sf);
if (!nflag) {
sprintf(cmdln, "%s%s %s",
(dpath != NULL) ? "-l -u -s " : "",
(dpath != NULL) ? dpath : "",
sf);
if (docmd(apath, cmdln)) {
fprintf(stderr, "cc: assembler failed '%s'\n",
sf);
if (istmp)
unlink(sf);
free(sf);
exit(1);
}
}
if (nflag) {
free(sf);
return;
}
if (istmp)
unlink(sf);
free(sf);
}
/*
* dold() - run the loader
*/
dold()
{
FILE *fp, *fopen();
int i;
char tfile[128];
char *lpath;
char *s;
char *l;
if (cflag || Sflag)
return;
/*
* Construct the name of the loader data file.
*/
if (*tmp != '\0') {
strcpy(tfile, tmp);
if (tfile[strlen(tfile)-1] != '\\')
strcat(tfile, "\\");
} else
tfile[0] = '\0';
strcat(tfile, LTMP);
unlink(tfile);
/*
* Construct loader command file
*/
if ((fp = fopen(tfile, "w")) == NULL) {
fprintf(stderr, "cc: can't open loader temp file\n");
exit(1);
}
l = pflag ? PCSU : CSU;
if ((lpath = findfile(lib, l, "", TRUE)) == NULL) {
fprintf(stderr, "cc: can't find C startup code '%s'\n", l);
exit(1);
}
fprintf(fp, "%s\n", lpath);
for (i = 0; i < ncfiles ;i++) {
s = chsuf(cfiles[i], ".o");
fprintf(fp, "%s\n", s);
free(s);
}
for (i = 0; i < nsfiles ;i++) {
s = chsuf(sfiles[i], ".o");
fprintf(fp, "%s\n", s);
free(s);
}
for (i = 0; i < nofiles ;i++)
fprintf(fp, "%s\n", ofiles[i]);
for (i = 0; i < nlfiles ;i++) {
if (isfile(lfiles[i])) {
fprintf(fp, "%s\n", lfiles[i]);
} else {
lpath = findfile(lib, lfiles[i], LIBSUF, TRUE);
if (lpath == NULL) {
fprintf(stderr, "cc: can't find library '%s'\n", lfiles[i]);
exit(1);
}
fprintf(fp, "%s\n", lpath);
}
}
if (fflag) {
l = pflag ? PLIBM : LIBM;
if ((lpath = findfile(lib, l, LIBSUF, TRUE)) == NULL) {
fprintf(stderr, "cc: can't find floating point library '%s'\n",l);
exit(1);
}
fprintf(fp, "%s\n", lpath);
}
l = pflag ? PLIBC : LIBC;
if ((lpath = findfile(lib, l, LIBSUF, TRUE)) == NULL) {
fprintf(stderr, "cc: can't find C runtime library '%s'\n", l);
exit(1);
}
fprintf(fp, "%s\n", lpath);
fclose(fp);
if ((lpath = findfile(path, LD, EXSUF, FALSE)) == NULL) {
fprintf(stderr, "cc: can't find loader program '%s'\n", LD);
exit(1);
}
sprintf(cmdln, "%s%s-p -u _main %s -o %s -f %s",
mflag ? "-m " : "",
tflag ? "-t " : "",
fflag ? "-u __printf -u __scanf " : "",
output,
tfile);
if (nflag || vflag)
fprintf(stderr, "%s %s\n", lpath, cmdln);
if (!nflag) {
if (docmd(lpath, cmdln)) {
fprintf(stderr, "cc: loader failed\n");
unlink(tfile);
unlink(output);
exit(1);
}
}
if (nflag)
return;
for (i = 0; i < ncfiles ;i++) {
s = chsuf(cfiles[i], ".o");
unlink(s);
free(s);
}
for (i = 0; i < nsfiles ;i++) {
s = chsuf(sfiles[i], ".o");
unlink(s);
free(s);
}
unlink(tfile);
}