/******************************************************************************
** Optimizer.c
*******************************************************************************
**
** description:
**
** This file contains the optimizer for the Boolean equations.
**
** In the first step the syntax of the source file is checked via the routines
** of the GAL assembler. After this the equations will be coded (bytes instead
** of strings - this is easier to deal with). In the next step the coded
** equations will be optimized by use of the Quine-McCluskey algorithm.
** After this the coded equations are decoded to strings and written in a file.
**
******************************************************************************/
 





/********************************* includes **********************************/

#include <libraries/mui.h>

#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/gadtools.h>
#include <libraries/locale.h>
#include <intuition/intuition.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include <proto/locale.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include <proto/muimaster.h>

#include "GALer.h"
#include "Localize.h"






/********************************** defines **********************************/

#define TAKEIT_GADID    1
#define FORGETIT_GADID  2






/******************************** functions **********************************/
static struct ActBuffer GetProdTermStart(struct ActBuffer pos);

static void  KillProdTerm(struct ActBuffer term);

static int   OptimizeEqua(struct ActBuffer buff);

static int   Resolvente(struct ActBuffer optstart, struct ActBuffer optend,
                        struct ActBuffer alteSchicht);

static int   NumOfVar(struct ActBuffer term);

static int   AddResolvente(struct ActBuffer pos1, struct ActBuffer pos2,
                           struct ActBuffer equastart,
                           struct ActBuffer *equaend);

static int   SearchVar(struct ActBuffer *, struct ActBuffer, UBYTE);

static int   WriteNewSource(struct ActBuffer buff, UBYTE *equastart,
                            UBYTE *equaend);

static int   CopyEqua(struct ActBuffer from_buff, struct ActBuffer to_buff);

static int   PrintEqua(struct ActBuffer buff, struct ActBuffer *filebuff);

static int   GetNext(struct ActBuffer *buff);

static int   GetNextEqua(struct ActBuffer *buff);

static void  PrintOptText(UBYTE *txt);

static int   TranslateEqua(struct ActBuffer *buff);
 





/******************************** variables **********************************/

extern  struct  AppString { LONG   as_ID;
                            STRPTR as_Str;
                          };

extern  struct  AppString AppStrings[];

extern  int     num_of_pins, asmreadyflag, gal_type, num_of_col;
extern  LONG    fsize;
extern  UBYTE   *fbuff;
extern  UBYTE   *actptr, *buffend;
extern  UBYTE   PinNamesOpt[24][10];
extern  char    path[];

extern  struct  Pin             actPin;
extern  struct  Catalog         *catalog;

extern  APTR    app;




UBYTE   OptTxt1[30];


int     num_of_ORs, num_of_ANDs;
int     numofpins_Opt;
                                /*oypos: y-Pos. für Text im Optimizer-Window*/
                                /*scrolls: wie oft gescrollt wurde*/
                                /*reqflag: Scrollreq. ja oder nein ?*/

char    opttitle[] = {"Optimizer"};


APTR    LV_opt;







/******************************************************************************
** Optimizer()
*******************************************************************************
** input:   none
**
** output:    0:  o.k.
**          <>0:  an error occured
**
** remarks: This function optimizes the Boolean equations of a source file.
******************************************************************************/

int Optimizer(void)
{
    int     open;                       /* variables for the user interface */
    ULONG   id, signals;
    APTR    win, take_it, forget_it;
    APTR    old_ORs, old_ANDs, opt_ORs, opt_ANDs, equ_num;

    UBYTE   *equastart, *equaend;            /* start/end of an equation */
    int     n, equaflag, asmreadyflag2;
    int     gal_type2, num_of_pins2, num_of_col2;
    int     notready;
    char    strng[10];

    struct  ActBuffer       AllEquas, OptEqua, FileEquas;
    struct  Buffer          *FirstAllEquas, *FirstOptEqua, *FirstFileEquas;
 

                    /* AllEquas:       buffer to store the coded equations    */
                    /* FirstAllEquas:  pointer to the first buffer of the     */
                    /*                 equations                              */
                    /* OptEqua:        buffer in which an optimized equation  */
                    /*                 should be stored                       */
                    /* FirstOptEquas:  pointer to the first buffer in which   */
                    /*                 an optimized equation should be stored */
                    /* FileEquas:      buffer to store the optimized          */
                    /*                 equations in string form(!); this      */
                    /*                 buffer is used to generate the new     */
                    /*                 source file                            */


    set(app, MUIA_Application_Sleep, TRUE);     /* deactivate the application */


    asmreadyflag2 = asmreadyflag;      /* save some variables which will be */
    gal_type2     = gal_type;          /* changed when call the assembler   */
    num_of_pins2  = num_of_pins;
    num_of_col2   = num_of_col;

    n = AssembleInputFile(OPTIMIZER);  /* syntax check for the source file */

    numofpins_Opt = num_of_pins;
    asmreadyflag  = asmreadyflag2;      /* restore variables */
    num_of_pins   = num_of_pins2;
    num_of_col    = num_of_col2;



    if (gal_type == GAL22V10)
    {
        strcpy(&PinNamesOpt[24][0], "AR");  /* define additional "pins" for */
        strcpy(&PinNamesOpt[25][0], "SP");  /* AR and SP                    */

        numofpins_Opt += 2;
    }

    gal_type = gal_type2;



    if (!n)                         /* no syntax error detected? */
    {
        equastart = actptr;

        if (!(FirstAllEquas = (struct Buffer *)
              AllocMem((long)sizeof(struct Buffer), MEMF_PUBLIC|MEMF_CLEAR)))
        {
            FreeMem(fbuff, fsize);          /* buffer for source file */
            ErrorReq(2);                    /* not enough free memory */
            set(app, MUIA_Application_Sleep, FALSE); /* reactivate app. */

            return(-1);
        }

        AllEquas.ThisBuff = FirstAllEquas;
        AllEquas.Entry    = (UBYTE *)(&FirstAllEquas->Entries[0]);
        AllEquas.BuffEnd  = (UBYTE *)FirstAllEquas + (long)sizeof(struct Buffer);

        if (!TranslateEqua(&AllEquas))      /* code the equations */
        {
            equaend = actptr;               /* save pointer to DESCRIPTION */

            if (!(FirstFileEquas = (struct Buffer *)
                  AllocMem((long)sizeof(struct Buffer), MEMF_PUBLIC|MEMF_CLEAR)))
            {
                FreeMem(fbuff, fsize);        /* buffer for source file   */
                FreeBuffer(FirstAllEquas);    /* buffer for the equations */
                ErrorReq(2);                  /* not enough free memory   */
                set(app, MUIA_Application_Sleep, FALSE); /* reactivate  app. */

                return(-1);
            }

            FileEquas.ThisBuff = FirstFileEquas;
            FileEquas.Entry    = (UBYTE *)(&FirstFileEquas->Entries[0]);
            FileEquas.BuffEnd  = (UBYTE *)FirstFileEquas +
                                 (long)sizeof(struct Buffer);

            if (AddByte(&FileEquas, (UBYTE)0x0A))
            {                                   /* add some returns at the */
                FreeMem(fbuff, fsize);          /* start of the equations  */
                FreeBuffer(FirstAllEquas);
                FreeBuffer(FirstFileEquas);
                ErrorReq(2);
                set(app, MUIA_Application_Sleep, FALSE); /* reactivate   */

                return(-1);
            }

            if (AddByte(&FileEquas, (UBYTE)0x0A))
            {
                FreeMem(fbuff, fsize);
                FreeBuffer(FirstAllEquas);
                FreeBuffer(FirstFileEquas);
                ErrorReq(2);
                set(app, MUIA_Application_Sleep, FALSE); /* reactivate   */

                return(-1);
            }



                                    /* make MUI window */

                                          /* prepare the string for         */
                                          /* displaying the equation number */
            strcpy(OptTxt1, AppStrings[MSG_OPT_EQUNUM].as_Str);
            strcat(OptTxt1, "     ");

            win = WindowObject,
            MUIA_Window_Title, opttitle,
            MUIA_Window_CloseGadget, FALSE,
            MUIA_Window_NoMenus, TRUE,
            MUIA_HelpNode, "Optimizer",

                WindowContents, VGroup,
                    Child, LV_opt = ListviewObject,
                        MUIA_Listview_Input, FALSE,
                        MUIA_Listview_List, ListObject,
                        MUIA_List_ConstructHook, MUIV_List_ConstructHook_String,
                        MUIA_List_DestructHook, MUIV_List_DestructHook_String,
                        ReadListFrame,
                        End, 
                    End,

                    Child, HGroup,
                        Child, ColGroup(3), GroupFrameT(AppStrings[MSG_STAT_TXT].as_Str),
                            Child, HSpace(0),
                            Child, Label("ORs"),
                            Child, Label("ANDs"),

                            Child, LLabel1(AppStrings[MSG_OLD_EQU].as_Str),
                            Child, old_ORs  = Label("    "),
                            Child, old_ANDs = Label("    "),
 
                            Child, LLabel1(AppStrings[MSG_OPT_EQU].as_Str),
                            Child, opt_ORs  = Label("    "),
                            Child, opt_ANDs = Label("    "),
                            End,

                        Child, VGroup,
                            Child, equ_num = LLabel(OptTxt1),

                            Child, ColGroup(2),
                                Child, take_it = SimpleButton(AppStrings[MSG_OPT_USE_GAD].as_Str),

                                Child, forget_it = SimpleButton(AppStrings[MSG_OPT_REJECT_GAD].as_Str),
                                End,
                            End,
                        End,
                    End,
                End;


                                            /* set gadget IDs */

            DoMethod(take_it, MUIM_Notify, MUIA_Pressed, FALSE,
                     app, 2, MUIM_Application_ReturnID, TAKEIT_GADID);

            DoMethod(forget_it, MUIM_Notify, MUIA_Pressed, FALSE,
                     app, 2, MUIM_Application_ReturnID, FORGETIT_GADID);


                                                /* init cycle chain */

            DoMethod(win, MUIM_Window_SetCycleChain, take_it, forget_it, NULL);




            if (!win)                    /* failed to create window object? */
            {
                FreeMem(fbuff, fsize);       /* buffer of source file     */
                FreeBuffer(FirstAllEquas);   /* buffer of coded equations */
                FreeBuffer(FirstFileEquas);  /* buffer of uncoded equ.    */
                ErrorReq(12);
                set(app, MUIA_Application_Sleep, FALSE); /* reactivate   */

                return(-1);
            }
            else
            {
                DoMethod(app, OM_ADDMEMBER, win);  /* add win to application */

                set(win, MUIA_Window_Open, TRUE);       /* open window */
                get(win, MUIA_Window_Open, &open);

                if (!open)              /* failed to open the window? */
                {
                    FreeMem(fbuff, fsize);       /* buffer of source file    */
                    FreeBuffer(FirstAllEquas);   /* buffer of coded equations*/
                    FreeBuffer(FirstFileEquas);  /* buffer of uncoded equ.   */

                    set(win, MUIA_Window_Open, FALSE);       /* close window */
                    DoMethod(app, OM_REMMEMBER, win);        /* remove win   */
                    MUI_DisposeObject(win);                  /* delete object*/
                    set(app, MUIA_Application_Sleep, FALSE); /* reactivate   */
 
                    return(-1);
                }
            }




            AllEquas.ThisBuff = FirstAllEquas;
            AllEquas.Entry    = (UBYTE *)(&FirstAllEquas->Entries[0]);
            AllEquas.BuffEnd  = (UBYTE *)FirstAllEquas +
                                (long)sizeof(struct Buffer);
            n = 0;

            equaflag = TRUE;        /* there are equations */


            while (equaflag)        /* as long as there are equations */
            {
                DoMethod(LV_opt, MUIM_List_Clear);      /* clear listview */

                PrintOptText(AppStrings[MSG_OLD_EQU].as_Str);  /* display the */
                PrintEqua(AllEquas, NULL);                     /* old equa.   */

                sprintf(strng, "%d", num_of_ORs);           /* statistics */
                set(old_ORs, MUIA_Text_Contents, strng);

                sprintf(strng, "%d", num_of_ANDs);
                set(old_ANDs, MUIA_Text_Contents, strng);
 
                set(opt_ORs,  MUIA_Text_Contents, "-");
                set(opt_ANDs, MUIA_Text_Contents, "-");


                if (!(FirstOptEqua = (struct Buffer *)
                    AllocMem((long)sizeof(struct Buffer), MEMF_PUBLIC|MEMF_CLEAR)))
                {
                    FreeMem(fbuff, fsize);       /* buffer of source file     */
                    FreeBuffer(FirstAllEquas);   /* buffer of coded equations */
                    FreeBuffer(FirstFileEquas);  /* buffer of uncoded equ.    */

                    set(win, MUIA_Window_Open, FALSE);       /* close window */
                    DoMethod(app, OM_REMMEMBER, win);        /* remove win   */
                    MUI_DisposeObject(win);                  /* delete object*/
                    set(app, MUIA_Application_Sleep, FALSE); /* reactivate   */
 
                    ErrorReq(2);                 /* out of memory */

                    return(-1);
                }

                OptEqua.ThisBuff = FirstOptEqua;
                OptEqua.Entry    = (UBYTE *)(&FirstOptEqua->Entries[0]);
                OptEqua.BuffEnd  = (UBYTE *)FirstOptEqua +
                                   (long)sizeof(struct Buffer);

                            /* copy an equation into the optimizer buffer */

                if (CopyEqua(AllEquas, OptEqua))
                {
                    FreeMem(fbuff, fsize);
                    FreeBuffer(FirstAllEquas);
                    FreeBuffer(FirstOptEqua);
                    FreeBuffer(FirstFileEquas);

                    set(win, MUIA_Window_Open, FALSE);       /* close window */
                    DoMethod(app, OM_REMMEMBER, win);        /* remove win   */
                    MUI_DisposeObject(win);                  /* delete object*/
                    set(app, MUIA_Application_Sleep, FALSE); /* reactivate   */

                    ErrorReq(2);

                    return(-1);
                }


                                /* try to optimize one equation */

                set(win, MUIA_Window_Title, AppStrings[MSG_OPT_WAIT].as_Str);

                set(app, MUIA_Application_Sleep, TRUE); /* deactivate the     */
                                                        /* optimizer's window */
 
                if (OptimizeEqua(OptEqua))
                {
                    FreeMem(fbuff, fsize);
                    FreeBuffer(FirstAllEquas);
                    FreeBuffer(FirstOptEqua);
                    FreeBuffer(FirstFileEquas);

                    set(win, MUIA_Window_Open, FALSE);       /* close window */
                    DoMethod(app, OM_REMMEMBER, win);        /* remove win   */
                    MUI_DisposeObject(win);                  /* delete object*/
                    set(app, MUIA_Application_Sleep, FALSE); /* reactivate   */

                    ErrorReq(2);

                    return(-1);
                }

                set(app, MUIA_Application_Sleep, FALSE); /* reactivate the    */
                                                         /* optimizer's window*/
                set(win, MUIA_Window_Title, opttitle);
 

                PrintOptText(" ");                       /* add an empty line */

                PrintOptText(AppStrings[MSG_OPT_EQU].as_Str);  /* display the */
                PrintEqua(OptEqua, NULL);                      /* old equa.   */

                sprintf(strng, "%d", num_of_ORs);           /* statistics */
                set(old_ORs, MUIA_Text_Contents, strng);

                sprintf(strng, "%d", num_of_ANDs);
                set(old_ANDs, MUIA_Text_Contents, strng);
 
                sprintf(strng, "%d", num_of_ORs);
                set(opt_ORs, MUIA_Text_Contents, strng);

                sprintf(strng, "%d", num_of_ANDs);
                set(opt_ANDs, MUIA_Text_Contents, strng);
 
                n++;
                strcpy(OptTxt1, AppStrings[MSG_OPT_EQUNUM].as_Str);
                sprintf(strng, " %d: ", n);
                strcat(OptTxt1, (const char*)strng);
                set(equ_num, MUIA_Text_Contents, OptTxt1);



                notready = 1;

                while (notready)
                {
                    id = DoMethod(app, MUIM_Application_Input, &signals);

                    switch (id)
                    {                                   /* take this    */
                        case TAKEIT_GADID:              /* optimization */
                            PrintEqua(OptEqua, &FileEquas);
                            notready = 0;

                            break;

                                                        /* don't take this */
                        case FORGETIT_GADID:            /* optimization    */
                            PrintEqua(AllEquas, &FileEquas);
                            notready = 0;

                            break;
                    }

                    if (notready && signals)
                        Wait(signals);              /* wait for the next event */
                }

                FreeBuffer(FirstOptEqua);

                equaflag = GetNextEqua(&AllEquas);
            }



                                            /* generate new source file */

            FileEquas.ThisBuff = FirstFileEquas;
            FileEquas.Entry    = (UBYTE *)(&FirstFileEquas->Entries[0]);
            FileEquas.BuffEnd  = (UBYTE *)FirstFileEquas +
                                 (long)sizeof(struct Buffer);

            if (MyFileReq(AppStrings[MSG_WRITE_SOURCE].as_Str, ".pld", YES, SAVE))
            {
                PrintText(AppStrings[MSG_WRITE_OPTSOURCE].as_Str, 1);

                if (WriteNewSource(FileEquas, equastart, equaend))
                {
                    PrintText(AppStrings[MSG_ERROR].as_Str,0);

                    TxtRequest(AppStrings[MSG_WRITE_ERR].as_Str,
                               AppStrings[MSG_CANCEL_GAD].as_Str, NULL);
                }
                else
                    PrintText(AppStrings[MSG_LOWER_OK].as_Str, 0);

            }

            FreeMem(fbuff, fsize);      /* buffer for source file */
            FreeBuffer(FirstFileEquas); /* buffer for uncoded optimized */
                                        /* equations                    */

            set(win, MUIA_Window_Open, FALSE);      /* close window */
  
            DoMethod(app, OM_REMMEMBER, win);       /* remove win from app. */

            MUI_DisposeObject(win);                 /* delete window object */

        }

        FreeBuffer(FirstAllEquas);

    }

    set(app, MUIA_Application_Sleep, FALSE);    /* reactivate application */
 

    return(0);
}





/******************************************************************************
** GetProdTermStart()
*******************************************************************************
** input:   pos     pointer to a product term
**
** output:          pointer to the beginning of the product term
**
** remarks: This function searches for the start of a product term.
******************************************************************************/

static struct ActBuffer GetProdTermStart(struct ActBuffer pos)
{

    while(*pos.Entry)
    {
        if (IsOR(*pos.Entry))
        {
            IncPointer(&pos);
            return(pos);
        }

        DecPointer(&pos);
    }

    IncPointer(&pos);

    return(pos);
}





/******************************************************************************
** KillProdTerm()
*******************************************************************************
** input:   term    pointer to the term
**                  the product term is replaced by an EQUSKIP
**
** output:  none
**
** remarks: This function removes a product term from an equation.
******************************************************************************/
 
static void KillProdTerm(struct ActBuffer term)
{
    struct  ActBuffer  start;


    start = term;

    while(*term.Entry && (!IsOR(*term.Entry)))
    {
        *term.Entry = EQUASKIP;
        IncPointer(&term);
    }


    if (IsOR(*term.Entry))
        *term.Entry = EQUASKIP;

    if (!*term.Entry)
    {
        while((*start.Entry) && (!IsOR(*start.Entry)))
            DecPointer(&start);

        if (IsOR(*start.Entry))
            *start.Entry = EQUASKIP;
    }
}





/******************************************************************************
** OptimizeEqua()
*******************************************************************************
** input:   buff        pointer to the equations
**
** output:    0:  o.k.
**           -1:  not enough free memory
**
** remarks: This function is the main function where the equations are
**          optimized.
******************************************************************************/
 
static int OptimizeEqua(struct ActBuffer buff)
{
    int     varfound, prodfound, result;
    UBYTE   merker;

    struct  ActBuffer optend, pos1, pos2, prodterm1, prodterm2;



    optend = buff;

    while (*optend.Entry != EQUAEND)        /* search the end of equation */
        IncPointer (&optend);

    *optend.Entry = 0;                  /* signify the end of the equation */
                                        /* instead of an EQUAEND with a 0  */

                                        /* signify the beginning of the */
                                        /* equation with a 0 too        */

    IncPointer (&buff);                 /* first entry is the output pin */
                                        /* so skip it                    */

    if (!(*buff.Entry == 'T' || *buff.Entry == 'R' || *buff.Entry == 'E'
        ||*buff.Entry == 'C' || *buff.Entry == 'S' || *buff.Entry == 'P'))
        DecPointer (&buff);             /* consider suffix */


    merker = *buff.Entry;               /* Zeichen merken */

    *buff.Entry = 0;                    /* Markierung setzen */
                                        /* optend = Gleichungsende */
    IncPointer (&buff);                 /* Zeiger auf erstes Zeichen */

    if (!*buff.Entry)                   /* no character there? */
    {
        if (AddByte(&buff, (UBYTE)(numofpins_Opt/2))) /* GND eintragen      */
            return(-1);                               /* und Gleichungsende */

        *buff.Entry = EQUAEND;

        DecPointer(&buff);
        DecPointer(&buff);

        *buff.Entry = merker;

        return(0);                      /* finished */
    }


    if (result = Resolvente(buff, optend, buff))
    {                                           /* Resolventen bilden  */
        if (result == -1)                       /* Fehler aufgetreten? */
            return(-1);                         /* ja, dann Fehlercode */
        else
        {
            if (AddByte(&buff, (UBYTE)numofpins_Opt))  /* VCC eintragen      */
                return(-1);                            /* und Gleichungsende */

            *buff.Entry = EQUAEND;

            DecPointer(&buff);
            DecPointer(&buff);

            *buff.Entry = merker;

            return(0);                          /* fertig */
        }
    }


    optend = buff;

    while (*optend.Entry)                   /* search end of equation */
        IncPointer(&optend);

                /*Absorptions-Gesetz anwenden: a + a * b <=> a */
                /*Prinzip: Es wird der Produktterm "prodterm1" mit allen*/
                /*andern ("prodterm2") verglichen und untersucht, ob einer*/
                /*ein Teil von diesem ist. Wenn ja, wird der andere Produkt-*/
                /*term gelöscht (mit EQUASKIP).*/

    pos1 = prodterm1 = buff;

    for (;;)
    {
        pos2 = buff;

        while (*pos2.Entry == EQUASKIP)      /* gelöschte Produktterme */
            IncPointer(&pos2);               /* überspringen           */

        for(;;)
        {
            varfound = 0;

            while (*prodterm1.Entry == EQUASKIP)  /* gelöschte Produktterme */
                IncPointer(&prodterm1);           /* überspringen           */

            while (*pos2.Entry)
            {                                        /* in der Gleichung nach */
                if (*pos2.Entry == *prodterm1.Entry) /* der Variable suchen,  */
                {                                    /* die als erstes im     */
                    varfound = 1;                    /* Produktterm steht     */
                    break;
                }

                IncPointer(&pos2);
            }

            if (!varfound)                  /* for-Schleife abbrechen, wenn */
                break;                      /* keine entsprechende Variable */
                                            /* gefunden wurde               */

            prodterm2 = GetProdTermStart(pos2);  /* Prod.term-Anfang suchen */

            while (*prodterm2.Entry == EQUASKIP)    /* gelöschte Prod.terme */
                IncPointer(&prodterm2);             /* überspringen         */

            if ((prodterm1.Entry != prodterm2.Entry) ||
                (prodterm1.ThisBuff != prodterm2.ThisBuff) ||
                (prodterm1.BuffEnd != prodterm2.BuffEnd))
            {
                pos1 = prodterm1;     /* Prod.terme miteinander vergleichen */

                for (;;)
                {
                    pos2      = prodterm2;
                    prodfound = 0;

                    for (;;)
                    {
                        if (*pos1.Entry == *pos2.Entry)
                        {
                            prodfound = 1;
                            break;
                        }

                        IncPointer(&pos2);

                        if ((*pos2.Entry) && (!IsOR(*pos2.Entry)) &&
                            (*pos2.Entry != EQUASKIP))
                            IncPointer(&pos2);
                        else
                            break;
                    }

                    if (!prodfound)
                        break;

                    IncPointer(&pos1);

                    if ((*pos1.Entry) && (!IsOR(*pos1.Entry)) &&
                        (*pos1.Entry != EQUASKIP))
                        IncPointer(&pos1);
                    else
                        break;
                }

                if (prodfound)
                    KillProdTerm(prodterm2);
            }

            if (*pos2.Entry)
                IncPointer(&pos2);
        }

        while((!IsOR(*pos1.Entry)) && (*pos1.Entry)) /* nächsten Prod.term */
            IncPointer(&pos1);                       /* suchen             */

        if (!*pos1.Entry)                         /* kein Prod.term mehr da */
            break;                                /* dann fertig            */

        IncPointer(&pos1);

        prodterm1 = pos1;
    }

    DecPointer(&buff);
    *buff.Entry = merker;                   /* Gleichung wieder herstellen */

    if (AddByte(&optend, (UBYTE)EQUAEND))   /* Gleichungsende wieder durch */
        return(-1);                         /* EQUAEND markieren           */

    if (AddByte(&optend, (UBYTE)0))
        return(-1);


    return(0);
}





/******************************************************************************
** Resolvente()
*******************************************************************************
** input:   optstart        pointer to the start of the equation
**          optend          pointer to the end of the equation
**          alteSchicht     pointer to previous "Schicht"
**
** output:    0:  o.k.
**            1:  A + /A (=VCC) found, result of equation is always TRUE
**           -1:  not enough free memory
**
** remarks: hängt eine neue Schicht von Resolventen an die zu optimierende
**          Gleichung an (I don't know how to translate this... ;-))
**
******************************************************************************/
 
static int Resolvente(struct ActBuffer optstart,
                      struct ActBuffer optend,
                      struct ActBuffer alteSchicht)
{
    int     result, flag, resflag;          /* resflag: neue Resolvente */
    UBYTE   var;                            /* gefunden?                */

    struct  ActBuffer  pos1, pos2, neueSchicht;

                                        /* neueSchicht: zeigt auf Stelle, an */
                                        /* der weitere Resolventen angefügt  */
                                        /* werden können (Ende)              */

    if ((IsOR(*alteSchicht.Entry)) || (IsAND(*alteSchicht.Entry)))
        IncPointer(&alteSchicht);

    resflag     = 0;                    /* lokale Variablen initialisieren */
    pos1        = alteSchicht;
    neueSchicht = optend;


    for (;;)
    {
        var = *pos1.Entry;                  /* Variable (Pinnummer) holen */

        if (var & NEGATION)                 /* Variable negieren */
            var = var & (~NEGATION);
        else
            var = var | NEGATION;

        pos2 = optstart;                    /* suche nach "/var" */

        for(;;)
        {
            if (!SearchVar(&pos2, neueSchicht, var))
            {
                result = AddResolvente(pos1, pos2, optstart, &optend);

                flag = 0;           /* Wenn die Variable gefunden wurde,   */
                                    /* wird pos2 auf den nächsten Produkt- */
                                    /* term gestellt. Wenn keiner da ist,  */
                                    /* bleibt flag 0 und weiter unten er-  */
                                    /* folgt dann der Abbruch (if(!flag).. */

                while (pos2.Entry != neueSchicht.Entry)
                {
                    if (IsOR(*pos2.Entry))
                    {
                        flag = 1;
                        IncPointer(&pos2);
                        break;
                    }

                    IncPointer (&pos2);
                }

                if (!result)
                    resflag = 1;
                else
                {
                    if (result == 2)    /* A + /A gefunden? => Ausdruck wahr */
                        return(1);      /* dann fertig                       */

                    if (result == -1)
                        return(-1);
                }

                if (!flag)              /* kein Produktterm mehr da? */
                    break;              /* dann Abbruch              */
            }
            else
                break;
        }


        IncPointer(&pos1);              /* Operator überspringen und pos1    */
                                        /* auf nächste Variable, falls nicht */
                                        /* bereits der neue Schichtanfang    */
                                        /* erreicht wurde, sonst Abbruch     */
        if (pos1.Entry != neueSchicht.Entry)
            IncPointer(&pos1);
        else
            break;
    }


    if (!resflag)                       /* wurde neue Resolvente gefunden? */
        return(0);                      /* nein, dann fertig               */
    else                                /* ja, dann Rekursion              */
        return (Resolvente(optstart, optend, neueSchicht));

    return 0;                   /* just to keep the compiler happy */
}





/******************************************************************************
** NumOfVar()
*******************************************************************************
** input:   term    pointer to the product term
**
** output:          number of variables
**
** remarks: This function returns the number of variables of a product
**          term.
******************************************************************************/
 
static int NumOfVar(struct ActBuffer term)
{
    int     numofvar;


    numofvar = 0;

    for (;;)
    {
        numofvar++;

        IncPointer(&term);

        if (!*term.Entry || (IsOR(*term.Entry)))
            break;

        IncPointer(&term);
    }

    return (numofvar);
}





/******************************************************************************
** AddResolvente()
*******************************************************************************
** input:   pos1, pos2      ActBuffer structure
**          equastart       start of equation
**          equaend         pointer(!) to end of equation
**
** output:      0: es wurde eine Resolvente gebildet und angehängt
**                 equaend zeigt auf neues Ende
**              1: keine Resolvente
**              2: A + /A wurde gefunden (VCC -> fertig)
**             -1: Fehler, kein Speicher
**
** remarks: Fügt die beiden Produktterme in die "pos1" und "pos2"
**        zeigt zusammen, wobei die Variablen (Pinnummern) die unter "pos1"
**        und "pos2" stehen nicht berücksichtigt werden. Dann wird untersucht,
**        ob der neuentstandene Produktterm schon in der Gleichung steht.
**        Wenn nicht, wird der Produktterm an "equaend" angehängt.
**        Eine neue Resolvente ist geboren - welch' Dramatik.
******************************************************************************/

static int AddResolvente(struct ActBuffer pos1, struct ActBuffer pos2,
                         struct ActBuffer equastart, struct ActBuffer *equaend)
{
    int    n, i, numofvar, numofvar1, numofvar2;
    int    found;

    UBYTE  *termbuff, *term, entry;

    struct ActBuffer  pos, res, res1, res2, prodterm, nextprodterm;



    res1 = GetProdTermStart(pos1);    /* ActBuffer-Struktur für den         */
    res2 = GetProdTermStart(pos2);    /* jeweiligen Produkttermanfang holen */

    if ((res1.Entry == res2.Entry) && (res1.ThisBuff == res2.ThisBuff) &&
        (res1.BuffEnd == res1.BuffEnd))
        return(1);

    numofvar1 = NumOfVar(res1);       /* Anzahl der benötigten Bytes     */
    numofvar2 = NumOfVar(res2);       /* für die beiden Prod.terme holen */

    if (!(termbuff = (UBYTE *)AllocMem((long)(numofvar1 + numofvar2 + 1),
                                       MEMF_PUBLIC|MEMF_CLEAR)))
        return(-1);

                                     /* hier werden die beiden Produktterme */
    numofvar = numofvar1;            /* res1 und res2 zusammengehängt und   */
    res      = res1;                 /* in "termbuff" abgelegt (ohne '*'!)  */
    pos      = pos1;

                                     /* zwei Produktterme */
    for (i = 0; i < 2; i++)
    {
        for (n=0; n<numofvar; n++)
        {
            if (res.Entry != pos.Entry)
            {
                term  = termbuff;    /* keine doppelten Pins zulassen */
                entry = *res.Entry;
                found = 0;

                while (*term)
                {
                                            /* "a * /a" nicht zulassen */
                    if (entry & NEGATION)
                    {
                        if (*term == (entry & (~NEGATION)))
                        {
                            FreeMem(termbuff, (long)(numofvar1+numofvar2+1));
                            return(1);
                        }
                    }
                    else
                    {
                        if (*term == (entry | NEGATION))
                        {
                            FreeMem(termbuff, (long)(numofvar1 + numofvar2 + 1));
                            return (1);
                        }
                    }

                    if (*term == entry)
                        found = 1;

                    term++;
                }

                if (!found)
                    *term = entry;
            }

            IncPointer(&res);
            IncPointer(&res);
        }

        numofvar = numofvar2;
        res      = res2;
        pos      = pos2;
    }

    if (!*termbuff)                      /* wenn termbuff leer ist, dann     */
        *termbuff = numofpins_Opt;       /* war A+/A in der Gleichung => VCC */

                                    /* untersuchen, ob der neue Prod.term */
                                    /* "termbuff" schon existiert         */
    pos   = equastart;
    found = 0;

    for(;;)
    {
        prodterm = pos;

        while ((!IsOR(*pos.Entry)) && (entry = *pos.Entry))
        {
            term  = termbuff;
            found = 0;

            while (*term)
            {
                if (*term == entry)
                {
                    found = 1;
                    break;
                }

                term++;
            }

            if (!found)
                break;

            IncPointer(&pos);

            if (IsAND(*pos.Entry))  /* '*' überspringen, falls vorhanden */
                IncPointer(&pos);
        }

                                            /* nächsten Prod.term suchen */

        while ((!IsOR(*pos.Entry)) && (*pos.Entry))
            IncPointer(&pos);

        nextprodterm = pos;

        if (found)
        {
            term = termbuff;

            while (*term)
            {
                pos   = prodterm;
                found = 0;

                while ((!IsOR(*pos.Entry)) && (entry = *pos.Entry))
                {
                    if (entry == *term)
                    {
                        found = 1;
                        break;
                    }

                    IncPointer(&pos);

                    if (IsAND(*pos.Entry))
                        IncPointer(&pos);
                }

                if (!found)
                    break;

                term++;
            }
        }

        if (found)
            break;                          /* for-Schleife verlassen */

        pos = nextprodterm;

        if (!*pos.Entry)
            break;

        IncPointer(&pos);
    }


    if (!found)
    {                                   /* existiert Prod.term schon ?      */
                                        /* nein, dann an Gleichung anhängen */

        if (AddByte(equaend, (UBYTE)'+'))
        {
            FreeMem(termbuff, (long)(numofvar1+numofvar2+1));
            return(-1);
        }

        term = termbuff;

        while (*term)
        {
            if (AddByte(equaend, (UBYTE)*term))
            {
                FreeMem(termbuff, (long)(numofvar1+numofvar2+1));
                return(-1);
            }

            if (AddByte(equaend, (UBYTE)'*'))
            {
                FreeMem(termbuff, (long)(numofvar1+numofvar2+1));
                return(-1);
            }

            term++;
        }

        DecPointer(equaend);

        *equaend->Entry = 0;                        /* Endmarkierung */

        entry = *termbuff;

        FreeMem(termbuff, (long)(numofvar1+numofvar2+1));

        if (entry == numofpins_Opt)             /* wenn VCC gefunden wurde, */
            return(2);                          /* dann 2 zurückgeben       */
        else
            return(0);
    }

    FreeMem(termbuff, (long)(numofvar1+numofvar2+1));

    return(1);
}





/******************************************************************************
** SearchVar()
*******************************************************************************
** input:   pos     pointer to start position
**          end     end position
**          var     pin name to be searched
**
** output:      0:  name found
**             -1:  not found
**
** remarks: This function does search the pin "var". Search from "pos" to
**          "end". Since this function is called very often registered
**          variables are necessary to be fast enough.
******************************************************************************/

static int SearchVar(register struct ActBuffer *pos,
                     register struct ActBuffer end,
                     register UBYTE var)
{

    while (pos->Entry != end.Entry)
    {
        if (*pos->Entry == var)
            return(0);

        IncPointer(pos);
    }

    return(-1);
}





/******************************************************************************
** WriteNewSource()
*******************************************************************************
** input:   buff        buffer where the equations are stored in
**          equastart   pointer to the start of the equation in the
**                      original source file
**          equend      pointer to the end of the equations in the
**                      original source file (DESCRIPTION)
**
** output:      0:  o.k.
**             -1:  failed to write file
**
** remarks: This function generates from the original source file and
**          from the optimized equations a new source file.
******************************************************************************/

static int WriteNewSource(struct ActBuffer buff, UBYTE *equastart,
                          UBYTE *equaend)
{
    long    result;
    BPTR    fh;
    UBYTE   *filebuffer, *filebuffer2;


    if ((fh = Open(&path[0], (long)MODE_NEWFILE)))
    {
                                /* write header of the new source file */

        result = Write(fh, (char *)fbuff, (long)(equastart-fbuff));

        if (result == -1L)
        {                       /* write error? */
            Close(fh);          /* then end     */
            return(-1);
        }

                                /* write the equations */
        for (;;)
        {
            filebuffer = filebuffer2 = buff.Entry;

            while (filebuffer2 < buff.BuffEnd)  /* get size of buffer */
            {
                if (!*filebuffer2)
                    break;

                filebuffer2++;
            }

            result = Write(fh, (char *)filebuffer,
                           (long)(filebuffer2 - filebuffer));

            if (result == -1L)
            {                           /* write error? */
                Close(fh);              /* then end     */
                return(-1);
            }

            if (!buff.ThisBuff->Next)       /* are there some more buffers? */
                break;                      /* no, then finish              */

            buff.ThisBuff = buff.ThisBuff->Next;
            buff.Entry    = (UBYTE *)(&buff.ThisBuff->Entries[0]);
            buff.BuffEnd  = (UBYTE *)buff.ThisBuff+(long)sizeof(struct Buffer);
        }

                                        /* write DESCRIPTION part */

        result = Write(fh, (char *)equaend, (long)(fbuff+fsize-equaend));

        if (result == -1L)
        {                               /* write error? */
            Close(fh);                  /* the cancel   */
            return(-1);
        }

        Close(fh);
    }
    else
        return(-1);

    return(0);
}





/******************************************************************************
** CopyEqua()
*******************************************************************************
** input:       from    ActBuffer structure of source
**              to      ActBuffer structure of destination
**
** output:      0:      o.k.
**            <>0:      failed (not enough free memory)
**
** remarks: This function copies a equation from "from" to "to".
******************************************************************************/

static int CopyEqua(struct ActBuffer from_buff, struct ActBuffer to_buff)
{
    register int    n;

    UBYTE    entry, pins[2*24];

    struct   ActBuffer  equastart, prodtermstart, pos;



    if (AddByte(&to_buff, (UBYTE)*from_buff.Entry)) /* copy output pin */
        return(-1);

    IncPointer(&from_buff);

    entry = *from_buff.Entry;

    if (entry == 'T' || entry == 'R' || entry == 'E' ||
        entry == 'C' || entry == 'S' || entry == 'P')
    {

        if (AddByte(&to_buff, (UBYTE)entry))        /* copy suffix T,R,E */
            return(-1);

        IncPointer(&from_buff);
    }

                                                    /* copy equation */
    equastart = prodtermstart = to_buff;

    for (;;)
    {
        for (n = 0; n < 2*24; pins[n++] = 0);       /* clear pins */

        for (;;)
        {
            entry = *from_buff.Entry;

            if (entry & NEGATION)
            {
                if (pins[(entry & ~NEGATION) - 1])  /* A * /A? */
                {
                    pos = prodtermstart;            /* yes, then skip */
                                                    /* this term      */
                    while (pos.Entry != to_buff.Entry)
                    {
                        *pos.Entry = EQUASKIP;
                        IncPointer(&pos);
                    }

                    to_buff = prodtermstart;

                    while ((!IsOR(*from_buff.Entry)) &&
                           (*from_buff.Entry != EQUAEND))
                        IncPointer(&from_buff);

                    DecPointer(&from_buff);
                }
                else
                {
                    if (!pins[(entry & ~NEGATION) -1 + 24])
                    {                                /* is pin used several */
                                                     /* times within the    */
                                                     /* product term?       */

                                                     /* no, then copy */
                        pins[(entry & ~NEGATION) - 1 + 24] = 1;

                        if (AddByte(&to_buff, (UBYTE)entry)) /* copy pin num */
                            return(-1);
                    }
                }
            }
            else
            {
                if (pins[entry - 1 + 24])          /* A * /A? */
                {

                    pos = prodtermstart;           /* yes, then copy term */

                    while (pos.Entry != to_buff.Entry)
                    {                              /* erase and skip */
                        *pos.Entry = EQUASKIP;
                        IncPointer(&pos);
                    }

                    to_buff = prodtermstart;

                    while ((!IsOR(*from_buff.Entry)) &&
                           (*from_buff.Entry != EQUAEND))
                        IncPointer(&from_buff);

                    DecPointer(&from_buff);
                }
                else
                {

                    if (!pins[entry-1])         /* is pin name used several */
                    {                           /* times?                   */
                        pins[entry - 1] = 1;    /* no, then copy            */

                        if (AddByte(&to_buff, (UBYTE)entry)) /* copy pin num */
                            return(-1);
                    }
                }
            }


            IncPointer(&from_buff);         /* pointer to operation or */
                                            /* EQUAEND                 */
            entry = *from_buff.Entry;

            if (entry == EQUAEND)           /* end reached? */
            {
                DecPointer(&to_buff);       /* yes, then we are ready */

                if (!(IsOR(*to_buff.Entry) || IsAND(*to_buff.Entry) ))
                    IncPointer(&to_buff);   /* remove +, * at the end */

                if (AddByte(&to_buff, (UBYTE)EQUAEND))  /* send end mark */
                    return(-1);

                return(0);
            }

            if (to_buff.Entry != equastart.Entry) /* still at the beginning? */
            {
                DecPointer(&to_buff);

                if (!IsOR(*to_buff.Entry))
                {
                    if (!IsAND(*to_buff.Entry))
                    {
                        IncPointer(&to_buff);

                        if (AddByte(&to_buff, (UBYTE)entry))
                            return(-1);
                    }
                    else
                    {
                        if (IsOR(entry))
                            *to_buff.Entry = '+';

                        IncPointer(&to_buff);
                    }
                }
                else
                    IncPointer(&to_buff);
            }


            if (IsOR(entry))                /* end of product term reached? */
                break;                      /* then leave loop              */


            IncPointer(&from_buff);         /* set pointer to pin name */
        }

        prodtermstart = to_buff;

        IncPointer(&from_buff);
    }
}





/******************************************************************************
** PrintEqua()
*******************************************************************************
** input:   buff      ActBuffer structure of an equation
**          filebuff  NULL: prints an equation into the window
**                    else: put the optimized equations in a buffer which is
**                          then used to generate the source file
**
** output:    0:    ok
**          <>0:    failed (not enough free memory)
**
** remarks: This function does print the coded equation which ends with
**          ENDEQUAS or ENDEQUA.
******************************************************************************/

static int PrintEqua(struct ActBuffer buff, struct ActBuffer *filebuff)
{
    char    estrng[SIZE_OF_EQUASTRING];
    int     n, entry, xoffset, notready;


    num_of_ORs = num_of_ANDs = 0;
    estrng[0] = 0;                                /* clear string */

    entry = *buff.Entry;

    if (entry & NEGATION)
    {
        strcat((char *)&estrng[0], "/");
        entry = entry & (~NEGATION);
    }

    if (IsNEG(PinNamesOpt[entry-1][0]))         /* output */
        strcat((char *)&estrng[0], (char *)&PinNamesOpt[entry-1][1]);
    else
        strcat((char *)&estrng[0], (char *)&PinNamesOpt[entry-1][0]);

    entry = GetNext(&buff);

    if (entry == 'T')
    {
        entry = GetNext(&buff);
        strcat ((char *)&estrng[0], ".T");          /* print suffix */
    }
    else
        if (entry == 'E')
        {
            entry = GetNext(&buff);
            strcat ((char *)&estrng[0], ".E");
        }
        else
            if (entry == 'R')
            {
                entry = GetNext(&buff);
                strcat ((char *)&estrng[0], ".R");
            }
            else
                if (entry == 'C')
                {
                    entry = GetNext(&buff);
                    strcat ((char *)&estrng[0], ".CLK");
                }
                else
                    if (entry == 'S')
                    {
                        entry = GetNext(&buff);
                        strcat ((char *)&estrng[0], ".ARST");
                    }
                    else
                        if (entry == 'P')
                        {
                            entry = GetNext(&buff);
                            strcat ((char *)&estrng[0], ".APRST");
                        }



    strcat ((char *)&estrng[0], " = ");           /* add '=' */

    xoffset = strlen(&estrng[0]);                 /* save length of string */

    notready = TRUE;

    while (notready)
    {
        while (strlen(&estrng[0]) < (SIZE_OF_EQUASTRING - 15))
        {

            if (entry & NEGATION)
            {
                strcat((char *)&estrng[0], "/");
                entry = entry & (~NEGATION);
            }

            if (IsNEG(PinNamesOpt[entry-1][0]))               /* get pin name */
                strcat ((char *)&estrng[0], (char *)&PinNamesOpt[entry-1][1]);
            else
                strcat ((char *)&estrng[0], (char *)&PinNamesOpt[entry-1][0]);

            if ((entry = GetNext(&buff)) == EQUAEND)
            {
                notready = FALSE;
                break;
            }

            if (IsOR(entry))
            {
                strcat((char *)&estrng[0], " + ");      /* get op. */
                num_of_ORs++;
            }
            else
            {
                strcat((char *)&estrng[0], "*");
                num_of_ANDs++;
            }

            if ((entry = GetNext(&buff)) == EQUAEND)
            {
                notready = FALSE;
                break;
            }
        }

        if (!filebuff)
            PrintOptText((UBYTE *)&estrng[0]);        /* print one line */
        else
        {
            n = 0;                                    /* put string into list */

            while (estrng[n])
            {
                if (AddByte(filebuff, (UBYTE)estrng[n]))
                    return(-1);

                n++;
            }

            if (AddByte(filebuff, (UBYTE)0x0A))        /* add a return */
                return(-1);
        }

        for (n=0; n<xoffset; n++)               /* add spaces ' ' up to */
            estrng[n] = ' ';                    /* xoffset              */

        estrng[xoffset] = 0;                    /* clear the rest of string */
    }

    if (filebuff)                               /* make file list?         */
        if (AddByte(filebuff, (UBYTE)0x0A))     /* add a return at the end */
            return(-1);                         /* of an equation          */


    return(0);
}





/******************************************************************************
** GetNext()
*******************************************************************************
** input:   buff    pointer to ActBuffer structure
**
** output:          next entry which is no EQUASKIP
**
** remarks: gets the next entry from the buffer "buff" which is no EQUASKIP
******************************************************************************/

static int GetNext(struct ActBuffer *buff)
{

    do
        IncPointer(buff);
    while (*buff->Entry == EQUASKIP);

    return(*buff->Entry);
}





/******************************************************************************
** GetNextEqua()
*******************************************************************************
** input:   buff    pointer to the ActBuffer structure
**
** output:  FALSE:  there are no more equations
**          TRUE:   one equation found
**          buff:   actuell pointer to the equation
**
** remarks: searchs for the next coded equation
******************************************************************************/
 
static int GetNextEqua(struct ActBuffer *buff)
{

    while (*buff->Entry != EQUAEND)
        IncPointer(buff);

    IncPointer(buff);

    if (*buff->Entry == EQUASEND)
        return(FALSE);
    else
        return(TRUE);
}
 




/******************************************************************************
** PrintOptText()
*******************************************************************************
** input:   txt     text to be displayed
**
**          global: LV_opt is the pointer to the listview object
**
** output:  none
**
** remarks: This function does add a string to the optimizer's listview.
******************************************************************************/

static void PrintOptText(UBYTE *txt)
{

    DoMethod(LV_opt, MUIM_List_InsertSingle,  /* add line to  */
             txt, MUIV_List_Insert_Bottom);   /* the listview */

}





/******************************************************************************
** TranslateEqua()
*******************************************************************************
** input:   buff    pointer to the equations
**
** output:    0: ok
**          <>0: failed (not enough free memory)
**
** remarks: This function translates all Boolean equations from the ASCII
**          form into a coded form. So it's easier to deal with the equations.
**          Code: pinname   ->  pin number
**                /pinname  ->  pin number and bit 7 set
**                T,R,E,+,* ->  T,R,E,+,*
**                CLK, ARST, APRST -> C, S, P
**                CR,LF,'.','=' are skiped
******************************************************************************/

static int TranslateEqua(struct ActBuffer *buff)
{
    int     n;
    UBYTE   chr, entry;
    char    suffix_strn[MAX_SUFFIX_SIZE];



    if (GetNextChar())
    {                                   /* end of file?  */
        AsmError(2, 0);                 /* yes, then end */
        return(-1);
    }
                                        /* is there an equation? */

    if (!strncmp((char *)actptr, "DESCRIPTION", (size_t)11))
    {
        AsmError(33, 0);                /* no, then error */
        return(-1);
    }


    for (;;)
    {
        IsPinName((UBYTE *)&PinNamesOpt[0], numofpins_Opt);

        if (!actPin.p_Pin)
        {                               /* pin name?      */
            AsmError(11, 0);            /* no, then error */
            return(-1);
        }

        if (actPin.p_Neg)
            entry = actPin.p_Pin | NEGATION;
        else
            entry = actPin.p_Pin;

        if (AddByte(buff, (UBYTE)entry))
            return(-1);


        if (*actptr == '.')
        {                               /* get suffix */

            actptr++;

            n = 0;

            while (isalpha(*actptr))
            {                                   /* copy suffix string into */
                if (n < MAX_SUFFIX_SIZE)        /* suffix array            */
                    suffix_strn[n++] = *actptr++;
                else
                {                               /* string too long, then */
                    AsmError(13, 0);            /* unknown suffix        */
                    return(-1);
                }
            }

            suffix_strn[n] = 0;                    /* mark end of string */

            if (!strcmp(&suffix_strn[0], "T"))
                chr = 'T';
            else
                if (!strcmp(&suffix_strn[0], "R"))
                    chr = 'R';
                else
                    if (!strcmp(&suffix_strn[0], "E"))
                        chr = 'E';
                    else
                        if (!strcmp(&suffix_strn[0], "CLK"))
                            chr = 'C';
                        else
                            if (!strcmp(&suffix_strn[0], "ARST"))
                                chr = 'S';
                            else
                                if (!strcmp(&suffix_strn[0], "APRST"))
                                    chr = 'P';
                                else
                                {
                                    AsmError(13, 0);
                                    return(-1);
                                }

            if (AddByte(buff, (UBYTE)chr))            /* add code of suffix */
                return(-1);
        }


        if (GetNextChar())
        {                                   /* end of file? */
            AsmError(2, 0);
            return(-1);
        }

        if (*actptr != '=')
        {                                   /* '='?           */
            AsmError(14, 0);                /* no, then error */
            return(-1);
        }

        actptr++;

        if (GetNextChar())
        {                                   /* end of file?    */
            AsmError(2, 0);                 /* yes, then error */
            return(-1);
        }


        for (;;)
        {
            IsPinName((UBYTE *)&PinNamesOpt[0], numofpins_Opt);

            if (!actPin.p_Pin)
            {                               /* pin name?      */
                AsmError(11, 0);            /* no, then error */
                return(-1);
            }

            if (actPin.p_Neg)
                entry = actPin.p_Pin | NEGATION;
            else
                entry = actPin.p_Pin;

            if (AddByte(buff, (UBYTE)entry))
                return(-1);

            if (GetNextChar())
            {                               /* end of file?    */
                AsmError(2, 0);             /* yes, then error */
                return(-1);
            }

            if (!( IsOR(*actptr) || IsAND(*actptr) ))
            {                                           /* OR or AND? */
                if (strncmp((char *)actptr, "DESCRIPTION", (size_t)11))
                {                                       /* DESCRIPTION? */
                    if (AddByte(buff, (UBYTE)EQUAEND))  /*set mark for the   */
                        return(-1);                     /*end of the equation*/

                    break;                      /* no OR nor AND, then end */
                }
                else
                {
                    if (AddByte(buff, (UBYTE)EQUAEND)) /* set mark for the    */
                        return(-1);                    /* end of the equation */

                    if (AddByte(buff, (UBYTE)EQUASEND))
                        return(-1);         /* set mark for the end of all   */
                                            /* equations (after this mark    */
                                            /* DESCRIPTION follows). Now     */
                                            /* all equations are translated. */
                    return(0);
                }
            }

            if (AddByte(buff, (UBYTE)*actptr))
                return(-1);

            actptr++;

            if (GetNextChar())
            {                               /* unexpected end of file? */
                AsmError(2, 0);
                return(-1);
            }
        }
    }
}





/* EOF */
