{$opt q,s+} Module Analysis; {$path "ram:include/","pascal:include/"; include"mathieeedoubtrans.lib" } CONST e = 2.718281828; inputlen = 80; LF = chr($0a); TYPE typ = (variable,operator,literal,funktion); atyp = Double; p = ^node; node = RECORD t:typ; name:char; op1,op2:p; value:atyp END; MyStr = String[inputlen]; Buffer = Record s:MyStr; p:integer END; VAR f: ARRAY['f'..'h',0..99] OF p; EXPORT; x,y,hi,lo,step: atyp; v: ARRAY['a'..'d',0..99] OF atyp; EXPORT; c1: char; c: char; EXPORT; i: integer; fx: p; everr: boolean; EXPORT; Ein: Buffer; IMPORT; PROCEDURE InitAnalysis; EXPORT; BEGIN OpenLib(mathieeedoubtransbase,'mathieeedoubtrans.library',0); END; PROCEDURE ReadEin(VAR b:Buffer); IMPORT; PROCEDURE WriteC(s:Str); IMPORT; PROCEDURE WriteP(s:Str); IMPORT; PROCEDURE WritePR(r:atyp; f:integer); IMPORT; Function Pri(b:p):integer; Begin Case b^.t Of operator: Case b^.name Of '+','-': Pri:=1; '*','/': Pri:=2; '^': Pri:=3 End; funktion: Pri:=4; variable,literal: Pri:=5 End End; Procedure WriteFunkName(n:char); Begin Case n Of '-': writeP('-'); '+': writeP('abs'); 'c': writeP('cos'); 'e': writeP('exp'); 'g': writeP('lg'); 'l': writeP('ln'); 'o': writeP('cot'); 'q': writeP('sqr'); 'r': writeP('sqrt'); 's': writeP('sin'); 't': writeP('tan'); 'v': writeP('sgn'); 'C': writeP('arccos'); 'O': writeP('arccot'); 'S': writeP('arcsin'); 'T': writeP('arctan'); End End; Procedure InFix(b:p; pr:integer); EXPORT; Var ap:integer; Begin If b<>Nil Then Case b^.t Of variable: Begin writeP(b^.name); If b^.name='p' Then writeP('i') End; operator: Begin ap:=pri(b); If ap=4) And (b^.name<>'-') Then writeP(' '); InFix(b^.op1,4) End End End; FUNCTION sgn(x:atyp):integer; EXPORT; BEGIN sgn:=ord(x>0)-ord(x<0) END; Function eval(b:p; x:atyp):atyp; EXPORT; Var f,e1,e2:atyp; PROCEDURE Fehler; BEGIN everr:=true END; Begin case b^.t Of Variable:Case b^.name Of 'x': eval:=x; 'e': eval:=e; 'p': eval:=pi End; literal: eval:=b^.value; operator: BEGIN e1:=eval(b^.op1,x); e2:=eval(b^.op2,x); Case b^.name Of '+': eval:=e1+e2; '-': eval:=e1-e2; '*': eval:=e1*e2; '/': IF e2=0 THEN Fehler ELSE eval:=e1/e2; '^': IF e2=0 THEN eval:=1 ELSE IF e2=1 THEN eval:=e1 ELSE IF e2=-1 THEN IF e1=0 THEN Fehler ELSE eval:=1/e1 ELSE IF e1>0 THEN eval:=IEEEDpexp(e2*IEEEDpLog(e1)) ELSE IF e1=0 THEN eval:=0 ELSE IF Abs(Frac(e2))<1e-5 THEN BEGIN e1:=IEEEDpexp(e2*IEEEDpLog(Abs(e1))); IF Odd(Round(e2)) THEN Eval:=-e1 ELSE Eval:=e1 END ELSE Fehler; END End; funktion: Begin f:=eval(b^.op1,x); Case b^.name Of '-': eval:=-f; '+': eval:=abs(f); 'c': eval:=IEEEDpcos(f); 'e': eval:=IEEEDpexp(f); 'g': eval:=IEEEDpLog(f)/IEEEDpLog(10); 'l': IF f<=0 THEN Fehler ELSE eval:=IEEEDpLog(f); 'o': BEGIN e1:=IEEEDpsin(f); IF e1=0 THEN Fehler ELSE eval:=IEEEDpcos(f)/e1 END; 'q': eval:=f*f; 'r': IF f<0 THEN Fehler ELSE eval:=IEEEDpsqrt(f); 's': eval:=IEEEDpsin(f); 't': BEGIN e1:=IEEEDpcos(f); IF e1=0 THEN Fehler ELSE eval:=IEEEDpsin(f)/e1 END; 'v': eval:=round(ord(f>0)-ord(f<0)); 'T': eval:=IEEEDpatan(f); 'O': IF f=0 THEN Fehler ELSE eval:=IEEEDpatan(1/f) End End End End; Procedure Forget(Var z:p); EXPORT; Begin If z<>Nil Then Begin Forget(z^.op1); Forget(z^.op2); dispose(z); z:=Nil End End; Function konstant(b:p):boolean; EXPORT; Begin If b=Nil Then konstant:=true Else Case b^.t Of variable: konstant:=b^.name<>'x'; operator: konstant:=konstant(b^.op1) And konstant(b^.op2); literal: konstant:=true; funktion: konstant:=konstant(b^.op1) End End; Procedure Optimize(Var b:p); Var h:p; Begin If b<>Nil Then Begin Optimize(b^.op1); Optimize(b^.op2); If konstant(b) Then Begin New(h); With h^ Do Begin t:=literal; name:=' '; op1:=Nil; op2:=Nil; value:=eval(b,0) End; Forget(b); b:=h End End End; FUNCTION copy(c:p):p; VAR h:p; BEGIN IF c=Nil THEN copy:=Nil ELSE BEGIN New(h); h^:=c^; h^.op1:=copy(c^.op1); h^.op2:=copy(c^.op2); copy:=h END END; PROCEDURE Subst(a:p; VAR b:p); { In Funktion b wird fuer x jeweils eine Kopie von a eingesetzt } BEGIN IF b<>NIL THEN IF (b^.t=variable) AND (b^.name='x') THEN BEGIN dispose(b); b:=copy(a) END ELSE BEGIN Subst(a,b^.op1); Subst(a,b^.op2) END END; FUNCTION diff(b:p):p; VAR h,h1,h2: p; b1,b2: boolean; e1,e2: atyp; FUNCTION Neulit(r:atyp):p; VAR hl:p; BEGIN New(hl); hl^.t:=literal; hl^.value:=r; hl^.name:=' '; hl^.op1:=Nil; hl^.op2:=Nil; Neulit:=hl END; FUNCTION Neuop(n:char; o1,o2:p):p; VAR hl:p; BEGIN New(hl); hl^.t:=operator; hl^.name:=n; hl^.op1:=o1; hl^.op2:=o2; hl^.value:=0; Neuop:=hl END; FUNCTION Neufun(nam:char; o:p):p; VAR hl:p; BEGIN New(hl); hl^.t:=funktion; hl^.name:=nam; hl^.op1:=o; hl^.op2:=Nil; hl^.value:=0; Neufun:=hl END; FUNCTION Null(h:p):boolean; BEGIN IF konstant(h) THEN Null:=eval(h,1)=0 ELSE Null:=false; END; BEGIN CASE b^.t OF literal: h:=Neulit(0); variable: IF b^.name='x' THEN h:=Neulit(1) ELSE h:=Neulit(0); operator: BEGIN h1:=diff(b^.op1); b1:=konstant(h1); h2:=diff(b^.op2); b2:=konstant(h2); IF b1 THEN e1:=eval(h1,0) ELSE e1:=-1; IF b2 THEN e2:=eval(h2,0) ELSE e2:=-1; CASE b^.name OF '+','-': IF e2=0 THEN IF e1=0 THEN BEGIN h:=neulit(0); Forget(h1); Forget(h2) END ELSE BEGIN h:=h1; Forget(h2) END ELSE IF e1=0 THEN BEGIN IF b^.name='+' THEN h:=h2 ELSE h:=Neufun('-',h2); Forget(h1) END ELSE h:=Neuop(b^.name,h1,h2); '*': IF e1=0 THEN IF e2=0 THEN BEGIN h:=Neulit(0); Forget(h1); Forget(h2) END ELSE IF e2=1 THEN BEGIN h:=copy(b^.op1); Forget(h1); Forget(h2) END ELSE BEGIN h:=Neuop('*',copy(b^.op1),h2); Forget(h1) END ELSE IF e2=0 THEN BEGIN h:=Neuop('*',copy(b^.op2),h1); Forget(h2) END ELSE IF e1=1 THEN BEGIN h:=Neuop('+',copy(b^.op2),Neuop('*',copy(b^.op1),h2)); Forget(h1) END ELSE IF e2=1 THEN BEGIN h:=Neuop('+',Neuop('+',h1,copy(b^.op2)),copy(b^.op1)); Forget(h2) END ELSE h:=Neuop('+',Neuop('*',h1,copy(b^.op2)),Neuop('*',copy(b^.op1),h2)); '/': BEGIN IF e2=0 THEN { Nenner konstant } BEGIN h:=Neuop('/',h1,copy(b^.op2)); Forget(h2) END ELSE IF e1=0 THEN { Zähler konstant } BEGIN IF e2=1 THEN { und Nenner 1-linear } BEGIN h:=Neuop('*',Neulit(-eval(b^.op1,0)), Neuop('^',copy(b^.op2), Neulit(-2))); Forget(h1); Forget(h2) END ELSE BEGIN h:=Neuop('*', Neuop('*',Neulit(-eval(b^.op1,0)), h2), Neuop('^',copy(b^.op2), Neulit(-2))); Forget(h1) END END ELSE BEGIN { Quotientenregel } h:=Neuop('/',Neuop('-', Neuop('*',h1,copy(b^.op2)),Neuop('*',copy(b^.op1),h2)), Neuop('^',copy(b^.op2),Neulit(2))) END END; '^': IF e2=0 THEN BEGIN e2:=eval(b^.op2,0); IF e2=0 THEN { f(x)^0 } BEGIN h:=Neulit(0); Forget(h1); Forget(h2) END ELSE IF e2=1 THEN BEGIN h:=h1; Forget(h2) END ELSE BEGIN { f(x)^n } IF e2=2 THEN h:=copy(b^.op1) { f(x)^2 } ELSE h:=Neuop('^',copy(b^.op1),Neulit(e2-1)); IF e1=1 THEN h:=Neuop('*',Neulit(e2),h) ELSE h:=Neuop('*',Neuop('*',Neulit(e2),h1),h); Forget(h2) END END ELSE IF e1=0 THEN BEGIN e1:=eval(b^.op1,0); IF e2=1 THEN { a^x } IF e1=e THEN { e^x } BEGIN h:=Neufun('e',copy(b^.op2)); Forget(h1); Forget(h2) END ELSE { a<>e } BEGIN h:=NeuOp('*',Neufun('l',copy(b^.op1)), NeuOp('^',copy(b^.op1), copy(b^.op2))); Forget(h1); Forget(h2) END ELSE { a^f(x) } IF e1=e THEN { e^f(x) } IF e2=1 THEN { e^x } BEGIN h:=Neufun('e',copy(b^.op2)); Forget(h1);Forget(h2) END ELSE BEGIN h:=Neuop('*',h2,Neufun('e',copy(b^.op2))); Forget(h1) END ELSE { a<>e} IF e2=1 THEN { a^x } BEGIN h:=Neuop('*',Neufun('l',copy(b^.op1)) ,copy(b)); Forget(h1); Forget(h2) END ELSE BEGIN h:=Neuop('*',Neuop('*', Neufun('l',copy(b^.op1)),h2) ,copy(b)); Forget(h1) END END ELSE { g(x)^h(x) } BEGIN Forget(h1); Forget(h2); h1:=Neufun('e',Neuop('*',copy(b^.op2), Neufun('l',copy(b^.op1)))); h:=diff(h1); Forget(h1) END END END; funktion: BEGIN h1:=copy(b^.op1); h2:=diff(h1); CASE b^.name OF '-': BEGIN h:=Neulit(-1); Forget(h1) END; '+': h:=Neufun('v',h1); 'c': h:=NeuOp('*',Neulit(-1),Neufun('s',h1)); 'e': h:=Neufun('e',h1); 'g': h:=Neuop('*',Neulit(ln(10)),Neuop('^',h1,Neulit(-1))); 'l': h:=Neuop('^',h1,Neulit(-1)); 'o': h:=Neuop('*',Neulit(-1) ,NeuOp('^',Neufun('s',h1),Neulit(-2))); 'q': h:=Neuop('*',Neulit(2),h1); 'r': h:=Neuop('*',Neulit(0.5), NeuOp('^',h1,Neulit(-0.5))); 's': h:=Neufun('c',h1); 't': h:=NeuOp('^',Neufun('c',h1),Neulit(-2)); 'v': BEGIN h:=Neulit(0); Forget(h1) END; 'C': h:=Neuop('*',Neulit(-1), Neuop('^',Neuop('-',Neulit(1), Neufun('q',h1)), Neulit(-0.5))); 'O': h:=Neuop('*',Neulit(-1), Neuop('^',Neuop('+',Neulit(1), Neufun('q',h1)), Neulit(-1))); 'S': h:=Neuop('^',Neuop('-',Neulit(1), Neufun('q',h1)), Neulit(-0.5)); 'T': h:=Neuop('^',Neuop('+',Neulit(1), Neufun('q',h1)), Neulit(-1)) END; IF konstant(h2) THEN e2:=eval(h2,0) ELSE e2:=-1; IF e2=1 THEN Forget(h2) ELSE h:=Neuop('*',h2,h) END End; diff:=h End; FUNCTION GetNum(VAR tx:Buffer; VAR z:char):integer; EXPORT; VAR i:integer; BEGIN i:=0; WHILE (z>='0') AND (z<='9') DO BEGIN i:=10*i + ord(z)-ord('0'); z := tx.s[tx.p]; tx.p := tx.p+1 END; GetNum:=i END; PROCEDURE Inp(VAR tx:Buffer; VAR i:p); EXPORT; VAR c: char; err: boolean; pos: 1..100; einstr: string[100]; PROCEDURE gts; BEGIN IF err THEN c:=chr(0) ELSE BEGIN c := tx.s[tx.p]; tx.p := tx.p+1; IF (c>='A') AND (c<='Z') THEN c:=chr(ord(c)-ord('A')+ord('a')); einstr[pos]:=c; pos:=pos+1 END END; PROCEDURE get; BEGIN REPEAT gts UNTIL c<>' ' END; FUNCTION Neu(tp:typ):p; VAR h:p; BEGIN New(h); WITH h^ DO BEGIN t:=tp; name:=' '; op1:=NIL; op2:=NIL; value:=0 END; Neu:=h END; PROCEDURE Fehler; BEGIN IF NOT err THEN BEGIN einstr[pos]:=chr(0); WriteC('Error: '); WriteC(einstr); WriteC(LF) END; c:=chr(0); err:=true END; PROCEDURE Summe(Var s:p); VAR t:p; PROCEDURE Term(Var h: p); VAR z, hlp:atyp; g:p; c1:char; num:integer; PROCEDURE Parameter; BEGIN iF c='(' THEN BEGIN get; Summe(h^.op1); IF c<>')' THEN Fehler; get END ELSE term(h^.op1) END; PROCEDURE Fun(n:char); BEGIN h:=Neu(funktion); h^.name:=n; get; Parameter END; BEGIN { Term } h:=NIL; IF c='x' THEN BEGIN h:=Neu(variable); h^.name:='x'; get END ELSE IF ((c>='0') AND (c<='9')) or (c='.') THEN BEGIN z:=0; WHILE (c>='0') And (c<='9') DO BEGIN z:=round(10*z+ord(c)-ord('0')); gts End; h:=Neu(literal); IF c='.' THEN BEGIN gts; hlp:=1; WHILE (c>='0') AND (c<='9') DO BEGIN hlp:=hlp/10; z:=z+hlp*round(ord(c)-ord('0')); gts END END; IF c='e' THEN BEGIN gts; IF c='-' THEN BEGIN gts; num:=getnum(tx,c); z:=z*pwr10(-num) END ELSE BEGIN IF c='+' THEN gts; num:=getnum(tx,c); z:=z*dbpwr10(num) END END; IF c=' ' THEN get; h^.value:=z END ELSE If c='(' Then Begin get; Summe(h); If c<>')' Then Fehler; get End ELSE IF c='|' THEN BEGIN get; Summe(g); IF c<>'|' THEN Fehler; get; h := Neu( Funktion ); h^.name := '+'; h^.op1 := g END Else If c='-' Then Fun('-') Else If c='a' Then Begin gts; If c='r' Then Begin gts; If c='c' Then Begin gts; If c='c' Then Begin gts; If c='o' Then Begin gts; If c='s' Then Fun('C') { arccos } Else If c='t' Then Fun('O') { arccot } Else Fehler End Else Fehler End Else If c='s' Then Begin gts; If c='i' Then Begin gts; If c='n' Then Fun('S') Else Fehler { arcsin } End Else Fehler End Else If c='t' Then Begin gts; If c='a' Then Begin gts; If c='n' Then Fun('T') Else Fehler { arctan } End Else Fehler End Else Fehler End Else Fehler End Else If c='b' Then Begin gts; If c='s' Then Fun('+') Else Fehler { abs } End Else { a } BEGIN num:=getnum(tx,c); h:=Neu(literal); h^.value:=v['a',num] END End Else IF c='b' THEN { b } BEGIN get; num:=getnum(tx,c); h:=neu(literal); h^.value:=v['b',num] END ELSE If c='c' Then Begin gts; If c='o' Then Begin gts; If c='s' Then Fun('c') { cos } ELSE IF c='t' THEN Fun('o') { cot } Else Fehler End ELSE BEGIN { c } num:=getnum(tx,c); h:=Neu(literal); h^.value:=v['c',num] END END ELSE IF c='d' THEN BEGIN get; num:=getnum(tx,c); h:=Neu(literal); h^.value:=v['d',num] END ELSE If c='e' Then Begin gts; If c='x' Then Begin gts; If c='p' Then Fun('e') Else Fehler { exp } End Else Begin { e } h:=Neu(variable); h^.name:='e'; If c=' ' Then get End End ELSE IF (c>='f') AND (c<='h') THEN { f, g, h } BEGIN c1:=c; gts; num:=Getnum(tx,c); IF f[c1,num]=NIL THEN Fehler ELSE BEGIN h:=copy(f[c1,num]); WHILE c='''' DO BEGIN get; g:=h; h:=diff(g); Forget(g) END; IF c=' ' THEN get; IF c='(' THEN BEGIN get; Summe(g); Subst(g,h); IF c<>')' THEN Fehler; get; Forget(g) END END END ELSE IF c='l' THEN BEGIN gts; IF c='n' THEN Fun('l') ELSE IF c='g' THEN Fun('g') ELSE Fehler END ELSE IF c='p' THEN BEGIN gts; IF c='i' THEN BEGIN { pi } h:=Neu(variable); h^.name:='p'; get End Else Fehler End Else If c='s' Then Begin gts; If c='i' Then Begin gts; If c='n' Then Fun('s') Else Fehler { sin } End Else If c='g' Then Begin gts; If c='n' Then Fun('v') Else Fehler { sgn } End Else If c='q' Then Begin gts; If c='r' Then Begin get; If c='t' Then Fun('r') { sqrt } Else Begin h:=Neu(funktion); { sqr } h^.name:='q'; Parameter End End Else Fehler End Else Fehler End ELSE IF c='t' THEN BEGIN gts; IF c='a' THEN BEGIN gts; IF c='n' THEN Fun('t') ELSE Fehler END ELSE Fehler END ELSE Fehler; IF c='^' THEN BEGIN get; g:=neu(operator); g^.name:='^'; g^.op1:=h; h:=g; Term(h^.op2) End; If (c>='a') and (c<='z') Or (c='(') Then Begin g:=Neu(operator); g^.op1:=h; h:=g; h^.name:='*'; Term(h^.op2) End End; Procedure Produkt(Var h:p); Var hp:p; Begin Term(h); While (c='*') Or (c='/') Do Begin hp:=Neu(operator); hp^.name:=c; hp^.op1:=h; get; Term(hp^.op2); h:=hp End End; BEGIN { Summe } Produkt(s); WHILE (c='+') OR (c='-') DO BEGIN t:=Neu(operator); t^.name:=c; t^.op1:=s; get; Produkt(t^.op2); s:=t END END; BEGIN { Inp } i:=Nil; err:=false; pos:=1; get; Summe(i); IF err THEN Forget(i) END; PROCEDURE ReadKonst(VAR r:atyp; Var err:boolean); EXPORT; VAR f:p; t:Buffer; BEGIN ReadEin(t); Inp(t,f); IF not konstant(f) Then Begin writeC('not konstant.'\n); forget(f) End; err:=f=Nil; If not err then BEGIN everr:=false; r:=eval(f,0); err:=everr END END; PROCEDURE GetC; EXPORT; BEGIN REPEAT c:=Ein.s[Ein.p]; Ein.p := Ein.p+1 UNTIL c<>' ' END; {$link "AnaII.o","AnaIO.o"; ulink 'Intuition.o', 'Graphics.o', 'Graphtypes.o', 'Exec1.o' }