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

📄 ccpp.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
static
char *plevindent();
static
char *tkids();
 #endif
#endif

/* PPINIT() - Invoke to initialize preprocessor at start of file scan.
**	Called once for each file compiled.
*/
void
ppinit(void)
{
    /* Set globals */
    eof = 0;
    tline = 0;
    fline = page = line = 1;

    /* Set variables local to preprocessor */
    ppcreset();
    pptreset();
    inlevel = iflevel = flushing = inasm = indirp = maclevel = 0;
    iftype[0] = 0;		/* Just in case */
    tadset = 0;			/* Date/time strings not set */
    erptr = errlin;		/* Init pointer to error-context buffer */
    erpleft = ERRLSIZE;		/* Set countdown of chars left in errlin */
    memset((char *) erptr, 0, erpleft);	/* Clear the circular buffer */
    pushstr("\n");		/* Prime input with EOL, set up 1st char! */

    /* Enter special macro pre-definitions into symbol table. */
    mdefstr("__COMPILER_KCC__", MACF_KCC, NULL);
    mdefstr("__LINE__",		MACF_LINE, NULL);
    mdefstr("__FILE__",		MACF_FILE, NULL);

#if __MSDOS__ /* KAR-8/92, predefine __KCCDOS__ if KCCDOS */
    mdefstr("__KCCDOS__", MACF_DOS, "1");
#endif

    if (clevel >= CLEV_CARM)
	{
	mdefstr("__DATE__", MACF_DATE, NULL);
	mdefstr("__TIME__", MACF_TIME, NULL);
	/* "defined" is a bit more special.  Need to remember ptr to
	** 1st char of the symbol name, so it can be turned on and off.
	*/
	defcsname = &(mdefstr("defined", MACF_DEFD, NULL)->Sname[0]);
	*defcsname = SPC_MACDEF;	/* Hide sym by smashing 1st char */
	}
    if (clevel >= CLEV_STDC)		/* When we're fully ready */
	{
	mdefstr("__STDC__", MACF_STDC, "1");
	}
    if (clevkcc)
	{
	mdefstr("_KCCsymfnd", MACF_SYMF, NULL);
	mdefstr("_KCCsymval", MACF_SYMV, NULL);
	}
}

/* DOTAD - Initialize datestr and timestr for __DATE__ and __TIME__.
**	This is only invoked if one of those macros is seen; otherwise,
**	the overhead is avoided.
*/
static
void
dotad()
{
    register char *cp;
    time_t utad;

    if (time(&utad) == (time_t)-1)
	{
	warn("Cannot get date/time, using %s %s", timestr, datestr);
	return;			/* Leave both strings alone */
	}
    cp = ctime(&utad);		/* Get pointer to ascii date and time */

    /* Now have "Dow Mon dd hh:mm:ss yyyy\n\0" */
    /*		 012345678901234567890123 4 5  */
    strncpy(datestr+1, cp+4, 6);	/* Copy "Mon dd" */
    strncpy(datestr+8, cp+20, 4);	/* Copy "yyyy" */
    strncpy(timestr+1, cp+11, 8);	/* Copy "hh:mm:ss" */
    tadset = 1;				/* Strings now set! */
}

/* PPDEFINE(cruft) - Process startup #undefs and #defines requested by the
**	-U and -D switches in the main CC loop.
**	We assume the syntax has already been checked by chkmacname() in CC.
*/
void
ppdefine(unum, utab, dnum, dtab)
int unum, dnum;		/* # of strings in table */
char **utab, **dtab;	/* Address of char-pointer array */
{
    int savch;
    char *cp;
    SYMBOL *sym;

    /* First handle all -U undefinitions... */
    for ( ; --unum >= 0; utab++)
	{
	if ((sym = findmacsym(*utab)) != NULL)	/* Look up the macro symbol */
	    freemacsym(sym);		/* Found it, flush it! */
	else
	    note("Macro in -U%s doesn't exist", *utab);
	}

    /* Now handle all -D definitions. */
    for ( ; --dnum >= 0; dtab++)
	{
	cp = *dtab;			/* Get this -D string */
	while (*++cp && *cp != '=')
	    ;	/* Scan for start of body if any */
	savch = *cp;			/* Remember terminator char */
	*cp = '\0';			/* Tie name off in case of '=' */
	if ((sym = findmacsym(*dtab)) != NULL)	/* See if already defined */
	    {
	    advise("Redefining macro: -D%s", *dtab);	/* Ugh! */
	    freemacsym(sym);
	    }
	mdefstr(*dtab, MACF_ATOM,	/* Define object-like macro */
		savch ? cp+1 : "1");	/* with "1" if no body. */
	*cp = savch;			/* Restore zapped char if any */
	}
}

/*
 * PASSTHRU(fp) - Pass through text to file
 *	Used only by -E (i.e. prepf is set)
 *
 * General strategy:
 *	Attempts to do a fast scan through the input whenever possible, just
 * reading and outputting on the character level.
 * It necessarily has to simulate some of what nextrawpp() and nextpp()
 * do.
 *	(nextrawpp: handle comments, string-type literals)
 *	(nextpp: handle directives, macro expansion)
 *
 * When it encounters a directive or macro, it punts and asks nextpp() to
 * handle it, whereupon it just translates tokens until it determines
 * that things are back at top level again.  This return of control may
 * be tricky.
 */

static
void	    pass_ident (FILE *),
	    pass_num (void),
	    pass_hwsp (void),
	    pass_line (int),
	    pass_comm (void),
	    pass_str (int);

static
FILE*	    passfp;



void
passthru (FILE* fp)
    {
#if 0	/* 8/91 shrink KCC */
    prepfp = fp;		/* Set for benefit of ppasm() */
#endif

    passfp = fp;

#if DEBUG_PP
    if (debpp && debppt)		/* Do trivial passthru */
	{
	while (nextpp() != T_EOF)
	    {
	    pptreset();
	    ppcreset();
	    pptfput(tlpcur(tlmake(curpp, curval)), fp);
	    }
	return;
	}
#endif

    /* Note at start of file, ch should always contain \n as "first" char */

    for (;;)
	{
	switch (ch)	/* Scan starting with current char */
	    {
	    case EOF:			/* Done when hit EOF */
		return;

	    /* Check for whitespace other than new-line */

	    case '\r':			/* Include CR here */
	    case '\v':			/* Vert tab */
	    case '\f':			/* Ditto FF */
	    case '\t':			/* Horiz tab */
	    case ' ':			/* Space */

		if (keepcmts)		/* If keeping comments, */
		    {
		    putc (ch, fp);	/* just pass it all */
		    nextch ();
		    }
		else
		    pass_hwsp ();	/* Flushing, so try to be clever */

		continue;


	    case '\n':
		/* Newline needs special handling (maybe directives, etc) */

		pass_line (0);
		continue;

	    case '/':
		/* Check for possible start of comment */

		if (nextch () == '*')
		    pass_comm ();

		/*
		 * KAR-2/93, added for PPS 4574, C++ comments
		 * FW 2A(45) July 93, added check of clevnocpp
		 *
		 * NB. The test of 'ch' is right here because the
		 * previous call to nextch () set it up.
		 */

		else if (ch == '/' && !clevnocpp)
		    {
		    /* C++ style comment */

		    comment_type = CPP;
		    pass_comm ();
		    comment_type = C;
		    }
		else
		    putc ('/', fp);

		continue;

	    default:
		if (iscsymf (ch))
		    {
		    /* start of ident, check for macro */

		    pass_ident (fp);
		    continue;
		    }

		putc (ch, fp);		/* Normal char, pass it on */
		nextch ();		/* Get next */

		continue;

	    case '.':			/* '.' may start a pp-number */
		putc ('.', fp);

		if (!isdigit (nextch ()))
		    continue;		/* Nope, handle whatever it is */

	    /* Is pp-number, drop thru to handle it */

	    case '0':
	    case '1':
	    case '2':
	    case '3':
	    case '4':
	    case '5':
	    case '6':
	    case '7':
	    case '8':
	    case '9':
		pass_num ();
		continue;

	    /*
	     * Pass through string constants.  Note that character constants
	     * (e.g. 'a') are handled a little differently because they
	     * shouldn't be longer than the largest possible char constant.
	     */

	    case '\'':
		pass_str (tgcpw+2);
		continue;	/* Char constant */

	    case '"':
		pass_str (0);
		continue;	/* String literal */

	    case '`':			/* Quoted identifier (maybe) */

		if (clevkcc)		/* If KCC extensions allowed, */
		    {
		    pass_str (0);	/* parse like string! */
		    continue;
		    }

		putc (ch, fp);		/* Normal char, pass it on */
		nextch ();		/* Get next */
		continue;
	    }				/* End of loop */
	}
    }

/*
 * PASS_IDENT - auxiliary for passthru () and d_asm () to parse an
 *	identifier and either pass it along or expand it if it's a macro.
 *	Current char is the first char of the identifier.
 *	Returns with current char the 1st thing after ident (or expansion).
 */

static
void
pass_ident (FILE* fp)
    {
    SYMBOL*	sym;
    register
    PPTOK*	p;
    register
    char*	cp;


    cp = ppcbeg ();

    do
	ppcput (ch);		/* Gobble up ident starting with current ch */
    while (iscsym (nextch ()));

    (void) ppcend ();		/* Tie off so can look it up */

    if (((sym = findmacsym (cp)) == NULL)	/* If not a macro, */
	    || !mexptop (sym, 0))	/* or can't expand it, */
	{
	fputs (cp, fp);		/* just output the identifier. */
	ppcreset ();		/* Clean up token char pool */
	return;
	}

    /*
     * Expanded macro!
     * Since mexptop () leaves a tokenlist in curtl, we grab that and
     * translate it into a string that is then output, with special
     * quoting if in #asm.
     */

    if (!inasm)
	{
	for ( ; (p = tlpcur (curtl)) != NULL; tlpskip (curtl))
	    pptfput (p, fp);
	}
    else			/* in #asm, must do special quoting */
	{
	curtl = tlstrize (curtl);	/* Turn into giant string literal */
	cp = curtl.tl_head->pt_val.cp;	/* Get ptr to start */
	cp[strlen (cp) - 1] = '\0';	/* Chop '"' off end */
	fputs (cp + 1, fp);		/* And skip '"' at beg */
	}

    tlzinit (curtl);	/* Ensure curtl flushed out */
    ppcreset ();		/* Also be safe and flush stg used */
    pptreset ();
    }

/*
 * PASS_NUM - auxiliary for PASSTHRU () to pass a PP-number.
 *	Returns with delimiting char still in CH, not yet output.
 */

static
void
pass_num (void)
    {
    register
    int		i;


    for ( ; ; )
	{
	i = ch;
	putc (i, passfp);	/* Pass char, remember it */

	switch (nextch ())
	    {
	    case '+' :
	    case '-' :		/* Sign chars are part of number, */

		if (toupper ((char) i) != 'E')	/* if prev char was E */ // FW KCC-NT
		    return;		/* Oops, gotta stop */

	    case '.' :

		break;

	    default :

		if (!iscsym (ch))
		    return;

		break;
	    }
	}
    }

/*
 * PASS_STR - auxiliary for PASSTHRU () to parse a string-type literal
 *	Returns with delimiting char still in CH, not yet output.
 *	Return value is 0 if EOF encountered, else non-zero.
 */

static
void
pass_str (int cnt)
    {
    int		delim = ch;		/* Delimiter char */


    putc (ch, passfp);		/* Send initial delimiter */

    while ((nextch () != EOF) && (ch != '\n') && (--cnt != 0))
	{
	putc (ch, passfp);

	if (ch == delim)	/* If that was end of string, */
	    {
	    nextch ();		/* set up next char and return. */
	    return;
	    }

	if (ch == '\\')		/* Handle backslash */
	    putc (nextch (), passfp);	/* by quoting next char */
	}

    /*
     * Either EOF, or char length exceeded, or illegal char (newline).
     * For now, we don't complain about anything but EOF.
     */

    if (ch == EOF)
	error ("Unexpected EOF within %s",
	       (delim == '\"' ? "string literal"
			       : (delim == '\'' ? "char constant"
						: "quoted identifier")));
    }

/*
 * PASS_HWSP - auxiliary for PASSTHRU () to scan horiz whitespace NOT at
 *	start of a line, and not being kept.  Just reduce to one space,
 *	unless hit EOL in which case do nothing.
 *	Returns with delimiting char still in CH, not yet output.
 */

static
void
pass_hwsp (void)
    {
    for ( ; ; )
	{
	while (ischwsp (nextch ()))
	    ;				/* Flush all horiz wsp */

	if (ch == '/')
	    {
	    if (nextch () == '*')	/* Start of comment? */
		{
		scancomm ();		/* Flush it!  Leaves last '/' in ch */
		continue;
		}
	    else if (ch == '/' && !clevnocpp)
		{
		comment_type = CPP;
		scancomm ();
		pushch (ch);		/* FW 2A(50) September 1993 */
		comment_type = C;
		continue;
		}
	    else
		{
		fputs (" /", passfp);
		return;
		}
	    }

	break;
	}

    if (ch != '\n')
	putc (' ', passfp);
    }

/*
 * PASS_LINE - auxiliary for PASSTHRU () to handle start of a line.
 *	Must check for directives, etc.
 *	If keeping comments, pass on all whitespace & comments, up to
 *		first non-whitespace.
 *	If not keeping comments, store all whitespace in temp buffer
 *		(using 1 space for each comment) up to 1st non-wsp.
 *	If 1st non-wsp is "#" then invoke directive processing.
 *	If 1st non-wsp is EOL just re-invoke without outputting an EOL.
 *	Returns with delimiting char still in CH, not yet output.
 */

static
void
pass_line (int suppress)
    {
    char	wspbuf[120];	/* # chars of leading whitespace to save */
    register
    char*	cp = wspbuf;
    register
    int		cnt = sizeof (wspbuf) - 2;


    if (!suppress)
	putc ('\n', passfp);		/* First must end any current line */

    if (!keepcmts || inasm)
	{
	for ( ; ; )			/* Flush whitespace and comments */
	    {
	    switch (nextch ())
		{
		case '/':

		    if ((nextch () != '*') && (ch != '/')) /* KAR PPS4574 */
			{
			pushch (ch);
			ch = '/';
			break;
			}
		    else if (ch == '/' && !clevnocpp)
			comment_type = CPP;

		    pass_comm ();
		    comment_type = C;		/* KAR-2/93, PPS 4574 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -