7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
16 * @package Zend_Search_Lucene
17 * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
22 /** Zend_Search_Lucene_FSMAction */
23 require_once $CFG->dirroot
.'/search/Zend/Search/Lucene/FSMAction.php';
25 /** Zend_Search_Exception */
26 require_once $CFG->dirroot
.'/search/Zend/Search/Exception.php';
30 * Abstract Finite State Machine
32 * Take a look on Wikipedia state machine description: http://en.wikipedia.org/wiki/Finite_state_machine
34 * Any type of Transducers (Moore machine or Mealy machine) also may be implemented by using this abstract FSM.
35 * process() methods invokes a specified actions which may construct FSM output.
36 * Actions may be also used to signal, that we have reached Accept State
39 * @package Zend_Search_Lucene
40 * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
41 * @license http://framework.zend.com/license/new-bsd New BSD License
43 abstract class Zend_Search_Lucene_FSM
46 * Machine States alphabet
50 private $_states = array();
57 private $_currentState = null;
64 private $_inputAphabet = array();
67 * State transition table
69 * [sourceState][input] => targetState
73 private $_rules = array();
76 * List of entry actions
77 * Each action executes when entering the state
83 private $_entryActions = array();
86 * List of exit actions
87 * Each action executes when exiting the state
93 private $_exitActions = array();
96 * List of input actions
97 * Each action executes when entering the state
99 * [state][input] => action
103 private $_inputActions = array();
106 * List of input actions
107 * Each action executes when entering the state
109 * [state1][state2] => action
113 private $_transitionActions = array();
116 * Finite State machine constructor
118 * $states is an array of integers or strings with a list of possible machine states
119 * constructor treats fist list element as a sturt state (assignes it to $_current state).
120 * It may be reassigned by setState() call.
121 * States list may be empty and can be extended later by addState() or addStates() calls.
123 * $inputAphabet is the same as $states, but represents input alphabet
124 * it also may be extended later by addInputSymbols() or addInputSymbol() calls.
126 * $rules parameter describes FSM transitions and has a structure:
127 * array( array(sourseState, input, targetState[, inputAction]),
128 * array(sourseState, input, targetState[, inputAction]),
129 * array(sourseState, input, targetState[, inputAction]),
132 * Rules also can be added later by addRules() and addRule() calls.
134 * FSM actions are very flexible and may be defined by addEntryAction(), addExitAction(),
135 * addInputAction() and addTransitionAction() calls.
137 * @param array $states
138 * @param array $inputAphabet
139 * @param array $rules
141 public function __construct($states = array(), $inputAphabet = array(), $rules = array())
143 $this->addStates($states);
144 $this->addInputSymbols($inputAphabet);
145 $this->addRules($rules);
149 * Add states to the state machine
151 * @param array $states
153 public function addStates($states)
155 foreach ($states as $state) {
156 $this->addState($state);
161 * Add state to the state machine
163 * @param integer|string $state
165 public function addState($state)
167 $this->_states
[$state] = $state;
169 if ($this->_currentState
=== null) {
170 $this->_currentState
= $state;
176 * No any action is invoked
178 * @param integer|string $state
179 * @throws Zend_Search_Exception
181 public function setState($state)
183 if (!isset($this->_states
[$state])) {
184 throw new Zend_Search_Exception('State \'' . $state . '\' is not on of the possible FSM states.');
187 $this->_currentState
= $state;
193 * @return integer|string $state|null
195 public function getState()
197 return $this->_currentState
;
201 * Add symbols to the input alphabet
203 * @param array $inputAphabet
205 public function addInputSymbols($inputAphabet)
207 foreach ($inputAphabet as $inputSymbol) {
208 $this->addInputSymbol($inputSymbol);
213 * Add symbol to the input alphabet
215 * @param integer|string $inputSymbol
217 public function addInputSymbol($inputSymbol)
219 $this->_inputAphabet
[$inputSymbol] = $inputSymbol;
224 * Add transition rules
227 * array( array(sourseState, input, targetState[, inputAction]),
228 * array(sourseState, input, targetState[, inputAction]),
229 * array(sourseState, input, targetState[, inputAction]),
233 * @param array $rules
235 public function addRules($rules)
237 foreach ($rules as $rule) {
238 $this->addrule($rule[0], $rule[1], $rule[2], isset($rule[3])?
$rule[3]:null);
243 * Add symbol to the input alphabet
245 * @param integer|string $sourceState
246 * @param integer|string $input
247 * @param integer|string $targetState
248 * @param Zend_Search_Lucene_FSMAction|null $inputAction
249 * @throws Zend_Search_Exception
251 public function addRule($sourceState, $input, $targetState, $inputAction = null)
253 if (!isset($this->_states
[$sourceState])) {
254 throw new Zend_Search_Exception('Undefined source state (' . $sourceState . ').');
256 if (!isset($this->_states
[$targetState])) {
257 throw new Zend_Search_Exception('Undefined target state (' . $targetState . ').');
259 if (!isset($this->_inputAphabet
[$input])) {
260 throw new Zend_Search_Exception('Undefined input symbol (' . $input . ').');
263 if (!isset($this->_rules
[$sourceState])) {
264 $this->_rules
[$sourceState] = array();
266 if (isset($this->_rules
[$sourceState][$input])) {
267 throw new Zend_Search_Exception('Rule for {state,input} pair (' . $sourceState . ', '. $input . ') is already defined.');
270 $this->_rules
[$sourceState][$input] = $targetState;
273 if ($inputAction !== null) {
274 $this->addInputAction($sourceState, $input, $inputAction);
280 * Add state entry action.
281 * Several entry actions are allowed.
282 * Action execution order is defined by addEntryAction() calls
284 * @param integer|string $state
285 * @param Zend_Search_Lucene_FSMAction $action
287 public function addEntryAction($state, Zend_Search_Lucene_FSMAction
$action)
289 if (!isset($this->_states
[$state])) {
290 throw new Zend_Search_Exception('Undefined state (' . $state. ').');
293 if (!isset($this->_entryActions
[$state])) {
294 $this->_entryActions
[$state] = array();
297 $this->_entryActions
[$state][] = $action;
301 * Add state exit action.
302 * Several exit actions are allowed.
303 * Action execution order is defined by addEntryAction() calls
305 * @param integer|string $state
306 * @param Zend_Search_Lucene_FSMAction $action
308 public function addExitAction($state, Zend_Search_Lucene_FSMAction
$action)
310 if (!isset($this->_states
[$state])) {
311 throw new Zend_Search_Exception('Undefined state (' . $state. ').');
314 if (!isset($this->_exitActions
[$state])) {
315 $this->_exitActions
[$state] = array();
318 $this->_exitActions
[$state][] = $action;
322 * Add input action (defined by {state, input} pair).
323 * Several input actions are allowed.
324 * Action execution order is defined by addInputAction() calls
326 * @param integer|string $state
327 * @param integer|string $input
328 * @param Zend_Search_Lucene_FSMAction $action
330 public function addInputAction($state, $inputSymbol, Zend_Search_Lucene_FSMAction
$action)
332 if (!isset($this->_states
[$state])) {
333 throw new Zend_Search_Exception('Undefined state (' . $state. ').');
335 if (!isset($this->_inputAphabet
[$inputSymbol])) {
336 throw new Zend_Search_Exception('Undefined input symbol (' . $inputSymbol. ').');
339 if (!isset($this->_inputActions
[$state])) {
340 $this->_inputActions
[$state] = array();
342 if (!isset($this->_inputActions
[$state][$inputSymbol])) {
343 $this->_inputActions
[$state][$inputSymbol] = array();
346 $this->_inputActions
[$state][$inputSymbol][] = $action;
350 * Add transition action (defined by {state, input} pair).
351 * Several transition actions are allowed.
352 * Action execution order is defined by addTransitionAction() calls
354 * @param integer|string $sourceState
355 * @param integer|string $targetState
356 * @param Zend_Search_Lucene_FSMAction $action
358 public function addTransitionAction($sourceState, $targetState, Zend_Search_Lucene_FSMAction
$action)
360 if (!isset($this->_states
[$sourceState])) {
361 throw new Zend_Search_Exception('Undefined source state (' . $sourceState. ').');
363 if (!isset($this->_states
[$targetState])) {
364 throw new Zend_Search_Exception('Undefined source state (' . $targetState. ').');
367 if (!isset($this->_transitionActions
[$sourceState])) {
368 $this->_transitionActions
[$sourceState] = array();
370 if (!isset($this->_transitionActions
[$sourceState][$targetState])) {
371 $this->_transitionActions
[$sourceState][$targetState] = array();
374 $this->_transitionActions
[$sourceState][$targetState][] = $action;
381 * @param mixed $input
382 * @throws Zend_Search_Exception
384 public function process($input)
386 if (!isset($this->_rules
[$this->_currentState
])) {
387 throw new Zend_Search_Exception('There is no any rule for current state (' . $this->_currentState
. ').');
389 if (!isset($this->_rules
[$this->_currentState
][$input])) {
390 throw new Zend_Search_Exception('There is no any rule for {current state, input} pair (' . $this->_currentState
. ', ' . $input . ').');
393 $sourceState = $this->_currentState
;
394 $targetState = $this->_rules
[$this->_currentState
][$input];
396 if ($sourceState != $targetState && isset($this->_exitActions
[$sourceState])) {
397 foreach ($this->_exitActions
[$sourceState] as $action) {
401 if (isset($this->_inputActions
[$sourceState]) &&
402 isset($this->_inputActions
[$sourceState][$input])) {
403 foreach ($this->_inputActions
[$sourceState][$input] as $action) {
409 $this->_currentState
= $targetState;
411 if (isset($this->_transitionActions
[$sourceState]) &&
412 isset($this->_transitionActions
[$sourceState][$targetState])) {
413 foreach ($this->_transitionActions
[$sourceState][$targetState] as $action) {
417 if ($sourceState != $targetState && isset($this->_entryActions
[$targetState])) {
418 foreach ($this->_entryActions
[$targetState] as $action) {
424 public function reset()
426 if (count($this->_states
) == 0) {
427 throw new Zend_Search_Exception('There is no any state defined for FSM.');
430 $this->_currentState
= $this->_states
[0];