276 lines
6.6 KiB
C
276 lines
6.6 KiB
C
/*****************************************************************************
|
|
*
|
|
* obj.c
|
|
*
|
|
* Mid-level memory management -- objects.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "m4.h"
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FreePtok
|
|
*
|
|
* Free the memory associated with a token.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
INLINE void
|
|
FreePtok(PTOK ptok)
|
|
{
|
|
AssertSPtok(ptok);
|
|
Assert(fHeapPtok(ptok));
|
|
FreePv(ptchPtok(ptok));
|
|
D(ptok->sig = 0);
|
|
D(ptok->tsfl = 0);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* PopdefPmac
|
|
*
|
|
* Pop the topmost value node (definition) off a macro.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void STDCALL
|
|
PopdefPmac(PMAC pmac)
|
|
{
|
|
PVAL pval;
|
|
|
|
AssertPmac(pmac);
|
|
AssertPval(pmac->pval);
|
|
|
|
pval = pmac->pval->pvalPrev;
|
|
FreePtok(&pmac->pval->tok);
|
|
FreePv(pmac->pval);
|
|
pmac->pval = pval;
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ptchDupPtok
|
|
*
|
|
* Copy a token into the heap as a C-style string, returning a pointer
|
|
* to the copy.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PTCH STDCALL
|
|
ptchDupPtok(PCTOK ptok)
|
|
{
|
|
PTCH ptch;
|
|
AssertSPtok(ptok);
|
|
ptch = ptchAllocCtch(ctchSPtok(ptok) + 1);
|
|
if (ptch) {
|
|
CopyPtchPtchCtch(ptch, ptchPtok(ptok), ctchSPtok(ptok));
|
|
ptch[ctchSPtok(ptok)] = '\0';
|
|
}
|
|
return ptch;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ptchDupPtch
|
|
*
|
|
* Duplicate a null-terminated string onto the heap. This doesn't
|
|
* happen often, so speed is not an issue.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PTCH STDCALL
|
|
ptchDupPtch(PCTCH ptch)
|
|
{
|
|
TOK tok;
|
|
SetStaticPtokPtchCtch(&tok, ptch, strlen(ptch));
|
|
return ptchDupPtok(&tok);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* DupPtokPtok
|
|
*
|
|
* Copy a token into the heap, returning the new token location in
|
|
* the first argument. (Remember, first argument is always destination;
|
|
* second argument is always source.)
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void STDCALL
|
|
DupPtokPtok(PTOK ptokDst, PCTOK ptokSrc)
|
|
{
|
|
Assert(ptokDst != ptokSrc);
|
|
AssertSPtok(ptokSrc);
|
|
D(ptokDst->sig = sigSPtok);
|
|
ptokDst->u.ptch = ptchAllocCtch(ctchSPtok(ptokSrc));
|
|
ptokDst->ctch = ctchSPtok(ptokSrc);
|
|
D(ptokDst->tsfl = tsflClosed | tsflHeap);
|
|
CopyPtchPtchCtch(ptchPtok(ptokDst), ptchPtok(ptokSrc), ctchSPtok(ptokSrc));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* PushdefPmacPtok
|
|
*
|
|
* Push a new value node (definition) onto a macro.
|
|
*
|
|
* The ptok is cloned.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void STDCALL
|
|
PushdefPmacPtok(PMAC pmac, PCTOK ptok)
|
|
{
|
|
PVAL pval;
|
|
|
|
AssertPmac(pmac);
|
|
|
|
pval = pvAllocCb(sizeof(VAL));
|
|
D(pval->sig = sigPval);
|
|
pval->fTrace = 0; /* Redefinition resets trace */
|
|
DupPtokPtok(&pval->tok, ptok);
|
|
pval->pvalPrev = pmac->pval;
|
|
pmac->pval = pval;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FreePmac
|
|
*
|
|
* Free a macro structure and all its dependents. Also removes it from the
|
|
* hash table.
|
|
*
|
|
* Macros are not freed often, so we can afford to be slow.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void STDCALL
|
|
FreePmac(PMAC pmac)
|
|
{
|
|
HASH hash;
|
|
PMAC pmacDad;
|
|
|
|
AssertPmac(pmac);
|
|
|
|
hash = hashPtok(&pmac->tokName);
|
|
|
|
pmacDad = pvSubPvCb(&mphashpmac[hash], offsetof(MAC, pmacNext));
|
|
AssertPmac(pmacDad->pmacNext);
|
|
while (pmacDad->pmacNext != pmac) {
|
|
Assert(pmacDad->pmacNext); /* Macro not in hash table */
|
|
pmacDad = pmacDad->pmacNext;
|
|
AssertPmac(pmacDad->pmacNext);
|
|
}
|
|
|
|
pmacDad->pmacNext = pmac->pmacNext; /* Unlink */
|
|
|
|
while (pmac->pval) { /* Free any values */
|
|
PopdefPmac(pmac);
|
|
}
|
|
|
|
FreePtok(&pmac->tokName);
|
|
|
|
FreePv(pmac);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* pmacFindPtok
|
|
*
|
|
* Locate a macro node corresponding to the supplied token. If no such
|
|
* macro exists, then return 0.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PMAC STDCALL
|
|
pmacFindPtok(PCTOK ptok)
|
|
{
|
|
PMAC pmac;
|
|
for (pmac = mphashpmac[hashPtok(ptok)]; pmac; pmac = pmac->pmacNext) {
|
|
if (fEqPtokPtok(&pmac->tokName, ptok)) {
|
|
break;
|
|
}
|
|
}
|
|
return pmac;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* pmacGetPtok
|
|
*
|
|
* Locate a macro node corresponding to the supplied token. If no such
|
|
* macro exists, create one.
|
|
*
|
|
* This happens only during macro definition, so it can be slow.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PMAC STDCALL
|
|
pmacGetPtok(PCTOK ptok)
|
|
{
|
|
PMAC pmac = pmacFindPtok(ptok);
|
|
if (!pmac) {
|
|
HASH hash;
|
|
pmac = pvAllocCb(sizeof(MAC));
|
|
D(pmac->sig = sigPmac);
|
|
pmac->pval = 0;
|
|
DupPtokPtok(&pmac->tokName, ptok);
|
|
hash = hashPtok(ptok);
|
|
pmac->pmacNext = mphashpmac[hash];
|
|
mphashpmac[hash] = pmac;
|
|
}
|
|
return pmac;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* fEqPtokPtok
|
|
*
|
|
* Determine whether two tokens are completely identical.
|
|
*
|
|
* The tokens must be snapped.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
F STDCALL
|
|
fEqPtokPtok(PCTOK ptok1, PCTOK ptok2)
|
|
{
|
|
AssertSPtok(ptok1);
|
|
AssertSPtok(ptok2);
|
|
return (ctchSPtok(ptok1) == ctchSPtok(ptok2)) &&
|
|
fEqPtchPtchCtch(ptchPtok(ptok1), ptchPtok(ptok2), ctchSPtok(ptok1));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* fIdentPtok
|
|
*
|
|
* Determine whether the token is a valid identifier.
|
|
*
|
|
* The token must be snapped.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* SOMEDAY! not quite right; thinks that `0' is an identifier */
|
|
|
|
F STDCALL
|
|
fIdentPtok(PCTOK ptok)
|
|
{
|
|
AssertSPtok(ptok);
|
|
if (ctchSPtok(ptok)) {
|
|
PTCH ptch = ptchPtok(ptok);
|
|
do {
|
|
if (!fIdentTch(*ptch)) {
|
|
return 0;
|
|
}
|
|
} while (++ptch < ptchMaxPtok(ptok));
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|