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