📄 ncpp.c
字号:
goto syntax;
np = InstallToken(trp->tp);
np->flag |= ISDEFINED;
trp->tp += 1;
if (trp->tp >= trp->lp || trp->tp->type == END) {
np->vp = &onetr;
return np;
}
if (trp->tp->type != ASGN)
goto syntax;
trp->tp += 1;
if ((trp->lp - 1)->type == END)
trp->lp -= 1;
np->vp = normtokenrow(trp);
return np;
syntax:
error(CPPFATAL, StrTab[151], trp); // <Illegal -D or -U argument %r>
return NULL;
}
/*
* Do macro expansion in a row of tokens.
* Flag is NULL if more input can be gathered.
*/
static void expandrow(Tokenrow * trp, unsigned char *flag)
{
Token *tp;
Nlist *np;
if (flag)
setsource(flag, -1, "");
for (tp = trp->tp; tp < trp->lp;) {
if (tp->type != NAME
|| quicklook(tp->t[0], tp->len > 1 ? tp->t[1] : 0) == 0
|| (np = cpplookup(tp)) == NULL
|| (np->flag & (ISDEFINED | ISMAC)) == 0
|| tp->hideset && checkhideset(tp->hideset, np)) {
tp++;
continue;
}
trp->tp = tp;
if (np->val == KDEFINED) {
tp->type = DEFINED;
if ((tp + 1) < trp->lp && (tp + 1)->type == NAME)
(tp + 1)->type = NAME1;
else if ((tp + 3) < trp->lp && (tp + 1)->type == LP
&& (tp + 2)->type == NAME && (tp + 3)->type == RP)
(tp + 2)->type = NAME1;
else
error(CPPERROR, StrTab[152]); // <Incorrect syntax for 'defined'>
tp++;
continue;
}
if (np->flag & ISMAC) {
#ifndef LRC
if (trp->tp->len == 10 && trp->tp->t[2] == 'd') {
dodeclspec(trp);
expand(trp, np);
}
else
#endif
builtin(trp, np->val);
}
else {
expand(trp, np);
}
tp = trp->tp;
}
if (flag)
unsetsource();
}
/*
* Expand the macro whose name is np, at token trp->tp, in the tokenrow.
* Return trp->tp at the first token next to be expanded
* (ordinarily the beginning of the expansion)
*/
static void expand(Tokenrow * trp, Nlist * np)
{
Tokenrow ntr;
int ntokc, narg, i;
Token *tp;
Tokenrow *atr[NARG + 1];
int hs;
copytokenrow(&ntr, np->vp); /* copy macro value */
np->flag |= ISUSED;
if (np->ap == NULL) /* parameterless */
ntokc = 1;
else {
ntokc = gatherargs(trp, atr, &narg);
if (narg < 0) { /* not actually a call (no '(') */
trp->tp += 1;
return;
}
if (narg != rowlen(np->ap)) {
error(CPPERROR, StrTab[153]); // <Disagreement in number of macro arguments>
trp->tp->hideset = (unsigned short) newhideset(trp->tp->hideset, np);
trp->tp += ntokc;
return;
}
substargs(np, &ntr, atr); /* put args into replacement */
for (i = 0; i < narg; i++) {
dofree(atr[i]->bp);
dofree(atr[i]);
}
}
doconcat(&ntr); /* execute ## operators */
hs = newhideset(trp->tp->hideset, np);
for (tp = ntr.bp; tp < ntr.lp; tp++) { /* distribute hidesets */
if (tp->type == NAME) {
if (tp->hideset == 0)
tp->hideset = (unsigned short) hs;
else
tp->hideset = (unsigned short) unionhideset(tp->hideset, hs);
}
}
ntr.tp = ntr.bp;
insertrow(trp, ntokc, &ntr);
trp->tp -= rowlen(&ntr);
dofree(ntr.bp);
return;
}
/*
* Gather an arglist, starting in trp with tp pointing at the macro name.
* Return total number of tokens passed, stash number of args found.
* trp->tp is not changed relative to the tokenrow.
*/
static int gatherargs(Tokenrow * trp, Tokenrow ** atr, int *narg)
{
int parens = 1;
int ntok = 0;
Token *bp, *lp;
Tokenrow ttr;
int ntokp;
*narg = -1; /* means that there is no macro call */
/* look for the ( */
for (;;) {
trp->tp++;
ntok++;
if (trp->tp >= trp->lp) {
gettokens(trp, 0);
if ((trp->lp - 1)->type == END) {
trp->lp -= 1;
trp->tp -= ntok;
return ntok;
}
}
if (trp->tp->type == LP)
break;
if (trp->tp->type != NL)
return ntok;
}
*narg = 0;
ntok++;
ntokp = ntok;
trp->tp++;
/* search for the terminating ), possibly extending the row */
while (parens > 0) {
if (trp->tp >= trp->lp)
gettokens(trp, 0);
if (trp->tp->type == END) {
trp->lp -= 1;
trp->tp -= ntok;
error(CPPERROR, StrTab[154]); // <EOF in macro arglist>
return ntok;
}
if (trp->tp->type == NL) {
trp->tp += 1;
adjustrow(trp, -1);
trp->tp -= 1;
makespace(trp);
continue;
}
if (trp->tp->type == LP)
parens++;
else if (trp->tp->type == RP)
parens--;
trp->tp++;
ntok++;
}
trp->tp -= ntok;
/* Now trp->tp won't move underneath us */
lp = bp = trp->tp + ntokp;
for (; parens >= 0; lp++) {
if (lp->type == LP) {
parens++;
continue;
}
if (lp->type == RP)
parens--;
if (lp->type == DSHARP)
lp->type = DSHARP1; /* ## not special in arg */
if (lp->type == COMMA && parens == 0 || parens < 0 && (lp - 1)->type != LP) {
if (*narg >= NARG - 1)
error(CPPFATAL, StrTab[155]); // <Sorry, too many macro arguments>
ttr.bp = ttr.tp = bp;
ttr.lp = lp;
atr[(*narg)++] = normtokenrow(&ttr);
bp = lp + 1;
}
}
return ntok;
}
/*
* substitute the argument list into the replacement string
* This would be simple except for ## and #
*/
static void substargs(Nlist * np, Tokenrow * rtr, Tokenrow ** atr)
{
Tokenrow tatr;
Token *tp;
int ntok, argno;
for (rtr->tp = rtr->bp; rtr->tp < rtr->lp;) {
if (rtr->tp->type == SHARP) { /* string operator */
tp = rtr->tp;
rtr->tp += 1;
if ((argno = lookuparg(np, rtr->tp)) < 0) {
error(CPPERROR, StrTab[156]); // <# not followed by macro parameter>
continue;
}
ntok = 1 + (rtr->tp - tp);
rtr->tp = tp;
insertrow(rtr, ntok, stringify(atr[argno]));
continue;
}
if (rtr->tp->type == NAME
&& (argno = lookuparg(np, rtr->tp)) >= 0) {
if ((rtr->tp + 1)->type == DSHARP
|| rtr->tp != rtr->bp && (rtr->tp - 1)->type == DSHARP)
insertrow(rtr, 1, atr[argno]);
else {
copytokenrow(&tatr, atr[argno]);
expandrow(&tatr, "<macro>");
insertrow(rtr, 1, &tatr);
dofree(tatr.bp);
}
continue;
}
rtr->tp++;
}
}
/*
* Evaluate the ## operators in a tokenrow
The double-number-sign or 'token-pasting' operator (##), which is sometimes
called the 'merging' operator, is used in both object-like and function-like
macros. It permits separate tokens to be joined into a single token and
therefore cannot be the first or last token in the macro definition.
If a formal parameter in a macro definition is preceded or followed by the
token-pasting operator, the formal parameter is immediately replaced by the
unexpanded actual argument. Macro expansion is not performed on the argument
prior to replacement.
*/
static void doconcat(Tokenrow * trp)
{
Token *ltp, *ntp;
Tokenrow ntr;
int len;
for (trp->tp = trp->bp; trp->tp < trp->lp; trp->tp++) {
if (trp->tp->type == DSHARP1)
trp->tp->type = DSHARP;
else if (trp->tp->type == DSHARP) {
char tt[128];
ltp = trp->tp - 1;
ntp = trp->tp + 1;
if (ltp < trp->bp || ntp >= trp->lp) {
error(CPPERROR, StrTab[157]); // <## occurs at border of replacement>
continue;
}
len = ltp->len + ntp->len;
strncpy((char *) tt, (char *) ltp->t, ltp->len);
strncpy((char *) tt + ltp->len, (char *) ntp->t, ntp->len);
tt[len] = '\0';
setsource((unsigned char *) "<##>", -1, tt);
maketokenrow(3, &ntr);
gettokens(&ntr, 1);
unsetsource();
if (ntr.lp - ntr.bp != 2 || ntr.bp->type == UNCLASS)
error(CPPWARNING, StrTab[158], &ntr); // <Bad token %r produced by ##>
ntr.lp = ntr.bp + 1;
trp->tp = ltp;
makespace(&ntr);
insertrow(trp, (ntp - ltp) + 1, &ntr);
dofree(ntr.bp);
trp->tp--;
}
}
}
/*
* tp is a potential parameter name of macro mac;
* look it up in mac's arglist, and if found, return the
* corresponding index in the argname array. Return -1 if not found.
*/
static int lookuparg(Nlist * mac, Token * tp)
{
Token *ap;
if (tp->type != NAME || mac->ap == NULL)
return -1;
for (ap = mac->ap->bp; ap < mac->ap->lp; ap++) {
if (ap->len == tp->len && strncmp((char *) ap->t, (char *) tp->t, ap->len) == 0)
return ap - mac->ap->bp;
}
return -1;
}
/*
* Return a quoted version of the tokenrow (from # arg)
*/
#define STRLEN 512
static Tokenrow *stringify(Tokenrow * vp)
{
static Token t = {STRING};
static Tokenrow tr = {&t, &t, &t + 1, 1};
Token *tp;
uchar s[STRLEN];
uchar *sp = s, *cp;
unsigned int i;
int instring;
*sp++ = '"';
for (tp = vp->bp; tp < vp->lp; tp++) {
instring = tp->type == STRING || tp->type == CCON;
if (sp + 2 * tp->len >= &s[STRLEN - 10]) {
error(CPPERROR, StrTab[159]); // <Stringified macro arg is too long>
break;
}
if (tp->wslen && (tp->flag & XPWS) == 0)
*sp++ = ' ';
for (i = 0, cp = tp->t; i < tp->len; i++) {
if (instring && (*cp == '"' || *cp == '\\'))
*sp++ = '\\';
*sp++ = *cp++;
}
}
*sp++ = '"';
*sp = '\0';
sp = s;
t.len = strlen((char *) sp);
t.t = newstring(sp, t.len, 0);
return &tr;
}
/* double the backslashs when outputting strings */
static int filestrcpy(char *op, char *src)
{
int i, c;
i = 0;
while ((c = *src++) != 0) {
if (c == '\\') {
*op++ = (char) c;
i++;
}
*op++ = (char) c;
i++;
}
return (i);
}
#ifndef LRC
static void dodeclspec(Tokenrow * trp)
{
if (trp->tp[1].type != LP) {
declspecerr:
error(CPPERROR, StrTab[160]); // <bad __declspec syntax!>
return;
}
if (trp->tp[3].type != RP)
goto declspecerr;
}
#endif
/*
* expand a builtin name
*/
static void builtin(Tokenrow * trp, int biname)
{
char *op;
Token *tp;
Source *s;
tp = trp->tp;
trp->tp++;
/* need to find the real source */
s = cursource;
while (s && s->fd == -1)
s = s->next;
if (s == NULL)
s = cursource;
/* most are strings */
tp->type = STRING;
if (tp->wslen) {
*OutputPtr++ = ' ';
tp->wslen = 1;
}
op = OutputPtr;
*op++ = '"';
switch (biname) {
case KLINENO:
tp->type = NUMBER;
op = outnum(op - 1, s->line);
break;
case KFILE:
op += filestrcpy(op, s->filename);
break;
case KDATE:
strncpy(op, curtime + 4, 7);
strncpy(op + 7, curtime + 20, 4);
op += 11;
break;
case KTIME:
strncpy(op, curtime + 11, 8);
op += 8;
break;
default:
error(CPPERROR, StrTab[161]); // <cpp botch: unknown internal macro>
return;
}
if (tp->type == STRING)
*op++ = '"';
tp->t = (uchar *) OutputPtr;
tp->len = op - OutputPtr;
OutputPtr = op;
}
static void setup_kwtab(void)
{
struct kwtab *kp;
Nlist *np;
Token t;
static Token deftoken[1] = {{NAME, 0, 0, 0, 7, (uchar *) "defined"}};
static Tokenrow deftr = {deftoken, deftoken, deftoken + 1, 1};
for (kp = kwtab; kp->kw; kp++) {
t.t = (uchar *) kp->kw;
t.len = strlen(kp->kw);
np = InstallToken(&t);
np->flag = (char) kp->flag;
np->val = (char) kp->val;
if (np->val == KDEFINED) {
kwdefined = np;
np->val = NAME;
np->vp = &deftr;
np->ap = 0;
}
}
}
#ifdef ASM_LIB
extern int DoHash(int, char *);
extern Nlist *cpplookup(Token *);
#else
static int DoHash(int s, char *cp)
{
int r = 0;
while (s--)
r += *cp++;
return (r);
}
static Nlist *cpplookup(Token * tp)
{
unsigned int h;
Nlist *np;
uchar *cp, *start;
register s;
start = cp = tp->t;
s = tp->len;
if (s <= 0) {
fprintf(stderr, StrTab[162]); // <Token of length 0?\n>
exit(1);
}
h = DoHash(s, cp);
s = tp->len;
np = nlist[h & 0x3FF];
while (np) {
if (s == np->len) {
if (strncmp((char *) start, (char *) np->name, s) == 0)
break;
}
np = np->next;
}
return np;
}
#endif
static Nlist *InstallToken(Token * tp)
{
Nlist *np;
uchar *cp;
register s;
unsigned int h;
np = cpplookup(tp);
if (np)
return (np);
cp = tp->t;
s = tp->len;
h = DoHash(s, cp);
np = allocate(sizeof(Nlist) + tp->len, 0);
np->vp = NULL;
np->ap = NULL;
np->flag = 0;
np->val = 0;
np->len = tp->len;
np->h = h;
// np->name = newstring(tp->t, tp->len, 0);
strncpy(np->name, tp->t, tp->len);
np->next = nlist[h & 0x3FF];
nlist[h & 0x3FF] = np;
quickset(tp->t[0], tp->len > 1 ? tp->t[1] : 0);
return np;
}
/*
* 1 for tokens that don't need whitespace when they get inserted
* by macro expansion
*/
static const char wstab[] = {
0, /* END */
0, /* UNCLASS */
0, /* NAME */
0, /* NUMBER */
0, /* STRING */
0, /* CCON */
1, /* NL */
0, /* WS */
0, /* DSHARP */
0, /* EQ */
0, /* NEQ */
0, /* LEQ */
0, /* GEQ */
0, /* LSH */
0, /* RSH */
0, /* LAND */
0, /* LOR */
0, /* PPLUS */
0, /* MMINUS */
0, /* ARROW */
1, /* SBRA */
1, /* SKET */
1, /* LP */
1, /* RP */
0, /* DOT */
0, /* AND */
0, /* STAR */
0, /* PLUS */
0, /* MINUS */
0, /* TILDE */
0, /* NOT */
0, /* SLASH */
0, /* PCT */
0, /* LT */
0, /* GT */
0, /* CIRC */
0, /* OR */
0,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -