如何命名和组织有限状态机使用的方法?

时间:2010-08-26 00:50:24

标签: c# parsing naming-conventions organization state-machine

在下面的代码中,您将看到一个符合以下正则表达式的简单词法分析器:

 \d*(\.\d*)?([eE]([+-]\d+|\d+))?

如果我将这个设计用于更复杂的事情,那么所有匿名代表都将成为维护的噩梦。我面临的最大挑战是如何命名将作为状态机中的选择点的方法。在变量exponentPart中,传递给MatchOne的最后一个匿名委托将决定我们是否有有符号整数,整数或错误匹配。请发布关于我如何组织这样一个项目的任何想法,假设一个复杂的语言有很多共享符号。

static void Main(string[] args)
{
    var exponentPart =
        Lex.Start()
        .MatchOne(s => s.Continue(s.Current == 'e' || s.Current == 'E'))
        .MatchOne(
            s => // What would I name this?
            {
                if (char.IsDigit(s.Current))
                {
                    return Lex.Start().MatchZeroOrMore(s1 => s1.Continue(char.IsDigit(s1.Current)))(s.Continue(true));
                }
                else if (s.Current == '+' || s.Current == '-')
                {
                    return Lex.Start().MatchOneOrMore(s1 => s1.Continue(char.IsDigit(s1.Current)))(s.Continue(true));
                }
                else
                {
                    return s.RememberedState();
                }
            }
        );

    var fractionalPart =
        Lex.Start()
        .MatchOne(s => s.Continue(s.Current == '.'))
        .MatchOneOrMore(s1 => s1.Continue(char.IsDigit(s1.Current)))
        .Remember()
        .MatchOne(exponentPart);

    var decimalLiteral =
        Lex.Start()
        .MatchOneOrMore(s => s.Continue(char.IsDigit(s.Current)))
        .Remember()
        .MatchOne(
            s => // What would I name this?
            {
                if (s.Current == '.')
                {
                    return fractionalPart(s);
                }
                else if (s.Current == 'e' || s.Current == 'E')
                {
                    return exponentPart(s);
                }
                else
                {
                    return s.RememberedState();
                }
            }
        );

    var input = "999.999e+999";
    var result = decimalLiteral(new LexState(input, 0, 0, 0, true));

    Console.WriteLine(result.Value.Substring(result.StartIndex, result.EndIndex - result.StartIndex + 1));
    Console.ReadLine();
}

1 个答案:

答案 0 :(得分:2)

在尝试编写某种解析器时,首先应将表达式划分为规则和终端。然后,您可以按照他们检查的规则命名方法。例如,类似于:

<literal> := <fractional> | <fractional_with_exponent>
<fractional> := \d*(\.\d*)?
<fractional_with_exponent> := <fractional><exponent>
<exponent> := [eE]([+-]\d+|\d+)

这将为您提供名为Literal()Fractional()FractionalWithExponent()Exponent()的方法,每个方法都能识别或拒绝自己的规则。 Literal()会调用Fractional()和FractionalWithExponent()并决定哪一个不拒绝等等。