[PHP打野] 對pear-FSM的研究(二)實測pear-FSM的rpn(四則運算)例子

首先,看看pear-FSM的自帶例子examples\rpn.php 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的四則運算表達式計算器 git

在longlong ago之前,我在數據結構課學習棧和廣義表的時候學習過相似手法,下面來分析下這段代碼執行後輸入四則運算表達式的結果。 github

1. 輸入了0~9,加減乘除以外的符號,則觸發Error,到INIT狀態 express

2. INIT能夠到INIT 數據結構

3. 碰到=,DoEqual,而後回到INIT 函數

4. 在INIT和數字輸入狀態,可輸入0~9數字,轉到數字輸入階段 學習

5. 在INIT階段可輸入加減乘除,觸發DoOperator,而後能夠繼續運算 測試

6. 空格是結束 ui

經實測,(命令行下 php 你的文件目錄\fsm\rpn.php)
this

這個example有bug,要把

BeginBuildNumber

等幾個函數的參數

$payload
改爲
&$payload
而後輸入測試的格式是


3 4 + =

中間要有空格。

而後就能夠輸出個7

若是要進一步觀察,print_r下$fsm可大體觀察到這個狀態機的設計。

然而須要進一步注意的是,在github上有個荷蘭人提出

在fsm.php中,process函數中,

$this->_currentState = $transition[0];
這句有問題,由於狀態轉換還沒有完成,我的以爲有道理,建議這裏改掉。


這裏就感受FSM的例子不是很爽,除了有bug外, 測試例子都是要摸索出來,接下來我來改改這例子,讓它好用一些。

相關文章
相關標籤/搜索