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

Parsing 在antlr4语法中实现标记文本样式运算符时,如何首先进行最短匹配?,parsing,antlr,antlr4,ll,Parsing,Antlr,Antlr4,Ll,我在互联网上找到了以下(简化的)语法,当时我正在寻找一种解决方案,解决了一个必须解析类似Markdown的语法的问题 grammar Markdown; parse : stat+; stat : bold | text | WS ; text : TEXT|SPACE; bold : ('**'stat*'**'); TEXT : [a-zA-Z0-9]+; SPACE :

我在互联网上找到了以下(简化的)语法,当时我正在寻找一种解决方案,解决了一个必须解析类似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
将是粗体的
不粗体的
不,并且
bold2
再次粗体

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

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

更新: 显然我把这个例子简化得太多了。 现在这里有一个扩展语法(不再识别标记),但它说明了我的问题。 需要注意的是,
stat
也可以是一个
变量
,它只是我的语言可能包含的任何关键字的占位符

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\u下划线//斜体//\u下划线==非

问题是规则的数量随着您引入的样式的数量呈指数增长,我想避免这种情况。

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

  • lex本质上不含糊的位
  • 在lexer-emit上,评估每个词的语义上下文,并根据需要进行调整
  • 再次解析增强的lexer流,直到令牌序列本质上是无歧义的
  • 树漫游以注释树或以其他方式构建数据结构,这些数据结构以标记语法术语完全描述树元素
  • 因此,对于标记样式的
    WORD
    (定义为不包含限定属性的文本字符串)的一般情况,解析器定义为

    word
        : attrLeft* 
          w=( WORD | ENTITY | UNICODE
            | URL  | URLTAG | SPAN | HTML 
            )
          attrRight*
        ;
    
    attrLeft  : LBOLD | LITALIC | LSTRIKE | LDQUOTE | LSQUOTE ;
    attrRight : RBOLD | RITALIC | RSTRIKE | RDQUOTE | RSQUOTE ;
    
    在lexer中,将所有属性定义为默认的
    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 | . ;
    
    在lexer
    超类中,覆盖

    public void emit(Token t) {...}
    
    并决定是否

  • 任何特定的
    属性实际上都应该重新指定为
    属性
  • CHAR
    应累积到当前的
    WORD
    中,或应添加到新的
    WORD
    实例中

  • 现在,树漫游者可以评估
    word
    s的序列,并处理潜在的多个重叠嵌套属性的处理。

    为什么要区分
    SPACE
    WS
    ?无论如何,你的问题是你的语法没有反映出粗体部分不能相互嵌套的事实。因此,
    bold
    规则不应该与
    stat
    相互递归。很抱歉造成混淆。我过分简化了这个例子。请再看看我的更新。