Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/old/kcc/ccinp.c
There are 6 other files named ccinp.c in the archive. Click here to see a list.
/* <KCC.CC>CCINP.C.60, 27-Jun-85 17:20:49, Edit by KRONJ */
/* Don't pass \n after #x through to input */
/* <KCC.CC>CCINP.C.58, 27-Jun-85 10:09:50, Edit by KRONJ */
/* Set firstime variously to be careful of %$ in ident */
/* <KCC.CC>CCINP.C.57, 27-Jun-85 10:06:14, Edit by KRONJ */
/* Always close input file (even if main source) on eof */
/* <KCC.CC>CCINP.C.55, 25-Jun-85 10:39:33, Edit by KRONJ */
/* No complaints when redefining already-defined macro */
/* Rework macro defs not to use string pool (runs out for monsym.h) */
/* <KCC.CC>CCINP.C.50, 18-Jun-85 10:46:46, Edit by KRONJ */
/* Fancy comment handling for #asm */
/* <KCC.CC>CCINP.C.48, 13-Jun-85 14:01:40, Edit by KRONJ */
/* #asm and #endasm */
/* <KCC.CC>CCINP.C.39, 4-Jun-85 11:18:49, Edit by KRONJ */
/* Support -I */
/* <KCC.CC>CCINP.C.37, 3-Jun-85 15:51:07, Edit by KRONJ */
/* Support -D */
/* <KCC.CC>CCINP.C.36, 21-May-85 15:40:13, Edit by KRONJ */
/* #undef when symbol not known is not an error */
/* <KCC.CC>CCINP.C.32, 9-Mar-85 15:37:32, Edit by KRONJ */
/* Don't loop forever on unclosed comment */
/* <KCC.CC>CCINP.C.31, 4-Mar-85 02:44:43, Edit by SATZ */
/* Make some constants bigger. 32 => _STRSIZ */
/* <KCC.CC>CCINP.C.30, 27-Feb-85 19:44:07, Edit by SATZ */
/* Make sure user sees a warning for doubly defined macros */
/* <KCC.CC>CCINP.C.29, 27-Feb-85 11:17:16, Edit by SATZ */
/* Make sure #define, #undef, and #if[n]def use macro arguments */
/* <KCC.CC>CCINP.C.26, 20-Feb-85 23:55:01, Edit by SATZ */
/* Make sure all include files get closed upon EOF */
/* <KCC.CC>CCINP.C.25, 18-Feb-85 12:35:33, Edit by SATZ */
/* check for eof while flushing lines between #ifdef */
/* <KCC.CC>CCINP.C.25, 18-Feb-85 11:45:36, Edit by SATZ */
/* Check for unmatching #endif */
/* <KCC.CC>CCINP.C.23, 17-Feb-85 11:45:31, Edit by SATZ */
/* Make #include "foo.h" not print C:foo.h on error (or C:C:foo.h) */
/* and make missing include files warnings not errors */
/* <KCC.CC>CCINP.C.22, 29-Jan-85 20:50:09, Edit by SATZ */
/* #if expr was eating \n which caused the next line to be skiped */
/* <KCC.CC>CCINP.C.21, 29-Jan-85 19:31:06, Edit by SATZ */
/* Don't complain if argument to #undef is already undefined */
/* <KCC.CC>CCINP.C.20, 8-Jan-85 01:04:38, Edit by SATZ */
/* fix undefine(); it always returned the error EIDENT */
/* <KCC.CC>CCINP.C.18, 3-Jan-85 12:36:39, Edit by SATZ */
/* make sure #define handles comments by calling nextcc() */
/* <KCC.CC>CCINP.C.16, 3-Jan-85 00:13:39, Edit by SATZ */
/* make skipblanks() call nextcc() */
/* <KCC.CC>CCINP.C.15, 2-Jan-85 23:35:06, Edit by SATZ */
/* fix up calling conventions for nextcc() */
/* <KCC.CC>CCINP.C.14, 2-Jan-85 23:20:16, Edit by SATZ */
/* break out comment processing in nextc() to nextcc() so it */
/* can be used by other routines */
/* SCORE:<KCC.CC>CCINP.C.12, 17-Aug-84 15:19:09, Edit by KRONJ */
/* try looking in C: for included files if not in DSK: */
/* SCORE:<KCC.CC>CCINP.C.2, 3-Aug-84 12:53:42, Edit by KRONJ */
/* comment processing moves here */
/* SCORE:<KCC.CC>CC3.C.12, 29-Jun-84 15:38:59, Edit by KRONJ */
/* fix #else */
/* cc3.c -- Preprocessor (C) 1981 K. Chen */
#include "cc.h"
struct SYMBOL *findasym();
/* ------------------------------------------------------- */
/* get next character without comment processing */
/* ------------------------------------------------------- */
_nextc()
{
int i;
/* first, try for macro handling */
if (maclevel) { /* are we expanding macros? */
if (i = *macptr++) { /* yes, are there more chars? */
if (i >= 7) return ch = i; /* yes, not arg char, just return */
mac[maclevel].mptr = macptr; /* is arg, push pointer */
macptr = mac[maclevel++].marg[i-1]; /* push to arg */
return _nextc(); /* and try for a new char */
}
if (--maclevel) macptr = mac[maclevel].mptr; /* end of macro, pop */
return _nextc(); /* and try for a new char */
}
/* not in a macro, just normal char */
switch (i = getc(in)) {
case EOF: /* end of file on input */
fclose(in); /* make sure we close it */
if (level-- > 0) { /* drop level. do we have more? */
in = inc[level].cptr; /* yes, set vars from popped level */
line = inc[level].cline;
page = inc[level].cpage;
strcpy(input, inc[level].cname);
ch = '\n';
erptr = errlin;
*erptr = 0;
return _nextc(); /* try for another char */
}
eof = 1; /* end of file at top level. */
return ch = 0;
case '\\':
*erptr++ = i; /* add to line */
i = ifflag; /* get conditional flag */
ifflag = 0; /* not during this */
_nextc(); /* get another char */
ifflag = i; /* now we can set one line flag back */
if (ch == '\n') return _nextc(); /* back eol is nothing */
pushc(ch); /* otherwise put char back */
return ch = '\\'; /* and return backslash */
case '\n':
line++; /* new line, same page */
tline++;
*erptr = 0; /* terminate old line */
erptr = errlin; /* start at beginning of line */
if (ifflag) {
ifflag = 0; /* in const expr, return from it */
ungetc(i, in); /* put it back for flushline etc. */
return ch = ';'; /* with a semicolon */
}
break;
case 014:
line = 1; /* first line of */
page++; /* new page */
*erptr = 0; /* terminate old line */
erptr = errlin; /* start at beginning of line */
break;
default:
*erptr++ = i;
}
return ch = i;
}
/* ---------------------------------------------- */
/* get next character from input source */
/* ---------------------------------------------- */
nextc()
{
static macdepth = 0; /* level of recursion */
if (ch != '\n') _nextc();
else if (_nextc() == '#') {
macdepth++;
preprocess(); /* process preprocessor directive */
if (--macdepth == 0) return nextc(); /* top level, don't pass \n */
return ch = '\n'; /* recursive, don't lose next char */
}
return nextcc(); /* handle comment processing */
}
/* -------------------------------------------------- */
/* get next character but handle comments */
/* must be primed with _nextc() */
/* -------------------------------------------------- */
nextcc()
{
if (ch != '/') return ch; /* not slash, normal char */
if (_nextc() != '*') { /* is it comment? */
pushc(ch); /* no, put it back */
return ch = '/'; /* get slash again */
}
_nextc(); /* skip over star */
if (!keepcmts || (!prepf && !inasm)) { /* simple fast comment skip */
while (1) {
if (ch != '*') _nextc(); /* find a star */
else if (_nextc() == '/') break; /* and a slash to terminate */
if (eof) fatal (EEOF); /* break out of infinite loop */
}
} else if (prepf) { /* comment skip for -E */
fputs ("/*", stdout); /* pass comment start */
while (1) { /* until we break */
putc (ch, stdout); /* send char off */
if (ch != '*') _nextc(); /* find a star */
else if (_nextc() == '/') break; /* and a slash to terminate */
if (eof) fatal (EEOF); /* break out of infinite loop */
}
putc ('/', stdout); /* finish -E comments */
} else if (ch == '\n') { /* multi-line #asm comment */
fputs ("\n\tCOMMENT \\", out); /* start it */
while (1) { /* until we break */
if (ch != '*') {
if (ch != '\\') putc (ch, out);
_nextc();
} else {
if (_nextc() == '/') break;
putc ('*', out);
}
if (eof) fatal (EEOF);
}
fputs ("\t\\\n", out); /* finish it */
} else { /* comment skip for #asm */
putc (';', out); /* start it */
while (1) { /* until we break */
if (ch != '*') {
putc (ch, out); /* send comment char */
if (ch == '\n') putc (';', out); /* continue comment */
_nextc();
} else {
if (_nextc() == '/') break; /* star slash exits */
putc ('*', out); /* otherwise pass star */
}
if (eof) fatal (EEOF);
}
if (nextc() != '\n') putc ('\n', out); /* if not end of line */
return ch; /* then have to terminate here */
}
return nextc(); /* go get another char after comment */
}
/* ----------------------------------------------------- */
/* push a character back into the input source */
/* ----------------------------------------------------- */
pushc(c)
{
if (c == '\n') {
line--; /* dont lose track of line count */
tline--;
} else erptr--; /* back over char in error line */
if (maclevel) macptr--; /* macro input, back up over it */
else ungetc(c, in); /* file input, back up over that */
}
/* ------------------------------- */
/* service a # statement */
/* ------------------------------- */
preprocess()
{
char s[_STRSIZ];
_nextc(); nextcc(); skipblanks(); /* skip # and spaces and comments */
if (ch == '\n') return; /* ignore if nothing else on line */
if (map[ch] != IDENT) { /* complain if not identifier */
error(EIDENT);
flushline(ch);
} else {
switch (getstring(s)) { /* read in the ident, check length */
case 2:
if (!strcmp(s,"if")) cif();
else error(EMACRO, s);
break;
case 3:
if (!strcmp(s,"asm")) asm();
else error(EMACRO, s);
break;
case 4:
if (!strcmp(s,"else")) celse();
else if (!strcmp(s,"line")) cline();
else error(EMACRO, s);
break;
case 5:
if (!strcmp(s,"endif")) cendif();
else if (!strcmp(s,"ifdef")) cifdef(0);
else if (strcmp(s,"undef")) error(EMACRO, s);
else if (!flushing) undefine();
break;
case 6:
if (!strcmp(s,"ifndef")) cifdef(1);
else if (!strcmp(s,"endasm")) endasm();
else if (strcmp(s,"define")) error(EMACRO, s);
else if (!flushing) define();
break;
case 7:
if (strcmp(s,"include")) error(EMACRO, s);
else if (!flushing) include();
break;
default:
error(EMACRO, s);
}
flushline(ch);
}
}
/*
** Process implicit #define requested by -D
*/
pdefine()
{
int i, reeq;
char *cp;
struct SYMBOL *creatsym(), *sym;
for (i = 0; i < npredef; i++) {
/*
** Map through the -D arguments, defining each to the given string.
** First we find the identifier and what to define it to.
*/
cp = predefs[i]; /* get this -D string */
reeq = 0; /* assume no def string */
if (map[*cp] != IDENT) fatal (EPREDEF, cp); /* must be an ident */
do cp++; while (map[*cp] == IDENT || map[*cp] == CONST);
if (*cp == '\0') cp = "1"; /* -D without =, use 1 */
else if (*cp != '=') fatal (EPREDEF, predefs[i]);
else {
*cp++ = '\0'; /* terminate and move on */
reeq = 1; /* have to put = back later */
}
/*
** Now the identifier is null-terminated in predefs[i], and we
** have the definition for it pointed to by cp.
** Add the symbol as a macro to the symbol table.
*/
sym = creatsym(predefs[i]); /* make new symbol */
sym->smptr = cp; /* base of def is new string */
sym->sclass = SMACRO; /* this symbol is now a macro */
sym->svalue = 0; /* with no args */
if (reeq) *--cp = '='; /* maybe put back equal sign */
}
}
/* ----------------------- */
/* #define macro */
/* ----------------------- */
define()
{
int i, nargs;
struct SYMBOL *creatsym(), *sym;
char *defptr, defch, *args[MAXMARG], defstr[MAXMAC], *malloc();
nextcc();
skipblanks();
if (map[ch] != IDENT) {
error(EIDENT);
return;
}
getstring (defstr); /* read macro name */
if ((sym = findasym (defstr, SMACRO)) == NULL) sym = creatsym (defstr);
sym->sclass = SMACRO; /* this symbol is now a macro */
sym->svalue = 0; /* with no args yet */
defptr = defstr; /* point to start of string */
/* look for arguments */
nargs = 0;
if (ch == '(') {
while (1) {
_nextc(); nextcc(); skipblanks();
if (ch == ')') {
nargs = -1; /* mac() */
break;
}
if (map[ch] != IDENT) { /* unexpected strange char */
nargs = 0;
error (EARG);
break;
}
if (nargs == MAXMARG - 1) error (EBIGMAC, "args", sym->sname);
else args[nargs++] = defptr; /* remember position */
getstring (defptr); /* read in arg name */
while (*defptr++ != '\0') ; /* skip past null at end */
nextcc(); skipblanks();
if (ch != ',') break;
}
if (ch != ')') error (EARGEND);
else _nextc();
}
sym->svalue = nargs; /* remember number of args */
sym->smptr = defptr; /* and string start */
/* arguments read, now read body of macro */
nextcc(); skipblanks();
while (!eof && ch != '\n') {
if (nargs && map[ch] == IDENT) { /* ident that can be an arg? */
getstring (defptr); /* yes, read in rest of identifier */
for (i = 0; i < nargs && strcmp (args[i], defptr) != 0; i++) ;
if (i < nargs) *defptr++ = i + 1; /* found arg, use its number */
else while (*defptr != '\0') defptr++; /* no match, use ident */
} else {
*defptr++ = ch;
_nextc();
nextcc();
}
}
*defptr = '\0';
/*
** Now defptr points to the null at the end of the string, and sym->smptr
** points to the beginning of the string, but they both point to defstr
** which is on the stack. We need to rearrange these to point to allocated
** memory instead.
**
** We take this opportunity to make sure we haven't overflowed defstr.
** It will still work if we have, we will merely run off the end of the
** stack. But if we go too far we could hit code...
*/
if (defptr >= defstr + MAXMAC) error (EBIGMAC, "chars", sym->sname);
defptr = malloc (defptr - sym->smptr + 1); /* get space */
if (defptr == NULL) fatal (EOUTMEM); /* make sure we got it */
strcpy (defptr, sym->smptr); /* put macro text there */
sym->smptr = defptr; /* save as macro expansion */
}
/*
** #asm and #endasm
**
** #asm passes text through to the FAIL file until ended by a #endasm.
** Maybe someday this will be useful inside functions.
*/
static asm()
{
flushline (ch); /* ignore rest of line */
if (flushing) return; /* inside failing #ifdef, stop now */
if (inasm++) error (EASMNEST); /* bump level. if nested, complain */
else if (prepf) fputs ("#asm", stdout); /* -E, pass #asm through */
else { /* none of above, normal #asm */
codeseg(); /* make sure set up for code gen */
passthru (out); /* pass text through until #endasm */
}
}
static endasm()
{
flushline (ch); /* ignore rest of line */
if (flushing) return; /* inside failing #ifdef, stop now */
if (inasm == 0) error (EASMEND); /* not inside #asm, complain */
else {
if (prepf) fputs ("#endasm", stdout); /* -E, pass #endasm through */
inasm--; /* normal #asm, tell it to stop */
}
}
/*
** Pass through text to file
** Used by #asm and by -E
*/
passthru (fd)
FILE *fd;
{
char qc;
firstime = 1; /* never treat %$ as part of ident */
/* skip newlines (from definition files with -E) */
while ((prepf || inasm) && nextc() == '\n') ;
/* now pass rest through to output */
while (prepf || inasm) switch (map[ch]) {
case EOF:
if (eof) return;
case IDENT:
if (getident() != 0) fputs (ident, fd); /* handle ident or macro */
break; /* next char could be quote, loop */
/*
** Semicolon is special for assembly language.
** If -C is lit, we pass it through.
** Otherwise, we remove it and the rest of the line.
*/
case SCOLON:
if (inasm && !keepcmts) while (_nextc() != '\n') ; /* ignore to eol */
putc (ch, fd); /* add semicolon or end of line */
nextc(); /* move on in input */
break; /* go back for another char */
/*
** Pass through string constant. This needs special handling because
** we don't want to fold out comments. Note that character constants
** (map[ch] == SQUOTE) should not be handled this way, because we only
** want to have one char in them (and therefore they aren't going to have
** imbedded comments) and because we want apostrophes in assembly comments
** to work.
*/
case DQUOTE: /* quoted string and */
do {
if (eof) fatal (EEOF); /* don't run off end of file */
putc (ch, fd); /* send start quote or text */
if (ch == '\\') putc (_nextc(), fd); /* handle backslash */
} while (map[_nextc()] != DQUOTE); /* until string const through */
default: /* then fall through with it to... */
putc (ch, fd); /* send normal char or close quote */
nextc(); /* move on to next char from file */
}
}
/* ---------------------- */
/* #ifdef macro */
/* ---------------------- */
cifdef(doit)
{
char s[_STRSIZ]; /* buffer for char names */
struct SYMBOL *sym; /* symbol that was looked up */
iflevel++; /* this is a new if level */
if (flushing) return; /* if in false condition, that's all */
skipblanks(); /* skip over blanks */
if (map[ch] == IDENT) {
getstring(s);
if (doit == ((sym=findasym(s, SMACRO)) == NULL))
return; /* good condition, return */
} else error (EIDENT);
flushing = iflevel; /* set level */
do flushline(nextc()); /* flush lines */
while (flushing && !eof); /* until done */
}
/* ------------------- */
/* #if macro */
/* ------------------- */
cif()
{
int yes;
iflevel++; /* this is a new if level */
if (flushing) return; /* flushing means that's all */
ifflag = 1; /* we only want one line */
nextoken(); /* start up token parser again */
yes = pconst(); /* parse constant expression */
if (ifflag) {
error(ECONST); /* complain constant needed */
ifflag = 0;
yes = 0;
}
if (yes) return; /* if ok, return now */
flushing = iflevel; /* not ok, set flushing */
do flushline(nextc()); /* and flush lines */
while (flushing); /* until done */
}
/* ---------------------- */
/* #else macro */
/* ---------------------- */
celse()
{
if (flushing == iflevel) flushing = 0; /* stop flushing */
else if (flushing == 0) { /* start flushing */
flushing = iflevel; /* (note we can have more than */
do flushline(nextc()); /* one #else, and they will */
while (flushing); /* each toggle flushing). */
}
}
/* ---------------------- */
/* #endif macro */
/* ---------------------- */
cendif()
{
if (iflevel) { /* have we seen #if or #ifdef yet? */
if (iflevel == flushing) flushing = 0; /* stop flushing */
iflevel--; /* drop a level */
} else
error(EENDIF);
}
/* ------------------------ */
/* #include macro */
/* ------------------------ */
include()
{
char f[_FILSIZ], f2[_FILSIZ];
FILE *fp, *fopen();
skipblanks();
getfile(f);
fp = fopen(f, "r");
if (fp == NULL) { /* unsuccessful open */
strcpy (f2, usrincludes); /* get prefix */
strcat (f2, f); /* add file name */
if ((fp = fopen(f2, "r")) == NULL) {
strcpy (f2, sprefix); /* still no go, try include dir */
strcat (f2, f);
strcat (f2, spstfix);
if ((fp = fopen(f2, "r")) == NULL) {
error (EFILE, f); /* not there either, complain */
return; /* and give up */
}
}
}
strcpy(inc[level].cname, input); /* save old context */
inc[level].cptr = in;
inc[level].cline = line;
inc[level].cpage = page;
level++; /* create new context */
strcpy(input, f); /* remember file name */
in = fp; /* this is current input stream */
line = 1;
page = 1;
}
/* --------------------- */
/* #line macro */
/* --------------------- */
cline()
{
char *s;
nextoken();
if (token != CONST || constant.ctype->ttype != INT) error(ECONST);
else {
line = constant.cvalue - 1; /* get line number */
skipblanks();
if (ch != '\n') getfile(input);
}
}
/* ------------------------- */
/* #undefine macro */
/* ------------------------- */
undefine()
{
char s[_STRSIZ];
struct SYMBOL *sym;
nextcc();
skipblanks();
if (map[ch] == IDENT) {
getstring(s);
if ((sym=findasym(s, SMACRO)))
freesym(sym); /* found it, so flush it */
} else
error(EIDENT);
}
/* ----------------------------------------------- */
/* flushes input until the next \n or EOF */
/* ----------------------------------------------- */
flushline(i)
{
if (i <= 0) i = 1;
ch = i;
while (ch > 0 && ch != '\n') _nextc();
}
/* --------------------------------------- */
/* get a string from input source */
/* --------------------------------------- */
getstring(s)
string s;
{
int n;
*s = ch; /* first char always goes in */
n = 1; /* count it */
while (1) {
switch (map[_nextc()]) { /* if succeeding char is alphanum */
case IDENT:
case CONST:
*++s = ch; /* then it goes in too */
n++; /* and gets counted */
continue;
}
break; /* not part of ident, break out */
}
*++s = '\0'; /* null terminate */
return n; /* return number of chars in string */
}
/* ------------------------------ */
/* skip blanks and tabs */
/* ------------------------------ */
skipblanks()
{
while (ch == ' ' || ch == '\t') {
_nextc();
nextcc();
}
}
/* ------------------------ */
/* unexpected eof */
/* ------------------------ */
earlyend()
{
fatal(EEOF);
}
/* ---------------------------------------- */
/* read file name as for #include */
/* ---------------------------------------- */
getfile(f)
char *f;
{
char *s, *t;
s = f; /* copy pointer */
switch (ch) {
case '"':
_nextc();
while (ch != '"') {
if (ch == '\n' || eof) {
if (eof) earlyend();
error(EXFILE, f);
return;
}
*s++ = ch;
_nextc();
}
break;
case '<':
t = sprefix;
while (*t) *s++ = *t++;
_nextc();
while (ch != '>') {
if (ch == '\n' || eof) {
error(EXFILE, f);
return;
}
*s++ = ch;
_nextc();
}
t = spstfix;
while (*t) *s++ = *t++;
break;
default:
if (eof) earlyend();
else error(EXFILE);
}
*s = 0;
flushline(ch);
}