注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Silence的博客

大师只有一个

 
 
 

日志

 
 

转:LUA实现状态机  

2010-09-05 00:28:15|  分类: 技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

如果完全以FP的方式使用LUA,那么似乎不必要使用状态机,相比于FP状态机就不是很优美的东东了:)。不过既然图灵他老人家创造了图灵机,LUA作为一门编程语言,自然也是图灵完备的那么出于对伟大先驱的尊敬,用状态机来解决问题自然也是义不容辞的了。

      我们在用C/C++来实现状态机的时候,免不了要用某种代码生成的技术来产生状态迁移表(当然完全的SWITCH CASE也是可以的),用LUA来实现就简单多了,只需100行左右的代码就可以实现一个较完备的状态机框架。

       状态迁移有如下几个方面来描述:

?from 源状态
?event 引起迁移的事件
?to 迁移的目标状态,如果是自身迁移则from和to相同
?guard 迁移可以成立的守卫条件
?entry 新状态的进入动作
?action 执行迁移的动作
? leave 转移到其他状态时的离开动作
 

      在LUA中可以这样表示:

        transitions={} --状态迁移表

     function   add_transition(from,evt,to,guard,entry,action,leave)

          local transition =  transitions[from]

          local t = {to=to,guard=guard,entry=entry,action=action,leave=leave}
          if transition then
               transition[evt]=t
          else
              transition={}
              transition[evt] = t
              transitions[from]=transition
          end

     end

                

      迁移的代码可以这样写:

 

    local initstate = ...

       --...

        function  do_transition(evt)
              local  row = assert(transitions[initstate] )   
              local  transition = row[evt]
              if not transition then return end
              assert(transition.to)
              if transition.guard(initstate,evt,transition.to) then

transition.entry(initstate,evt,transition.to)
               if transition.action(evt) then

transition.leave(initstate,evt,transition.to)
                     initstate = transition.to
              end

end
  end

 

       guard、entry、action、leave都是函数,可以被不同的迁移重用,因此状态机框架可以有效减少冗余代码,更有点像一个代码编织机--把各种guard、action、entry等函数按照要求放到适当的“空位”上。

      状态和事件的定义可以很简单用整数(效率高)或字符串(描述性更好)就可以了,定义好了状态迁移,还需要一个驱动接口:

    function process_event(evt)   
      assert(evt)   
      do_transition(evt)

    end

奥,你该说了怎么就是一个转发调用呀,其实这只是一个中间版,因为process_event还要处理在状态迁移过程中产生的事件(也就是内部事件),这是通过post_event接口来完成的:

    function  post_event(evt)
     if not events then
         events={}
         front = 0
         back = -1
     end    
     back = back + 1
     events[back] = evt
    end

    post_event将事件放入事件队列events中然后再由process_event来处理:

  

    function process_event(evt)   
       do_transition(evt) 
       if  front then
          while front <= back do
             local event = events[front]
                events[front] = nil       
                front = front + 1
                do_transition(event)
           end
        end
    end

 

   把上面的代码用用一个state_machine表封装一下看起来会好些:

state_machine={}

state_machine.new=function(initstate) 
   local fsm = state_machine
   fsm.transitions={}
   fsm.initstate = initstate  
   return fsm
end

function state_machine:add_transition(from,evt,to,guard,entry,action,leave)

--...

end

 

function state_machine:do_transition(evt)

 --...

end

 

function state_machine:post_event(evt)

end

 

function state_machine:process_event(evt)

end

我们还可以以add_transition为基础写些语法糖衣出来,类似于self_transition、add_simple_transition等等。

 

    这研究过boost mpl库的朋友一定会觉得眼熟,对!上面的代码就是模仿boost mpl库的状态机的例子写的,因此索性例子也照搬了:)

 

    local play_event = 100
local stop_event = 101
local pause_event = 102

local play_state="playing"
local stopped_state="stopped"
local paused_state="paused"

 

local  guard=function(fsm,from,evt,to)
    return true
end
local void_=function(_,_,_,_
urn true
end

local do_play=function(fsm,evt)
   print("do_play\n")
  fsm:post_event(pause_event)
  return true
end

local do_stop=function(fsm,evt)
  print("do_stop\n")
  return true
end

local do_pause=function(fsm,evt)
  print("do_pause\n")
  return true
end

local do_resume=function(fsm,evt)
   print("do_resume\n")
 
  return true
end

 

 

local fsm = state_machine.new(stopped_state)

fsm:add_transition(stopped_state,play_event,play_state,guard,void_,do_play,void_)
fsm:add_transition(play_state,pause_event,paused_state_guard,void_,do_pause,void_)
fsm:add_transition(paused_state,play_event,play_state,guard,void_,do_resume,void_)
fsm:add_transition(paused_state,stop_event,stopped_state,guard,void_,do_stop,void_)
fsm:add_transition(play_state,stop_event,stopped_state,guard,void_,do_stop,void_)

 

fsm:process_event(play_event)
fsm:process_event(stop_event)
fsm:process_event(pause_event)
fsm:process_event(play_event)
fsm:process_event(pause_event)
fsm:process_event(stop_event)
fsm:process_event(play_event)
fsm:process_event(stop_event)


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/caslwzgks/archive/2009/03/08/3970476.aspx

  评论这张
 
阅读(2309)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017