/***************************************************************************** * * 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; } }