微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 antlr4 语法中实现标记文本样式运算符时如何首先进行最短匹配?

如何解决在 antlr4 语法中实现标记文本样式运算符时如何首先进行最短匹配?

我在互联网上找到了以下(简化的)语法,因为我正在寻找解决问题的方法,我必须解析类似于 Markdown 的语法。

grammar Markdown;

parse    :   stat+;

stat    :   bold
        |   text
        |   WS
        ;

text    :   TEXT|SPACE;

bold    :   ('**'stat*'**');

TEXT    :   [a-zA-Z0-9]+;

SPACE   :   ' ';

WS      :   [\t\r\n]+;

我想要实现的是 antlr4 首先对看起来像 **bold1** not bold **bold2** 的句子进行最短匹配。 这意味着 bold1 会加粗,not bold 不会,而 bold2 会再次加粗。

然而,由于 antlr4 首先使用最长匹配,antlr4 将示例解析为两个嵌套的粗体,这是错误的。

对于这个问题,我已经想过多种非常复杂的解决方案,但实际上我不想使用。 有没有简单的解决办法?

更新: 显然我过于简化了这个例子。 现在这一个扩展语法(不再识别降价),但它说明了我遇到的问题。 请务必注意,stat 也可以是 variable,它只是我的语言可能包含的任何关键字的占位符。

grammar StyleParser;

parse    :   styled_stat+;

styled_stat : italic
            | bold
            | underline
            | stat
            ;

stat    :   variable
        |   text
        ;

variable: VARIABLE;
text    :   TEXT|SPACE;

italic  :   ITALIC (stat | italic_bold | italic_underline)* ITALIC;
italic_bold: BOLD (stat | italic_bold_underline)* BOLD;
italic_bold_underline: UNDERLINE stat* UNDERLINE;

italic_underline: UNDERLINE (stat | italic_underline_bold)* UNDERLINE;
italic_underline_bold: BOLD stat* BOLD;

bold    :   BOLD (stat | bold_italic | bold_underline)* BOLD;
bold_italic: ITALIC (stat | bold_italic_underline)* ITALIC;
bold_italic_underline: UNDERLINE stat* UNDERLINE;

bold_underline: UNDERLINE (stat | bold_underline_italic)* UNDERLINE;
bold_underline_italic: ITALIC stat* ITALIC;

underline   :   UNDERLINE (stat | underline_bold | underline_italic)* UNDERLINE;   
underline_italic: ITALIC (stat | underline_italic_bold)* ITALIC;
underline_italic_bold: BOLD stat* BOLD;

underline_bold: BOLD (stat | underline_bold_italic)* BOLD;
underline_bold_italic: ITALIC stat* ITALIC; 

SPACE   :   ' ';

VARIABLE : 'VAR';
TEXT    :   [a-zA-Z0-9]+;

ITALIC: '//';
BOLD: '==';
UNDERLINE: '__';

使用这种语法,我不能嵌套相同的样式,但可以嵌套不同的样式。例如,它正确解析 ==bold1 __underline //italic//__== not __underline__ //italic// bold ==VAR==。 问题是规则的数量随着您引入的样式数量呈指数增长,我想避免这种情况。

解决方法

解析 markdown 非常重要。一种方法是

  1. 对本质上没有歧义的位进行词法处理;
  2. 在词法分析器发出时,评估每个语义上下文并进行适当调整;
  3. 解析增强的词法分析器流,再次使标记序列本质上是无歧义的;
  4. tree-walk 以对树进行注释或以其他方式构建以降价语法术语完整描述树元素的数据结构。

因此,对于 Markdown 样式的 WORD 的一般情况,定义为一些排除限定属性的文本字符串,解析器定义为

word
    : attrLeft* 
      w=( WORD | ENTITY | UNICODE
        | URL  | URLTAG | SPAN | HTML 
        )
      attrRight*
    ;

attrLeft  : LBOLD | LITALIC | LSTRIKE | LDQUOTE | LSQUOTE ;
attrRight : RBOLD | RITALIC | RSTRIKE | RDQUOTE | RSQUOTE ;

在词法分析器中,将所有属性定义为默认 left 并为 right 属性和 WORD 保留标记

tokens {
    WORD,RBOLD,RITALIC,RSTRIKE,RDQUOTE,RSQUOTE
}

// attributes
LBOLD   : Bold   ;
LITALIC : Italic ;
LSTRIKE : Strike ;
LDQUOTE : Quote  ;
LSQUOTE : Mark   ;

... 

// last line in the lexer
CHAR : EscChar | . ;

在词法分析器 superclass 中,覆盖

public void emit(Token t) {...}

并决定是否

  1. 任何特定的 left 属性都应该真正重新分配为 right 属性
  2. CHAR 应该累积到当前的 WORD 中,或者应该添加到新的 WORD 实例中。

现在,tree-walker 可以评估 word 的序列并处理潜在的多个重叠嵌套属性。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。