<?php
/**************************************************
 *                 Kalkulator RPN                 *
 **************************************************
 * Ostatnia modyfikacja: 01.11.2012 (wersja 1.0)  *
 * Autor: Jacek Kowalski (http://jacekk.info)     *
 *                                                *
 * Strona WWW: http://jacekk.info/scripts/rpn     *
 *                                                *
 * Utwór rozprowadzany na licencji                *
 * http://creativecommons.org/licenses/by-nc/2.5/ *
 **************************************************/

/* Kodowanie znaków UTF-8 */

function test($wyr) {
    if(
substr_count($in, '(')!==substr_count($in, ')')) {
        return 
FALSE;
    }
    return 
trim($wyr, '+-*/^ 0123456789.,()')==='';
}

$test = test($_GET['wyrazenie']);

if(!
$_GET['wyrazenie'] OR strlen($_GET['wyrazenie'])>60 OR !$test) {
?>
<form action="" method="get">
<?php if(!$test) {echo '<p><strong>Błąd w wyrażeniu</strong></p>'.$test."\n";} ?>
<input type="text" name="wyrazenie"/> <input type="submit" value="Oblicz"/>
<hr/>
<ul>
<li>Dostępne operatory: + - * / ^ ( )</li>
<?php if(strlen($_GET['wyrazenie'])>100) {echo '<li><strong>Maksymalna ilość znaków: 60</strong></li>'."\n";}
else {echo 
'<li>Maksymalna ilość znaków: 60</li>'."\n";} ?>
<li>Algorytm: Odwrotna Notacja Polska</li>
<li>Autor: <a href="http://jacekk.info">Jacek Kowalski</a></li>
</ul>
</form>
<?php
    
die(0);
}

function 
prior($op) {
    
$prior = array('+' => 1, '-' => 1, '*' => 2, '/' => 2, '^' => 3);

    return 
$prior[$op];
}

function 
error($msg, $code) {
    echo 
'<p>Błąd '.$code.': '.$msg.'</p>';
}

function 
onp_1($in) {
    
$err = array('10' => 'Nierozpoznany znak', '11' => 'Nieprawidłowa ilość nawiasów');

    
$out = array();
    
$stos = array();
    
$tmp = '';

    
$in = str_split($in);

    foreach(
$in as $v) {
        if(
is_numeric($v) OR $v==',' OR $v=='.') {
            if(
$v==',') $v = '.';
            
$tmp .= $v;
        }
        elseif(
$v=='(') {
            if(!empty(
$tmp)) {
                
$out[] = $tmp;
                
$tmp = '';
            }

            
array_push($stos, '(');
        }
        elseif(
$v==')') {
            if(!empty(
$tmp)) {
                
$out[] = $tmp;
                
$tmp = '';
            }

            while(
TRUE) {
                
$wyr = array_pop($stos);

                if(
$wyr==NULL) {
                    
error($err['11'], 11);
                    die(
11);
                }
                if(
$wyr!=='(') {
                    
$out[] = $wyr;
                }
                else
                {
                    break;
                }
            }
        }
        elseif(
$v=='+' OR $v=='-' OR $v=='*' OR $v=='/') {
            
$tmp_prior = prior($v);

            if(!empty(
$tmp)) {
                
$out[] = $tmp;
                
$tmp = '';
            }

            while(
TRUE) {
                
$wyr = array_pop($stos);

                if(
$wyr==NULL) {
                    
array_push($stos, $v);
                    break;
                }
                elseif(
prior($wyr)<$tmp_prior) {
                    
array_push($stos, $wyr, $v);
                    break;
                }
                else
                {
                    
$out[] = $wyr;
                }
            }
        }
        elseif(
$v=='^') {
            if(!empty(
$tmp)) {
                
$out[] = $tmp;
                
$tmp = '';
            }

            
array_push($stos, $v);
        }
        elseif(
$v==' ') {
            continue;
        }
        else
        {
            
error($err['10'].': \''.$v.'\', kod: '.ord($v), 10);
        }
    }

    if(!empty(
$tmp)) {
        
$out[] = $tmp;
        
$tmp = '';
    }

    while(
TRUE) {
        
$wyr = array_pop($stos);

        if(
$wyr==NULL) {
            break;
        }
        else
        {
            
$out[] = $wyr;
        }
    }

    return 
$out;
}

function 
onp_2($in) {
    
$stos = array();

    foreach(
$in as $val) {
        if(
is_numeric($val)) {
            
array_push($stos, $val);
        }
        else
        {
            
$a = array_pop($stos);
            
$b = array_pop($stos);
            switch(
$val) {
                case 
'+':
                    
array_push($stos, bcadd($b, $a, 10));
                break;
                case 
'-':
                    
array_push($stos, bcsub($b, $a, 10));
                break;
                case 
'*':
                    
array_push($stos, bcmul($b, $a, 10));
                break;
                case 
'/':
                    
array_push($stos, bcdiv($b, $a, 10));
                break;
                case 
'^':
                    
array_push($stos, bcpow($b, $a, 10));
                break;
                default:
                    
error('Nierozpoznany znak: '.$val, 10);
                break;
            }
        }
    }

    return 
array_pop($stos);
}

$res1 = onp_1($_GET['wyrazenie']);
$res2 = onp_2($res1);

?>
<form action="" method="get">
<input type="text" name="wyrazenie"/> <input type="submit" value="Oblicz"/>
<hr/>
<pre><?php echo htmlspecialchars($_GET['wyrazenie']).' = '.implode(' ', $res1).' = '.$res2; ?></pre>
<hr/>
<ul>
<li>Dostępne operatory: + - * / ^ ( )</li>
<li>Maksymalna ilość znaków: 60</li>
<li>Algorytm: Odwrotna Notacja Polska</li>
<li>Autor: <a href="http://jacekk.info">Jacek Kowalski</a></li>
</ul>
</form>