[PHP打野] 对pear-FSM的研究(二)实测pear-FSM的rpn(四则运算)例子

首先,看看pear-FSM的自带例子examples\rpn.php

<?php

require_once 'FSM.php';

function BeginBuildNumber($symbol, $payload)
{
    array_push($payload, $symbol);
}

function BuildNumber($symbol, $payload)
{
    $n = array_pop($payload);
    $n = $n . $symbol;
    array_push($payload, $n);
}

function EndBuildNumber($symbol, $payload)
{
    $n = array_pop($payload);
    array_push($payload, (int)$n);
}

function DoOperator($symbol, $payload)
{
    $ar = array_pop($payload);
    $al = array_pop($payload);

    if ($symbol == '+') {
        array_push($payload, $al + $ar);
    } elseif ($symbol == '-') {
        array_push($payload, $al - $ar);
    } elseif ($symbol == '*') {
        array_push($payload, $al * $ar);
    } elseif ($symbol == '/') {
        array_push($payload, $al / $ar);
    }
}

function DoEqual($symbol, $payload)
{
    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');
//如果输入符号是"=",则从"INIT"到"INIT"状态,并调用“DoEqual"
 $fsm->addTransition('=', 'INIT', 'INIT', 'DoEqual');
//如果输入符号是0~9,从"INIT"到”BUILD_NUMBER',调用‘BeginBuildNumber’
 $fsm->addTransitions(range(0,9), 'INIT', 'BUILDING_NUMBER', 'BeginBuildNumber');
//如果输入符号是0~9, 则从"BUILDING_NUMBER",到”BUILDING_NUMBER“,调用BuildNumber
 $fsm->addTransitions(range(0,9), 'BUILDING_NUMBER', 'BUILDING_NUMBER', 'BuildNumber');
//输入为空格就从BUILDING_NUMBER回到INIT,且调用EndBuildNumber
 $fsm->addTransition(' ', 'BUILDING_NUMBER', 'INIT', 'EndBuildNumber');
//输入为加减乘除就从INIT回到INIT,调用DoOperator
 $fsm->addTransitions(array('+','-','*','/'), 'INIT', 'INIT', 'DoOperator');

echo "Expression:\n";
$stdin = fopen('php://stdin', 'r');
$expression = rtrim(fgets($stdin));
$symbols = preg_split('//', $expression, -1, PREG_SPLIT_NO_EMPTY);

$fsm->processList($symbols);

这个例子没有调用实例,但是可以从代码上看出,这是一个简单的0~9的四则运算表达式计算器

在longlong ago以前,我在数据结构课学习栈和广义表的时候学习过类似手法,下面来分析下这段代码执行后输入四则运算表达式的结果。

1. 输入了0~9,加减乘除之外的符号,则触发Error,到INIT状态

2. INIT可以到INIT

3. 碰到=,DoEqual,然后回到INIT

4. 在INIT和数字输入状态,可输入0~9数字,转到数字输入阶段

5. 在INIT阶段可输入加减乘除,触发DoOperator,然后可以继续运算

6. 空格是结束

经实测,(命令行下 php 你的文件目录\fsm\rpn.php)

这个example有bug,要把

BeginBuildNumber

等几个函数的参数

$payload
改成
&$payload
然后输入测试的格式是


3 4 + =

中间要有空格。

然后就可以输出个7

如果要进一步观察,print_r下$fsm可大致观察到这个状态机的设计。

然而需要进一步注意的是,在github上有个荷兰人提出

在fsm.php中,process函数中,

$this->_currentState = $transition[0];
这句有问题,因为状态转换尚未完成,个人觉得有道理,建议这里改掉。


这里就感觉FSM的例子不是很爽,除了有bug外, 测试例子都是要摸索出来,接下来我来改改这例子,让它好用一些。





你可能感兴趣的:([PHP打野] 对pear-FSM的研究(二)实测pear-FSM的rpn(四则运算)例子)