[PHP打野] 对pear-FSM的研究(三)改进pear-FSM的四则运算
pear-FSM自带的例子很不好用,带空格输入还要古怪的输入方式,现在我来改个改进版的。
<?php /* rpnEasy.php author: mx 2014-12-04 用fsm实现简单四则运算,不支持先乘除后加减 */ require_once ‘FSM.php‘; //操作对象1遇到数字 function BuildSmallNumber($symbol, &$payload) { array_push($payload, $symbol); } //操作对象1连续遇到数字 function BuildBigNumber($symbol, &$payload) { $n = array_pop($payload); $n = $n . $symbol; $n = (int)$n; array_push($payload, $n); } //遇到运算符 function BuildOp($symbol, &$payload){ array_push($payload, $symbol); } //操作对象2遇到数字 function BuildSmallNumber2($symbol, &$payload) { array_push($payload, $symbol); } //操作对象2连续遇到数字 function BuildBigNumber2($symbol, &$payload) { $n = array_pop($payload); $n = $n . $symbol; $n = (int)$n; array_push($payload, $n); } // function EndBuildNumber($symbol, &$payload) // { // $n = array_pop($payload); // array_push($payload, (int)$n); // } function DoEqualTemp($symbol, &$payload) { // 先将栈里的几个计算计算 //操作对象2 $ar = array_pop($payload); //运算符 $s = array_pop($payload); //操作对象1 $al = array_pop($payload); if ($s == ‘+‘) { array_push($payload, $al + $ar); } elseif ($s == ‘-‘) { array_push($payload, $al - $ar); } elseif ($s == ‘*‘) { array_push($payload, $al * $ar); } elseif ($s == ‘/‘) { array_push($payload, $al / $ar); } //最新运算符压入 array_push($payload, $symbol); } function DoEqual($symbol, &$payload) { if(count($payload)>2){ //操作对象2 $ar = array_pop($payload); //运算符 $s = array_pop($payload); //操作对象1 $al = array_pop($payload); if ($s == ‘+‘) { array_push($payload, $al + $ar); } elseif ($s == ‘-‘) { array_push($payload, $al - $ar); } elseif ($s == ‘*‘) { array_push($payload, $al * $ar); } elseif ($s == ‘/‘) { array_push($payload, $al / $ar); } } echo array_pop($payload) . "\n"; } function Error($symbol, $payload) { echo "This does not compute: $symbol\n"; } $stack = array(); $fsm = new FSM(‘INIT‘, $stack); $fsm->setDefaultTransition(‘INIT‘, ‘Error‘); //状态:起始读入必须是数字。 数字后面可以跟数字或加减乘除或=, 运算符后必须跟数字。 // $fsm->addTransitionAny(‘INIT‘, ‘INIT‘); $fsm->addTransitions(range(0,9), ‘INIT‘, ‘INPUT1‘, ‘BuildSmallNumber‘); $fsm->addTransitions(range(0,9), ‘INPUT1‘, ‘INPUT1‘, ‘BuildBigNumber‘); $fsm->addTransitions(array(‘+‘,‘-‘,‘*‘,‘/‘), ‘INPUT1‘, ‘OPERATE‘, ‘BuildOp‘); $fsm->addTransitions(range(0,9), ‘OPERATE‘, ‘INPUT2‘, ‘BuildSmallNumber2‘); $fsm->addTransitions(range(0,9), ‘INPUT2‘, ‘INPUT2‘, ‘BuildBigNumber2‘); $fsm->addTransitions(array(‘+‘,‘-‘,‘*‘,‘/‘), ‘INPUT2‘, ‘OPERATE‘, ‘DoEqualTemp‘); $fsm->addTransition(‘=‘, ‘INPUT2‘, ‘INIT‘, ‘DoEqual‘); echo "Expression:\n"; $stdin = fopen(‘php://stdin‘, ‘r‘); $expression = rtrim(fgets($stdin)); $symbols = preg_split(‘//‘, $expression, -1, PREG_SPLIT_NO_EMPTY); $fsm->processList($symbols);
运行下 php 目录\rpnEasy.php
输入 11+22-3+5之类,测试成功!
这个例子的主要改动在于,原代码是维持栈里只有数字,用空格作为输入结束分隔符,碰到符号开始算,于是就要输入3 4 + 这样的格式。 现在改成 区分 操作对象1,运算符,操作对象2 (即对应原代码里al,ar象征的左右值),把运算符也暂存到栈里,则可支持连续不间断的紧密计算表达式。
但是,这个是坚持从左到右的平滑计算,如果要先乘除后加减带或者先加减或乘除,运算符有先后优先级的呢?
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。