仅包含可选规则的规则需要至少一个

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)}?
;