From: Robert Klemme Date: 2003-06-20T23:15:37+09:00 Subject: Re: Code generation and state machines This is a multi-part message in MIME format. ------=_NextPart_000_00D9_01C33744.9F31CA10 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit "Zellyn Hunter" schrieb im Newsbeitrag news:200306200848.02798.ruby-list@zellyn.com... > On Friday 20 June 2003 06:34, Robert Klemme wrote: > > I'd store the state info in an instance variable of the class instance and > > not use a class variable, because the latter is inherited and thus visible > > to sub classes. > > Okay - I understand that. I take it class instance variables are not > inherited, then? Exactly. > > I also wonder why your state machine runs automatically in method run. > > Yeah. The run method is as simple as possible to demonstrate the principles - > at the moment I'm worried about classes, superclasses, instances, and syntax > extension (the "state" and "transition" keyword-looking functions used to > easily define state machines). Ah, I see. > The run method will definitely change, > probably in the direction you've mentioned. I like the event idea - I'll > have to think about it a little more. It's not my idea but it's the typical way state machines are implemented. I "guess" this has a lot to do with the tasks state machines are built for, i.e., parsing etc. :-) One more point: I'd make endState a collection (hash or array) because typically there is more than one terminating state. You then could add a method that checks for termination. I attach an example of a SM that accepts the language a+b+. > > Also, is it possible that you use 0 to mean "false"? This is true for Perl > > but not Ruby. In Ruby the only two values that are equivalent to false > > are false itself and nil. > > Aah. Yes, oops! It's going to be difficult getting used to that one! Yeah. Took me a while in the beginning, too. > Thanks for your help! You're welcome! Regards robert ------=_NextPart_000_00D9_01C33744.9F31CA10 Content-Type: application/octet-stream; name="StateMachine.rb" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="StateMachine.rb" class StateMachine class StateInfo attr_accessor :terminal def initialize(sym) @name = sym @transitions = {} @terminal = false end def transition(event, target) @transitions[event] = target end def transit(event) @transitions[event] end end # class level def StateMachine.state(sym) states[sym] ||= StateInfo.new(sym) end def StateMachine.[](sym) st = states[ sym ] raise "Not a state: #{sym}" unless st st end def StateMachine.transition(from, to, event) state( from ).transition( event, to ) end def StateMachine.initial(sym) @initial = sym end def StateMachine.error_state(sym) @error = sym end def StateMachine.terminal(*sym) sym.each do |s| state(sym).terminal = true end end def StateMachine.get_error_state() @error end def StateMachine.get_initial() @initial end # instance level def initialize c = self.class @current = c.get_initial end def transit(event) c = self.class nxt = c[@current].transit(event) @current = ( nxt ? nxt : c.get_error_state ) end def terminated? return false unless @current self.class[@current].terminal end def error? @current == self.class.get_error_state end protected def StateMachine.states @states ||= {} end end ------=_NextPart_000_00D9_01C33744.9F31CA10 Content-Type: application/octet-stream; name="StateTest.rb" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="StateTest.rb" require 'StateMachine' class Test < StateMachine state :start state :a state :b state :error initial :start terminal :b transition :start, :a, "a"[0] transition :a, :a, "a"[0] transition :a, :b, "b"[0] transition :b, :b, "b"[0] end def test(str) puts "checking '#{str}'" sm = Test.new pos = 0 str.each_byte do |b| sm.transit b if sm.error? puts "error at char '#{b.chr}' pos #{pos}" return false end pos += 1 end puts "error? #{sm.error?}" puts "terminated? #{sm.terminated?}" sm.terminated? end test "aaaaaaaaaabbbbbb" test "bbbbbbbaaaaaaaaaa" test "" ------=_NextPart_000_00D9_01C33744.9F31CA10--