oper = $op; $this->number = $num; } function getFix() // -1 = prefiksowy, 0 = infiksowy, 1 = postfiksowy { $fix = array("+"=>0,"-"=>0,"*"=>0,"/"=>0,"%"=>0,"|"=>0,"^"=>0, /* operatory 2-arg infiksowe */ "sin"=>-1,"asin"=>-1,"cos"=>-1,"acos"=>-1, /* operatory 1-arg. prefiksowe */ "tg" =>-1,"atg" =>-1,"ctg"=>-1,"actg"=>-1, "ln" =>-1,"log" =>-1,"exp"=>-1,"~" =>-1,"#"=>-1, "!"=>1, /* silnia to operator 1-arg. postfiksowy */ "("=>0,")"=>0,"val"=>0,"end"=>0); /* pozostałe tokeny nie będące operatorami */ if(array_key_exists($this->oper, $fix)) { return $fix[$this->oper]; } echo "Token " . $this->output . "zawiera nieznany funkcji Elem::getArgsCnt() operator!
\n"; return false; } function getArgsCnt() { $type = array("+"=>2,"-"=>2,"*"=>2,"/"=>2,"%"=>2,"|"=>2,"^"=>2, /* operatory 2-arg infiksowe */ "sin"=>1,"asin"=>1,"cos"=>1,"acos"=>1, /* operatory 1-arg. prefiksowe */ "tg" =>1,"atg" =>1,"ctg"=>1,"actg"=>1, "ln"=>1,"log"=>1,"exp"=>1,"~"=>1,"#"=>1, "!"=>1, /* silnia to operator 1-arg. postfiksowy */ "("=>0,")"=>0,"val"=>0,"end"=>0); /* pozostałe tokeny nie będące operatorami */ if(array_key_exists($this->oper, $type)) { return $type[$this->oper]; } echo "Token " . $this->output . "zawiera nieznany funkcji Elem::getArgsCnt() operator!
\n"; return false; } function getPriority() { $prior = array("+"=>1,"-"=>1,"*"=>2,"/"=>2,"%"=>2,"|"=>4,"^"=>4, /* operatory 2-arg infiksowe */ "sin"=>5,"asin"=>5,"cos"=>5,"acos"=>5, /* operatory 1-arg. prefiksowe */ "tg" =>5,"atg" =>5,"ctg"=>5,"actg"=>5, "ln"=>5,"log"=>5,"exp"=>5,"~"=>3,"#"=>4, "!"=>7, /* silnia to operator 1-arg. postfiksowy */ "("=>0,")"=>0,"val"=>0,"end"=>0); /* pozostałe tokeny nie będące operatorami */ if(array_key_exists($this->oper, $prior)) { return $prior[$this->oper]; } echo "Token " . $this->output . "zawiera nieznany funkcji Elem::getPriority() operator!
\n"; return false; } function isNumber() { return ($this->oper == "val"); } function output() { if($this->isNumber()) return $this->number; else if($this->oper != "end") return $this->oper; } } function NWD(&$x, &$y) { while($y) { $r=$x%$y; $x=$y; $y=$r; } return(abs($x)); } function dwumian_newtona(&$n, &$k) { $wl=1; $wm=1; $lt[0] = 1; $mt[0] = 1; for($i=1;$i<=$n-$k;$i++) $lt[$i]=$k+$i; for($i=1;$i<=$n-$k;$i++) $mt[$i]=$i; for($l=$n-$k;$l>0;$l--) if ($lt[$l]>1) { for($m=$n-$k;$m>0;$m--) if ($mt[$m]>1) { if($lt[$l]==$mt[$m]) {$lt[$l]=1;$mt[$m]=1;} else { $i=NWD($lt[$l],$mt[$m]); if($i>1) { $lt[$l]/=$i; $mt[$m]/=$i; } } } } for($l=$n-$k;$l>0;$l--) if ($lt[$l]>1) $wl*=$lt[$l]; for($m=$n-$k;$m>0;$m--) if ($mt[$m]>1) $wm*=$mt[$m]; return($wl/$wm); } function ctg(&$x) { if(sin($x)) return cos($x) / sin($x); else return false; } function actg(&$x) { return M_PI / 2 - atan($x); } function ns(&$n) { if ($n <= 1) return 1; else { $a = 1; for ($i = 2; $i <= $n; $i++) $a = $a * $i; return $a; } } function blad(&$lista) { if($lista->valid()) echo "Blad skladni - token ". $lista->current()->output() ."
\n"; else echo "Błąd składni - nieoczekiwany koniec wyrażenia matematycznego
\n"; return false; } function nastepny_token(&$lista) { if($lista->valid()) { $lista->next(); return $lista->valid(); } return false; } function p_(&$lista) { while ($lista->current()->getFix() == -1) /* operatory prefiksowe */ { if(!nastepny_token($lista)) return false; } return true; } function n_(&$lista) { while ($lista->current()->getFix() == 1) /* operatory postfiksowe (silnia) */ { if(!nastepny_token($lista)) return false; } return true; } function f_(&$lista) { switch ($lista->current()->oper) { case "val": return nastepny_token($lista); case "(": return (nastepny_token($lista) && e_($lista) && ($lista->current()->oper == ")") && nastepny_token($lista)); default: return false; } } function e1_(&$lista) { switch ($lista->current()->oper) { case "end": case ")" : return true; default: if($lista->current()->getFix() == 0) // operator infiksowy { return (nastepny_token($lista) && p_($lista) && f_($lista) && n_($lista) && e1_($lista)); } return false; } } function e_(&$lista) { return (p_($lista) && f_($lista) && n_($lista) && e1_($lista)); } function analizator_skladniowy(&$lista) { /* analizator skladniowy */ $lista->rewind(); $ok = e_($lista); if(!$ok || !$lista->valid() || ($lista->current()->oper != "end")) return blad($lista); return $ok; } function wez_slowo(&$wiersz, &$i, &$terazliczba) { $j = 0; $dl = strlen($wiersz); if($i > $dl) return ""; $s = str_split($wiersz); $s[] = ""; while (($i < $dl) && ($s[$i] == " ")) $i++; if (!$terazliczba && (($s[$i] == "+") || ($s[$i] == "-")) || ($s[$i] == "*") || ($s[$i] == "/") || ($s[$i] == ":") || ($s[$i] == ")") || ($s[$i] == "(") || ($s[$i] == "^") || ($s[$i] == "!") || ($s[$i] == "|") || ($s[$i] == "%") || ($s[$i] == "#")) { $slowo = $s[$i]; $i++; $j++; } else { $slowo = ""; $lastch = " "; $liczba = true; while (($s[$i] != " ") && ($i < $dl) && (!(((($s[$i] == "+") || ($s[$i] == "-")) && !$terazliczba) || ($s[$i] == "*") || ($s[$i] == "/") || ($s[$i] == ":") || ($s[$i] == ")") || ($s[$i] == "(") || ($s[$i] == "^") || ($s[$i] == "!") || ($s[$i] == "|") || ($s[$i] == "%") || ($s[$i] == "#")) || ($liczba && ($lastch == "e")))) { $lastch = strtolower($s[$i]); if (((ord($lastch) >= ord("a")) && (ord($lastch) <= ord("z")) && ($lastch != "e")) || (($lastch == "e") && ($j == 0)) || ((($s[$i - $j] == "-") || ($s[$i - $j] == "+")) && ($j == 1) && ($lastch == "e"))) $liczba = false; $terazliczba = false; $slowo = $slowo . strtolower($s[$i]); $i++; $j++; } } return $slowo; } function sprawdz_slowo(&$slowo, &$lista, &$terazliczba) { $terazliczba = false; if(!strncmp($slowo,"0x",2)) { $slowohex = substr($slowo,2,strlen($slowo)-2); if($slowohex == dechex(hexdec($slowohex))) { $lista->push(new Elem(hexdec(substr($slowo,2,strlen($slowo)-2)))); } } else if(is_numeric($slowo)) { $lista->push(new Elem($slowo)); } else { if(!strncmp($slowo, "-", 1)) { $slowo = substr($slowo, 1); $lista->push(new Elem(0, "~")); } else if(!strncmp($slowo, "+", 1)) { $slowo = ltrim($slowo, "+"); } if(!strncmp($slowo,"0x",2)) { $slowohex = substr($slowo,2,strlen($slowo)-2); if($slowohex == dechex(hexdec($slowohex))) { $lista->push(new Elem(hexdec(substr($slowo,2,strlen($slowo)-2)))); } } else { $terazliczba = true; switch($slowo) { case "sin": case "cos": case "tg": case "ctg": case "asin": case "acos": case "atg": case "actg": case "exp": case "ln": case "log": $lista->push(new Elem(0, $slowo));break; case "e": $lista->push(new Elem(M_E)); $terazliczba = false; break; case "pi": $lista->push(new Elem(M_PI)); $terazliczba = false; break; default: echo "Funkcja sprawdz_slowo nie rozpoznała słowa " . $slowo . "
\n"; return false; } } } return true; } function parsuj_wiersz(&$wiersz, &$lista) { $i = 0; $terazliczba = true; $slowo = wez_slowo($wiersz, $i, $terazliczba); while ($slowo != "") { $terazliczba = true; if((strlen($slowo) > 1) || $slowo == "e") { if(!sprawdz_slowo($slowo, $lista, $terazliczba)) return false; } else { $znak = substr($slowo, 0, 1); switch($znak) { case "+": if(!$lista->isEmpty() && (($lista->top()->oper == "+") || ($lista->top()->oper == "-"))) break; $lista->push(new Elem(0,"+")); break; case "-": if(!$lista->isEmpty()) { if($lista->top()->oper == "+") { $lista->pop(); } elseif($lista->top()->oper == "-") { $lista->pop(); $lista->push(new Elem(0, "+")); break; } $lista->push(new Elem(0, "-")); } else $lista->push(new Elem(0, "~")); break; case ":": case "/": $lista->push(new Elem(0, "/")); break; case "*": case "^": case "%": case "|": $lista->push(new Elem(0, $znak)); break; case "!": $lista->push(new Elem(0, "!")); $terazliczba = false; break; case ")": $lista->push(new Elem(0, ")")); $terazliczba = false; break; case "(": case "#": if(!$lista->isEmpty()) { $topoper = $lista->top()->oper; $beforetopoper = ""; if($lista->offsetExists($lista->count() - 2)) { $beforetopoper = $lista->offsetGet($lista->count() - 2)->oper; } if(($topoper == "val") || ($topoper == ")") || ($topoper == "!")) { $lista->push(new Elem(0, "*")); } else if(($topoper == "+") || ($topoper == "-")) { if(($lista->count() == 1) || !(strpos("+-^*/%|(#", $beforetopoper) === false)) { $lista->pop(); if($topoper == "-") { $lista->push(new Elem(0, "~")); } } } } $lista->push(new Elem(0, $znak)); break; default: if(!sprawdz_slowo($slowo, $lista, $terazliczba)) return false; break; } } $slowo = wez_slowo($wiersz, $i, $terazliczba); } $lista->push(new Elem(0, "end")); return true; } function odwroc_notacje(&$lista, &$pol) { $ws = new SplStack(); $lista->rewind(); while($lista->valid()) { $biezacy = $lista->current(); switch($biezacy->oper) { case "end": break; case "val": $pol->push($biezacy); break; case "(": $ws->push($biezacy); break; case ")": do { /* zdejmij ze stosu wszystkie operatory aż do nawiasu otwierającego włącznie */ $szczyt = $ws->pop(); if($szczyt->oper != "(") $pol->push($szczyt); } while (!$ws->isEmpty() && ($szczyt->oper != "(")); break; default: if($biezacy->getArgsCnt() > 0) { if($pol->isEmpty() || $ws->isEmpty()) $ws->push($biezacy); else { $szczyt = $ws->top(); $stop = ($szczyt->getPriority() < $biezacy->getPriority()); /* niezmiennik stosu - priorytety operatorów powinny rosnąć w kierunku wierzchołka stosu */ /* gdy biezacy operator ma nizszy priorytet od poprzedniego */ /* zdejmij poprzednie operatory ze stosu i zapisz na kolejke wyjsciowa */ while(!$stop) { $szczyt = $ws->pop(); $pol->push($szczyt); if(!$ws->isEmpty()) { $szczyt = $ws->top(); $stop = ($szczyt->getPriority() < $biezacy->getPriority()); } else $stop = true; } /* poloz biezacy operator na stos */ $ws->push($biezacy); } } else return false; break; } // switch $lista->next(); } // while($lista->valid()) while(!$ws->isEmpty()) { $szczyt = $ws->pop(); $pol->push($szczyt); } return true; } function wypisz_liste(&$lista) { $lista->rewind(); while($lista->valid()) { $biezacy = $lista->current(); echo $biezacy->output() . " "; $lista->next(); } echo "
\n"; } function oblicz(&$pol) { $stos = new SplStack(); $pol->rewind(); while($pol->valid()) { while($pol->valid() && ($pol->current()->oper == "val")) { $stos->push($pol->current()->number); $pol->next(); } if($pol->valid()) { $oper = $pol->current(); $pol->next(); if($oper->getArgsCnt() <= 0) { echo "Oblicz: nieprawidłowy operator ". $oper->output() . "
\n"; return false; } for($iArg = $oper->getArgsCnt() - 1; $iArg >= 0; $iArg--) { if($stos->isEmpty()) { echo "Oblicz: zbyt mała ilość argumentów dla ".$oper->getArgsCnt()."-argumentowego operatora ".$oper->output()."
\n"; return false; } $arrArg[$iArg] = $stos->pop(); } switch($oper->oper) { case "+": $wynik = $arrArg[0] + $arrArg[1]; break; case "-": $wynik = $arrArg[0] - $arrArg[1]; break; case "*": $wynik = $arrArg[0] * $arrArg[1]; break; case "/": if($arrArg[1]) $wynik = $arrArg[0] / $arrArg[1]; else { echo "Błąd dzielenia przez 0
\n"; return false; } break; case "%": if($arrArg[1]) $wynik = $arrArg[0] % $arrArg[1]; else { echo "Błąd dzielenia przez 0
\n"; return false; } break; case "^": $wynik = pow($arrArg[0], $arrArg[1]); break; case "!": if(($arrArg[0] >=0) && ($arrArg[0] <= 140)) $wynik = ns($arrArg[0]); else { echo "Błąd - argument silni spoza przedziału <0. 140>
\n"; return false; } break; case "~": $wynik = -$arrArg[0]; break; case "#": if($arrArg[0] >=0) $wynik = sqrt($arrArg[0]); else { echo "Błąd obliczania pierwiastka liczby ujemnej\n"; return false; } break; case "|": if(($arrArg[0] >= $arrArg[1]) && ($arrArg[1] >= 0)) $wynik = dwumian_newtona($arrArg[0], $arrArg[1]); else { echo "Błąd obliczania dwumianu Newtona
\n"; return false; } break; case "sin" : $wynik = sin($arrArg[0]); break; case "asin": if(($arrArg[0] >= -1) && ($arrArg[0] <= 1)) $wynik = asin($arrArg[0]); else { echo "Błąd - argument funkcji asin spoza przedziału <-1,1>
\n"; return false; } break; case "cos" : $wynik = cos($arrArg[0]); break; case "acos": if(($arrArg[0] >= -1) && ($arrArg[0] <= 1)) $wynik = acos($arrArg[0]); else { echo "Błąd - argument funkcji acos spoza przedziału <-1,1>
\n"; return false; } break; case "tg" : $wynik = tan($arrArg[0]); break; case "atg" : $wynik = atan($arrArg[0]); break; case "ctg" : $wynik = ctg($arrArg[0]); if($wynik === false) { echo "Błąd obliczania funkcji ctg
\n"; return false; } break; case "actg": $wynik = actg($arrArg[0]); break; case "exp" : $wynik = exp($arrArg[0]); break; case "ln" : $wynik = log($arrArg[0]); break; case "log" : $wynik = log10($arrArg[0]); break; } $stos->push($wynik); } } if($stos->count() == 1) return $stos->pop(); echo "Oblicz: nieprawidłowa ilość danych na stosie (".$stos->count().") po zakończeniu obliczeń
\n"; return false; } function dec_to_hex(&$dec) { $sign = ""; // suppress errors if( $dec < 0){ $sign = "-"; $dec = abs($dec); } $hex = Array( 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 10 => 'a', 11 => 'b', 12 => 'c', 13 => 'd', 14 => 'e', 15 => 'f' ); $h=''; do { $h = $hex[($dec%16)] . $h; $dec /= 16; } while( $dec >= 1 ); return $sign . "0x" . $h; } $wiersz = $_POST["oblicz"]; $lista = new SplDoublyLinkedList(); $pol = new SplQueue(); $ok = parsuj_wiersz($wiersz, $lista); if($ok) { echo "Oblicz: "; wypisz_liste($lista); $ok = analizator_skladniowy($lista); if($ok) { $ok = odwroc_notacje($lista, $pol); if($ok) { echo "
ONP: "; wypisz_liste($pol); $wynik = oblicz($pol); if(is_numeric($wynik)) { echo "
= ".$wynik . "
\n"; $wynikhex = dec_to_hex($wynik); if((strlen($wynikhex)<20) && (strpos($wynik,".")===false)) echo "
= ". $wynikhex ."
\n"; } } else echo "Błąd konwersji na odwrotną notację polską
\n"; } } else echo "Błąd parsera
\n"; ?>