3

我可以在 parboiled2 解析器中动态生成规则吗?用例是我已经定义了一堆规则,但是想添加更多而不是每次添加规则时都编译。

4

1 回答 1

2

如果您想在运行时生成规则(就像您在 Parboiled1 中所做的那样),这是不可能的。Parboiled 2 正在使用 marco 表达式,因此您无法在运行时生成规则。所有事情都发生在编译阶段。

如果您有许多已定义的规则,并且想要以任意顺序组合它们,即使其中一些规则丢失。这是可能的。我做的。

有两个已知的选项,你可以如何实现这一点:

第一个选项(我还没有尝试过)被称为DynamicRuleDispatch你可以在文档中找到它并在此处查看它的测试。

第二个选项是手动执行调度(就像我一样)。

  1. 您应该创建一堆可以动态组合的规则。这些规则必须具有 Rule0 类型。它们不应影响值堆栈。在规则评估之后为这些规则添加副作用。副作用操作必须将捕获的数据保存在解析器状态内的某个位置。您应该使用capture++ bundle 来实现这一点,请看下面的示例~run

    def RuleWithSideEffect = rule { capture(EmailAddress) ~ run { address: String => saveItSomewhere(address) } ~ EOI

  2. 您需要在解析器中创建某种可变状态。一个可以保存解析结果的地方。它可以是哈希图。此 Hashmap 应存储所有可能的规则及其值。您不能使用值堆栈,因为您无法确定匹配规则的数量。维护可变状态时要小心。每次通话后必须对其进行清洁。

  3. 您需要一种规则对齐格式来对齐规则。例如:

    类解析器(输入:解析器输入,格式:字符串)扩展解析器....

然后您需要解析格式字符串并获取格式标记。使用模式匹配将相应格式标记的列表分派给dispatchRule下面的 Rule0 字段方法。然后将字符串标记列表映射到规则。

当您拥有规则列表时,您需要执行以下操作:

// concatenates two rules. Must be inside rule block
def concatRules(f: Rule0, s: Rule0): Rule0 = rule {
  f ~ s
}

val rootRule = 
    stringTokens map dispatchRule reduce concatRules

def RootRule: Rule0 = rule { mainRule ~ EOI }

def dispatchRule(token: String): Rule0 = match token {
   case "DATE" => DateParser.DateRule
   ....
}

您可以通过在解析器构造函数中使用 logformat 来解析生成器访问日志。因此,您需要一种数据模型来调整规则。

于 2016-01-08T10:47:47.560 回答