📄 cc.c
字号:
/* CC.C - KCC Main program
**
** (c) Copyright Ken Harrenstien 1989
** All changes after v.187, 26-May-1988
** (c) Copyright Ken Harrenstien, SRI International 1985, 1986
** All changes after v.74, 8-Aug-1985
**
** Original version (c) 1981 K. Chen
*/
#include "ccsite.h"
#include "cc.h"
#include "ccchar.h"
#include <string.h>
#include <stdlib.h> /* calloc(), EXIT_SUCCESS, EXIT_FAILURE */
#include <time.h> /* For clock() to get runtime */
#include <sys/types.h>
#include <sys/stat.h>
#if !__MSDOS__ // FW KCC-NT
#include <muuo.h> /* KAR-8/92, needed for set_level(); PPS 4516 */
#endif
/*
* KAR-8/92, value sent to STLEV$ to return current running level and to
* return a failure.
*/
#define RET_CUR_LEV -2
#define STLEV_FAILURE -2
typedef struct flagent /* Structure of an entry in flag table */
{
char *name; /* Flag name */
int *fladdr; /* Address of runtime flag value */
INT flval; /* Value to set it to if user gives flag */
}
flagent_t;
/* KAR-3/92, took out sys/kccver.h because implemented new way to spec ver */
#include "kcchst.h" /* For revision history */
#if __MSDOS__
#ifndef WIN32 // FW KCC-NT
/* _stklen < 25K breaks CCDECL,CCGEN, and CCOPT (Borland: Stack overflow!)
* _stklen > 35K breaks CCDATA,CCOUT, and KCCDBG (KCC: more nodes(x used))
*/
extern unsigned _stklen = 30000;
#define CLOCKS_PER_SEC 18.2
#endif
#endif
/* Exported functions */
/* none */
/* Imported functions */
extern void dbginit(void); /* CCDBUG */
extern void outpghdr(void); /* CCOUT */
extern void outstr (char *); /* CCOUT */
extern void savesymtab(SYMBOL *); /* CCSYM */
extern SYMBOL *symfidstr(char *); /* CCSYM */
extern int asmb(char *, char *, char *); /* CCASMB */
extern void runlink(int, int, char **, char *, char *); /* CCASMB */
#ifdef __COMPILER_KCC__
extern char *execargs(int *, char ***); /* CCASMB */
#endif
extern char *fnparse(char *, char *, char *, char *, char *); /* CCASMB */
extern char *estrcpy(char *, char *); /* CCASMB */
extern NODE *extdef(void), *tntdef(void); /* CCDECL */
extern void syminit(void), ppinit(void), lexinit(void), initpar(void),
outinit(void), outdone(int),
ppdefine(int, char **, int, char **), passthru(FILE *),
gencode(NODE *);
extern void errfopen (char *, char *); /* CCERR */
extern int fclose (FILE *);
extern char *fnparse(char *, char *, char *, char *, char *);
extern int fnxisrel(char *);
#if DEBUG_KCC /* 5/91 KCC size */
extern void symdump(SYMBOL *, char *), typedump(void), nodedump(NODE *);
#endif
/* Internal functions */
static void cindfiles(int *, char ***);
static void showcpu(clock_t);
static void coptimize(char *), cdebug(char *), csidebug(char *),
ctargmach(char *), cportlev(char *), cwarnlev(char *),
cverbose(char *);
static int cswitch(char *, int *, char ***), cfile(char *),
files(char *), mainsymp(void), needcomp(char *, char *);
static int chkmacname(char *);
static void parcswi(char *, flagent_t *, int);
static char *cmpname(char *, char *);
static int set_level (int level); /* KAR-8/92, support leveled headers PPS 4516 */
extern char *mlbuf, *mlbptr; /* mixed listing */
char *savofnam = NULL; /* KAR-3/92, save -R= name */
static void getimestr(char *src_fname);
static
char mainname[FNAMESIZE]
/* = {0} */
; /* Name of module containing "main" */
static char *savname = NULL; /* Pointer to desired -o filename */
static int vrbarg = 0; /* Patch 1 to show args on outmsgs */
static int sourcebytewidth = 7; /* FW 2A(47) */
/*
* Help Screen (displayed when KCC is invoked without parameters)
* - Michael Snyder, CSI, 6/3/90
*/
static const _char7 *helpscreen = "\
CompuServe Inc. Columbus, Ohio, 1991\n\n\
Syntax is: cc [switches] file[s] * indicates default.\n\
-b[789] source-file byte width\n\
-c compile, assemble, no link -C retain space in preprocess\n\
-Dident #define ident -Dident=str #define ident str\n\
-d=list mixed listing .mac -E pre-process only, stdout\n\
-g link with DDT -g=debug source-level debugger\n\
-g=fnprof function profiler -g=sprof statement profiler\n\
-Hppn ppn for #include <...> -hppn ppn for #include <sys/...>\n\
-Ippn ppn for #include \"...\" -lname use library LIBname.REL\n\
-Lppn ppn for libraries -L=option relay option to LINK\n\
-n do no optimizations -Nxxx set stack to xxx words\n\
-o=name generate name.EXE -P=kcc * allow KCC lang. extensions\n\
-P=base Kernighan & Ritchie C -P=carm Harbison & Steele C\n\
-P=ansi carm with some ANSI stuff -P=stdc * Full ANSI-Standard C\n\
-p link with Bliss profiler -q compile only if changed\n\
-R=<fname> designate .REL, .MAC name -s redirect messages to stdout\n\
-S compile: don't asm or link -Uident #undef ident\n\
-v dump all -v messgs & cmd args -v=fundef dump function names\n\
-v=load dump link loader commands -v=nostats suppress lines/minute\n\
-w=note suppress [Note] messages -w=advise suppress [Advisory] also\n\
-w=warn suppress [Warning] also -w, -w=all suppress all warnings\n\
-x=ch7 default char size 7 bits.";
#if DEBUG_KCC
static const _char7 *debugscreen = "\n\
-O=parse do parser optimizations -O=all * do all optimizations\n\
-O=gen do code gen optimizations -O=object do peephole optimizations\n\
-d=parse dump parse tree file -d=pho dump peephole file\n\
-d=sym dump symbol file -d=all dump diagnostic files.";
#endif
/* -r registers OFF, only uses 1-5\n\ ;add above for KCC2B(1)
* -i includes files only once (at CSI)\n\
*/
int
main (int argc, char **argv)
{
extern int JOBERR;
int ac; /* temp copy of argc */
char **av; /* temp copy of argv */
char *nextprog = NULL; /* Set to program to chain through, if any */
int toterrs = 0; /* Total # errors for all files */
int nfiles = 0; /* # files to try compiling */
int asmfiles = 0; /* # files for which assembly was deferred */
/* KAR-3/92, changed to use new version number specification */
/* Set up CSI version number. See kcchst.h */
#ifdef __COMPILER_KCC__
_version(REV);
#endif
ver_str = REV;
#if defined (__COMPILER_KCC__)
/* Clear out .JBERR */
JOBERR = EXIT_SUCCESS;
#elif __MSDOS__
unsign_int = 0; /* only turned on in gizconst() */
#endif
/* Initialize KCC command switch values.
** All are either initially 0, or given default values in CCDATA.
*/
link = assemble = delete = 1;
module_pragma = XF4_call_spill = r_preserve = _reg_count = 0;
#if REGISTER_VARIABLES
/* set this to "-1" when register variables are implemented */
use_registers = 0; /* '-r' switch zeros this */
#endif
r_minnopreserve = R_MIN_NOPRESERVE; /* FW 2A(52) default */
r_maxnopreserve = R_MAX_NOPRESERVE; /* FW 2A(47) default */
outmsgs = stderr; /* '-s' switch to stdout, PPS 4298 */
insert_all_files = mlist = 0;
longidents = 0; /* FW 2A(51) default */
coptimize("all"); /* Turn on all optimizer flags */
/* Get command line arguments */
if (argc <= 1) /* No command line? */
{
#ifdef __COMPILER_KCC__
nextprog = execargs(&argc, &argv); /* Try getting from RPG/CCL */
#endif
if (argc > 1)
link = 0; /* Got stuff, so act as if -c given */
else /* Sigh, tell user where help lives */
{
fprintf(stderr, "KCC Version %s", ver_str);
fprintf(stderr, (void *) helpscreen); /* MVS 9/8/90 */
#if DEBUG_KCC
fprintf(stderr, (void *) debugscreen);
#endif
return EXIT_FAILURE;
}
}
/* Have initial command line; now scan for any indirect files (@file) */
cindfiles(&argc, &argv);
/* Now have complete command line, report it if desired.
** This debugging switch needs to be patched in by hand, because at this
** point it cannot have been set yet from the command line!
*/
if (vrbarg)
{
fprintf(outmsgs, "KCC args (%d):", argc);
for (ac = 0; ac < argc; ++ac)
fprintf(outmsgs, " %s", argv[ac] ? argv[ac] : "<null>");
fprintf(outmsgs,"\n");
}
/* Now process command line. First scan for all switches */
for (av = argv+1, ac = argc; --ac > 0; ++av)
if (**av == '-')
{
if (cswitch(*av, &ac, &av)) /* Process a switch */
*av = NULL; /* OK to zap it now */
}
else
++nfiles; /* Assume a filename spec */
#if !__MSDOS__ /* KAR-8/92, support for leveled header files; PPS 4516 */
/* but not for KCCDOS. */
switch (set_level (RET_CUR_LEV))
{
case 5: /* level 5; fall through because we need lev 1 also */
if (nhfpaths < MAXINCDIR-1)
hfpaths[nhfpaths++] = "SSL:[1,175]";
else
jerr("More than %d -H paths", MAXINCDIR);
if (nhfpaths < MAXINCDIR-1)
hfsypaths[nhfsypaths++] = "SSL:[1,165]";
else
jerr("More than %d -h paths", MAXINCDIR);
case 1: /* level 1 */
if (nhfpaths < MAXINCDIR-1)
hfpaths[nhfpaths++] = "SSL:[1,171]";
else
jerr("More than %d -H paths", MAXINCDIR);
if (nhfpaths < MAXINCDIR-1)
hfsypaths[nhfsypaths++] = "SSL:[1,161]";
else
jerr("More than %d -h paths", MAXINCDIR);
break;
case 0: /* level 0 system's default header file area */
default: /* error assume level 0 */
break;
}
#endif /* !__MSDOS__ */
/* Get the string rep. of the version */
if (mlist)
{
mlbptr = mlbuf = (char *) calloc (1, MAXMLBUF * sizeof(char));
mlbuf[0] = '\0';
if (mlbuf == NULL)
{
warn("Out of memory for mixed listing");
mlist = 0;
}
}
/* Now finalize after all switches scanned */
#ifndef __COMPILER_KCC__
tgmachuse.mapdbl = -1;
#endif
if (nfiles == 0) /* This sometimes happens */
jerr("No filenames specified");
/* If no errors, now scan for all filenames, and process them. */
if ((toterrs += nerrors) == 0)
for (av = argv+1, ac = argc; --ac > 0; ++av)
if (*av && **av != '-')
{
if (cfile(*av) == 0) /* Compile a file */
asmfiles++; /* Count deferred assemblies */
nfiles++;
toterrs += nerrors;
}
/* Now see what to invoke next, if any. Note runlink() never returns. */
if (toterrs) /* If any errors, */
{
link = 0; /* never invoke loader. */
nextprog = NULL;
}
if (asmfiles || link || nextprog)
runlink(link, /* Whether to invoke loader or not */
argc-1, argv+1, /* Loader args (.REL files) */
(savname ? savname /* Loader arg: output file name */
: mainname),
nextprog); /* Chained program to invoke next */
return (toterrs ? EXIT_FAILURE : EXIT_SUCCESS);
}
/* CINDFILES() - Scan an argv array for indirect file specs and
** expand them into a new argv array.
*/
static void
cindfiles (int *aac, char ***aav)
{
static int dynarr = 0; /* Set if array was calloced */
register int i, cnt;
register char *cp;
FILE *f;
char *buf;
int bufsiz;
#define NINDARGS 500
int locac;
char *locav[NINDARGS];
int ac = *aac;
char **newav, **avp, **av = *aav;
/* Scan current array and process any indirect files. */
for (i = 0; i < ac; ++i)
if (av[i] && av[i][0] == '@')
{
if ((f = fopen(&av[i][1], "r")) == NULL)
{
errfopen("indirect", av[i]); /* Couldn't open, tell user */
av[i] = NULL;
continue;
}
/* Read all of file into a memory block */
bufsiz = cnt = 0;
buf = cp = NULL;
while (!feof(f))
{
if (++cnt >= bufsiz) /* Ensure have room in buffer */
{
char *nbuf;
if ((nbuf = realloc(buf, bufsiz += 128)) == NULL)
{
jerr("Out of memory for indirect file \"%s\"", av[i]);
--cnt;
break; /* Leave loop now */
}
cp = (buf = nbuf) + (cnt-1);
}
*cp++ = getc(f);
}
fclose(f);
if (cp == NULL) /* If got nothing, scan for next file */
{
av[i] = NULL;
continue;
}
cp[-1] = '\0'; /* Ensure buffer tied off with null */
/* Now scan through the buffer to find arguments, dropping NULLs in
** to split them up, and add pointers to our local array.
** "cnt" has the # chars in the buffer, including a terminating null.
*/
locac = 0;
cp = buf;
for (; --cnt > 0; ++cp)
{
if (!isgraph(*cp))
continue; /* Ignore whitespace/cntrls */
if (*cp == '-' && (cnt <= 0 || cp[1] == '\n'))
continue; /* Ignore T20 "line continuation" */
if (*cp == ';')
{
while (--cnt > 0 && *++cp != '\n')
;
continue; /* Ignore ;-commented lines */
}
if (*cp == '!')
{
while (--cnt > 0 && *++cp != '!' && *cp != '\n')
;
continue; /* Ignore !-commented phrases/lines */
}
/* Start scanning over an argument */
if (locac >= NINDARGS)
{
jerr("More than %d args in indirect file \"%s\"",
NINDARGS, av[i]);
break;
}
locav[locac++] = cp; /* Remember ptr to arg */
while (--cnt >= 0 && isgraph(*++cp))
;
if (cnt >= 0)
*cp = '\0'; /* Terminate arg with null */
}
/* Now combine new args with old args. New table size is
** # old args (minus current arg),
** plus # new args (plus ending null pointer).
*/
if ((newav = (char **)calloc(1, (ac+locac)*sizeof(char *))) == NULL)
{
jerr("Out of memory for args of indirect file \"%s\"", av[i]);
av[i] = NULL;
continue;
}
avp = newav;
for (cnt = 0; cnt < i; ++cnt) /* Copy already checked args */
*avp++ = av[cnt];
for (cnt = 0; cnt < locac; ++cnt) /* Copy new args */
*avp++ = locav[cnt];
for (cnt = i+1; cnt < ac; ++cnt) /* Copy old unchecked args */
*avp++ = av[cnt];
*avp = NULL; /* Last one always null */
ac = (ac - 1) + locac; /* Old args minus 1, plus new args */
if (!dynarr)
++dynarr; /* If old not dynamic, say new one is */
else
free((char *)av); /* else must free up old dynamic array */
av = newav; /* Pointer to new array */
--i; /* Compensate for loop increment */
}
*aac = ac; /* Return new values (normally the same) */
*aav = av;
}
/* CSWITCH - Scan argv array for command line switches
**
** Returns 0 if should keep this switch spec around (used for -l).
** Otherwise, OK to zap switch spec, don't need to keep around.
*/
static
int
cswitch (char *s, int *aac, char ***aav)
{
char* t; /* KAR-3/91, fix bug in -L lib path */
while (*++s)
{
switch (*s)
{
#if DEBUG_KCC /* 9/91 KCC size */
case 'a': /* -a<file> Set #asm tmp file name */
asmtfile = ++s; /* rest of arg is filename */
return 1;
case 'A': /* -A<file> Set asm hdr file name */
asmhfile = ++s; /* rest of arg is filename */
return 1;
case 'O': /* -O Optimize (same as -O=all) */
if (s[1] == '=') /* -O=<flags> If extended syntax, */
{
++s;
coptimize(++s); /* go hack rest of arg string. */
return 1;
}
else
coptimize("all"); /* Else just turn everything on */
break;
#endif /* DEBUG_KCC */
case 'b': /* FW 2A(47) */
/*
* "-b[789]" specifies the desired byte width of source files.
*/
sourcebytewidth = atoi (++s);
if ((sourcebytewidth < 7) || (sourcebytewidth > 9))
jwarn ("source-file byte width %d out of range, defaulting to 7 bits", sourcebytewidth);
return 1;
case 'c': /* -c Compile only */
link = 0; /* Don't run linking loader */
break;
case 'C': /* -C Pass on comments during -E */
keepcmts = 1; /* pass comments thru to stdout */
break;
case 'd': /* -d Debug (same as -d=all) */
if (s[1] == '=') /* -d=<flags> If extended syntax, */
{
++s;
cdebug(++s); /* go hack rest of arg string. */
return 1;
}
else
cdebug("all"); /* Else just turn everything on */
break;
case 'D': /* -D<ident> Define a macro */
if (!chkmacname(s)) /* -D<ident>=<def> */
return 1;
if (npredef < MAXPREDEF)
predefs[npredef++] = ++s; /* rest of arg is def string */
else
jerr("More than %d predefined macros", MAXPREDEF);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -