在下面的代码中,您将看到一个符合以下正则表达式的简单词法分析器:
\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();
}
答案 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()并决定哪一个不拒绝等等。