如何在类似 Markdown 的语法中实现对粗体和斜体文本范围的词法进行词法分析的后瞻和前瞻



我正在为类似 Markdown 的语法构建一个解析器,目前正在努力实现对粗体和斜体文本范围的强大支持。我想将以下粗体范围开头的正则表达式"翻译"为 ANTLR4 词法分析器语法(该表达式取自 Atom 编辑器的 Markdown 语法突出显示(:

(?<=^|[^wd*])**(?!$|*|s)

正面后视检查"**"序列是否位于字符串的开头,或者前面没有单词、数字或其他星号。负前瞻检查序列是否不在字符串末尾之前,并且后面没有另一个星号或任何空格字符。

我已经知道我必须在 ANTLR4 中使用语义谓词来做一个前瞻(使用 _input。LA(1((,做这样的事情:

  ASTERISK_BOLD_START
      : { /*Lookbehind checks*/}? '**' {/*Lookahead checks with _input.LA(1)*/}?
      ;

但是,如何实施后视检查呢?如何检查解析的整个字符串的开头或结尾?

不要使用正则表达式来创建解析器语法。这两种技术的工作方式不同,您很容易朝着错误的方向移动。你认为做很多向后看和向前看的想法是如此错误的方向。这是(复杂(正则表达式的典型特征,但不是普通解析器。相反,看看其他语法作者写了什么。SO有一个语法,Github那边有Antmark。您也可以从Markdown的EBNF开始,并从中创建语法。

但是,要为一些麻烦做好准备。Markdown 不是一种上下文无关的语法,因此难以解析。博客文章为什么没有 Markdown 的正式语法?解释一些细节。

我个人发现单字符展望在某些情况下在词法分析器中很有用。我使用它的目的是匹配数字 - 现在您可以将数字写成数字或带有分隔符的数字,以三人为一组,例如 100,000,000 .

这是语法文件中的预瞻实现:

@lexer::members {
    //implements one character look ahead
    public boolean charLA(String strPattern) {
        String nextCharacter = _input.getText(new Interval(getCharIndex(), getCharIndex()+1));
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(strPattern,java.util.regex.Pattern.UNICODE_CASE);
        return (nextCharacter != null && !nextCharacter.isEmpty() && pattern.matcher(nextCharacter).find());
    }  
}

以下是与数字匹配的语法规则:

INTEGER_GROUPED : ([0-9])?([0-9])?[0-9] ((' '|',') [0-9][0-9][0-9])+ {!charLA("[0-9]")}?;

INTEGER : [0-9]+ ;

这确保了当用户写入 1,000 时 - 它将与 INTEGER_GROUPED 匹配,但当用户写入 1,1234 时,它实际上将由两个INTEGER s 1 和 1234 匹配。如果没有前瞻,它将匹配为INTEGER_GROUPED 1,123INTEGER 4

并不是说这是唯一的方法,但我发现它非常有用。

最新更新