我正在尝试使用Superpower创建解析器。我已经看过我在回购中发现的样品,但是它们有点难以理解,至少对于像我这样的初学者来说:)所以我带来了这个小挑战。
我发明了一个非常基本的语法,只是为了学习。我想到了一个电梯,它遵循一系列指令,上下,等待。
示例:
(UP 100),
(DOWN 200),
(DOWN 100),
(DOWN @1),
(UP @3),
(WAIT),
(UP 300)
如您所见,它包含一个逗号分隔的动词列表,例如电梯。
我真的想学习如何为这个语法创建一个基于令牌的解析器作为开始,以便了解如何使用SuperPower。
答案 0 :(得分:9)
第1步是要弄清楚令牌种类是什么。你有类似的东西:
// ECL - Elevator Control Language ;-)
enum EclToken {
LParen,
RParen,
UpKeyword,
DownKeyword,
WaitKeyword,
AtSymbol,
Number,
Comma
}
第2步,撰写Tokenizer<EclToken>
。这是Superpower v1的直接编程任务 - 没有多少帮助者依赖,你只需要像the examples那样编写代码。
标记生成器获取输入字符串,去掉空格,并确定标记序列是什么。
对于您的示例输入,第一行将是:
// (UP 100),
LParen, UpKeyword, Number, RParen, Comma
对于包含内容的Number
之类的令牌,与Result<EclToken>
关联的范围将指向与令牌对应的输入字符串部分。在此行中,该数字将为TextSpan
,涵盖100
。
第3步是要弄清楚要将输入解析为的内容。对于具有嵌套表达式的编程语言,这通常是AST。对于ECL样本,它非常简单,因此您可以将其缩减为:
struct ElevatorCommand {
public int Distance; // + or -
public bool IsRelative;
}
第4步,解析器。这通常嵌入在静态类中。解析器的工作是从更简单的结果(数字,移动)构建更复杂的结果(此处为ElevatorCommand[]
)。
这是超级大国的重任,特别是在期望和错误方面。
static class EclParser
{
static TokenListParser<EclToken, int> Number =
Token.EqualTo(EclToken.Number).Apply(Numerics.IntegerInt32);
}
我们要做的第一件事是为数字定义解析器;这个内置的TextParser<int>
适用于EclToken.Number
范围的内容。
您可以在this example中看到更多解析机制。
帮助您找到方法的更多线索(未检查语法,更不用说编译/测试):
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
是您可以应用于输入的已完成解析器。
最好逐步构建解析器,在他们希望解析的输入块上测试每个较小的解析器。
答案 1 :(得分:1)
我已创建a project in GitHub来说明该方案。由于课程对于帖子来说很重要,我会链接到文件: