【问题标题】:Parsing Semantic Version using Antlr使用 Antlr 解析语义版本
【发布时间】:2020-11-09 16:27:38
【问题描述】:

我将SemVer 2 BNF grammar 翻译成下面的Antlr 语法。

grammar SemVer;

@header {
package com.me.semver;
}

semVer : normal ('-' preRelease)? ('+' build)? ;
normal : major '.' minor '.' patch ;
major : NUM ;
minor : NUM ;
patch : NUM ;
preRelease : PRE_RELEASE ('.' preRelease)* ;
build : BUILD ('.' build)*;
NUM : '0'
    | POSITIVE_DIGIT
    | POSITIVE_DIGIT DIGITS
    ;
BUILD : ALPHANUM
      | DIGITS
      ;
PRE_RELEASE : ALPHANUM
            | NUM
            ;
fragment
ALPHANUM : NON_DIGIT
         | NON_DIGIT CHARS
         | CHARS NON_DIGIT
         | CHARS NON_DIGIT CHARS
         ;
fragment
CHARS : CHAR+ ;
fragment
CHAR : DIGIT
     | NON_DIGIT
     ;
fragment
NON_DIGIT : LETTER
          | '-'
          ;
fragment
DIGITS : DIGIT+ ;
fragment
DIGIT : '0'
      | POSITIVE_DIGIT
      ;
fragment
POSITIVE_DIGIT : [1-9] ;
fragment
LETTER : [a-zA-Z] ;

但解析1.0.0-beta+exp.sha.5114f85 会出现以下错误:

第 1:4 行不匹配的输入“0-beta”需要 NUM

监听器的输出如下:

Normal: 1.0.0-beta
Major: 1
Minor: 0
Patch: 0-beta
Build: exp.sha.5114f85
Build: sha.5114f85
Build: 5114f85

显然,补丁版本不是应有的版本。正确的输出应该是 Patch = 0、Pre release = beta 和 Build = exp.sha.5114f85。

如何修正语法?

【问题讨论】:

    标签: antlr antlr4 grammar bnf semantic-versioning


    【解决方案1】:

    您有太多重叠的词法分析器规则。例如,输入 0 可以被以下 3 个规则中的任何一个匹配:

    NUM : '0'
        | POSITIVE_DIGIT
        | POSITIVE_DIGIT DIGITS
        ;
    BUILD : ALPHANUM
          | DIGITS
          ;
    PRE_RELEASE : ALPHANUM
                | NUM
                ;
    

    并且由于 NUM 被放在首位,输入 0 将始终成为 NUM 标记。解析器尝试匹配的标记无关紧要,它始终是NUM 标记。

    这正是 ANTLR 词法分析器的工作原理:

    1. 它尝试为每个标记匹配尽可能多的字符,并且
    2. 当两个或多个词法分析器规则匹配相同数量的字符时,第一个定义的“获胜”。

    根据您的语法和输入 "1.0.0-beta+exp.sha.5114f85",创建这些标记:

    NUM                       `1`
    null                      `.`
    NUM                       `0`
    null                      `.`
    BUILD                     `0-beta`
    null                      `+`
    BUILD                     `exp`
    null                      `.`
    BUILD                     `sha`
    null                      `.`
    BUILD                     `5114f85`
    

    请注意,0-beta 被标记为单个 BUILD 标记(规则 #1)。

    您应该做的是定义不重叠的词法分析器规则。在您的情况下,这意味着定义这些规则/令牌:

    HYPHEN
     : '-'
     ;
    
    PLUS
     : '+'
     ;
    
    DOT
     : '.'
     ;
    
    ZERO_DIGIT
     : '0'
     ;
    
    POSITIVE_DIGIT
     : [1-9]
     ;
    
    LETTER
     : [a-zA-Z]
     ;
    

    然后像 DIGIT 和 DIGITS 这样的规则将变成解析器规则:

    digits
     : digit+
     ;
    
    digit
     : ZERO_DIGIT
     | POSITIVE_DIGIT
     ;
    

    【讨论】:

    • 我有几个后续问题。 1.non-digit是letter和-;您似乎已将non-digit 替换为LETTER,这是不正确的。 2. 预发布版本中的数字标识符must not include leading zeroes;但是,构建元数据的数字标识符没有这样的限制。您的语法没有这种微妙的区别(我认为这就是 BNF 分别使用 digits 和 numeric identifier 的原因)。 3.你的valid_semver规则和我的semVer规则有什么区别(我不是Antlr专家)?
    • (因为我超出了上面的评论长度)...4。为什么要创建像build : dot_separated_build_identifiers 这样的别名?一种更常识的方法似乎重命名dot_separated_build_identifiers,然后使用它。
    • 我删除了语法并强调了您语法中的实际问题。
    猜你喜欢
    • 2016-08-19
    • 2016-11-09
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 2015-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多