parsing - 在 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==
正确解析。问题是规则的数量随着你引入的样式数量呈指数增长,我想避免这种情况。
解决方案
解析降价并非易事。一种方法是
- lex 本质上没有歧义的位;
- 在词法分析器发出时,评估每个语义上下文并酌情调整;
- 再次解析增强的词法分析器流,以使令牌序列本质上是非歧义的;
- tree-walk 来注释树或以其他方式构建以 Markdown 语法术语完全描述树元素的数据结构。
因此,对于 markdown-styled 的一般情况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) {...}
并决定是否
- 任何特定
left
属性都应该真正重新分配为right
属性 - a
CHAR
应该累积到当前实例WORD
中,或者应该添加到新WORD
实例中。
现在,tree-walker 可以评估word
s 的序列并处理潜在的多个重叠嵌套属性的处理。
推荐阅读
- javascript - 以编程方式选择浏览器中未更新的选项
- python - 为向量创建索引时,“列表”对象不可调用
- java - SpringBoot:如何使用 Wrapper Class 将两个 JSON pojo 绑定到两个单独的对象中并将它们保存到我的数据库中?
- amazon-web-services - 使用clojure调用aws lambda函数的空指针异常?
- typescript - Typescript中带有参数的动态键
- javascript - 在页面上以表格格式显示存储在 SharePoint 列表中的数据,并在页面上的表格列上放置过滤器以过滤数据
- python - Django3 - 使用上下文处理器填充导航栏项目 SQlite DB 数据的问题
- python - 每次在 tkinter 中将文本插入文本框时,如何添加间距?
- google-custom-search - 使用 Google 自定义搜索 JSON 在多个站点中搜索
- powerbi - 在 UI 中显示的 DAX 过滤器列字符串值