windows-nt/Source/XPSP1/NT/sdktools/m4/xtoken.c
2020-09-26 16:20:57 +08:00

248 lines
6.8 KiB
C

/*****************************************************************************
*
* xtoken.c
*
* Expanding tokens via macro expansion.
*
*****************************************************************************/
#include "m4.h"
/*****************************************************************************
*
* ptokGet
*
* Allocate the next available token in the argv array, possibly realloc'ing
* the array as well.
*
*****************************************************************************/
PTOK STDCALL
ptokGet(void)
{
if (ptokTop >= ptokMax) {
ITOK itok = itokTop();
PTOK ptok;
ctokArg += ctokGrow;
ptok = pvReallocPvCb(rgtokArgv, ctokArg * sizeof(TOK));
ptokTop = ptok + itok;
ptokMax = ptok + ctokArg;
rgtokArgv = ptok;
Assert(ptokTop < ptokMax);
}
#ifdef DEBUG
ptokTop->tsfl = 0;
D(ptokTop->sig = sigUPtok);
#endif
return ptokTop++;
}
/*****************************************************************************
*
* PopPtok
*
* Free all the tokens in the token array starting at ptok.
*
*****************************************************************************/
void STDCALL
PopPtok(PTOK ptok)
{
Assert(ptok >= rgtokArgv && ptok < ptokTop);
ptokTop = ptok;
}
/*****************************************************************************
*
* CrackleArgv
*
* All the arguments to a macro have been parsed, collected, and snapped.
* All that's left to do is dispatch it.
*
* If the macro has no value, it got undefined behind our back.
* Emit the macro name with any possible arguments, quoted.
* In other words, pretend its expansion is ``$0ifelse($#,0,,($*))''.
*
* If the macro value is precisely a magic, then do the magic.
*
* Otherwise, perform substitution into the macro value.
*
*****************************************************************************/
void STDCALL
CrackleArgv(ARGV argv)
{
PMAC pmac = pmacFindPtok(ptokArgv(0));
if (pmac) { /* Found a real macro */
if (g_fTrace | pmac->pval->fTrace) { /* Not a typo */
TraceArgv(argv);
}
if (ctchSPtok(&pmac->pval->tok) == 2 &&
ptchPtok(&pmac->pval->tok)[0] == tchMagic) { /* Builtin */
Assert(fValidMagicTch(ptchPtok(&pmac->pval->tok)[1]));
rgop[ptchPtok(&pmac->pval->tok)[1]](argv);
} else { /* User-level macro */
PushSubstPtokArgv(&pmac->pval->tok, argv);
}
} else { /* Macro vanished behind our back */
/* SOMEDAY -- DefCracklePtok */ /* not even quoted! */
PushPtok(ptokArgv(0)); /* Just dump its name */
}
}
/*****************************************************************************
*
* argvParsePtok
*
* Parse a macro and its arguments, leaving everything unsnapped.
*
* Entry:
*
* ptok -> token that names the macro
*
* Returns:
* argv = argument vector cookie
*
*****************************************************************************/
ARGV STDCALL
argvParsePtok(PTOK ptok)
{
ITOK itok;
ARGV argv;
ptokGet(); /* ctok */
itok = itokTop(); /* Unsnap it in case it grows */
*ptokGet() = *ptok; /* $0 */
if (tchPeek() == tchLpar) {
TOK tok;
tchGet(); /* Eat the lparen */
do { /* Collect arguments */
int iDepth;
/*
* Eat leading whitespace. Note that this is *not*
* via expansion. Only literal leading whitespace
* is eaten.
*/
#ifdef fWhiteTch
#error fWhiteTch cannot be a macro
#endif
while (fWhiteTch(tchPeek())) {
tchGet();
}
/*
* If the argv buffer moves, ptokTop will move with it,
* so it's safe to read directly into it.
*/
OpenArgPtok(ptokGet());
D(ptokTop[-1].tsfl |= tsflScratch);
/*
* The loop is complicated by the need to maintain
* proper parenthesis nesting during argument collection.
*/
iDepth = 0;
for (;;) {
TYP typ = typXtokPtok(&tok);
/* SOMEDAY -- Assert the hold buffer and stuff */
if (typ == typPunc) {
if (ptchPtok(&tok)[0] == tchLpar) {
++iDepth;
} else if (ptchPtok(&tok)[0] == tchRpar) {
if (--iDepth < 0) {
break; /* End of argument */
}
} else if (ptchPtok(&tok)[0] == tchComma && iDepth == 0) {
break; /* End of argument */
}
}
DesnapArg();
}
DesnapArg();
CloseArgPtok(ptokTop-1); /* $n */
EatTailUPtokCtch(ptokTop-1, 1); /* That comma doesn't count */
} while (ptchPtok(&tok)[0] == tchComma);
}
argv = rgtokArgv + itok; /* Hooray, we have an argv! */
SetArgvCtok(itokTop() - itok - 1); /* $# (ctokArgv uses argv) */
OpenArgPtok(ptokGet()); /* Create extra null arg */
CloseArgPtok(ptokTop-1); /* SOMEDAY - could be better */
return argv;
}
/*****************************************************************************
*
* XmacPtok
*
* Parse and expand a macro, pushing the expansion back onto
* the input stream.
*
* Entry:
*
* ptok -> token that names the macro
*
* Exit:
* None
*
*****************************************************************************/
void STDCALL
XmacPtok(PTOK ptok)
{
ITOK itok;
ARGV argv;
UnsnapArgPtok(ptok); /* Unsnap it because it's gonna move */
argv = argvParsePtok(ptok); /* Argv is not yet snapped */
for (itok = 0; itok <= ctokArgv + 1; itok++) { /* $0 to $(n+1) */
SnapArgPtok(ptokArgv(itok)); /* Snap the args */
}
CrackleArgv(argv); /* Dispatch the macro */
PopArgPtok(ptokArgv(0));
PopPtok(ptokArgv(-1)); /* Pop off the args */
/* Part of this nutritious breakfast */
}
/*****************************************************************************
*
* XtokPtok
*
* Read and expand tokens until something unexpandable comes back,
* which is returned unsnapped.
*
*****************************************************************************/
TYP STDCALL
typXtokPtok(PTOK ptok)
{
TYP typ;
/*
* While the next token is a macro, expand it.
*/
while ( (typ = typGetPtok(ptok)) == typId && pmacFindPtok(ptok)) {
Gc();
XmacPtok(ptok);
Gc();
}
return typ;
}