用Superpower解析一个简单的文本语法

Sup*_*JMN 6 .net c# parsing superpower

我正在尝试用Superpower创建一个解析器.我已经看过我在回购中找到的样品,但是它们有点难以理解,至少对于像我这样的初学者来说:)所以我带来了这个小挑战.

我发明了一个非常基本的语法,只是为了学习.我想到了一个电梯,它遵循一系列指令,上下,上下等待.

例:

(UP 100),
(DOWN 200),
(DOWN 100),
(DOWN @1),
(UP @3),
(WAIT),
(UP 300)
Run Code Online (Sandbox Code Playgroud)

如您所见,它由一系列以逗号分隔的动词组成,例如电梯.

  • 动词是UP,DOWNWAIT.
  • 每个动词都用括号括起来:( )
  • UPDOWN需要绝对数字相对数字,表示电梯应移动的楼层.相对楼层号码在号码前加@.
  • WAIT不接受任何号码,因为它会暂停电梯一段时间.

我真的想学习如何为这个语法创建一个基于令牌的解析器作为开始,以了解如何使用SuperPower.

Nic*_*rdt 10

编写任何Superpower解析器的第1步是弄清楚令牌种类是什么.你有类似的东西:

// ECL - Elevator Control Language ;-)
enum EclToken {
    LParen,
    RParen,
    UpKeyword,
    DownKeyword,
    WaitKeyword,
    AtSymbol,
    Number,
    Comma
}
Run Code Online (Sandbox Code Playgroud)

第2步,写一个Tokenizer<EclToken>.这是Superpower v1的直接编程任务 - 没有多少帮助器可以依赖,您只需要像示例中那样编写代码.

标记生成器获取输入字符串,去除空白,并确定标记序列是什么.

对于您的示例输入,第一行将是:

// (UP 100),
LParen, UpKeyword, Number, RParen, Comma
Run Code Online (Sandbox Code Playgroud)

对于Number包含内容的标记,与Result<EclToken>意志相关联的范围指向与标记对应的输入字符串部分.在这一行中,数字将是一个TextSpan覆盖100.

第三步是要弄清楚你要分析输入什么.对于具有嵌套表达式的编程语言,这通常是AST.对于ECL示例,它非常简单,因此您可以将其缩减为:

struct ElevatorCommand {        
    public int Distance; // + or -
    public bool IsRelative;
}
Run Code Online (Sandbox Code Playgroud)

第4步,解析器.这通常嵌入在静态类中.解析器的工作是ElevatorCommand[]从更简单的结果(数字,移动)构建更复杂的结果(在这里).

这就是超级大国的重任,特别是在期望和错误方面.

static class EclParser 
{
    static TokenListParser<EclToken, int> Number =
        Token.EqualTo(EclToken.Number).Apply(Numerics.IntegerInt32);
}
Run Code Online (Sandbox Code Playgroud)

我们要做的第一件事是为数字定义解析器; 这个将内置应用于跨度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));
}
Run Code Online (Sandbox Code Playgroud)

Commands 是可以应用于输入的完整解析器.

最好以增量方式构建解析器,在预期要解析的输入块上测试每个较小的解析器.