
/*
 *  agReduce.c
 *  $Id: agReduce.c,v 2.5 1999/07/07 19:30:52 bkorb Exp $
 *  Parse Reduction processing routines
 */

/*
 *  AutoGen copyright 1992-1999 Bruce Korb
 *
 *  AutoGen is free software.
 *  You may redistribute it and/or modify it under the terms of the
 *  GNU General Public License, as published by the Free Software
 *  Foundation; either version 2, or (at your option) any later version.
 *
 *  AutoGen is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with AutoGen.  See the file "COPYING".  If not,
 *  write to:  The Free Software Foundation, Inc.,
 *             59 Temple Place - Suite 330,
 *             Boston,  MA  02111-1307, USA.
 */


#include "autogen.h"

STATIC tDefEntry* pFreeEntryList = (tDefEntry*)NULL;
STATIC void*      pAllocList     = (void*)NULL;

#define ENTRY_ALLOC_CT     (4092 / sizeof(tDefEntry))
#define ENTRY_ALLOC_SIZE   ((ENTRY_ALLOC_CT * sizeof( tDefEntry )) + 4)

    void
unloadDefs( void )
{
    /*
     *  Free up the definitions data
     */
    for (;;) {
        tScanCtx* p = pDoneCtx->pCtx;
        AGFREE( (void*)pDoneCtx );
        pDoneCtx = p;
        if (p == (tScanCtx*)NULL)
            break;
    }

    for (;;) {
        void* p = *(void**)pAllocList;
        AGFREE( pAllocList );
        if (p == (void*)NULL)
            break;
        pAllocList = p;
    }
}

    STATIC tDefEntry*
getEntry( void )
{
    tDefEntry*  pRes = pFreeEntryList;

    if (pRes != (tDefEntry*)NULL) {
        pFreeEntryList = pRes->pNext;

    } else {
        int   ct = ENTRY_ALLOC_CT-1;
	void* p  = AGALOC( ENTRY_ALLOC_SIZE );

        if (p == (void*)NULL) {
            fprintf( stderr, zAllocErr, pzProg,
                     ENTRY_ALLOC_SIZE, "definition headers" );
            LOAD_ABORT;
        }

	*((void**)p) = pAllocList;
	pAllocList   = p;
        pRes = pFreeEntryList = (tDefEntry*)((void**)p + 1);

        /*
         *  This is a post-loop test loop.  It will cycle one fewer times
         *  than there are 'tDefEntry' structs in the memory we just alloced.
         */
        do  {
            tDefEntry* pNxt = pRes+1;
            pRes->pNext = pNxt;

            /*
             *  When the loop ends, "pRes" will point to the last allocated
             *  structure instance.  That is the one we will return.
             */
            pRes = pNxt;
        } while (--ct > 0);

        /*
         *  Unlink the last entry from the chain.  The next time this
         *  routine is called, the *FIRST* structure in this list will
         *  be returned.
         */
        pRes[-1].pNext = (tDefEntry*)NULL;
    }

    memset( (void*)pRes, 0, sizeof( *pRes ));
    return pRes;
}


    YYSTYPE
addSibMacro(
        YYSTYPE  def,
        YYSTYPE  list )
{
    tDefEntry* pDef  = (tDefEntry*)def;
    tDefEntry* pScn  = (tDefEntry*)list;

    for (;;) {
        if (strcmp( pDef->pzName, pScn->pzName ) == 0) {
            /*
             *  IF the new one preceeds the old first one,
             *  THEN swap the data and link the new data to
             *       the old first entry.  Remember that the
             *       old first entry now lives in the newly added struct!!
             */
            tDefEntry sav;

            /*
             *  Make sure that two entries with the same name
             *  are of the same type.
             */
            if (pDef->macType != pScn->macType) {
                fprintf( stderr, "ERROR:  two macros of the same name must "
                         "be of the same type:\n\t%s has conflicts\n",
                         pDef->pzName );
                LOAD_ABORT;
            }

            /*
             *  The new head of the list will still hold the "next" pointer
             */
            pDef->pNext = pScn->pNext;
            pScn->pNext = (tDefEntry*)NULL;

            /*
             *  Do the exchange
             */
            sav   = *pScn;
            *pScn = *pDef;
            *pDef = sav;
    
            /*
             *  The new data are now stashed in the struct at "pOld".
             *  Since it now heads the list, the twin pointer points to
             *  the old head data, now stashed in the newly allocated struct.
             */
            pScn->pTwin = pDef;
            break;
        }

        /*
         *  IF we are at the end of the list,
         *  THEN put the new entry at the start of the list
         */
        if (pScn->pNext == (tDefEntry*)NULL) {

            pDef->pNext = (tDefEntry*)list;
            list = def;
            break;
        }
        pScn = pScn->pNext;
    }

    return list;
}


    YYSTYPE
makeTextMacro(
        YYSTYPE place,
        YYSTYPE val )
{
    ((tDefEntry*)place)->pzValue = (char*)val;
    ((tDefEntry*)place)->macType = MACTYP_TEXT;
    return place;
}


    YYSTYPE
makeBlockMacro(
        YYSTYPE place,
        YYSTYPE list )
{
    ((tDefEntry*)place)->pzValue   = (char*)list;
    ((tDefEntry*)place)->macType   = MACTYP_BLOCK;

    return place;
}


    YYSTYPE
findPlace(
        YYSTYPE name,
        YYSTYPE index )
{
    tDefEntry*  pE = getEntry();
    const char* pz = (char*)index;

    pE->pzName  = (char*)name;

    if (pz == (char*)NULL)
        pE->index = NO_INDEX;

    else if (isdigit( *pz ) || (*pz == '-'))
        pE->index = strtol( pz, (char**)NULL, 0 );

    else {
        pz = getDefine( (char*)pz );
        if (pz != (char*)NULL)
             pE->index = strtol( pz, (char**)NULL, 0 );
        else pE->index = NO_INDEX;
    }
    strtransform( pE->pzName, pE->pzName );
    pE->macType = MACTYP_UNKNOWN;

    return (YYSTYPE)pE;
}


    YYSTYPE
identify( YYSTYPE template )
{
    /*
     *  Allow this routine to be called multiple times.
     *  This may happen if we #include another definition file.
     */
    if (pzTemplFileName == (char*)NULL) {

        if (HAVE_OPT(OVERRIDE_TPL))
             pzTemplFileName = OPT_ARG(OVERRIDE_TPL);
        else pzTemplFileName = (char*)template;
    }

    return (YYSTYPE)0;
}
/* end of agReduce.c */
