📄 ccpp.c
字号:
/* 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 + -