ANTLR4 将任何不匹配的部分匹配到一个单一的 STRING 令牌中

ANTLR4 match any not-matched sections into one single STRING token

我正在尝试使用 ANTLR 创建一个 Lexer/Parser,它可以解析散布在其间的 'tags' 的纯文本。 这些标签由开括号 ({) 和闭括号 (}) 表示,它们表示 Java 可以评估为字符串的对象,然后在原始输入中替换该字符串以创建各种动态模板。

这是一个例子: {player:name} 打招呼! {player:name} 应该替换为玩家的名字并导致输出,即 Mark says hi!对于名为 Mark 的玩家。

现在我可以很好地识别和解析标签,我遇到的问题是后面的文本。 这是我使用的语法:

    grammar : content+

    content : tag 
            | literal
            ;

    tag : player_tag
        | <...>
        | <other kinds of tags, not important for this example>
        | <...>
        ;

    player_tag : BRACKET_OPEN player_identifier SEMICOLON player_string_parameter BRACKET_CLOSE ;
    player_string_parameter : NAME
                            | <...>
                            ;
    player_identifier : PLAYER ;

    literal : NUMBER
            | STRING
            ;

    BRACKET_OPEN : '{';
    BRACKET_CLOSE : '}';

    PLAYER : 'player'
    NAME : 'name'

    NUMBER : <...>
    STRING : (.+)? /* <- THIS IS THE PROBLEMATIC PART !*/

现在这个 STRING Lexer 定义应该匹配任何不是空字符串的东西,但问题是它太贪心了,然后还消耗了标签规则所需的 { } 括号标记。 我试过将它设置为 ~[{}]+ ,它应该匹配任何不包含 { } 括号的东西,但它与我也不理解的标签解析有关。 我可以将它设置为 [ a-zA-Z0-9!"§$%&/()= etc...]+ 但我真的不想限制它只解析英式键盘上可用的字符(德语元音变音符或法语口音以及其他语言必须使用的所有其他特殊字符!) 虽然我真的不喜欢它,但唯一有点用的是强制字符串有一个前缀和一个后缀,如下所示:

  STRING : '\'' ~[}{]+ '\'' ;

这迫使我改变“{player:name} says hi!”的形式。到“{player:name}' says hi!'”,我真的非常想避免这样的限制,因为这样我就必须考虑字符串本身中的文字 ' 字符,而且使用起来很难看。

我想到的两种解决方案如下: - 有什么方法可以将词法分析器未匹配的任意数量的字符作为 STRING 标记进行匹配并将其传递给解析器吗?这样我就可以匹配所有标签并说输入的其余部分只是纯文本,将它作为 STRING 标记或其他任何东西返回给我...... - ANTLR 是否支持前瞻和后视正则表达式,我可以使用它们匹配第一个“{”之前、最后一个“}”之后以及“}”和“{”之间的任何字符的任意数量的字符? 我试过了

  STRING : (?<=})(.+)?(?={) ;

但我似乎无法获得正确的语法,因为它根本无法编译,这让我相信 ANTLR 不支持前瞻和后视语法,但我找不到明确的答案那个问题的互联网。

有什么建议吗?

A​​ntlr 不支持先行或后行。它确实支持非贪婪通配符匹配,但仅当 .* 非贪婪通配符后跟 规则 中的终止序列(如您所说,也是包含在匹配项中,尽管您可以将其推回到输入流中)。

所以~[{}]*是正确的。但是有一个小问题:词法分析器规则(通常)始终处于活动状态。因此词法分析器规则 在大括号内 也将处于活动状态,这意味着它将吞没大括号之间的全部内容(除非有嵌套大括号或引号内的大括号或类似的东西,并且那更糟)。

所以你需要定义不同的词法内容,在Antlr中叫做"lexical modes"。 Antlr Definitive Reference 中有一个 publically viewable example,它显示了一个非常相似的问题的解决方案:解析 HTML.