Как я могу назвать и организовать методы, используемые конечным автоматом? - PullRequest
0 голосов
/ 26 августа 2010

В следующем коде вы увидите простой лексер, который соответствует следующему регулярному выражению:

\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 Ответ

2 голосов
/ 26 августа 2010

Когда вы пытаетесь написать какой-то синтаксический анализатор, вы должны сначала разделить свое выражение на правила и терминалы. Затем вы можете назвать методы по правилам, которые они проверяют. Например, что-то вроде:

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

Это даст вам методы с именами Literal(), Fractional(), FractionalWithExponent() и Exponent(), каждый из которых сможет распознавать или отклонять свои правила. Literal () вызовет Fractional () и FractionalWithExponent () и решит, какой из них не отклонен и т. Д.

...