简体   繁体   English

动态创建parboiled2规则

[英]Dynamically create parboiled2 rules

Can I generate rules dynamically in parboiled2 parser? 我可以在parboiled2解析器中动态生成规则吗? The use case is that I have a bunch of rules already defined, but want to add more and not compile every time I add a rule. 用例是我已经定义了一堆规则,但是每次添加规则时都想添加更多而不是编译。

If you want to generate rules at runtime (like you did in Parboiled1) it's impossible. 如果你想在运行时生成规则(就像在Parboiled1中那样),那是不可能的。 Parboiled 2 is using marco exressions, So you can not generate rules in the runtime. Parboiled 2使用的是marco exressions,因此您无法在运行时生成规则。 All stuff happens during the compilation phase. 所有的东西都发生在编译阶段。

If you have a number of defined rules, and want to compose them in arbitrary order, even with some of them missing. 如果您有许多已定义的规则,并希望以任意顺序组合它们,即使其中一些缺失也是如此。 It's possible. 这是可能的。 I did it. 我做的。

There are two known options, how you can achieve this: 有两个已知的选项,如何实现这一目标:

The first option (I didn't try it yet) is called DynamicRuleDispatch you can find it in the documentation and look at it's test here . 第一个选项(我还没试过)叫做DynamicRuleDispatch你可以在文档中找到它并在这里查看它的测试。

The second option is to peform dispatch manually (As I did). 第二种选择是手动执行调度(正如我所做的那样)。

  1. You should create a bunch of rules that can be combined dynamically. 您应该创建一组可以动态组合的规则。 Those rules must have Rule0 type. 这些规则必须具有Rule0类型。 They should not affect the value stack. 它们不应该影响值堆栈。 Add side effect to those rules, after the rule evaluation. 在规则评估之后,为这些规则添加副作用。 Side effect operation must save the captured data somewhere inside your parser's sate. 副作用操作必须将捕获的数据保存在解析器状态中的某个位置。 You should use capture + ~ + run bundle to achieve this, look at the sample below: 您应该使用capture + ~ + run bundle来实现这一点,请看下面的示例:

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

  2. You need to create some kind of mutable state inside your parser. 您需要在解析器中创建某种可变状态。 A save place where you can save your parsing results. 保存解析结果的保存位置。 It can be hashmap. 它可以是hashmap。 This Hashmap should store all possible rules and their values. 此Hashmap应存储所有可能的规则及其值。 You can't use values stack because you won't have determined number of matched rules. 您不能使用值堆栈,因为您没有确定数量的匹配规则。 Be careful when maintaining mutable state. 保持可变状态时要小心。 It must be cleaned after each call. 每次通话后都必须清洁。

  3. You need a format for rule alignment to align the rules. 您需要一种规则对齐格式来对齐规则。 For example: 例如:

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

Then you need to parse the format string and get the format tokens. 然后你需要解析格式字符串并获取格式标记。 Use pattern matching to dispatch a list of corresponding format tokens to the Rule0 fields dispatchRule method below. 使用模式匹配将相应格式标记的列表分派给下面的Rule0字段dispatchRule方法。 And then map the list of string tokens to rules. 然后将字符串标记列表映射到规则。

When you have a list of rules you need to perform the following operation: 如果有规则列表,则需要执行以下操作:

// 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
   ....
}

You can parse generater access log by having logformat in your parser constructor. 您可以通过在解析器构造函数中使用logformat来解析generater访问日志。 So, you need kind of data model to aligh rules. 因此,您需要一种数据模型才能使规则相符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM