编写任何Superpower解析器的第 1 步是弄清楚令牌类型是什么。你有类似的东西:
// ECL - Elevator Control Language ;-)
enum EclToken {
LParen,
RParen,
UpKeyword,
DownKeyword,
WaitKeyword,
AtSymbol,
Number,
Comma
}
第 2 步,写一个Tokenizer<EclToken>
. 这是 Superpower v1 的一项直接编程任务 - 没有多少助手可以依靠,您只需要像示例中那样编写代码即可。
分词器获取输入字符串,去掉空格,并计算出分词序列是什么。
对于您的示例输入,第一行将是:
// (UP 100),
LParen, UpKeyword, Number, RParen, Comma
对于Number
包含内容的标记,与 关联的跨度Result<EclToken>
将指向与标记对应的输入字符串部分。在这一行中,数字将是一个TextSpan
覆盖100
。
第 3 步是弄清楚您要将输入解析为. 对于具有嵌套表达式的编程语言,这通常是 AST。对于 ECL 示例,它非常简单,因此您可以将其缩减为:
struct ElevatorCommand {
public int Distance; // + or -
public bool IsRelative;
}
第四步,解析器。这通常嵌入在静态类中。ElevatorCommand[]
解析器的工作是从更简单的结果(数字、运动)构建更复杂的结果(此处为 an )。
这就是 Superpower 进行繁重工作的地方,尤其是在期望和错误方面。
static class EclParser
{
static TokenListParser<EclToken, int> Number =
Token.EqualTo(EclToken.Number).Apply(Numerics.IntegerInt32);
}
我们要做的第一件事是定义数字解析器;这将内置应用TextParser<int>
到EclToken.Number
跨度的内容。
您可以在此示例中看到更多解析机制。
还有一些线索可以帮助您找到方法(不检查语法,更不用说编译/测试了):
static TokenListParser<EclToken, ElevatorCommand> Up =
from _ in Token.EqualTo(EclToken.UpKeyword)
from distance in Number
select new ElevatorCommand {
Distance = distance,
IsRelative = false
};
static TokenListParser<EclToken, ElevatorCommand> Command =
from lp in Token.EqualTo(EclToken.LParen)
from command in Up // .Or(Down).Or(Wait)
from rp in Token.EqualTo(EclToken.RParen)
select command;
static TokenListParser<EclToken, ElevatorCommand[]> Commands =
Command.ManyDelimitedBy(Token.EqualTo(EclToken.Comma));
}
Commands
是可以应用于输入的完整解析器。
最好逐步构建解析器,在每个较小的解析器上测试它们预期解析的输入块。