仅包含可选规则的规则需要至少一个
Rule containing only optional rules requires at least one
我遇到了与这个问题类似的问题:At least one Antlr rule optional part
但是我的情况略有不同,我没有像上面问题中那样的任何常量前缀和后缀。也就是说,我有一个看起来像这样的规则:
sequence_A: field_A_20? field_A_21R? field_A_28D? field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?;
如您所见,我有一些可选的子规则。基本上所有字段都可能存在,也可能不存在。当然,这会导致规则可以匹配空字符串的问题,并且由于规则 sequence_A
将与 *
一起使用,这会导致更多问题。
好消息是,如果存在 none 个字段,那么 sequence_A
也应该不匹配,这意味着必须至少存在上述字段之一才能进行匹配。然而,它可以是它们中的任何一个。当然,就像上面提到的问题一样,我稍后可以在访问者中断言这一点,但问题是语法本身将无效,因为规则匹配空字符串并在闭包中使用,所以我什至没有接触到访问者。
困难的部分是,没有任何迹象表明 sequence_A
开始,除了存在列表的随机字段。字段的顺序也很重要。如果它们存在,则它们必须按该顺序存在。
我有点不知所措。这甚至可以用 antlr 实现吗?
有一个解决方案,但我想避免它。我已经在使用代码生成器来生成语法,所以理论上我可以生成所有变体,其中我 |
一起生成所有变体,其中只有一个字段是强制性的,但我希望有一个更简单的解决方案。
尝试:
sequence_A: (
field_A_20 |
field_A_21R |
field_A_28D |
field_A_50a |
field_A_50a_1 |
field_A_52a |
field_A_51A |
field_A_30 |
field_A_25
)+;
这将允许匹配任何备选方案的多个实例,但您可以使用访问者添加语义检查。重要的是获得一个能够准确反映对输入流的正确解释的解析树。然后您可以检查重复项等语义问题。
由于顺序很重要而且 sequence_A
可以出现 zero-or-more 次,这可能是要走的路:
sequence_A: field_A_20 field_A_21R? field_A_28D? field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?;
如果sequence_A
匹配那么它必须总是以field_A_20
开头,所以你可以做这个non-optional并且解决了空字符串匹配和kleene规则匹配这样的问题空字符串规则。
更新
我不清楚您可能还需要子部件。在那种情况下,我会这样做:
sequence_A:
field_A_20 field_A_21R? field_A_28D? field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_21R field_A_28D? field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_28D field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_50a field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_50a_1 field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_52a field_A_51A? field_A_30? field_A_25?
| field_A_51A field_A_30? field_A_25?
| field_A_30 field_A_25?
| field_A_25
;
不是特别优雅,但至少不需要平台操作代码(如果这对您来说很重要的话)。您可以给所有备选方案贴上标签,这样您的访问者就会很轻松。
据我了解,您的 sequenceA
规则必须至少包含 sub-rules 之一,并且它们必须按规定的顺序排列。
(未经测试的代码)
您可以添加以下方法来评估给定上下文是否至少有一个 non-null 个子节点。
@parser::members {
boolean atLeastOne(ParserRuleContext ctx) {
return ctx.children.stream().anyMatch((c) -> {
return c != null;
});
}
}
然后,将其用作“全部可选”规则的谓词:
sequence_A:
field_A_20?
field_A_21R?
field_A_28D?
field_A_50a?
field_A_50a_1?
field_A_52a?
field_A_51A?
field_A_30?
field_A_25?
{atLeastOne(_localctx)}?
;
我遇到了与这个问题类似的问题:At least one Antlr rule optional part
但是我的情况略有不同,我没有像上面问题中那样的任何常量前缀和后缀。也就是说,我有一个看起来像这样的规则:
sequence_A: field_A_20? field_A_21R? field_A_28D? field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?;
如您所见,我有一些可选的子规则。基本上所有字段都可能存在,也可能不存在。当然,这会导致规则可以匹配空字符串的问题,并且由于规则 sequence_A
将与 *
一起使用,这会导致更多问题。
好消息是,如果存在 none 个字段,那么 sequence_A
也应该不匹配,这意味着必须至少存在上述字段之一才能进行匹配。然而,它可以是它们中的任何一个。当然,就像上面提到的问题一样,我稍后可以在访问者中断言这一点,但问题是语法本身将无效,因为规则匹配空字符串并在闭包中使用,所以我什至没有接触到访问者。
困难的部分是,没有任何迹象表明 sequence_A
开始,除了存在列表的随机字段。字段的顺序也很重要。如果它们存在,则它们必须按该顺序存在。
我有点不知所措。这甚至可以用 antlr 实现吗?
有一个解决方案,但我想避免它。我已经在使用代码生成器来生成语法,所以理论上我可以生成所有变体,其中我 |
一起生成所有变体,其中只有一个字段是强制性的,但我希望有一个更简单的解决方案。
尝试:
sequence_A: (
field_A_20 |
field_A_21R |
field_A_28D |
field_A_50a |
field_A_50a_1 |
field_A_52a |
field_A_51A |
field_A_30 |
field_A_25
)+;
这将允许匹配任何备选方案的多个实例,但您可以使用访问者添加语义检查。重要的是获得一个能够准确反映对输入流的正确解释的解析树。然后您可以检查重复项等语义问题。
由于顺序很重要而且 sequence_A
可以出现 zero-or-more 次,这可能是要走的路:
sequence_A: field_A_20 field_A_21R? field_A_28D? field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?;
如果sequence_A
匹配那么它必须总是以field_A_20
开头,所以你可以做这个non-optional并且解决了空字符串匹配和kleene规则匹配这样的问题空字符串规则。
更新
我不清楚您可能还需要子部件。在那种情况下,我会这样做:
sequence_A:
field_A_20 field_A_21R? field_A_28D? field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_21R field_A_28D? field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_28D field_A_50a? field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_50a field_A_50a_1? field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_50a_1 field_A_52a? field_A_51A? field_A_30? field_A_25?
| field_A_52a field_A_51A? field_A_30? field_A_25?
| field_A_51A field_A_30? field_A_25?
| field_A_30 field_A_25?
| field_A_25
;
不是特别优雅,但至少不需要平台操作代码(如果这对您来说很重要的话)。您可以给所有备选方案贴上标签,这样您的访问者就会很轻松。
据我了解,您的 sequenceA
规则必须至少包含 sub-rules 之一,并且它们必须按规定的顺序排列。
(未经测试的代码)
您可以添加以下方法来评估给定上下文是否至少有一个 non-null 个子节点。
@parser::members {
boolean atLeastOne(ParserRuleContext ctx) {
return ctx.children.stream().anyMatch((c) -> {
return c != null;
});
}
}
然后,将其用作“全部可选”规则的谓词:
sequence_A:
field_A_20?
field_A_21R?
field_A_28D?
field_A_50a?
field_A_50a_1?
field_A_52a?
field_A_51A?
field_A_30?
field_A_25?
{atLeastOne(_localctx)}?
;