智能合约开发
undefined11. 智能合约开发
undefined11.1 虚拟机的php实现设计与原型代码
智能合约是由指令来组成的. 先看下我们设计的基本指令集:
+-*/%and, or, xor, not< > = != = >=ADD, SUB, MUL, DIV, MODAND, OR, XOR, NOTLT, GT, EQ, NE, LEQ, GEQADD, SUB, MUL, DIV, MOD (INTEGER,INTEGER) -> INTEGERAND, OR ,XOR (INTEGER, INTEGER) -> BINARYLT,GT,EQ,NE,LEQ,GEQ (INTEGER,INTEGER) -> BINARYNOT (BINARY) -> BINARY
register machine
stack machine
(integer, integer) -> integer
(binary, binary) -> binary
binary -> binary
指令程序举例说明:
![image_1bv1q6hcu4ipkio1faa1a3i1rt9.png-669.9kB][33]
/* stack machine:JMP -- 无条件的跳JMPZ -- 有条件的跳 - 要是堆栈最上面是0DUPLT - 少于LTE - 少于或者等于EQ - 等于GT - 多于GTE - 多于或者等于LABEL - 控制地点, 即位置while() if()$i = 0;.1000 while ($i < 5) { $i++; } .2000PUSH 0 LABEL 1000 DUP PUSH 5 GT JMPZ 2000 PUSH 1 ADD JUMP 1000 POP*/
智能合约的代码:
<?php// execute(sprintf('PUSH %d PUSH %d HALT SEND', rand(), rand(1, 10)));// $i = 0; while($i < 5) { $i++; }// $a = 1; $b = 1; while(1) { $c = $a + $b; print($c); $a = $b; $b = $c;// PUSH 1 PUSH 1 LABEL 1000// DUP SWAP2 DUP SWAP3 ADD DUP PRINT// DUP PUSH 10 SWAP1 MOD PUSH 0 EQ JMP 2000// SWAP1 SWAP2 POP// JMP 1000// LABEL 2000// PUSH 1 PUSH 1 LABEL 1000 DUP SWAP2 DUP SWAP3 ADD DUP PRINT DUP PUSH 10 SWAP1 MOD PUSH 0 NEQ JMPZ 2000 SWAP1 SWAP2 POP JMP 1000 LABEL 2000// execute(sprintf('PUSH 0 LABEL 1000 DUP PUSH 5 GT JMPZ 2000 PUSH 1 ADD PUSH %d PUSH %d SEND JMP 1000 LABEL 2000', rand(), rand()));execute('PUSH 1 PUSH 1 LABEL 1000 DUP SWAP2 DUP SWAP3 ADD DUP PRINT DUP PUSH 10 SWAP1 MOD PUSH 0 NE JMPZ 2000 SWAP1 SWAP2 POP JMP 1000 LABEL 2000');// $_0000 = convert('PUSH 3 PUSH 4 LABEL 2000 POP POP JMP 2000 JMPZ 2000');//var_dump($_0000);/*ADD, SUB, MUL, DIV, MODAND, OR, XOR, NOTLT, GT, EQ, NE, LEQ, GEQ+ - * / %and, or, xor, not< > = != <= >=JMP -- wutiaojian de tiaoJMPZ -- youtiaojian de tiao - yaoshi duizhan zuishangmian shi lingDUPLT - shaoyuLTE - shaoyu huozhe dengyuEQ - dengyuGT - duoyuGTE - duoyu huozhe dengyuLABEL - kongzhi didianwhile() if()$i = 0;.1000 while ($i < 5) { $i++; } .2000PUSH 0 LABEL 1000 DUP PUSH 5 GT JMPZ 2000 PUSH 1 ADD JUMP 1000 POP*/function convert($string) {$operations = array();$_0000 = explode(' ', $string);$pieces = array();foreach ($_0000 as $_0001) {$_0001 = trim($_0001);if (strlen($_0001) > 0){ $pieces[] = $_0001; }}$index = 0;while ($index < count($pieces)) {if ($pieces[$index] == 'PUSH' || $pieces[$index] == 'LABEL' || $pieces[$index] == 'JMP' || $pieces[$index] == 'JMPZ') {$operations[] = array($pieces[$index], $pieces[$index + 1]);$index += 2;continue;}$operations[] = array($pieces[$index]);$index++;}return $operations;}/*shallow storage - byte array array()deep storage - byte array array()stack - four bytes array()instruction pointerADD SUB MUL DIV MODDONGCI: add, subtract, multiply, divide, modulateMINGCI: addition, subtraction, multiplication, division, modulationAND OR NOT XORREAD, WRITELOAD, STOREarray_pop, array_pushfunction: string -> string3 + 5array_push 3 array_push 5 ADDarray_push 3array_push 5ADDarray_push 3 array(3)array_push 5 array(3, 5)ADD array(8)*/function render($stack) {$_0000 = '';foreach ($stack as $_0001) {$_0000 = sprintf('%s, %d', $_0000, $_0001);}return substr($_0000, 2);}function execute($string) {execute_0984(convert($string));}function execute_0984($operations) {$stack = array();echo sprintf('stack: %s%c', render($stack), 10);$index = 0;$length = count($operations);while($index < $length) {$_0000 = $operations[$index];echo sprintf('-- %s %s%c', $_0000[0], isset($_0000[1])? strval($_0000[1]): '', 10);$bundle = step($stack, $_0000);if ($bundle[0] == 0) {echo sprintf('stack: %s%c', render($bundle[1]), 10);$stack = $bundle[1];$index++;continue;}if ($bundle[0] == 1) {echo sprintf('-- SPECIAL EVENT: HALTED!! DIED!!%c', 10);break;}if ($bundle[0] == 2) {echo sprintf('stack: %s%c', render($bundle[2]), 10);$stack = $bundle[2];$index = find($operations, $bundle[1]);if ($index == -1){ die('INVALID ADDRESS!!'); }continue;}}}function find($operations, $label) {$index = 0;while ($index < count($operations)) {if ($operations[$index][0] != 'LABEL'){ $index++; continue; }if ($operations[$index][34] == $label){ return $index; }$index++;}return -1;}function step($stack, $operation) {if ($operation[0] == 'JMP') {return array(2, $operation[1], $stack);}if ($operation[0] == 'JMPZ') {$a = array_pop($stack);if ($a == 0){ return array(2, $operation[1], $stack); }return array(0, $stack);}if ($operation[0] == 'LABEL') {return array(0, $stack);}if ($operation[0] == 'SWAP1') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a);array_push($stack, $b);return array(0, $stack);}if ($operation[0] == 'SWAP2') {$a = array_pop($stack);$b = array_pop($stack);$c = array_pop($stack);array_push($stack, $a);array_push($stack, $b);array_push($stack, $c);return array(0, $stack);}if ($operation[0] == 'SWAP3') {$a = array_pop($stack);$b = array_pop($stack);$c = array_pop($stack);$d = array_pop($stack);array_push($stack, $a);array_push($stack, $c);array_push($stack, $b);array_push($stack, $d);return array(0, $stack);}if ($operation[0] == 'ADD') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a + $b);return array(0, $stack);}if ($operation[0] == 'SUB') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a - $b);return array(0, $stack);}if ($operation[0] == 'MUL') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a * $b);return array(0, $stack);}if ($operation[0] == 'DIV') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, floor($a / $b));return array(0, $stack);}if ($operation[0] == 'MOD') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a % $b);return array(0, $stack);}if ($operation[0] == 'AND') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, boolval($a) && boolval($b)? 1: 0);return array(0, $stack);}if ($operation[0] == 'OR') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, boolval($a) || boolval($b)? 1: 0);return array(0, $stack);}if ($operation[0] == 'XOR') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, (boolval($a) && ! boolval($b)) || (! boolval($a) && boolval($b))? 1: 0);return array(0, $stack);}if ($operation[0] == 'NOT') {$a = array_pop($stack);array_push($stack, boolval($a)? 0: 1);return array(0, $stack);}if ($operation[0] == 'PUSH') {array_push($stack, $operation[1]);return array(0, $stack);}if ($operation[0] == 'POP') {array_pop($stack);return array(0, $stack);}if ($operation[0] == 'SEND') {$a = array_pop($stack);$b = array_pop($stack);echo sprintf('++ SPECIAL EVENT: %d was sent to %d%c', $a, $b, 10);return array(0, $stack);}if ($operation[0] == 'PRINT') {$a = array_pop($stack);echo sprintf('%c[32m++ PRINT: %d%c[0m%c', 27, $a, 27, 10);return array(0, $stack);}if ($operation[0] == 'HALT') {return array(1);}if ($operation[0] == 'DUP') {$a = array_pop($stack);array_push($stack, $a);array_push($stack, $a);return array(0, $stack);}if ($operation[0] == 'LT') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a < $b? 1: 0);return array(0, $stack);}if ($operation[0] == 'LTE') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a <= $b? 1: 0);return array(0, $stack);}if ($operation[0] == 'EQ') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a == $b? 1: 0);return array(0, $stack);}if ($operation[0] == 'NE') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a != $b? 1: 0);return array(0, $stack);}if ($operation[0] == 'GT') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a > $b? 1: 0);return array(0, $stack);}if ($operation[0] == 'GTE') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a >= $b? 1: 0);return array(0, $stack);}}
运行结果:
stack:-- PUSH 1stack: 1-- PUSH 1stack: 1, 1-- LABEL 1000stack: 1, 1-- DUPstack: 1, 1, 1-- SWAP2stack: 1, 1, 1-- DUPstack: 1, 1, 1, 1-- SWAP3stack: 1, 1, 1, 1-- ADDstack: 1, 1, 2-- DUPstack: 1, 1, 2, 2++ PRINT: 2stack: 1, 1, 2-- DUPstack: 1, 1, 2, 2-- PUSH 10stack: 1, 1, 2, 2, 10-- SWAP1stack: 1, 1, 2, 10, 2-- MODstack: 1, 1, 2, 2-- PUSH 0stack: 1, 1, 2, 2, 0-- NEstack: 1, 1, 2, 1-- JMPZ 2000stack: 1, 1, 2-- SWAP1stack: 1, 2, 1-- SWAP2stack: 1, 2, 1-- POPstack: 1, 2-- JMP 1000stack: 1, 2-- LABEL 1000stack: 1, 2-- DUPstack: 1, 2, 2-- SWAP2stack: 2, 2, 1-- DUPstack: 2, 2, 1, 1-- SWAP3stack: 1, 2, 1, 2-- ADDstack: 1, 2, 3-- DUPstack: 1, 2, 3, 3++ PRINT: 3stack: 1, 2, 3-- DUPstack: 1, 2, 3, 3-- PUSH 10stack: 1, 2, 3, 3, 10-- SWAP1stack: 1, 2, 3, 10, 3-- MODstack: 1, 2, 3, 3-- PUSH 0stack: 1, 2, 3, 3, 0-- NEstack: 1, 2, 3, 1-- JMPZ 2000stack: 1, 2, 3-- SWAP1stack: 1, 3, 2-- SWAP2stack: 2, 3, 1-- POPstack: 2, 3-- JMP 1000stack: 2, 3-- LABEL 1000stack: 2, 3-- DUPstack: 2, 3, 3-- SWAP2stack: 3, 3, 2-- DUPstack: 3, 3, 2, 2-- SWAP3stack: 2, 3, 2, 3-- ADDstack: 2, 3, 5-- DUPstack: 2, 3, 5, 5++ PRINT: 5stack: 2, 3, 5-- DUPstack: 2, 3, 5, 5-- PUSH 10stack: 2, 3, 5, 5, 10-- SWAP1stack: 2, 3, 5, 10, 5-- MODstack: 2, 3, 5, 5-- PUSH 0stack: 2, 3, 5, 5, 0-- NEstack: 2, 3, 5, 1-- JMPZ 2000stack: 2, 3, 5-- SWAP1stack: 2, 5, 3-- SWAP2stack: 3, 5, 2-- POPstack: 3, 5-- JMP 1000stack: 3, 5-- LABEL 1000stack: 3, 5-- DUPstack: 3, 5, 5-- SWAP2stack: 5, 5, 3-- DUPstack: 5, 5, 3, 3-- SWAP3stack: 3, 5, 3, 5-- ADDstack: 3, 5, 8-- DUPstack: 3, 5, 8, 8++ PRINT: 8stack: 3, 5, 8-- DUPstack: 3, 5, 8, 8-- PUSH 10stack: 3, 5, 8, 8, 10-- SWAP1stack: 3, 5, 8, 10, 8-- MODstack: 3, 5, 8, 8-- PUSH 0stack: 3, 5, 8, 8, 0-- NEstack: 3, 5, 8, 1-- JMPZ 2000stack: 3, 5, 8-- SWAP1stack: 3, 8, 5-- SWAP2stack: 5, 8, 3-- POPstack: 5, 8-- JMP 1000stack: 5, 8-- LABEL 1000stack: 5, 8-- DUPstack: 5, 8, 8-- SWAP2stack: 8, 8, 5-- DUPstack: 8, 8, 5, 5-- SWAP3stack: 5, 8, 5, 8-- ADDstack: 5, 8, 13-- DUPstack: 5, 8, 13, 13++ PRINT: 13stack: 5, 8, 13-- DUPstack: 5, 8, 13, 13-- PUSH 10stack: 5, 8, 13, 13, 10-- SWAP1stack: 5, 8, 13, 10, 13-- MODstack: 5, 8, 13, 3-- PUSH 0stack: 5, 8, 13, 3, 0-- NEstack: 5, 8, 13, 1-- JMPZ 2000stack: 5, 8, 13-- SWAP1stack: 5, 13, 8-- SWAP2stack: 8, 13, 5-- POPstack: 8, 13-- JMP 1000stack: 8, 13-- LABEL 1000stack: 8, 13-- DUPstack: 8, 13, 13-- SWAP2stack: 13, 13, 8-- DUPstack: 13, 13, 8, 8-- SWAP3stack: 8, 13, 8, 13-- ADDstack: 8, 13, 21-- DUPstack: 8, 13, 21, 21++ PRINT: 21stack: 8, 13, 21-- DUPstack: 8, 13, 21, 21-- PUSH 10stack: 8, 13, 21, 21, 10-- SWAP1stack: 8, 13, 21, 10, 21-- MODstack: 8, 13, 21, 1-- PUSH 0stack: 8, 13, 21, 1, 0-- NEstack: 8, 13, 21, 1-- JMPZ 2000stack: 8, 13, 21-- SWAP1stack: 8, 21, 13-- SWAP2stack: 13, 21, 8-- POPstack: 13, 21-- JMP 1000stack: 13, 21-- LABEL 1000stack: 13, 21-- DUPstack: 13, 21, 21-- SWAP2stack: 21, 21, 13-- DUPstack: 21, 21, 13, 13-- SWAP3stack: 13, 21, 13, 21-- ADDstack: 13, 21, 34-- DUPstack: 13, 21, 34, 34++ PRINT: 34stack: 13, 21, 34-- DUPstack: 13, 21, 34, 34-- PUSH 10stack: 13, 21, 34, 34, 10-- SWAP1stack: 13, 21, 34, 10, 34-- MODstack: 13, 21, 34, 4-- PUSH 0stack: 13, 21, 34, 4, 0-- NEstack: 13, 21, 34, 1-- JMPZ 2000stack: 13, 21, 34-- SWAP1stack: 13, 34, 21-- SWAP2stack: 21, 34, 13-- POPstack: 21, 34-- JMP 1000stack: 21, 34-- LABEL 1000stack: 21, 34-- DUPstack: 21, 34, 34-- SWAP2stack: 34, 34, 21-- DUPstack: 34, 34, 21, 21-- SWAP3stack: 21, 34, 21, 34-- ADDstack: 21, 34, 55-- DUPstack: 21, 34, 55, 55++ PRINT: 55stack: 21, 34, 55-- DUPstack: 21, 34, 55, 55-- PUSH 10stack: 21, 34, 55, 55, 10-- SWAP1stack: 21, 34, 55, 10, 55-- MODstack: 21, 34, 55, 5-- PUSH 0stack: 21, 34, 55, 5, 0-- NEstack: 21, 34, 55, 1-- JMPZ 2000stack: 21, 34, 55-- SWAP1stack: 21, 55, 34-- SWAP2stack: 34, 55, 21-- POPstack: 34, 55-- JMP 1000stack: 34, 55-- LABEL 1000stack: 34, 55-- DUPstack: 34, 55, 55-- SWAP2stack: 55, 55, 34-- DUPstack: 55, 55, 34, 34-- SWAP3stack: 34, 55, 34, 55-- ADDstack: 34, 55, 89-- DUPstack: 34, 55, 89, 89++ PRINT: 89stack: 34, 55, 89-- DUPstack: 34, 55, 89, 89-- PUSH 10stack: 34, 55, 89, 89, 10-- SWAP1stack: 34, 55, 89, 10, 89-- MODstack: 34, 55, 89, 9-- PUSH 0stack: 34, 55, 89, 9, 0-- NEstack: 34, 55, 89, 1-- JMPZ 2000stack: 34, 55, 89-- SWAP1stack: 34, 89, 55-- SWAP2stack: 55, 89, 34-- POPstack: 55, 89-- JMP 1000stack: 55, 89-- LABEL 1000stack: 55, 89-- DUPstack: 55, 89, 89-- SWAP2stack: 89, 89, 55-- DUPstack: 89, 89, 55, 55-- SWAP3stack: 55, 89, 55, 89-- ADDstack: 55, 89, 144-- DUPstack: 55, 89, 144, 144++ PRINT: 144stack: 55, 89, 144-- DUPstack: 55, 89, 144, 144-- PUSH 10stack: 55, 89, 144, 144, 10-- SWAP1stack: 55, 89, 144, 10, 144-- MODstack: 55, 89, 144, 4-- PUSH 0stack: 55, 89, 144, 4, 0-- NEstack: 55, 89, 144, 1-- JMPZ 2000stack: 55, 89, 144-- SWAP1stack: 55, 144, 89-- SWAP2stack: 89, 144, 55-- POPstack: 89, 144-- JMP 1000stack: 89, 144-- LABEL 1000stack: 89, 144-- DUPstack: 89, 144, 144-- SWAP2stack: 144, 144, 89-- DUPstack: 144, 144, 89, 89-- SWAP3stack: 89, 144, 89, 144-- ADDstack: 89, 144, 233-- DUPstack: 89, 144, 233, 233++ PRINT: 233stack: 89, 144, 233-- DUPstack: 89, 144, 233, 233-- PUSH 10stack: 89, 144, 233, 233, 10-- SWAP1stack: 89, 144, 233, 10, 233-- MODstack: 89, 144, 233, 3-- PUSH 0stack: 89, 144, 233, 3, 0-- NEstack: 89, 144, 233, 1-- JMPZ 2000stack: 89, 144, 233-- SWAP1stack: 89, 233, 144-- SWAP2stack: 144, 233, 89-- POPstack: 144, 233-- JMP 1000stack: 144, 233-- LABEL 1000stack: 144, 233-- DUPstack: 144, 233, 233-- SWAP2stack: 233, 233, 144-- DUPstack: 233, 233, 144, 144-- SWAP3stack: 144, 233, 144, 233-- ADDstack: 144, 233, 377-- DUPstack: 144, 233, 377, 377++ PRINT: 377stack: 144, 233, 377-- DUPstack: 144, 233, 377, 377-- PUSH 10stack: 144, 233, 377, 377, 10-- SWAP1stack: 144, 233, 377, 10, 377-- MODstack: 144, 233, 377, 7-- PUSH 0stack: 144, 233, 377, 7, 0-- NEstack: 144, 233, 377, 1-- JMPZ 2000stack: 144, 233, 377-- SWAP1stack: 144, 377, 233-- SWAP2stack: 233, 377, 144-- POPstack: 233, 377-- JMP 1000stack: 233, 377-- LABEL 1000stack: 233, 377-- DUPstack: 233, 377, 377-- SWAP2stack: 377, 377, 233-- DUPstack: 377, 377, 233, 233-- SWAP3stack: 233, 377, 233, 377-- ADDstack: 233, 377, 610-- DUPstack: 233, 377, 610, 610++ PRINT: 610stack: 233, 377, 610-- DUPstack: 233, 377, 610, 610-- PUSH 10stack: 233, 377, 610, 610, 10-- SWAP1stack: 233, 377, 610, 10, 610-- MODstack: 233, 377, 610, 0-- PUSH 0stack: 233, 377, 610, 0, 0-- NEstack: 233, 377, 610, 0-- JMPZ 2000stack: 233, 377, 610-- LABEL 2000stack: 233, 377, 610
undefined11.2 重写step函数
/*0 表示状态2 表示跳*/function step($stack, $shallow, $deep, $action, $immediate){if($action == 'JMP' ){array(0, $stack, $shallow, $deep);array(1);array(2, $jump)}}
undefined11.3 运行举例
execute('PUSH 0 LOAD PUSH 1000 GT JMPZ 1000 HALT LABEL 1000 PUSH 1 LOAD PUSH 200 SWAP1 WRITE');/*associative array6820 -> 2001977 -> 100PUSH 100 PUSH 6820 WRITEPUSH 200 PUSH 1977 WRITEPUSH 1977 READPUSH 6820 READ*/
undefined11.4 代码
第18次课程代码
$program = 'PUSH 0 LOAD PUSH 1000 GT JMPZ 1000 HALT LABEL 1000 PUSH 1 LOAD PUSH 200 SWAP1 WRITE';list($shallow, $deep) = execute($program, array(0 => 2000, 1 => 7440), array(7440 => 100, 6508 => 200));var_dump($deep);/*associative array6820 -> 2001977 -> 100PUSH 100 PUSH 6820 WRITEPUSH 200 PUSH 1977 WRITEPUSH 1977 READPUSH 6820 READ*/function convert($string) {$operations = array();$_0000 = explode(' ', $string);$pieces = array();foreach ($_0000 as $_0001) {$_0001 = trim($_0001);if (strlen($_0001) > 0){ $pieces[] = $_0001; }}$index = 0;while ($index < count($pieces)) {if ($pieces[$index] == 'PUSH' || $pieces[$index] == 'LABEL' || $pieces[$index] == 'JMP' || $pieces[$index] == 'JMPZ') {$operations[] = array($pieces[$index], $pieces[$index + 1]);$index += 2;continue;}$operations[] = array($pieces[$index]);$index++;}return $operations;}function render($stack) {$_0000 = '';foreach ($stack as $_0001) {$_0000 = sprintf('%s, %d', $_0000, $_0001);}return substr($_0000, 2);}function execute($string, $shallow, $deep) {return execute_0984(convert($string), $shallow, $deep);}function execute_0984($operations, $shallow, $deep) {$stack = array();echo sprintf('stack: %s%c', render($stack), 10);$index = 0;$length = count($operations);while($index < $length) {$_0000 = $operations[$index];echo sprintf('-- %s %s%c', $_0000[0], isset($_0000[1])? strval($_0000[1]): '', 10);$bundle = step($stack, $shallow, $deep, $_0000[0], $_0000[1]);if ($bundle[0] == 0) {echo sprintf('stack: %s%c', render($bundle[1]), 10);$stack = $bundle[1];$shallow = $bundle[2];$deep = $bundle[3];$index++;continue;}if ($bundle[0] == 1) {echo sprintf('-- SPECIAL EVENT: HALTED!! DIED!!%c', 10);break;}if ($bundle[0] == 2) {$index = find($operations, $bundle[2]);$stack = $bundle[1];if ($index == -1){ die('INVALID ADDRESS!!'); }continue;}}return array($shallow, $deep);}function find($operations, $label) {$index = 0;while ($index < count($operations)) {if ($operations[$index][0] != 'LABEL'){ $index++; continue; }if ($operations[$index][35] == $label){ return $index; }$index++;}return -1;}function step($stack, $shallow, $deep, $action, $immediate){if ($action == 'ADD') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a + $b);return array(0, $stack, $shallow, $deep);}if ($action == 'SUB') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a - $b);return array(0, $stack, $shallow, $deep);}if ($action == 'MUL') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a * $b);return array(0, $stack, $shallow, $deep);}if ($action == 'DIV') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, floor($a / $b));return array(0, $stack, $shallow, $deep);}if ($action == 'MOD') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a % $b);return array(0, $stack, $shallow, $deep);}if ($action == 'LT') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a < $b? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'LTE') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a <= $b? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'EQ') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a == $b? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'NE') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a != $b? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'GT') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a > $b? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'GTE') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a >= $b? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'AND') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, boolval($a) && boolval($b)? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'OR') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, boolval($a) || boolval($b)? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'XOR') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, (boolval($a) && ! boolval($b)) || (! boolval($a) && boolval($b))? 1: 0);return array(0, $stack, $shallow, $deep);}if ($action == 'NOT') {$a = array_pop($stack);array_push($stack, boolval($a)? 0: 1);return array(0, $stack, $shallow, $deep);}if ($action == 'JMP') {return array(2, $stack, $immediate);}if ($action == 'JMPZ') {$a = array_pop($stack);if ($a == 0)return array(2, $stack, $immediate);return array(0, $stack, $shallow, $deep);}if ($action == 'LABEL') {return array(0, $stack, $shallow, $deep);}if ($action == 'HALT') {return array(1);}if ($action == 'PUSH') {array_push($stack, $immediate);return array(0, $stack, $shallow, $deep);}if ($action == 'POP') {array_pop($stack);return array(0, $stack, $shallow, $deep);}if ($action == 'DUP') {$a = array_pop($stack);array_push($stack, $a);array_push($stack, $a);return array(0, $stack, $shallow, $deep);}if ($action == 'STORE') {$a = array_pop($stack);$b = array_pop($stack);$shallow[$a] = $b;return array(0, $stack, $shallow, $deep);}if ($action == 'LOAD') {$a = array_pop($stack);array_push($stack, isset($shallow[$a]) ? $shallow[$a] : 0);return array(0, $stack, $shallow, $deep);}if ($action == 'WRITE') {$a = array_pop($stack);$b = array_pop($stack);$deep[$a] = $b;return array(0, $stack, $shallow, $deep);}if ($action == 'READ') {$a = array_pop($stack);array_push($stack, isset($deep[$a]) ? $deep[$a] : 0);return array(0, $stack, $shallow, $deep);}if ($action == 'SWAP1') {$a = array_pop($stack);$b = array_pop($stack);array_push($stack, $a);array_push($stack, $b);return array(0, $stack, $shallow, $deep);}if ($action == 'SWAP2') {$a = array_pop($stack);$b = array_pop($stack);$c = array_pop($stack);array_push($stack, $a);array_push($stack, $b);array_push($stack, $c);return array(0, $stack, $shallow, $deep);}if ($action == 'SWAP3') {$a = array_pop($stack);$b = array_pop($stack);$c = array_pop($stack);$d = array_pop($stack);array_push($stack, $a);array_push($stack, $c);array_push($stack, $b);array_push($stack, $d);return array(0, $stack, $shallow, $deep);}}
执行结果:
stack:-- PUSH 0stack: 0-- LOADstack: 2000-- PUSH 1000stack: 2000, 1000-- GTstack: 0-- JMPZ 1000-- LABEL 1000stack:-- PUSH 1stack: 1-- LOADstack: 7440-- PUSH 200stack: 7440, 200-- SWAP1stack: 200, 7440-- WRITEstack:array(2) {[7440]=>string(3) "200"[6508]=>int(200)}
