14

对具有本机语言的建议(因此没有 FSM 生成工具)支持状态机开发和执行以及消息/信号的传递。这适用于电信,例如这种复杂程度的 FSM 的实施。

我考虑过 Erlang,但希望得到一些反馈、建议、教程指针、替代方案,尤其是基于 Java 的框架。也许是斯卡拉?

仅开源。我不是在寻找 UML 或正则表达式相关的解决方案。

由于这是为了实现电信协议,FSM 可能并不重要。许多状态,许多转换,基于信号,输入约束/保护。动态实例化将是一个加号。switch 语句是不可能的,它很快就会嵌套到不可用的状态。if/else 稍微好一点。

我宁愿依赖图形设计;FSM 描述的格式应该是人类可读/可编辑/可管理的。

--

我决定专注于基于 Actor 的 C++ 解决方案

例如,Theron 框架提供了一个起点http://theron.ashtonmason.net/并且为了避免在基于 FSM 的事件处理程序中使用 switch 语句,这个 C++ FSM 模板框架看起来很有用http://satsky.spb.ru/articles/ fsm/fsmEng.php

4

6 回答 6

10

这个特殊的应用程序,电信协议实现,正是 Erlang 的构建目标。Erlang 在爱立信的最初应用是电话交换机,最早的商业产品是支持各种电信协议的 ATM 交换机。

OTP 具有用于实现 FSM 的标准行为,称为gen_fsm. 在一些OTP 文档中有一个在非平凡 FSM 中使用它的示例。

OSERL是 Erlang 中的开源 SMPP 实现,并演示了如何使用gen_fsms 实现电信协议。一个很好的例子是gen_esme_session

虽然我不能指出代码,但我知道有不少 Erlang 公司销售面向电信的产品:CorelatusSynapseMotivity等。

于 2009-09-18T00:53:44.163 回答
8

我同意 switch 语句应该是不可能的......它们最终会导致维护噩梦。你不能使用状态模式来实现你的 FSM 吗?根据您的实际实现,您可以使用演员(如果您有多个 FSM 合作 - 嗯......这可能吗?)。Actor 的好处在于传递消息的框架已经存在。

使用状态的一个例子是:

trait State {
  def changeState(message: Any): State
}

trait FSM extends Actor {
  var state: State

  def processMessage(message: Any) {
    state = state.changeState(message)
  }

  override def act() {
    loop {
      react {
        case m: Any => processMessage(m)
      }
    }
  }
}

这是非常基本的代码,但由于我不知道更多的要求,这是我能想到的最多的。状态的优点是每个状态都自包含在一个类中。

于 2009-09-18T12:48:06.703 回答
4

我不同意 FSM 实施起来微不足道。这是非常短视的,表明要么不熟悉替代方案,要么缺乏复杂状态机的经验。

根本问题是状态机是显而易见的,但 FSM代码却不是。一旦超过十几个状态和一系列转换,FSM 代码就会变得丑陋且难以遵循。

有一些工具可以用来绘制状态机,并为其生成 Java 代码。但是,我不知道任何开源工具。

现在,回到 Erlang/Scala,Scala 也有 Actor 和消息传递,并且基于 JVM,因此考虑到您的限制,它可能是比 Erlang 更好的选择。

Scala 上也有一个 DFA/NFA 库,尽管它不是特别好。它支持从任意正则表达式(即文字不必是字符)到 DFA/NFA 的转换。

我将使用它在下面发布一些代码。在这段代码中,想法是创建一个 FSM,它将接受单词列表的任意前缀的任意顺序组合,想法是在没有预定义键绑定的情况下查找菜单选项。

import scala.util.regexp._
import scala.util.automata._

// The goal of this object below is to create a class, MyChar, which will
// be the domain of the tokens used for transitions in the DFA. They could
// be integers, enumerations or even a set of case classes and objects. For
// this particular code, it's just Char.
object MyLang extends WordExp {
  type _regexpT = RegExp
  type _labelT = MyChar

  case class MyChar(c:Char) extends Label
}

// We now need to import the types we defined, as well as any classes we
// created extending Label.    
import MyLang._

// We also need an instance (singleton, in this case) of WordBerrySethi,
// which will convert the regular expression into an automatum. Notice the
// language being used is MyLang.    
object MyBerrySethi extends WordBerrySethi {
  override val lang = MyLang
}

// Last, a function which takes an input in the language we defined,
// and traverses the DFA, returning whether we are at a sink state or
// not. For other uses it will probably make more sense to test against
// both sink states and final states.
def matchDet(pat: DetWordAutom[MyChar], seq: Seq[Char]): Boolean =
  !pat.isSink((0 /: seq) ((state, c) => pat.next(state, MyChar(c))))

// This converts a regular expression to a DFA, with using an intermediary NFA    
def compile(pat: MyLang._regexpT) = 
  new SubsetConstruction(MyBerrySethi.automatonFrom(pat, 100000)).determinize

// Defines a "?" function, since it isn't provided by the library
def Quest(rs: _regexpT*) = Alt(Eps, Sequ(rs: _*)) // Quest(pat) = Eps|pat = (pat)?


// And now, the algorithm proper. It splits the string into words
// converts each character into Letter[MyChar[Char]],
// produce the regular expression desired for each word using Quest and Sequ,
// then the final regular expression by using Sequ with each subexpression.
def words(s : String) = s.split("\\W+")
def wordToRegex(w : String) : Seq[MyLang._regexpT] = w.map(c => Letter(MyChar(c)))
def wordRegex(w : String) = Quest(wordToRegex(w) reduceRight ((a,b) => Sequ(a, Quest(b))))
def phraseRegex(s : String) = Sequ(words(s).map(w => wordRegex(w)) : _*)

// This takes a list of strings, produce a DFA for each, and returns a list of
// of tuples formed by DFA and string.
def regexList(l : List[String]) = l.map(s => compile(phraseRegex(s)) -> s)

// The main function takes a list of strings, and returns a function that will
// traverse each DFA, and return all strings associated with DFAs that did not
// end up in a sink state.
def regexSearcher(l : List[String]) = {
  val r = regexList(l)
  (s : String) => r.filter(t => matchDet(t._1, s)).map(_._2)
}
于 2009-09-17T21:14:41.777 回答
0

我几乎想不出任何语言可以实现 FSM 是不平凡的。也许这一个

...
if (currentState == STATE0 && event == EVENT0) return STATE1;
if (currentState == STATE1 && event == EVENT0) return STATE2;
...
于 2009-09-18T09:45:08.627 回答
0

State 模式(使用 Java 枚举)是我们在电信应用程序中使用的,但是我们使用小型 FSM:

public class Controller{
    private State itsState = State.IDLE;

    public void setState(State aState){
        itsState = aState;
    }

    public void action1(){
        itsState.action1(this);
    }

    public void action2(){
        itsState.action2(this);
    }

    public void doAction1(){
        // code
    }

    public void doAction2(){
        // code
    }
}

public enum State{
    IDLE{
        @Override
        public void action1(Controller aCtx){
            aCtx.doAction1();
            aCtx.setState(State.STATE1);
        }
    },

    STATE1{
        @Override
        public void action2(Controller aCtx){
            aCtx.doAction2();
            aCtx.setState(State.IDLE);
        }
    },

    public void action1(Controller aCtx){
        throw new IllegalStateException();
    }

    public void action2(Controller aCtx){
        throw new IllegalStateException();
    }
}
于 2011-02-04T05:34:53.137 回答
-1

FSM 在任何具有 case 语句的语言中都应该很容易实现。您选择的语言应该基于有限状态机需要做什么。

例如,您声明您需要为电信开发和提及消息执行此操作。我会看看支持分布式消息传递的系统/语言。Erlang 做到了这一点,我确信几乎所有其他通用语言都通过该语言的 API/库来支持这一点。

于 2009-09-17T20:15:14.777 回答