Na FreeHostingu Endora běžà desĂtky tisĂc webĹŻ. PĹ™idejte se ještÄ› dnes!
VytvoĹ™it web zdarmaNa FreeHostingu Endora běžà desĂtky tisĂc webĹŻ. PĹ™idejte se ještÄ› dnes!
VytvoĹ™it web zdarma--, +-, *-..., nahradit jediným symbolem už během tohoto kroku. Jistě, můžete si říct, že tyto kombinace operandů nepovolíte zadat, ale to by bylo hodně omezující. Hlavní využití vašeho parseru totiž bude patrně v tom, že bude vyhodnocovat rovnice s parametrickými proměnnými, které se budou dosazovat až za běhu programu.C záporné, vznikne (B--C). Věnujte pozornost i sekvenci *-. Naším cílem je nahradit víceznakové symboly za jednoznakové. Jenže symbol "vynásob a změň znaménko" neexistuje.*- změní na @ a sekvence /- na #Procedure Preprocesor(s:string;var t:string;var chyba:byte); var i,j:byte; k:integer; r:real; uvnitr:boolean; u:string; begin t:=ZrusMezery(s); s:=''; if t[1] in ['-'] then t:='0'+t; {cely vyraz zacina znamenkem minus?} uvnitr:=true; {zaciname uvnitr cisla} u:=''; for i:=1 to Length(t) do begin if uvnitr=true then {uvitr cisla...} begin if t[i] in ['.','0'..'9'] then u:=u+t[i] else begin Val(u,r,k); if (k<>0) or (u='') then {ze znaku '.' a '0'..'9' nevzniklo smysluplne cislo?} begin {(nejspise dve desetinne tecky v jednom cisle)} chyba:=i-Length(u)+k; Exit; end; s:=s+u; u:=t[i]; uvnitr:=false; end; end else begin {jsme vne cisla...} if not (t[i] in ['.','0'..'9']) then u:=u+t[i] else begin if Length(u)>1 then {kombinace symbolu?} begin if u='--' then u:='+' else if u='+-' then u:='-' else if u='*-' then u:='@' else {ZAPORNE NASOBENI} if u='/-' then u:='#' else {ZAPORNE DELENI} if u='*--' then u:='*' else if u='/--' then u:='/' else begin {ostatni kombinace nejsou povolene} chyba:=i; Exit; end; end; s:=s+u; u:=t[i]; uvnitr:=true; end; end; end; {for} if uvnitr=false then {na konci vyrazu musi byt cislo, ne symbol} begin chyba:=i; Exit; end; chyba:=0; s:=s+u; t:=s; end;
Function Uroven1(const s:string):real; var o:byte; {typ operace: (ZADNA, SOUCET, ODECET)} i:byte; r,r2:real; t:string; begin t:=''; o:=NIC; r:=0; for i:=1 to Length(s) do if not (s[i] in ['+','-']) then t:=t+s[i] else begin r2:=Uroven2(t); r:=Operace1(r,r2,o); t:=''; case s[i] of '+':o:=SOUCET; '-':o:=ODECET; end; {case} end; {else begin} {dodelame posledni cislo, za kterym uz neni zadny matematicky symbol} if druh_chyby<>CHYBA_ZADNA then begin Uroven1:=0; Exit; end; r2:=Uroven2(t); Uroven1:=Operace1(r,r2,o); end;Funkce tedy rozkládá výraz na úseky rozdělené znaky plus a mínus a tyto úseky posílá na "vyšší instanci" do funkce Uroven2. Smysl vynikne, podíváme-li se na příklad nějakého matematického výrazu:
3+4*6/2.4+6Function Uroven1(s:string):real; var z,i,o:byte; r,r2:real; t:string; begin if s='' then begin Uroven1:=0;Exit;end; t:=''; o:=NIC; r:=0; z:=0; for i:=1 to Length(s) do begin if s[i]='(' then inc(z); if s[i]=')' then dec(z); if (z<>0) or (not (s[i] in ['+','-'])) then t:=t+s[i] else begin r2:=Uroven2(t); r:=Operace1(r,r2,o); t:=''; case s[i] of '+':o:=SOUCET; '-':o:=ODECET; end; {case} end; {else begin} end; {dodelame posledni cislo, za kterym uz neni znak zadne operace} if druh_chyby<>CHYBA_ZADNA then begin Uroven1:=0; Exit; end; r2:=Uroven2(t); Uroven1:=Operace1(r,r2,o); end;Změnou je tedy zavedení čítače Z, který počítá, jak moc jsme zanořeni v závorkách. Jednotlivé členy výrazu tedy odděluje jen, pokud je zanoření 0, tedy nejsme uvnitř závorky. Výraz s závorkou je tedy rozsekán správně, a to takto:
Function Uroven2(const s:string):real; var i,o,z:byte; r,r2:real; k:integer; t:string; begin if s='' then begin Uroven2:=0;Exit;end; t:=''; o:=NIC; r:=0; z:=0; for i:=1 to Length(s) do begin if s[i]='(' then inc(z); if s[i]=')' then dec(z); if (z<>0) or (not (s[i] in ['*','/','@','#'])) then t:=t+s[i] else begin r:=ZpracujClen(t,r,r2,o); if druh_chyby<>CHYBA_ZADNA then begin Uroven2:=0; Exit; end; t:=''; case s[i] of '*':o:=NASOBENI; '/':o:=DELENI; '@':o:=ZAPORNE_NASOBENI; '#':o:=ZAPORNE_DELENI; end; {case} end; {else begin} end; {dodelame posledni cislo, za kterym uz neni znak zadne operace} Uroven2:=ZpracujClen(t,r,r2,o); end;Jak vidíme, Uroven2 se velmi podobá funkci Uroven1. I ona si musí hlídat zanoření do závorek, protože závorky mají ještě vyšší prioritu než násobení či dělení.
Function ZpracujClen(t:string;r,r2:real;o:byte):real; var k:integer; i:byte; n:real; s:string[10]; begin Val(t,r2,k); {napred to zkus proste prevest na cislo} if k<>0 then {konverze cisla se nepovedla, tudiz je to neco slozitejsiho} if t[1]='(' then begin {zacina to zavorkou, je to tedy zavorka} delete(t,Length(t),1); delete(t,1,1); r2:=Uroven1(t); end else begin k:=Pos('(',t); {zavorka je uvnitr kazdopadne, ale co je pred ni?} s:=Copy(t,1,k-1); delete(t,Length(t),1); delete(t,1,k); r2:=Uroven1(t); if s='SIN' then r2:=sin(r2) else if s='COS' then r2:=cos(r2); {Dalsi matematicke funkce jsem pro zkraceni zdrojaku vypustil} end; ZpracujClen:=Operace2(r,r2,o); end;Funkci si budeme demostrovat na tomto výrazu:
5*cos(0)*(1+2*(2-5))Val.Val ohlásí chybu, tudíž víme, že je to něco složitějšího, než pouhé číslo. První znak tohoto členu není závorka, tudíž jí předchází matematická funkce (nic jiného to být nemůže). Nicméně závorka tam někde musí být tak jako tak, protože mat. funkce mají svoje argumenty v závorkách. Tudíž ji najdeme, vytáhnu vnitřek závorky (v našem případě 0)