home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource4
/
243_01
/
cpp2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-14
|
21KB
|
644 lines
/*
* C P P 2 . C
*
* Process #control lines
*
* Edit history
* 13-Nov-84 MM Split from cpp1.c
* 06-Jun-85 KR fixed #include bug in doinclude()
*/
#include "cppdef.h"
#include "cpp.h"
FILE_LOCAL int openinclude();
FILE_LOCAL void doinclude();
FILE_LOCAL void doif();
#if HOST == SYS_VMS
/*
* Include the rms stuff. (We can't just include rms.h as it uses the
* VaxC-specific library include syntax that Decus CPP doesn't support.
* By including things by hand, we can CPP ourself.)
*/
#include <nam.h>
#include <fab.h>
#include <rab.h>
#include <rmsdef.h>
#endif
/*
* Generate (by hand-inspection) a set of unique values for each control
* operator. Note that this is not guaranteed to work for non-Ascii
* machines. CPP won't compile if there are hash conflicts.
*/
#define L_assert ('a' + ('s' << 1))
#define L_define ('d' + ('f' << 1))
#define L_elif ('e' + ('i' << 1))
#define L_else ('e' + ('s' << 1))
#define L_endif ('e' + ('d' << 1))
#define L_if ('i' + (EOS << 1))
#define L_ifdef ('i' + ('d' << 1))
#define L_ifndef ('i' + ('n' << 1))
#define L_include ('i' + ('c' << 1))
#define L_line ('l' + ('n' << 1))
#define L_nogood (EOS + (EOS << 1)) /* To catch #i */
#define L_pragma ('p' + ('a' << 1))
#define L_undef ('u' + ('d' << 1))
#if DEBUG
#define L_debug ('d' + ('b' << 1)) /* #debug */
#endif
int
control(counter)
int counter; /* Pending newline counter */
/*
* Process #control lines. Simple commands are processed inline,
* while complex commands have their own subroutines.
*
* The counter is used to force out a newline before #line, and
* #pragma commands. This prevents these commands from ending up at
* the end of the previous line if cpp is invoked with the -C option.
*/
{
register int c;
register char *tp;
register int hash;
char *ep;
c = skipws();
if (c == '\n' || c == EOF_CHAR)
return (counter + 1);
if (!isdigit(c))
scanid(c); /* Get #word to token[] */
else {
unget(); /* Hack -- allow #123 as a */
strcpy(token, "line"); /* synonym for #line 123 */
}
hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
switch (hash) {
case L_assert: tp = "assert"; break;
case L_define: tp = "define"; break;
case L_elif: tp = "elif"; break;
case L_else: tp = "else"; break;
case L_endif: tp = "endif"; break;
case L_if: tp = "if"; break;
case L_ifdef: tp = "ifdef"; break;
case L_ifndef: tp = "ifndef"; break;
case L_include: tp = "include"; break;
case L_line: tp = "line"; break;
case L_pragma: tp = "pragma"; break;
case L_undef: tp = "undef"; break;
#if DEBUG
case L_debug: tp = "debug"; break;
#endif
default: hash = L_nogood;
case L_nogood: tp = ""; break;
}
if (!streq(tp, token))
hash = L_nogood;
/*
* hash is set to a unique value corresponding to the
* control keyword (or L_nogood if we think it's nonsense).
*/
if (infile->fp == NULL)
cwarn("Control line \"%s\" within macro expansion", token);
if (!compiling) { /* Not compiling now */
switch (hash) {
case L_if: /* These can't turn */
case L_ifdef: /* compilation on, but */
case L_ifndef: /* we must nest #if's */
if (++ifptr >= &ifstack[BLK_NEST])
goto if_nest_err;
*ifptr = 0; /* !WAS_COMPILING */
case L_line: /* Many */
/*
* Are pragma's always processed?
*/
case L_pragma: /* options */
case L_include: /* are uninteresting */
case L_define: /* if we */
case L_undef: /* aren't */
case L_assert: /* compiling. */
dump_line: skipnl(); /* Ignore rest of line */
return (counter + 1);
}
}
/*
* Make sure that #line and #pragma are output on a fresh line.
*/
if (counter > 0 && (hash == L_line || hash == L_pragma)) {
putchar('\n');
counter--;
}
switch (hash) {
case L_line:
/*
* Parse the line to update the line number and "progname"
* field and line number for the next input line.
* Set wrongline to force it out later.
*/
c = skipws();
workp = work; /* Save name in work */
while (c != '\n' && c != EOF_CHAR) {
save(c);
c = get();
}
unget();
save(EOS);
/*
* Split #line argument into <line-number> and <name>
* We subtract 1 as we want the number of the next line.
*/
line = atoi(work) - 1; /* Reset line number */
for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
; /* Skip over digits */
if (*tp != EOS) { /* Got a filename, so: */
if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
tp++; /* Skip over left quote */
*ep = EOS; /* And ignore right one */
}
if (infile->progname != NULL) /* Give up the old name */
free(infile->progname); /* if it's allocated. */
infile->progname = savestring(tp);
}
wrongline = TRUE; /* Force output later */
break;
case L_include:
doinclude();
break;
case L_define:
dodefine();
break;
case L_undef:
doundef();
break;
case L_else:
if (ifptr == &ifstack[0])
goto nest_err;
else if ((*ifptr & ELSE_SEEN) != 0)
goto else_seen_err;
*ifptr |= ELSE_SEEN;
if ((*ifptr & WAS_COMPILING) != 0) {
if (compiling || (*ifptr & TRUE_SEEN) != 0)
compiling = FALSE;
else {
compiling = TRUE;
}
}
break;
case L_elif:
if (ifptr == &ifstack[0])
goto nest_err;
else if ((*ifptr & ELSE_SEEN) != 0) {
else_seen_err: cerror("#%s may not follow #else", token);
goto dump_line;
}
if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
compiling = FALSE; /* Done compiling stuff */
goto dump_line; /* Skip this clause */
}
doif(L_if);
break;
case L_if:
case L_ifdef:
case L_ifndef:
if (