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