使用 Antlr 解析语义版本
Parsing Semantic Version using Antlr
我将 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
出现以下错误:
line 1:4 mismatched input '0-beta' expecting 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
.
如何修改语法?
您有太多重叠的词法分析器规则。例如,输入 0
可以匹配以下 3 条规则中的任何一条:
NUM : '0'
| POSITIVE_DIGIT
| POSITIVE_DIGIT DIGITS
;
BUILD : ALPHANUM
| DIGITS
;
PRE_RELEASE : ALPHANUM
| NUM
;
并且由于 NUM
放在第一位,输入 0
将始终成为 NUM
标记。解析器尝试匹配什么标记并不重要,它始终是 NUM
标记。
这就是 ANTLR 的词法分析器的工作原理:
- 它会尝试为每个标记匹配尽可能多的字符,并且
- 当两个或多个词法分析器规则匹配相同数量的字符时,第一个定义的规则“获胜”。
根据您的语法和输入 "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)。
您应该做的是定义不重叠的词法分析器规则。在您的情况下,这意味着定义这些 rules/tokens:
HYPHEN
: '-'
;
PLUS
: '+'
;
DOT
: '.'
;
ZERO_DIGIT
: '0'
;
POSITIVE_DIGIT
: [1-9]
;
LETTER
: [a-zA-Z]
;
和 DIGIT
和 DIGITS
这样的规则将成为解析器规则:
digits
: digit+
;
digit
: ZERO_DIGIT
| POSITIVE_DIGIT
;
我将 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
出现以下错误:
line 1:4 mismatched input '0-beta' expecting 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
.
如何修改语法?
您有太多重叠的词法分析器规则。例如,输入 0
可以匹配以下 3 条规则中的任何一条:
NUM : '0'
| POSITIVE_DIGIT
| POSITIVE_DIGIT DIGITS
;
BUILD : ALPHANUM
| DIGITS
;
PRE_RELEASE : ALPHANUM
| NUM
;
并且由于 NUM
放在第一位,输入 0
将始终成为 NUM
标记。解析器尝试匹配什么标记并不重要,它始终是 NUM
标记。
这就是 ANTLR 的词法分析器的工作原理:
- 它会尝试为每个标记匹配尽可能多的字符,并且
- 当两个或多个词法分析器规则匹配相同数量的字符时,第一个定义的规则“获胜”。
根据您的语法和输入 "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)。
您应该做的是定义不重叠的词法分析器规则。在您的情况下,这意味着定义这些 rules/tokens:
HYPHEN
: '-'
;
PLUS
: '+'
;
DOT
: '.'
;
ZERO_DIGIT
: '0'
;
POSITIVE_DIGIT
: [1-9]
;
LETTER
: [a-zA-Z]
;
和 DIGIT
和 DIGITS
这样的规则将成为解析器规则:
digits
: digit+
;
digit
: ZERO_DIGIT
| POSITIVE_DIGIT
;