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

📄 ccpp.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* Drop thru to output single space */

		case ' ':
		case '\t':
		case '\r':
		case '\v':
		case '\f':
		    if (--cnt > 0)
			*cp++ = ch;

		    continue;

		case '\n':
		    pass_line (++suppress); /* Tail recurse, don't emit EOL */
		    return;

		default:
			break;		    
		}

	    *cp = 0;			/* Tie off */
	    break;
	    }
	}
    else			/* Keeping comments */
	{
	for (;;)			/* Flush whitespace and comments */
	    {
	    if (ischwsp (nextch ()))
		putc (ch, passfp);
	    else if (ch != '/')
		break;
	    else if (nextch () == '*')
		pass_comm ();
	    else if (ch == '/' && !clevnocpp) {
		comment_type = CPP;
		pass_comm ();
		comment_type = C;
		}
	    else
		{
		pushch (ch);
		ch = '/';
		break;
		}
	    }
	}

    if (ch == '#')
	{
	nextch ();		/* Must move past it to set up... */
	directive ();		/* Process directive! */

	while (inasm && nextpp() != T_EOF)	/* If in #asm, do hack */
	    {
	    pptreset ();
	    ppcreset ();
	    pptfput (tlpcur (tlmake (curpp, curval)), passfp);
	    }
	if (ch != EOF)		/* Sigh, must put back */
	    pushch (ch);		/* the 1st char of beg of line */
	pass_line (++suppress);		/* Then can tail recurse! */
	return;
	}
    else if (!keepcmts)
	fputs (wspbuf, passfp);	/* Output saved whitespace up to here */
}

/* PASS_COMM - auxiliary for PASSTHRU () to scan over a comment.
**	Current char is the '*' starting comment.
**	Returns with a space in CH; next input char will be 1st char
**	after the '/' that ended comment.
*/

static
void
pass_comm ()
    {
    if (!keepcmts)
	scancomm ();			/* Flush the comment! */
    else if (comment_type != CPP)	/* KAR-2/93, PPS 4574; C++ comments */
	{
	/* Comment skip for -E when retaining comments (-C) */

	fputs ("/*", passfp);		/* Pass comment start */
	nextch ();

	for (;;)			/* until we break */
	    {
	    putc (ch, passfp);		/* send char off */

	    if (ch != '*')
		nextch ();	/* find a star */
	    else if (nextch () == '/')	/* and a slash to terminate */
		{
		putc ('/', passfp);
		break;			/* Stop loop */
		}

	    if (eof)			/* Also stop if input gone */
		{
		error ("Unexpected EOF in comment");
		break;
		}
	    }
        }
    else
        {				/* KAR-2/93, PPS 4574; C++ comments */
	fputs ("//", passfp);
	nextch ();

	for (;;)
	    {
	    putc (ch, passfp);

	    if (ch != '\n')		/* C++ comment delimeter is EOL */
		nextch ();
	    else
		break;

	    if (eof)
	        {
		error ("Unexpected EOF in comment");
		break;
	        }
	    }
        }

    ch = ' ';		/* Pretend current char now a space */
    }

#if 0

 nextch()	Phase 1, 2 - produce source chars & logical lines
			(handles trigraphs, \-newlines)
 nextrawpp()	Phase 3 - produce raw PP tokens
			(handles comments, flushes WSP)
 nextmacpp()	Phase 3.5 - used to redirect source of raw tokens
			during macro expansion
 nextpp()	Phase 4 - produce clean expanded PP tokens
			(handles directives, macro expansion, flushes EOLs)
 nextoken()	Phase 5, 6, 7 - Produce C tokens from clean PP tokens
			(handles char escapes, string concatenation, token
				conversion & constant parsing)

There are 4 types of scanning, differentiated by the different end results
of the scan.  Each of them invokes at some point the types below it.
	A. Toplevel (language) tokenizing	(Phase 1-7)
	B. Macro/directive (preproc) tokenizing	(Phase 1-4)
	C. Passthru scanning (for -E and #asm)	(Phase 1-4)
	D. Passover scanning (for #if skipping)	(Phase 1-3)
#endif

/* NEXTCH() - Get next character.
**	Implements Translation Phase 1 and 2.
**	Handles trigraphs and quoted newlines ('\\' '\n').
**
**	Because the value returned by nextch() must be pushable by pushch(),
**	and because we cannot call pushch() twice in a row on file input
**	(otherwise STDIO's ungetc() complains), we have to divert input
**	to come from a string whenever this routine does need to call pushch().
**	This is why the calls to pushstr() exist.
**
**	Note: implement IESC escape char similar to MACESC so can
**	easily insert special tokens (like temporary EOF) into input.
*/
static
int
nextch (void)
{
    int prevch = ch;		/* Remember previous char */
    char	 tmpbuf[200];
    char	 *tmp = tmpbuf;
    int		 skp_nl = 0;


    /* First check for pushed-back string */
    if (backstr)			/* Pushback string exists? */
	{
	if ((ch = *backstr++) != '\0')	/* Yes, are there more chars? */
	    return (ch != TCH_ESC)	/* Yes, is this a special escape? */
		? ch			/* Nope, just return char. */
		: (ch = tchesc());	/* Aha!  Handle escape stuff! */
	bstrpop();			/* End of a pushback string, pop it */
	ch = prevch;			/* Ensure "prev chr" isn't NUL */
	return nextch();		/* and try for a new char */
	}

    /* Just get normal input char */

    if (module_pragma)
	ch = EOF;
    else
	ch = getc(in);

    _ch_cpy = ch;		/* 12/90 ccstmt.c needs _ch_cpy */

    if (mlist && fstart && (inlevel <= 0) && (fline == 1))
	{
	sprintf (tmp, "\n; %d\t", fline);	/* KAR 8/3/90 */
	oline++;
	strcat (mlbptr, tmp);
	fstart = 0;
	} /* if */

    if (mlist && (!ch_ungot) && (inlevel <= 0) && (ch != '\n') &&
	    (ch != '\r') && (ch != '\v') && (ch != '\f')) /* KAR 5/91 '\f' */
	{
	sprintf (tmp, "%c", ch);
	strcat (mlbptr, tmp);			/* KAR 8/3/90 */
	} /* if */
    else if (ch_ungot)
	{
	if (ch == '\n')
	    skp_nl = 1;
	ch_ungot = 0;
	} /* else if ch_ungot */

    /* Add char to small circular buffer for possible error messages */

    *erptr++ = ch;		/* Add to saved input line. */

    if (--erpleft <= 0)	/* If reached end of buffer, */
	{
	erptr = errlin;		/* wrap back around. */
	erpleft = ERRLSIZE;
	}

    switch (ch)
	{
	case EOF:			/* End Of File on input */
				/* Do a couple of checks to verify */
	    if (ferror(in))
	        error("I/O error detected while reading file %s", inpfname);
	    else if (!feof(in) && !module_pragma)
		int_error("nextch: spurious EOF");

	    if (prevch != '\n' && prevch != EOF) /* Was last ch in file EOL? */
		{
		if (!module_pragma)
		    warn("File does not end with EOL (\\n)");	/* Nope */
		return pushstr("\n");	/* Attempt graceful termination */
		}			/* by providing EOL as last char. */

	    if (scanning_comment)
		error ("EOF while scanning comment");

	    if (inlevel > 0)		/* Drop level.  If more, pop input. */
		{
		ifpopchk(inlevel);	/* Do balanced conditional check */
		fclose(in);		/* Close this file */
		--inlevel;
		in = inc[inlevel].cptr;	/* then set vars from popped level */
		page = inc[inlevel].cpage;
		line = inc[inlevel].cline;
		fline = inc[inlevel].cfline;
		ch_ungot = 1;
		strcpy(inpfname, inc[inlevel].cname);

#if DEBUG_PP
		if (debpp)
		    {
		    fprintf (fpp, "#include %d: restored \"%s\", new ch %#o\n",
			    inlevel+1, inpfname, nextch ());
		    return ch;
		    }
#endif

		return nextch();	/* try for another char */
		}

	    /*
	     * EOF at top level (main input file).  We DON'T close the
	     * stream at this point, so that it's OK to call this routine
	     * again.  Some preproc/parsing routines want to just punt
	     * on EOF and let a higher level take care of it.  The CC
	     * mainline fcloses the stream.
	     */

	    if (eof)
		{
		if (mlist)		 /* KAR 8/90 */
		    mlbuf[0] = '\0'; /* Don't dump garbage if seen EOF */

		break;		/* If already seen EOF, needn't redo stuff. */
		} /* eof */

	    eof = 1;		/* Flag end of file at top level. */

	    if (iflevel)		/* Error if preprocessor unbalanced */
		ifpopchk(0);	/* Spit out helpful error message */

	    break;			/* Return EOF char */


	case '?':			/* (&%#^#$(*@!!! trigraph hackery */
	    {
	    static
	    int		skipflg;	/* TRUE if skipped a '?' */
	    static
	    int		intrig = 0;	/* TRUE if in this code already */

	    
	    if (clevel < CLEV_STDC)	/* Only if STDC */
		break;

	    if (intrig)
		break;	/* If already scanning, just return char. */

	    ++intrig;		/* Say scanning trigraph! */

	    if (!skipflg		/* If we didn't skip a '?' already, */
		  && nextch() != '?')	/* OK to read next ch. Two in a row? */
		{
		pushch (ch);		/* Nope, push back peeked-at char */
		intrig = 0;		/* No longer scanning */
		return pushstr ("?");	/* Return original q-mark */
		}

	    nextch ();		/* Got two '?'s in row!  Scan for third... */
	    intrig = 0;		/* No longer scanning */
	    skipflg = 0;		/* Skip hackery done */

	    switch (ch)		/* Dispatch on 3rd char! */
		{
		case '=':
		    ch = '#'; break;

		case '(':
		    ch = '['; break;

		case '/':
		    ch = '\\'; break;

		case ')':
		    ch = ']'; break;

		case '\'':
		    ch = '^'; break;

		case '<':
		    ch = '{'; break;

		case '!':
		    ch = '|'; break;

		case '>':
		    ch = '}'; break;

		case '-':
		    ch = '~'; break;

		default:		/* Not trigraph, but simple pushback */
		    pushch (ch);	/* Make use of 1-char file backup */
		    return pushstr ("??"); /* OK to use string for other 2 */

		case '?':		/* Not a trigraph, big screwup. */
		    /*
		     * On the next call we have to make sure that
		     * re-examination starts again -- just pushing a
		     * string back won't work right.  We also can't
		     * count on having more than 1 char of file backup!
		     * The solution is to realize that we'll come here
		     * again when the pushch'd '?' is read from getc (),
		     * so we don't try to push back the middle '?' at
		     * all, and instead set a flag that says it was
		     * "skipped"; when we do come back, we'll check
		     * that flag and do the right thing.
		     */

		    pushch (ch);		/* Push back 3rd '?' */
		    skipflg = 1;		/* Say 2nd is skipped */
		    return pushstr ("?");	/* Return 1st */
		}
	    }

	break;

    case '\\':
	if (isceol(nextch()))	/* Check next char */
	    {
	    ch = 0;		/* Quoted EOL is ignored totally, to extent */
	    return nextch();	/* of forgetting last char was EOL! */
	    }
	pushch(ch);		/* otherwise put char back */
	ch_ungot = 1;		/* don't put in buffer twice -- KAR 8/90 */
	return pushstr("\\");	/* and set up a pushch-able input */
				/* and return backslash */

    case '\f':			/* Form-feed */
	page++;			/* Starts new page */
	line = 1;		/* at first line */
	break;
    case '\r':
    case '\v':
    case '\n':
	line++;			/* new line, same page */
	fline++;
	tline++;

	if (mlist && (inlevel <= 0))
	    {
	    oline++;
	    if (oline > MAX_OLINE)
		{
		opage++;
		sprintf(tmp,
		   "\n\f; %-26s\t\tCompuServe Incorporated\t\t%s\t  Page %d\n",
			dspfname, creatime, opage);
		strcat (mlbptr, tmp);
		sprintf(tmp, "; KCC: %-20s\t\t\t\t\t\t\t%s\n",
			ver_str, comptime);
		strcat (mlbptr, tmp);
		oline = HDR_LINES;
		} /* if MAX_OLINE */
	    if (!skp_nl)
		strcat(mlbptr, "\n");
	    if (!skp_nl)
		{
		dmpmlbuf();
		dmp_errmsg();
		sprintf (tmp, "; %d\t", fline); /* KAR 8/3/90 */
		strcat (mlbptr, tmp);
		} /* if  */
    else
	skp_nl = 0;
	} /* if mlist */

    break;
    default:
	;	/* do nothing */
	}
    return ch;
}

/* DMPMLBUF() - dump contents of the mixed listing buffer
**	Only function calls this, nextoken(); in cclex.c
*/
void
dmpmlbuf (void)
{
	#define EOS '\0'

	/* KAR-10/91, took out the if condition; no longer needed */
    fputs(mlbptr, out);
    mlbuf [0] = EOS;
	#undef EOS
}

/* DMP_ERRMSG() - dump error messages accumulated.
**
*/
static
void
dmp_errmsg (void)
{
	/* KAR-10/91, took out sup_dmp in if condition; no longer needed */
    if (err_waiting)
	{
	fprintf (out, "%s", errbuf);
	free (errbuf);
	errbuf = NULL;
	oline += ((err_waiting * 2) + 1);
	err_waiting = 0;
	} /* if */
}

/* TCHESC() - Handle token char escape.
**	backstr is set, and char it points to says what to do.
**	Returns char to be given to caller of nextch().
*/
static
int
tchesc()
{
    int i;
    switch (i = *backstr++)	/* Handle it */
	{
	default:
	    int_error("tchesc: token escape char %d='%c'", i, i);

	case TCH_ESC:		/* Quoting escape char */
	    return i;

	case TCH_EOF:
	    backstr -= 2;	/* Bump back to point at TCH_ESC */
	    return EOF;		/* and return EOF as char */
	}
}


/* SINBEG(cp) - Make nextch() return input from given string.
** SINEND() - Stop using string input, restore previous source.
**	Note that nextch() will return EOF when the string input is done,
**	instead of popping input and continuing.
**	SINEND() must be called to proceed further.
** These routines are recursive, but could be simplified by forbidding
** recursion and just saving/restoring CH rather than calling pushch/nextch.
*/
static
char eofstr[] =
{
    TCH_ESC, TCH_EOF
}
;

static
void
sinbeg(cp)
char *cp;
{
    pushch(ch);		/* Save current char (since not tokenized yet) */
    bstrpush(eofstr);	/* Put EOF on end of input string */
    pushstr(cp);	/* and set up string for input! */
}
static
void
sinend()
{
    while (backstr != eofstr)		/* We should have hit string EOF... */
	{
	int_error("sinend: leftover input");
	bstrpop();			/* Will get error if overpop */
	}
    bstrpop();		/* Take off EOF string, restore previous source */
    nextch();		/* Set up next char for tokenizer */
}

/* PUSHCH - Push back char for nextch()
** PUSHSTR - Push back string, sets up 1st char as current char
** BSTRPUSH - Push back string for ditto (save any current string)
** BSTRPOP - Pop pushback string, restore previous string
*/
void
pushch(c)

⌨️ 快捷键说明

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