--- Expr.rev32536.php	2008-04-09 17:45:51.000000000 +0200
+++ Expr.php	2008-04-09 18:44:37.000000000 +0200
@@ -31,6 +31,20 @@
 define( 'EXPR_NOTEQ', 20 );
 define( 'EXPR_ROUND', 21 );
 define( 'EXPR_EXPONENT', 22 );
+define( 'EXPR_SINE', 23 );
+define( 'EXPR_COSINE', 24 );
+define( 'EXPR_TANGENS', 25 );
+define( 'EXPR_ARCSINE', 26 );
+define( 'EXPR_ARCCOS', 27 );
+define( 'EXPR_ARCTAN', 28 );
+define( 'EXPR_EXP', 29 );
+define( 'EXPR_LN', 30 );
+define( 'EXPR_ABS', 31 );
+define( 'EXPR_FLOOR', 32 );
+define( 'EXPR_TRUNC', 33 );
+define( 'EXPR_CEIL', 34 );
+define( 'EXPR_POW', 35 );
+define( 'EXPR_PI', 36 );
 
 class ExprError extends Exception {
 	public function __construct($msg, $parameter = ''){
@@ -45,11 +59,24 @@
 	var $precedence = array(
 		EXPR_NEGATIVE => 10,
 		EXPR_POSITIVE => 10,
-		EXPR_EXPONENT => 9,
+		EXPR_EXPONENT => 10,
+		EXPR_SINE => 9,
+		EXPR_COSINE => 9,
+		EXPR_TANGENS => 9,
+		EXPR_ARCSINE => 9,
+		EXPR_ARCCOS => 9,
+		EXPR_ARCTAN => 9,
+		EXPR_EXP => 9,
+		EXPR_LN => 9,
+		EXPR_ABS => 9,
+		EXPR_FLOOR => 9,
+		EXPR_TRUNC => 9,
+		EXPR_CEIL => 9,
 		EXPR_NOT => 9,
-		EXPR_TIMES => 8,
-		EXPR_DIVIDE => 8,
-		EXPR_MOD => 8,
+		EXPR_POW => 8,
+		EXPR_TIMES => 7,
+		EXPR_DIVIDE => 7,
+		EXPR_MOD => 7,
 		EXPR_PLUS => 6,
 		EXPR_MINUS => 6,
 		EXPR_ROUND => 5,
@@ -61,6 +88,7 @@
 		EXPR_NOTEQ => 4,
 		EXPR_AND => 3,
 		EXPR_OR => 2,
+		EXPR_PI => 0,
 		EXPR_OPEN => -1,
 		EXPR_CLOSE => -1,
 	);
@@ -84,6 +112,20 @@
 		EXPR_AND => 'and',
 		EXPR_OR => 'or',
 		EXPR_EXPONENT => 'e',
+		EXPR_SINE => 'sin',
+		EXPR_COSINE => 'cos',
+		EXPR_TANGENS => 'tan',
+		EXPR_ARCSINE => 'asin',
+		EXPR_ARCCOS => 'acos',
+		EXPR_ARCTAN => 'atan',
+		EXPR_LN => 'ln',
+		EXPR_EXP => 'exp',
+		EXPR_ABS => 'abs',
+		EXPR_FLOOR => 'floor',
+		EXPR_TRUNC => 'trunc',
+		EXPR_CEIL => 'ceil',
+		EXPR_POW => '^',
+		EXPR_PI => 'pi',
 	);
 
 
@@ -95,6 +137,19 @@
 		'round' => EXPR_ROUND,
 		'div' => EXPR_DIVIDE,
 		'e' => EXPR_EXPONENT,
+		'sin' => EXPR_SINE,
+		'cos' => EXPR_COSINE,
+		'tan' => EXPR_TANGENS,
+		'asin' => EXPR_ARCSINE,
+		'acos' => EXPR_ARCCOS,
+		'atan' => EXPR_ARCTAN,
+		'exp' => EXPR_EXP,
+		'ln' => EXPR_LN,
+		'abs' => EXPR_ABS,
+		'trunc' => EXPR_TRUNC,
+		'floor' => EXPR_FLOOR,
+		'ceil' => EXPR_CEIL,
+		'pi' => EXPR_PI,
 	);
 
 	/**
@@ -161,9 +216,36 @@
 					throw new ExprError('unrecognised_word', $word);
 				}
 				$op = $this->words[$word];
-				// Unary operator
 				switch($op){
+				// constant
+				case EXPR_EXPONENT:
+					if ( $expecting != 'expression' ) {
+						continue;
+					}
+					$operands[] = exp(1);
+					$expecting = 'operator';
+					continue 2;
+				case EXPR_PI:
+					if ( $expecting != 'expression' ) {
+						throw new ExprError('unexpected_number');
+					}
+					$operands[] = pi();
+					$expecting = 'operator';
+					continue 2;
+				// Unary operator
 				case EXPR_NOT:
+				case EXPR_SINE:
+				case EXPR_COSINE:
+				case EXPR_TANGENS:
+				case EXPR_ARCSINE:
+				case EXPR_ARCCOS:
+				case EXPR_ARCTAN:
+				case EXPR_EXP:
+				case EXPR_LN:
+				case EXPR_ABS:
+				case EXPR_FLOOR:
+				case EXPR_TRUNC:
+				case EXPR_CEIL:
 					if ( $expecting != 'expression' ) {
 						throw new ExprError('unexpected_operator', $word);
 					}
@@ -220,6 +302,10 @@
 				$name = $char;
 				$op = EXPR_DIVIDE;
 				++$p;
+			} elseif ( $char == '^' ) {
+				$name = $char;
+				$op = EXPR_POW;
+				++$p;
 			} elseif ( $char == '(' )  {
 				if ( $expecting == 'operator' ) {
 					throw new ExprError('unexpected_operator', '(');
@@ -392,6 +478,72 @@
 				$left = array_pop( $stack );
 				$stack[] = $left * pow(10,$right);
 				break;
+			case EXPR_SINE:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = sin($arg);
+				break;
+			case EXPR_COSINE:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = cos($arg);
+				break;
+			case EXPR_TANGENS:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = tan($arg);
+				break;
+			case EXPR_ARCSINE:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = asin($arg);
+				break;
+			case EXPR_ARCCOS:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = acos($arg);
+				break;
+			case EXPR_ARCTAN:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = atan($arg);
+				break;
+			case EXPR_EXP:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = exp($arg);
+				break;
+			case EXPR_LN:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = ln($arg);
+				break;
+			case EXPR_ABS:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = abs($arg);
+				break;
+			case EXPR_FLOOR:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = floor($arg);
+				break;
+			case EXPR_TRUNC:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = (int)$arg;
+				break;
+			case EXPR_CEIL:
+				if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$arg = array_pop( $stack );
+				$stack[] = ceil($arg);
+				break;
+			case EXPR_POW:
+				if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]);
+				$right = array_pop( $stack );
+				$left = array_pop( $stack );
+				if ( false === ($stack[] = pow($left, $right)) ) throw new ExprError('division_by_zero', $this->names[$op]);
+				break;
 			default:
 				// Should be impossible to reach here.
 				throw new ExprError('unknown_error');
