scala - 动态创建 parboiled2 规则

标签 scala parboiled2

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

最佳答案

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

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

有两个已知选项,如何实现:

第一个选项(我还没有尝试过)称为 DynamicRuleDispatch,您可以在 documentation 中找到它看看它的测试 here .

第二种选择是手动执行调度(就像我所做的那样)。

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

    def RuleWithSideEffect = 规则 { 捕获(电子邮件地址)〜运行{地址:字符串=> saveItSomewhere(地址) } ~ 意向书

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

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

    class Parser(input: ParserInput, format: String) extends Parser....

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

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

// 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 来解析生成器访问日志。因此,您需要某种数据模型来匹配规则。

关于scala - 动态创建 parboiled2 规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32615256/

相关文章:

scala - 如何设置sbt的堆大小?

scala - Parboiled2 解析器示例

scala - parboiled2 非法规则构成

shapeless - 了解半熟 2's ' ~' 组合器

scala - 将 Seq[Any] 分解为案例类的巧妙方法

scala - 在 Scala 中实现 Java 接口(interface)方法

scala - 如何在 Play Framework (2.4.x) 中干净地处理 url 中的 api 版本?

scala - 为什么 SIGAR 随机返回 NaN 或零

templates - Play 2.x 空安全合并(避免模板中的 NPE)