A finite State Machine as example.
https://rosettacode.org/wiki/Finite_state_machine#M2000_Interpreter
A Finite state machine (FSM) is computational abstraction which maps a finite number of states to other states within the same set, via transitions. An FSM can only be in one state at any given moment. Transitions can either be explicit or implicit; explicit transitions are triggered by an input signal and implicit transitions by the internal state of the system (that is, the current state). Implicit transitions thus represent "automatic" or sequenced states that are generally processed between explicit transitions (although they can also be used to provide an optional path when no valid transition exists for a given input signal).
This program use:
- Class definition
- Event for the logging, so our object, the Model isn't coupled with some specific output.
- Use Call Local to call a function as module and as part of "current" module - so we can see any variable of the "current" module. The "current" module is the one which we declare WithEvents the object (type of Group in M2000). Also note the New clause first in parameter list. This direct the variables to be local. Normally all variables are local in a function, and have no conflict with same names from other functions, but when we call local we get the same environment as the one of the caller so maybe same names exist, and that will be bad for parameter list, but not but for other purposes. See the F variable is local to module FSM but can accessed from Logging(). A Call statement always pass the current stack of values to the callee.
- Event function is called like Call Local. The stack of values are different from the one on module FSM. Events called using fresh stack always.
- We use a sub for displaying a menu of choices. Calling a sub is like the Call Local but: No need for New in the parameter list (inserted automatic at runtime). We can call it using Gosub name() or name(). We can't call it from Events, but we can call it from modules which we define from current module, but that code run like exist in the caller module, so any name which not defined in sub and used on expressions or for calling must exist, or be visible in calling module.
- We use a label and a Gosub to that label to run the DATA statements, to fill the stack of values, before we use it.
- For output text we use Wide clause for output in UTF16LE (without it we use ANSI 8bit). For using UTF8 we have to use a Document object (or we use ANSI and we send String$(theline as Utf8Enc). This send the write data without BOM, the three bytes which mark the UTF8.
Module FSM {
flush
Function Logging(New t as string, NewLine as boolean=true, terminal as boolean=true) {
' this called only using Call Local (like it is part of the calling module)
If terminal Then If NewLine then Print t else Print t;
If F>0 then
if NewLine then Print #F, t else Print #F, t;
end if
}
CLASS FSM {
Events "log"
Private:
String ResetState, CurState
StateList=List
TransitionList=List
Public:
Module AddState (State as string) {
State=filter$(State, ";")
If not Exist(.StateList, State) then Append .StateList, State
}
Module AddTransition (State as string, Transition as string, StateTo as string) {
State=filter$(State, ";")
StateTo=filter$(StateTo, ";")
Transition=filter$(Transition, ";")
If State="" or StateTo="" then Error "Need State from -> State to"
If not Exist(.StateList, State) Then Error "State (from) ";State;" not defined"
If not Exist(.StateList, StateTo) Then Error "State (to) ";StateTo;" not defined"
If not Exist(.TransitionList, State+";"+Transition) then
Append .TransitionList, State+";"+Transition:=StateTo
else
Error "Transtition can't changed"
End if
}
Module SetResetState (State as string){
State=filter$(State, ";")
If not Exist(.StateList, State) then Error "State not defined yet"
.ResetState<=State
}
Module Reset {
Call Event "Log", "Machine Up"
.CurState<=.ResetState
}
Module ShowState {
Call Event "Log" "State: "+.CurState
}
Module Action (Transition as string) {
Transition=filter$(Transition, ";")
If Exist(.TransitionList, .CurState+";"+Transition) then
do
.CurState<=Eval$(.TransitionList)
.ShowState
when Exist(.TransitionList, .CurState+";")
End if
}
}
Group WithEvents Model=FSM()
Function Model_Log (new that) {
Call Local Logging(that)
}
Long i, F
Open "Output.txt" for wide output as #F
Call Local Logging("FINITE STATE MASCHINE")
Gosub GetData
do
read thisstate
if thisstate="" then exit
Model.AddState thisstate
always
Choice=list
N=1
do
read st1, tr1, st2
Print st1, tr1, st2
if st1="" then exit
Model.AddTransition st1, tr1, st2
If tr1<>"" Then if not exist(Choice, tr1) then Append Choice, N:=tr1:N++
always
Model.SetResetState ' value is on stack of values already
Model.Reset
Model.ShowState
Options()
do
Call Local Logging("Choose :", false)
Input "", I
Call Local Logging(""+I, ,false)
If I<0 or I>Len(Choice) then continue
if I=0 then Options() else Model.Action Choise(I)
Until I=2
Close #f
Win "Notepad", dir$+"Output.txt"
End
Sub Options()
local one =each(Choice)
while one
Call Local Logging(" "+eval$(one!)+"."+eval$(one))
end while
End Sub
GetData:
Flush
Data "ready", "waiting", "exit","dispense","refunding", ""
Data "ready" , "deposit","waiting"
Data "ready", "quit", "exit"
Data "waiting","select","dispense"
Data "waiting","refund","refunding"
Data "dispense", "remove", "ready"
Data "refunding","","ready"
data "","",""
data "ready"
Return
}
FSM
Output.txt
Machine Up
State: ready
1.deposit
2.quit
3.select
4.refund
5.remove
Choose :1
State: waiting
Choose :3
State: dispense
Choose :5
State: ready
Choose :1
State: waiting
Choose :4
State: refunding
State: ready
Choose :2
State: exit
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
You can feel free to write any suggestion, or idea on the subject.