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

📄 ccpp.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 5 页
字号:
/*	CCPP.C - New KCC Preprocessor
**
**	(c) Copyright Ken Harrenstien 1989
**
*/

#ifndef DEBUG_PP
#define DEBUG_PP 0	/* Include debugging printout capability */
#endif

#include "cc.h"
#include "ccchar.h"
#include "cclex.h"
#include <time.h>	/* Needed for __DATE__ and __TIME__ */
#include <string.h>
#include <stdlib.h>	/* calloc, free, atoi */

/* Imported functions used here */
extern
SYMBOL *symfind(char *, int); /*CCSYM to look up macro or identifier */
extern
SYMBOL *symgcreat(char *);	/* CCSYM to create a macro name */
extern
SYMBOL *symfnext(SYMBOL *),	/* CCSYM */
		*shmacsym(SYMBOL *);
extern
void freesym(SYMBOL *);		/* CCSYM */
extern
long pconst(void);		/* CCSTMT to parse constant expr */
extern
char *estrcpy(char *, char *),
	*fstrcpy(char *, char *, char *);	/* CCASMB */
extern
int symval(char *, char *, int);		/* CCASMB */
extern
int nextoken(void);			/* CCLEX  */
extern
void flushcode (void);
extern
void outstr (char *);			/* CCOUT  */

/* Exported functions */
void ppinit(void);		/* Initialize the input preprocessor. (CC) */
void ppdefine(int, char **, int, char **); /* Inits predefined macros (CC) */
void passthru(FILE *);	/*Invoked by -E for simple pass-thru processing (CC)*/
int nextpp(void);		/* Read next token from input (CCLEX) */
void pushpp(void);		/* Push back current token (CCLEX) */
int nsert_file (char *f, int insert_flag);

/* Internal functions */
static
void dotad(void);
static
int nextch(void), tchesc(void), pushstr(char *);
static
void pushch(int), bstrpush(char *), bstrpop(void);
static
int nextrawpp(void), scanhwsp(void), ppnconst(int), ppunknwn(void);
static
void ppsconst(int), scancomm(void);
static
void		pptresize(void);			// FW KCC-NT
static
int nextmacpp(void);
static
void pushmp(void), mtlpop(void);
static
int findident(void);
static
void directive(void);
static
int d_define(void), d_undef(void), d_asm(void), d_endasm(void),
	d_ifdef(int), d_if(void), d_else(void), d_elif(void), d_endif(void),
	d_include(void), d_line(void), d_error(void), d_pragma(void);
static
int iftest(void);
static
void iffwarn(char *), ifpush(int), ifpopchk(int);
static
void flushcond(void), filepush(FILE *, char *, int, int, int);
static
SYMBOL *findmacsym(char *);
static
void freemacsym(SYMBOL *);
static
int tskipwsp(void), tskiplwsp(void), cskiplwsp(void), flushtoeol(void);
static
void checkeol(void);
static
int getfile(char *, int);
static
void sinbeg(char *), sinend(void);
static
int  mpeekpar(void);
static
int get_title (char *pragma_str, char *ext);

static
void dmp_errmsg(void);
void dmpmlbuf(void);

 /* Flag for top-of-file, needed for mixed listing generation-KAR 8/3/90 */
 /* KAR-6/91, changed type to short */
static
short fstart = 1;

 /* KAR-11/91, flag for usage bef. init. code for signaling parsing the
  * the right side of and assignment expression.
  */
char ra_expr;

/*
 * KAR-2/93, adding the following enumerated type and instance for
 * needed support to allow C++ style comments (PPS 4574).
 */
typedef enum {		/* Used to signal style of comment, C or C++ */
    C,
    CPP
} comment_style;

static
comment_style comment_type = C;


/* The main global variables of interest to callers (i.e. CCLEX) are those
** set by nextpp(), as follows:
**
**	curpp - Current token (a tokdef enum)
**	curval - Token value (either unused or a string pointer)
**	curptr - Pointer to corresponding pptok in tokenlist, if any.
**	cursym - Pointer to symbol, if curpp == T_IDENT.  This will have
**			class SC_UNDEF if sym didn't exist previously.
*/

/* Note that most routines operate, or begin to operate, on the current
 * character in "ch", rather than immediately reading the next char.  When
 * a character is completely processed and is not needed any more, nextch()
 * must be called in order to get rid of it and set up a new char for
 * whatever will be next looking at the input.  Occasionally "ch" is
 * set directly for proper "priming".
 * This is to avoid having to call pushch() whenever a token ends.
 */

extern
char _ch_cpy;	/* set in nextpp() used in ccstmt.c */
/* Mixed listing output buffer variables */
char		*mlbuf = NULL;
char		*mlbptr = NULL;
static
short	ch_ungot = 0;	/* KAR-5/91, changed type to short */

/* Include file nesting stack - holds saved input file context.
 *	Indexed by inlevel.
 */
static
int inlevel;			/* 0 - top level */
static
int scanning_comment = 0;	/* flags true while in scancomm */

static
struct
    {
    FILE    *cptr;	/* file pointer  */
    filename cname;	/* filename      */
    int	    cpage;	/* page number   */
    int	    cline;	/* line number in page */
    int	    cfline;	/* line number in file */
    }
inc[MAXINCLNEST];

/* #if handling variables.  Arrays are indexed by iflevel. */
static
int iflevel,	/* #if-type command nesting level (0 = none) */
    flushing;		/* Set = iflevel when inside failing conditional */
static
int ifline[MAXIFLEVEL];	/* Line # that last if/elif/else was on */
static
int iffile[MAXIFLEVEL];	/* File # for ditto. 0 for current file, */
				/* -1 for expired file, N for inc[N-1] */
static
int iftype[MAXIFLEVEL];	/* iftype[lvl] set to one of the following: */
#define IN_ELSE	0		/* inside an #else, or nothing.  Must be 0 */
#define IN_IF	1		/* inside an #if */
#define IN_ELIF	2		/* inside an #elif */
static
char *ifname[] = { "else", "if", "elif" };	/* Indexed by iftype */


static
int indirp;	/* Set when handling a directive */
static
int inasm;	/* Set when inside assembly passthrough */

/* Pre-Processing TokenList definitions */
typedef struct		/* TokenList descriptor type */
    {
    PPTOK *tl_head;
    PPTOK *tl_tail;
    }
tlist_t;

static
PPTOK *pptptr = NULL;		/* Ptr to last allocated token */

static
PPTOK *pptoks = NULL;		/* Tokens allocated from pptoks */
static
PPTOK *pptmax = NULL;		/* Highest valid ptr */
 #define tokpcre() (++pptptr <= pptmax ? pptptr : (pptresize (), pptptr))
 #define pptreset() (pptptr = pptmax = pptoks = NULL) /* Flush all tokens, start over*/

 #ifndef MAXPOOLSIZE
 #define MAXPOOLSIZE 4000
 #endif



#define tokn2p(n) (n)		/* Return ptr, given next-ptr */
#define tokp2n(p) (p)		/* Return next-ptr, given ptr */
#define tlpinit(tl,p) ((tl).tl_head=(tl).tl_tail=(p))	/*Init w/ptr to tok */
#define tlzinit(tl) tlpinit(tl,0)		/* Init empty list */
#define tlpcur(tl) ((tl).tl_head)		/* Get ptr to 1st token */
#define tltcur(tl) (*tlpcur(tl))		/* Get 1st token */
#define tlppeek(tl) ((tl).tl_head->pt_nxt)	/* Ptr to next token */

#if 0	/* 8/91 shrink KCC */
#define tltpeek(tl) (*tlppeek(tl))		/* Peek at next token */
#endif

#define tlpskip(tl) ((tl).tl_head=tlppeek(tl))	/* Skip this token */

#define tlpadd(tl,p) (!(tl).tl_head \
	? tlpinit(tl,p) \
	: ((tl).tl_tail = (tl).tl_tail->pt_nxt = (p))) /* Add ptr at tail */
#define tltadd(tl,t) (*tlpadd(tl,tokpcre()) = (t))	/* Add tok at tail */
#define tlpins(tl,p) (((p)->pt_nxt = (tl).tl_head) == 0 \
	? tlpinit(tl,p) \
	: ((tl).tl_head = (p)))		/* Insert ptr at head of list */

#define tllapp(tl,il) ((tl).tl_tail->pt_nxt = tokp2n((il).tl_head), \
			(tl).tl_tail = (il).tl_tail)	/* Append list */

#if 0	/* 8/91 shrink KCC */
#define tllins(tl,il) ((il).tl_tail->pt_nxt = tokp2n((tl).tl_head), \
			(tl).tl_head = (il).tl_head)	/* Insert list */
#endif

/* Various TokenList declarations */
 /*
  * mltpush() moved down here where tlist_t is known... 
  */
static
tlist_t tlfrstr(char *),
       tlimake(INT, int), tlcopy(tlist_t), tlstrize(tlist_t);
static
char *tltostr(tlist_t, char *, int), *tltomac(tlist_t, char *);
static
PPTOK tokize(void);
static
void tlrawadd(tlist_t *), mtlpush(tlist_t);
static
void ppcqstr(char *), ppctstr(PPTOK *);
static
int pptfput(PPTOK *, FILE *);
static
void tkerr(char *, int);
static
tlist_t getlinetl(void), tlwspdel(tlist_t, int);
static
tlist_t asmrefill(void);
static
char *sltostr(PPTOK *, char *, int);


/* PP-Token char pool.  This is reset and the contents flushed whenever
** nextpp() is asked to read a new token at top level, by setting ppcptr NULL.
** Several handy macros are defined to use this pool.
**	ppcreset() - Resets pool, flushes all chars
**	ppcbeg() - Start depositing into pool, returns ptr to start
**	ppcput(c) - Put char into pool, returns c
**	ppclast() - Returns last char put into pool
**	ppclen() - Returns # chars deposited thus far
**	ppcend() - Ends deposit into pool, returns # chars
**			(invokes fatal error if overflowed)
**	ppcbackup() - Backs up over last char, can be used to undo ppcend().
**	ppcsave(st) - Saves state in "st" (type "ppcstate_t")
**	ppcrest(st) - Restores state from "st"
*/
static
char *ppcptr = NULL;	/* Ptr into ppcpool */
static
int ppcleft;		/* # chars left in ppcpool */
static
int ppcocnt;		/* Saved ppcleft for deriving string lens */
typedef struct		/* State struct for saving above vars */
    {
#if 0	/* 5/91 Dynamic tables */
    ptrdiff_t	    cptr;
    unsigned char   ppcsize;
#else
    char *cptr;
#endif
    int cleft;
    int cocnt;
    }
ppcstate_t;

#define ppcreset() (ppcptr = NULL)

#if 0	/* 5/91 Dynamic tables */
static
unsigned char ppcsize = 4;
static
char *ppcpool = NULL;
 #define ppcbeg() (!ppcptr? ((!ppcpool? ppcresize(): 0), ppcocnt=ppcleft=  \
     (ppcsize*DYN_SIZE - 1),(ppcptr=ppcpool)+1) : (ppcocnt=ppcleft, ppcptr+1))
 #define ppcput(c) ((--ppcleft > 0 ? 0 : ppcresize()), *++ppcptr = (c))
 #define ppcend() ((--ppcleft > 0 ? 0:ppcresize()), *++ppcptr = 0, ppclen()-1)
 #define ppcsave(st) \
	 (void)(st.cptr = ppcptr-ppcpool, st.cleft = ppcleft, \
	 st.cocnt = ppcocnt, st.ppcsize = ppcsize)
 #define ppcrest(st) \
	 (void)(ppcptr = (char *) ((ptrdiff_t) ppcpool + st.cptr), ppcleft = \
	 st.cleft + DYN_SIZE*(ppcsize-st.ppcsize), ppcocnt = st.cocnt)
#else
static
char ppcpool[MAXPOOLSIZE];
 #define ppcbeg() (!ppcptr?(ppcocnt=ppcleft=MAXPOOLSIZE-1,(ppcptr=ppcpool)+1)\
			: (ppcocnt=ppcleft, ppcptr+1))
 #define ppcput(c) (--ppcleft > 0 ? *++ppcptr = (c) : (c))
 #define ppcend() (--ppcleft > 0 ? (*++ppcptr = 0, ppclen()-1) : ppcresize())
 #define ppcsave(st)	\
	 (void)(st.cptr = ppcptr, st.cleft = ppcleft, st.cocnt = ppcocnt)
 #define ppcrest(st)	\
	 (void)(ppcptr = st.cptr, ppcleft = st.cleft, ppcocnt = st.cocnt)
#endif

#define ppclast() (*ppcptr)
#define ppclen() (ppcocnt - ppcleft)
#define ppcbackup() (++ppcleft, *--ppcptr)

static
tlist_t tlmake(/* int typ, union pptokval val */);
static
int ppcresize(void);
#if 0
static
int ppcresize();		/* Just invokes efatal(CPOOL) */
#endif

/* Raw Tokenizer variables - nextrawpp() */
static
int rawpp;		/* Current raw token type from nextrawpp() */
static
union pptokval rawval;	/* Current raw token value */
static
int rawpplen;		/* Length of token string, if any */
static
PPTOK *rawptr;		/* Ptr to current raw pptoken, if any */

/* Macro Tokenizer - nextmacpp() */
static
int mactlev = 0;		/* # levels nesting for nextmacpp() input */
static
tlist_t mactl;		/* Current tokenlist nextmacpp() is using */
static
tlist_t mactls[MAXMACNEST];	/* Stack of input tokenlists */

/* Cooked Tokenizer - nextpp()  (also declared by CCLEX.H)*/
extern
int curpp;		/* Current cooked token type from nextpp() */
extern
union pptokval curval;	/* Current cooked token value */
static
tlist_t curtl;		/* Current cooked token list, if any */
extern
PPTOK *curptr;		/* Ptr to current cooked pptoken, if any */
extern
SYMBOL *cursym;		/* Ptr to symbol, if token is T_IDENT */

/* Raw character input variables - nextch() */
static
int ch;			/* Current char awaiting tokenizer */
#define MAXBKSTRS (MAXINCLNEST+2)	/* Rough guess */
static
char *backstr = NULL;	/* If non-NULL, ptr to pushback string */
static
int bkstrlev = 0;	/* # of ptrs on saved pushback string stack */
static
char *bkstrs[MAXBKSTRS];

#define TCH_ESC '\305'		/* Input string escape char */
#define TCH_EOF 'E'		/* Input string EOF */


/* MACRO DETAILS:
**	A defined macro is stored in the symbol table as a symbol with
** class SC_MACRO.  It has no type and uses these components:
**	Smacptr	- char pointer to the macro body (allocated by calloc)
**	Smacnpar - # of params/arguments (or special value)
**	Smacparlen - # chars at start of body that are actually param names.
**	Smaclen - total # chars in macro body string, not counting final NUL.
** The value of Smacnpar has the following meanings:
**	>= 0	# of arguments in argument list.  0 = mac(), 1 = mac(a), etc.
**	< 0	Special value, one of:
*/
#define MACF_ATOM (-1)	/* Normal atomic, no argument list (i.e. "mac") */
#define MACF_DEFD (-2)	/* "defined" operator.  No body. */
#define MACF_LINE (-3)	/* "__LINE__" macro.  No body. */
#define MACF_FILE (-4)	/* "__FILE__" macro.  No body. */
#define MACF_DATE (-5)	/* "__DATE__" macro.  No body. */
#define MACF_TIME (-6)	/* "__TIME__" macro.  No body. */
#define MACF_STDC (-7)	/* "__STDC__" macro.  No body. */
#define MACF_KCC  (-8)	/* "__COMPILER_KCC__" macro.  No body. */
#define MACF_SYMF (-9)	/* "_KCCsymfnd("file","sym")" macro. No body. */
#define MACF_SYMV (-10)	/* "_KCCsymval("file","sym")" macro. No body. */

#if __MSDOS__ /* KAR-8/92, Add predefined macro __KCCDOS__ if KCCDOS */
#define MACF_DOS  (-11) /* "__KCCDOS__ macro. No body. evals to 1;only if KCCDOS */
#endif
/* All special macros other than MACF_ATOM cannot be redefined or
** undefined except by the command-line -U or -D switches.
*/

/* MACRO BODY FORMAT:
**
** Smacptr (if not null) points to the macro body, which consists of
** the tokenized text of the macro, perhaps prefixed by parameter names.
**	Smacptr ->  <"Smacparlen" chars of param-names>
**		    <tokenized text, see below>
**
** The parameter names are only checked during redefinition of a macro
** to see whether the new macro's params have the same spelling (CHOKE BLETCH).
**
** The text is entirely tokenized.  The first char of each token is the
** token type value, such as T_WSP or T_IDENT.  Following chars depend
** entirely on the token type.  There are currently three general types:
**	Simple token: just one char of token type and nothing else.
**	String token: token type is followed by the chars of the string, ending
**		with a zero byte.
**	Param token: the char after the token type is an encoded macro
**		parameter # -- see MAC_ARGOFF.
**
** In all cases, the next char after any of the above begins another token.
** A zero token marks the end of the macro body; this and not Smaclen is
** normally used to stop a scan.  This zero token is not included in the
** Smaclen count.
*/
#define MAC_ARGOFF '0'	/* Number to encode param # with */


/* Macro Frame definitions */
struct macframe
    {
    SYMBOL *mf_sym;		/* Pointer to macro symbol def */
    int mf_nargs;		/* # args we have */
    int mf_parlen;		/* # chars in param name prefix (bletch) */
    int mf_len;		/* # chars total in macro body string */
    char *mf_body;		/* Ptr to body of macro def */
    union
	{
	tlist_t mfp_tls[MAXMARG];	/* Argument token lists (for expand) */
	char *  mfp_cps[MAXMARG];	/* Parameter name strs (for define) */
	}
    mf_p;

#if 0	/* 8/91 shrink KCC */
    int mf_used[MAXMARG];	/* # times each arg is invoked */
#endif
    };
#define mf_argtl mf_p.mfp_tls
#define mf_parcp mf_p.mfp_cps

#if 0
static
nhidemacs = 0;		/* # macros in hideset */
#endif
static
SYMBOL *hidemacs[MAXMACNEST];	/* Used by hspush() and mishid() */

static
int maclevel;	/* Macro expansion level (used???) */

static
char defcdmy;			/* Needed if not using "define" */
static
char *defcsname = &defcdmy;	/* Ptr to "defined" macro sym name */

static
int tadset;		/* True if date/time strings are set */
static
char datestr[14] = "\"Jun 07 1989\"";	/* __DATE__ string */
static
char timestr[11] = "\"01:23:45\"";	/* __TIME__ string */


static
SYMBOL *mdefstr(char *, int, char *),
	     *mdefsym(char *, struct macframe
*);
static
int     mexptop(SYMBOL *, int), margs(tlist_t *, int, int);
static
tlist_t mexpand(tlist_t, int), mexplim(tlist_t, int),
	      mexpsym(SYMBOL *, int), msubst(struct macframe
*, int);
static
void mpaste(tlist_t, int, int);
static
int     hspush(SYMBOL *, int), tkhide(PPTOK *, int),
	      mishid(SYMBOL *, int);
static
int mdefinp(struct macframe
*mf);

#if DEBUG_PP
static
int debpp = 1;
static
FILE *fpp = stderr;
static
int debppt = 1;
static
void pmacframe(char *, struct macframe
*),
	  pmactl(char *, tlist_t, int),
	  tlfput(tlist_t, FILE *, int),
	  tkfput(PPTOK *, FILE *, int);
static
char *plevindent(void);
static
char *tkids(PPTOK *);
 #if 0
static
void pmacframe(), pmactl(), tlfput(), tkfput();

⌨️ 快捷键说明

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