动态创建parboiled2规则

时间:2015-09-16 17:41:47

标签: scala parboiled2

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

1 个答案:

答案 0 :(得分:2)

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

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

有两种已知选项,如何实现这一目标:

第一个选项(我尚未尝试)被称为DynamicRuleDispatch,您可以在documentation中找到它并查看它的测试here

第二个选项是手动执行调度(正如我所做的那样)。

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

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

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

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

    class Parser(输入:ParserInput,format:String)扩展Parser ....

  4. 然后你需要解析格式字符串并获取格式标记。 使用模式匹配将相应格式标记的列表分发给 下面的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来解析generater访问日志。因此,您需要一种数据模型来规范规则。

相关问题