Index: /trunk/decompilesample.php
===================================================================
--- /trunk/decompilesample.php	(revision 797)
+++ /trunk/decompilesample.php	(revision 799)
@@ -405,8 +405,10 @@
 $this::__construct();
 $obj::__construct();
-
 $a = $b ?: $d;
 $a = ($b ?: $d) + $c;
 $a = f1() ?: f2();
+$a = $b ? $c : $d;
+$a = ($b ? $c : $d) + $c;
+$a = f1() ? f3() : f2();
 
 if ($b ?: $d) {
Index: /trunk/Decompiler.class.php
===================================================================
--- /trunk/Decompiler.class.php	(revision 796)
+++ /trunk/Decompiler.class.php	(revision 799)
@@ -150,5 +150,4 @@
 	var $op2;
 	var $parent;
-	var $indent;
 
 	function Decompiler_Binop($parent, $op1, $opc, $op2)
@@ -164,11 +163,16 @@
 		$opstr = $this->parent->binops[$this->opc];
 
-		$op1 = foldToCode($this->op1, $indent);
-		if (is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
-			$op1 = "(" . str($op1, $indent) . ")";
-		}
-		$op2 = foldToCode($this->op2, $indent);
-		if (is_a($this->op2, 'Decompiler_Binop') && $this->op2->opc != $this->opc && substr($opstr, -1) != '=') {
-			$op2 = "(" . str($op2, $indent) . ")";
+		if (is_a($this->op1, 'Decompiler_TriOp') || is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
+			$op1 = "(" . str($this->op1, $indent) . ")";
+		}
+		else {
+			$op1 = $this->op1;
+		}
+
+		if (is_a($this->op2, 'Decompiler_TriOp') || is_a($this->op2, 'Decompiler_Binop') && $this->op2->opc != $this->opc && substr($opstr, -1) != '=') {
+			$op2 = "(" . str($this->op2, $indent) . ")";
+		}
+		else {
+			$op2 = $this->op2;
 		}
 
@@ -177,5 +181,33 @@
 		}
 
-		return str($op1) . ' ' . $opstr . ' ' . str($op2);
+		return str($op1, $indent) . ' ' . $opstr . ' ' . str($op2, $indent);
+	}
+}
+// }}}
+class Decompiler_TriOp extends Decompiler_Code // {{{
+{
+	var $condition;
+	var $trueValue;
+	var $falseValue;
+
+	function Decompiler_TriOp($condition, $trueValue, $falseValue)
+	{
+		$this->condition = $condition;
+		$this->trueValue = $trueValue;
+		$this->falseValue = $falseValue;
+	}
+
+	function toCode($indent)
+	{
+		$trueValue = $this->trueValue;
+		if (is_a($this->trueValue, 'Decompiler_TriOp')) {
+			$trueValue = "(" . str($trueValue, $indent) . ")";
+		}
+		$falseValue = $this->falseValue;
+		if (is_a($this->falseValue, 'Decompiler_TriOp')) {
+			$falseValue = "(" . str($falseValue, $indent) . ")";
+		}
+
+		return str($this->condition) . ' ? ' . str($trueValue) . ' : ' . str($falseValue);
 	}
 }
@@ -486,4 +518,5 @@
 				XC_ASSIGN_BW_XOR       => "^=",
 				XC_BOOL_XOR            => "xor",
+				XC_JMP_SET             => "?:",
 				);
 		// }}}
@@ -707,4 +740,26 @@
 		$lastOp = &$opcodes[$last];
 
+		// {{{ ?: excludign JMP_SET
+		if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
+		 && $last >= $first + 3
+		 && $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN
+		 && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $last + 1
+		 && $lastOp['opcode'] == XC_QM_ASSIGN
+		) {
+			$trueFirst = $first + 1;
+			$trueLast = $firstOp['jmpouts'][0] - 2;
+			$falseFirst = $firstOp['jmpouts'][0];
+			$falseLast = $last;
+			$this->removeJmpInfo($EX, $first);
+
+			$condition = $this->getOpVal($firstOp['op1'], $EX);
+			$this->recognizeAndDecompileClosedBlocks($EX, $trueFirst, $trueLast, $indent . INDENT);
+			$trueValue = $this->getOpVal($opcodes[$trueLast]['op1'], $EX, false, true);
+			$this->recognizeAndDecompileClosedBlocks($EX, $falseFirst, $falseLast, $indent . INDENT);
+			$falseValue = $this->getOpVal($opcodes[$falseLast]['op1'], $EX, false, true);
+			$T[$opcodes[$trueLast]['result']['var']] = new Decompiler_TriOp($condition, $trueValue, $falseValue);
+			return false;
+		}
+		// }}}
 		// {{{ try/catch
 		if (!empty($firstOp['jmpins']) && !empty($opcodes[$firstOp['jmpins'][0]]['isCatchBegin'])) {
@@ -974,5 +1029,10 @@
 						$this->decompileBasicBlock($EX, $starti, $blockFirst - 1, $indent);
 					}
-					$this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent);
+					if ($this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent) === false) {
+						if ($EX['lastBlock'] == 'complex') {
+							echo PHP_EOL;
+						}
+						$EX['lastBlock'] = null;
+					}
 					$starti = $blockLast + 1;
 					$i = $starti;
@@ -1030,5 +1090,5 @@
 			case XC_JMPZ_EX:
 			case XC_JMPNZ_EX:
-			case XC_JMP_SET:
+			// case XC_JMP_SET:
 			// case XC_FE_RESET:
 			case XC_FE_FETCH:
@@ -1111,4 +1171,5 @@
 		$EX['recvs'] = array();
 		$EX['uses'] = array();
+		$EX['lastBlock'] = null;
 
 		$first = 0;
@@ -1274,4 +1335,8 @@
 
 			$resvar = null;
+			unset($curResVar);
+			if (array_key_exists($res['var'], $T)) {
+				$curResVar = &$T[$res['var']];
+			}
 			if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
 				$istmpres = false;
@@ -1817,8 +1882,8 @@
 						$assoc = $this->getOpVal($op2, $EX);
 						if (isset($assoc)) {
-							$T[$res['var']]->value[] = array($assoc, $rvalue);
+							$curResVar->value[] = array($assoc, $rvalue);
 						}
 						else {
-							$T[$res['var']]->value[] = array(null, $rvalue);
+							$curResVar->value[] = array(null, $rvalue);
 						}
 					}
@@ -1842,5 +1907,10 @@
 					// }}}
 				case XC_QM_ASSIGN: // {{{
-					$resvar = $this->getOpVal($op1, $EX);
+					if (isset($curResVar) && is_a($curResVar, 'Decompiler_Binop')) {
+						$curResVar->op2 = $this->getOpVal($op1, $EX);
+					}
+					else {
+						$resvar = $this->getOpVal($op1, $EX);
+					}
 					break;
 					// }}}
@@ -1894,7 +1964,5 @@
 					break;
 				case XC_JMP_SET: // ?:
-					$resvar = $this->getOpVal($op1, $EX);
-					$op['cond'] = $resvar; 
-					$op['isjmp'] = true;
+					$resvar = new Decompiler_Binop($this, $this->getOpVal($op1, $EX), XC_JMP_SET, null);
 					break;
 				case XC_JMPNZ: // while
