 
 /********************************************************************/
 /****                                                            ****/
 /****                                                            ****/
 /****    Program          : Parser.c Baum                        ****/
 /****                                                            ****/
 /****    Version          :    01.15                             ****/
 /****                                                            ****/
 /****    Erstversion      : 21.05.1988                           ****/
 /****                                                            ****/
 /****    Letzte Änderung  : 05.08.1990                           ****/
 /****                                                            ****/
 /****    Compiliert mit   : siehe MAKEFILE                       ****/
 /****                                                            ****/
 /****    Gelinkt mit      : Für Tool.Library                     ****/
 /****                                                            ****/
 /********************************************************************/
 /****                                                            ****/
 /****                                                            ****/
 /****               Copyright by Rüdiger Dreier                  ****/
 /****                                                            ****/
 /****                                                            ****/
 /********************************************************************/
 
 /* 04.12.1989: Alle Konstanten außer e und x möglich   */
 /* 19.12.1989: Fehler in PreCalc bei pi/e beseitigt    */
 
 #include "ToolProto.h"
 #include <string.h>
 #include <exec/memory.h>
 
 extern struct Library *MathIeeeDoubBasBase;
 extern struct Library *MathIeeeDoubTransBase;
 int search(char *string);
 
 int search(char *string)
  {
   int i,a,Fehler=0;
   char VERGLEICH[38];
   if(strlen(string)==NULL)return(-1);
   strcpy(VERGLEICH,"xeintasinatanacossqrlogabssgnlnpi");
   for(i=0;i<=strlen(VERGLEICH)-1;i++)
    {
     Fehler=0;
     for(a=0;a<=strlen(string)-1;a++)
      {
       if(string[a]!=VERGLEICH[i+a])Fehler=-1;
      }
     if(Fehler==0)break;
    }
   if(Fehler==-1)i=-1;
   if(strlen(string)==1&&i>1)i=-1;
   return(i);
  }
 
 /* Diese Funktion arbeitet einen String ab und legt entsprechend einen */
 /* Baum im Speicher an.                                                */
 LONG __asm ev(register __d0 LONG l,register __d1 LONG r,register __d2 struct Block *block)
  {
   char Hilfe[9];
   char Ziffern[100];
   struct Block *BL,*BR;
   LONG Fehler=0;
   int Pos1,Anzahl_Zeichen;
   char Exponent_gefunden;
   
   block->Links=l;
   block->Rechts=r;
   
   if(r<l)return(0);
   
   BL=(struct Block *)AllocMem(sizeof(struct Block),MEMF_CLEAR);
   if(BL==NULL)return(NO_MEM);
   BR=(struct Block *)AllocMem(sizeof(struct Block),MEMF_CLEAR);
   if(BR==NULL)
    {
     FreeMem((UBYTE *)BL,sizeof(struct Block));
     return(NO_MEM);
    }
   
   BR->String=BL->String=block->String;
   block->Left=BL;
   block->Right=BR;
   
   /* Test auf Additive Blöcke */
   if((Pos1=checkback('+','-',l,r,block->String))!=-1L)
    {
     LONG ll; /* Zum Speichern der linken Ecke */
     ll=l;
     /* Wenn ein entsprechendes Rechenzeichen gefunden wurde : */
     do
      {
       /* Testet auf a^+-b                                      */
       /* Pos1==ll testet, ob ein ^ überhaupt im Bereich ist,   */
       /* denn das kann nur passieren, wenn ^ eins vor l (orig) */
       /* ist. ll wird zwar immer erhöht, das Zeichen davor ist */
       /* dann aber garantiert ein +-.                          */
       
       if((block->String[Pos1-1]!='^'&&block->String[Pos1-1]!='e'&&block->String[Pos1-1]!='d') || Pos1==ll)
        {
         Exponent_gefunden=FALSE;
         
         /* Solange aufmultiplizieren, bis alle Blöcke abgearbeitet sind */
         Fehler|=ev(ll,Pos1-1L,BL); /* Subtrahiert Block bis Minuszeichen */
         Fehler|=ev(Pos1+1L,r,BR);
         if (block->String[Pos1]=='-')
          {
           block->RechenArt|=SUBT;
          }
         else
          {
           block->RechenArt|=ADDI;
          }
        }
       else
        {
         Exponent_gefunden=TRUE;
        }
       Pos1=checkback('+','-',l,Pos1-1L,block->String);
      }
     while(Exponent_gefunden&&Pos1!=-1L);
     if(!Exponent_gefunden)return(Fehler);
    }
   
   
   /* Test auf Multiplikative Blöcke */
   if((Pos1=checkback('*','/',l,r,block->String))!=-1L)
    {
     /* Wenn Punktrechnung gefunden wurde : */
      {
       Fehler|=ev(l,Pos1-1L,BL);
       Fehler|=ev(Pos1+1L,r,BR);
       /* Solange Berechnen, bis kein Block mehr da */
       if (block->String[Pos1]=='/')
        {
         block->RechenArt|=DIVI;
        }
       else
        {
         block->RechenArt|=MULT;
        }
      }
     return(Fehler);
    }
   
   
     /* Abfrage auf Potenz                 */
     /* Muß vor Abfrage auf Klammern sein  */
     /* Getauscht : 07.09.1988             */
   
   if((Pos1=checkback('^','^',l,r,block->String))!=-1)
    {
     Fehler|=ev(l,Pos1-1L,BL);
     Fehler|=ev(Pos1+1L,r,BR);
     block->RechenArt|=POWE;
     return(Fehler);
    }
   
     /* Klammern um den Block ?                      */
     /* nicht korrekte Abfrage, aber sicherer        */
     /* Korrekt: Auf schließende Klammer testen      */
     /* Bearbeitet gleichen Block weiter             */
   
   if (block->String[l]=='(')  
    {
     block->Left=block->Right=0;
     FreeMem((UBYTE *)BL,sizeof(struct Block));
     FreeMem((UBYTE *)BR,sizeof(struct Block));
     if(!(block->String[r]==')'))
      {
       Fehler|=UNPAKLAM;
       Fehler|=(ev(l+1L,r,block));
      }
     else
      {
       Fehler|=(ev(l+1L,r-1,block));
      }
     return(Fehler);
    }
   
   FreeMem((UBYTE *)BL,sizeof(struct Block));
   block->Left=NULL;
   /* Abfrage der trigonometrischen Funktionen   */
   /* Hier wird auf schließende Klammer getestet */
   
   Anzahl_Zeichen=0;
   Pos1=min(5,r-l);
   Hilfe[0]='_';
   while(Anzahl_Zeichen<=Pos1&&block->String[l+Anzahl_Zeichen]!='(')
    {
     Hilfe[Anzahl_Zeichen]=block->String[l+Anzahl_Zeichen];
     Anzahl_Zeichen++;
    }
   Hilfe[Anzahl_Zeichen]=0;
   Pos1=search(Hilfe);
   
   if(Pos1<31&&Pos1>1)
    {
     Fehler|=(ev(l+(LONG)Anzahl_Zeichen,r,BR));
    }
   
   
   switch(Pos1)
    {
     /* int */
     case 2:
      {
       block->RechenArt|=FLOO;
       /*Fehler|=(ev(l+3L,r,BR));*/
       break;
      }
     
     /* Sinus */
     case 6:
      {
       block->RechenArt|=SINU;
       /*Fehler|=(ev(l+3L,r,BR));*/
       break;
      }
     
     /* Cosinus */
     case 14:
      {
       block->RechenArt|=COSI;
       /*Fehler|=(ev(l+3L,r,BR));*/
       break;
      }
     
     /* Tangens */
     case 10:
      {
       block->RechenArt|=TANG;
       /*Fehler|=(ev(l+3L,r,BR));*/
       break;
      }
     
     /* Wurzel Sqr */
     case 17:
      {
       block->RechenArt|=SQRT;
       /*Fehler|=ev(l+3L,r,BR);*/
       break;
      }
     
     /* log */
     case 20:
      {
       block->RechenArt|=LOG1;
       /*Fehler|=ev(l+3L,r,BR);*/
       break;
      }
     
     /* abs */
     case 23:
      {
       block->RechenArt|=ABSO;
       /*Fehler|=(ev(l+3L,r,BR));*/
       break;
      }
     
     /* sgn */
     case 26:
      {
       block->RechenArt|=SIGU;
       /*Fehler|=(ev(l+3L,r,BR));*/
       break;
      }
     
     /* ArcSinus */
     case 5:
      {
       block->RechenArt|=ASIN;
       /*Fehler|=ev(l+4L,r,BR);*/
       break;
      }
     
     /* ACosinus */
     case 13:
      {
       block->RechenArt|=ACOS;
       /*Fehler|=ev(l+4L,r,BR);*/
       break;
      }
     
     /* ArcTangens */
     case 9:
      {
       block->RechenArt|=ATAN;
       /*Fehler|=(ev(l+4L,r,BR));*/
       break;
      }
     
     /* ln */
     case 29:
      {
       block->RechenArt|=LNAT;
       /*Fehler|=ev(l+2L,r,BR);*/
       break;
      }
     
     /* x */
     case 0:
      {
       block->RechenArt=X;
       break;
      }
     
     /* PI         */
     case 31:
      {
       /* 07.09.1988 */
       block->Wert=PI;
       block->Valid=1;
       block->RechenArt=MKON;
       break;
      }
     
     /* E          */
     case 1:
      {
       /* 07.09.1988 */
       block->Wert=E;
       block->Valid=1;
       block->RechenArt=MKON;
       break;
      }
     
     default:
      {
       /* Wenn der Block aus nur einen Zeichen besteht */
       if(r==l&&(block->String[l]>='a'&&block->String[l]<='z'))
        {
         /* Abfrage der Konstanten a-d */
         /* a-z        */
         /* 05.10.1988 */
         Pos1=block->Konstante=(block->String[l]-96);
         if(Pos1<=0||Pos1>=26)Fehler|=NO_KONST;
         
         block->RechenArt=UKON;
         FreeMem((UBYTE *)BR,sizeof(struct Block));
         block->Right=NULL;
        }
       
       /* Nur noch Ziffern */
       if((block->String[l]>='0' && block->String[l]<='9')||block->String[l]=='.')
        {
         for (Pos1=l;Pos1<=r;Pos1++)
          {
           Ziffern[Pos1-l]=block->String[Pos1];
          }
         Ziffern[Pos1-l]=0;
         UmwStoF(&block->Wert,Ziffern);
         FreeMem((UBYTE *)BR,sizeof(struct Block));
         block->Right=NULL;
         block->RechenArt=ZIFF;
        }
       if(block->RechenArt==NULL)Fehler|=NO_FUNC;
      }
      /* ENDE default */
    }
    /* ENDE switch */
   return(Fehler);
  }
 
 
 VOID __asm Free_Block(register __a0 struct Block *First)
  {
   struct Block *Links,*Rechts;
   
   Links=First->Left;
   Rechts=First->Right;
   
   if(Links)Free_Block(Links);
   if(Rechts)Free_Block(Rechts);
   
   FreeMem((UBYTE *)First,sizeof(struct Block));
  }
 
 /* Gibt den Speicher wieder frei */
 VOID __asm Free_Konst(register __a0 APTR Zeiger)
  {
   FreeMem((char *)Zeiger,26*sizeof(DOUBLE));
  }
 
 /* Holt Speicher für Konstanten -> Null, wenn kein Erfolg */
 APTR Init_Konst()
  {
   APTR Zeiger;
   Zeiger=(APTR)AllocMem(26*sizeof(DOUBLE),MEMF_CLEAR);
   return(Zeiger);
  }
 
 /* Hilferoutine, die mit Zeigern auf DOUBLE arbeitet */
 LONG __asm Set_Konst_P(register __a0 APTR Zeiger,register __d0 LONG Nummer,register __d1 DOUBLE *Wert_P)
  {
   DOUBLE Wert;
   Wert=*Wert_P;
   return(Set_Konst(Zeiger,Nummer,Wert));
  }
 
 /* Setzt Konst-Nr. auf Wert */
 LONG Set_Konst(APTR Zeiger,LONG Nummer,DOUBLE Wert)
  {
   DOUBLE *Z;
   if(Nummer<=0||Nummer>=26)return(NO_KONST);
   Z=(DOUBLE *)Zeiger;
   Z[Nummer-1]=Wert;
   return(0);
  }
 
 struct Block * __asm Init_Mem(register __a0 char *string)
  {
   struct Block *FirstBlock;
   FirstBlock=(struct Block *)AllocMem((sizeof(struct Block)),MEMF_CLEAR);
   if(FirstBlock==NULL)return(0);
   FirstBlock->Rechts=strlen(string)-1;
   FirstBlock->String=string;
   return(FirstBlock);
  }
 
 LONG __asm Init_Block(register __a0 struct Block *Zeiger)
  {
   LONG Fehler;
   Fehler=ev(0L,strlen(Zeiger->String)-1L,Zeiger);
   return(Fehler);
  }
 
 /* Hilfsroutine, die das nächste Auftreten eines der beiden Zeichen sucht */
 LONG __asm check(register __d0 LONG z1,register __d1 LONG z2,
                  register __d2 LONG l,register __d3 LONG r,
                  register __a0 char *string)
  {
   int i,Klammern=0;
   
   for (i=l;i<=r;i++)
    {
     if (Klammern==0 && (string[i]==z1||string[i]==z2))
      {
       return(i); /* z1 gefunden */
      }
     if(string[i]=='(')
      {
       Klammern++; /* Auf anderer Klammerebene */
      }
     if(string[i]==')')
      {
       Klammern--;
      }
    }
   return(-1); /* Nicht gefunden */
  }
 
 /* Hilfsroutine, die das nächste Auftreten eines der beiden Zeichen sucht */
 /* Sucht von hinten..                                                     */
 LONG __asm checkback(register __d0 LONG z1,register __d1 LONG z2,
                      register __d2 LONG l,register __d3 LONG r,
                      register __a0 char *string)
  {
   int i,Klammern=0;
   
   for (i=r;i>=l;i--)
    {
     if (Klammern==0 && (string[i]==z1 || string[i]==z2))
      {
       return(i); /* z1 gefunden */
      }
     if(string[i]=='(')
      {
       Klammern++; /* Auf anderer Klammerebene */
      }
     if(string[i]==')')
      {
       Klammern--;
      }
    }
   return(-1); /* Nicht gefunden */
  }
 
 /* Hilfsroutine, die Teile des Strings kopiert */
 VOID __asm copy(register __d0 LONG i,register __d1 LONG Anzahl,
                 register __d2 char *Ziel,register __d3 char *Source)
  {
   int Schleife;
   for (Schleife=i;Schleife<i+Anzahl;Schleife++)
    {
     *(Ziel+Schleife-i)=*(Source+Schleife);
    }
   *(Ziel+Schleife-i)=0;
  }
 
 
 /* Liefert Vorzeichen zurück */
 double sgn(DOUBLE x)
  {
   DOUBLE Ergebnis;
   if(Cmp(x,0.0)==1)
    {
     Ergebnis=1.0;
    }
   else
    {
     if(Cmp(x,0.0)==-1)
      {
       Ergebnis=-1.0;
      }
     else
      {
       Ergebnis=0.0;
      }
    }
   return(Ergebnis);
  }
 
 
 LONG BereichsKontr(DOUBLE b)
  {
   if(Cmp(b,1.0)==1||Cmp(b,-1.0)==-1)
    {
     return(1);
    }
   return(0);
  }
 
 
 LONG __asm PreCalc(register __d0 struct Block *Zeiger,register __d1 APTR Konst)
  {
   DOUBLE Wert,links,rechts;
   LONG Valid=1,v1,v2,Fehler=0;
   Wert=Zeiger->Wert;
   Zeiger->Fehler=Fehler;
   if(Zeiger->Left )
    {
     Fehler=PreCalc(Zeiger->Left,Konst);
     links =Zeiger->Left->Wert;
     v1    =Zeiger->Left->Valid;
    }
   else
    {
     v1=1;
    }
   
   if(Zeiger->Right)
    {
     Fehler|=PreCalc(Zeiger->Right,Konst);
     rechts=Zeiger->Right->Wert;
     v2    =Zeiger->Right->Valid;
    }
   else
    {
     v2=1;
     /* Wenn rechts kein Block folgt, dann ist es der letzte Block */
     Wert=Zeiger->Wert;
    }
   if(v1&&v2)
    {
     switch(Zeiger->RechenArt)
      {
       case ADDI:
        {
         Wert=Add(links,rechts);
         break;
        }
       case SUBT:
        {
         Wert=Sub(links,rechts);
         break;
        }
       case MULT:
        {
         Wert=Mul(links,rechts);
         break;
        }
       case DIVI:
        {
         if(Tst(rechts))
          {
           Wert=Div(links,rechts);
          }
         else
          {
           Fehler|=DIVBYZERO;
          }
         break;
        }
       case POWE:
        {
         Wert=Pow(links,rechts);
         /* Testet, ob Fehler aufgetreten ist. 0 -> 0^x oder neg^bruch ! */
         if(Tst(Wert)==0&&Tst(links)!=0)Fehler|=POWERROR;
         break;
        }
       case SINU:
        {
         Wert=Sin(rechts);
         break;
        }
       case COSI:
        {
         Wert=Cos(rechts);
         break;
        }
       case TANG:
        {
         Wert=Tan(rechts);
         break;
        }
       case ASIN:
        {
         if(BereichsKontr(rechts))
          {
           Fehler|=ATRIG;
          }
         else
          {
           Wert=ASin(rechts);
          }
         break;
        }
       case ACOS:
        {
         if(BereichsKontr(rechts))
          {
           Fehler|=ATRIG;
          }
         else
          {
           Wert=ACos(rechts);
          }
         break;
        }
       case ATAN:
        {
         Wert=ATan(rechts);
         break;
        }
       case LOG1:
        {
         if(Cmp(rechts,0.0)<=0L)
          {
           Fehler|=LOGNEG;
          }
         else
          {
           Wert=Log10(rechts);
          }
         break;
        }
       case LNAT:
        {
         if(Cmp(rechts,0.0)<=0L)
          {
           Fehler|=LOGNEG;
          }
         else
          {
           Wert=Log(rechts);
          }
         break;
        }
       case ABSO:
        {
         Wert=Abs(rechts);
         break;
        }
       case SIGU:
        {
         Wert=sgn(rechts);
         break;
        }
       case SQRT:
        {
         if(Tst(rechts)==-1L)
          {
           Fehler|=SQRTNEG;
          }
         else
          {
           Wert=Sqr(rechts);
          }
         break;
        }
       case FLOO:
        {
         Wert=Floor(rechts);
         break;
        }
       case UKON:
        {
         if(Konst)Wert=GetKonst(Konst,(LONG)Zeiger->Konstante);
         break;
        }
       case X:
        {
         Wert=0.0;
         Valid=0;
        }
      }
     Zeiger->Fehler|=Fehler;
     if(Valid&&!Fehler)
      {
       Zeiger->Wert=Wert;
       Zeiger->Valid=1;
      }
     else
      {
       Zeiger->Valid=0;
      }
    }
   else
    {
     Zeiger->Valid=0;
     Zeiger->Wert=NULL;
    }
   return(Fehler);
  }
 
 /* Hilferoutine, die mit Zeigern auf DOUBLE arbeitet */
 VOID __asm GetKonst_P(register __a0 DOUBLE *Ziel,
                       register __a1 APTR Konst,
                       register __d0 LONG Nummer)
  {
   DOUBLE Wert;
   
   Wert=GetKonst(Konst,Nummer);
   Wert=Add(Wert,0.0);
   *Ziel=Wert;
  }
 
 DOUBLE __asm GetKonst(register __a0 APTR Konst,register __d1 LONG Nummer)
  {
   DOUBLE *Z;
   if(Nummer<=0||Nummer>=26)return(0.0);
   Z=(DOUBLE *)Konst;
   return(Z[Nummer-1]);
  }
 
 
 /* Hilferoutine, die mit Zeigern auf DOUBLE arbeitet */
 LONG __asm Calc_P(register __a0 DOUBLE *Ziel,
                   register __a1 struct Block *Zeiger,
                   register __a2 DOUBLE *x)
  {
   DOUBLE Wert;
   DOUBLE Ergebnis;
   struct Block *START;
   
   START=Zeiger;
   Wert=*x;
   Ergebnis=Calc(START,Wert);
   *Ziel=Ergebnis;
   return(Zeiger->Fehler);
  }
 
 DOUBLE Calc(struct Block *Zeiger,DOUBLE x)
  {
   DOUBLE Wert=0.0,links,rechts;
   LONG Fehler=0;
   /* Evt. die obige Zeile raus und dafür unten Zeiger->Fehler=0 */
   
   Zeiger->Fehler=0; /* Löscht Fehler alter Durchläufe */
   
   if(Zeiger->Valid==1)return(Zeiger->Wert); /* Schon berechnet */ 
   if(Zeiger->Left )
    {
     links=Calc(Zeiger->Left,x);
     Fehler|=Zeiger->Left->Fehler;
    }
   if(Zeiger->Right)
    {
     rechts=Calc(Zeiger->Right,x);
     Fehler|=Zeiger->Right->Fehler;
    }
   else
    {
     Wert=Zeiger->Wert;
    }
   switch(Zeiger->RechenArt)
    {
     case ADDI:
      {
       Wert=Add(links,rechts);
       break;
      }
     case SUBT:
      {
       Wert=Sub(links,rechts);
       break;
      }
     case MULT:
      {
       Wert=Mul(links,rechts);
       break;
      }
     case DIVI:
      {
       if(Tst(rechts))
        {
         Wert=Div(links,rechts);
        }
       else
        {
         Fehler|=DIVBYZERO;
        }
       break;
      }
     case POWE:
      {
       Wert=Pow(links,rechts);
       if(Tst(Wert)==0&&Tst(links)!=0)Fehler|=POWERROR;
       break;
      }
     case SINU:
      {
       Wert=Sin(rechts);
       break;
      }
     case COSI:
      {
       Wert=Cos(rechts);
       break;
      }
     case TANG:
      {
       Wert=Tan(rechts);
       break;
      }
     case ASIN:
      {
       if(BereichsKontr(rechts))
        {
         Fehler|=ATRIG;
        }
       else
        {
         Wert=ASin(rechts);
        }
       break;
      }
     case ACOS:
      {
       if(BereichsKontr(rechts))
        {
         Fehler|=ATRIG;
        }
       else
        {
         Wert=ACos(rechts);
        }
       break;
      }
     case ATAN:
      {
       Wert=ATan(rechts);
       break;
      }
     case LOG1:
      {
       if(Cmp(rechts,0.0)<=0)
        {
         Fehler|=LOGNEG;
        }
       else
        {
         Wert=Log10(rechts);
        }
       break;
      }
     case LNAT:
      {
       if(Cmp(rechts,0.0)<=0)
        {
         Fehler|=LOGNEG;
        }
       else
        {
         Wert=Log(rechts);
        }
       break;
      }
     case ABSO:
      {
       Wert=Abs(rechts);
       break;
      }
     case SIGU:
      {
       Wert=sgn(rechts);
       break;
      }
     case SQRT:
      {
       if(Tst(rechts)==-1L)
        {
         Fehler|=SQRTNEG;
        }
       else
        {
         Wert=Sqr(rechts);
        }
       break;
      }
     case FLOO:
      {
       Wert=Floor(rechts);
       break;
      }
     case UKON:
      {
       Wert=Zeiger->Wert;
       break;
      }
     case X:
      {
       Wert=x;
      }
    }
   Zeiger->Fehler|=Fehler;
   return(Wert);
  }
 
 
 LONG __asm AnzahlKlammern(register __a0 char *string)
  {
   int Laenge,Klammern;
   unsigned short i;
   Klammern=0;
   Laenge=strlen(string)-1;
   for(i=0;i<=Laenge;i++)
    {
     if(string[i]=='(')Klammern++;
     if(string[i]==')')Klammern--;
    }
   return(Klammern);
  }
 
 VOID __asm berechnen(register __a0 DOUBLE *Ziel,
                      register __d0 UBYTE *string,
                      register __d1 DOUBLE *var,
                      register __d2 struct Konstanten *kon,
                      register __d3 LONG *Fehler)
  {
   LONG f;
   DOUBLE Wert;
   DOUBLE Ruckgabe;
   struct Block *START;
   
   Wert=*var;
   
   START=Init_Mem(string);
   f=Init_Block(START);
   *Fehler=f;
   
   f=PreCalc(START,(APTR)kon);   /* Nötig, um Konstanten einzubinden */
   Ruckgabe=Calc(START,Wert);
   *Fehler|=f;
   
   Free_Block(START);
   
   *Ziel=Ruckgabe;
  }
 
