/********************************************************************/ /**** ****/ /**** ****/ /**** 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 #include 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(rString=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;SchleifeWert; 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; }