⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cc.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	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 + -