【问题标题】:Lexing token ambiguity in ANTLR4ANTLR4 中的 Lexing 令牌歧义
【发布时间】:2023-02-05 20:27:41
【问题描述】:

我在解析以下语法(Convnetional Commits)时遇到了一个非常有趣的问题——这是 git 提交消息应该如何格式化的约定。

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
  • 正文只是多行文本,任何内容都可以
  • 页脚是键值对,格式为fobar: this is value,换行符分隔。

现在,关于我的困境:什么是区分身体一部分来自页脚部分?根据规范,这些应该由两个换行符分隔,所以起初我认为这很适合 ANTLR4 岛语法。我想出了一些类似于我在here 发布的东西,但经过一些测试后,我发现它不灵活——如果没有正文(正文部分是可选的)但是页脚,它就不会工作那里。

我可以想出几种方法将语法限制为某种语言并使用语义谓词实现这种区分,但理想情况下,我想避免这种情况。

现在,我认为问题归结为如何正确区分发生冲突的 KEYSINGLE_LINE 标记(在我的下一次迭代中)

mode Text;
KEY: [a-z][a-z_-]+;
SINGLE_LINE: ~[\n]+;

MULTI_LINE: SINGLE_LINE (NEWLINE SINGLE_LINE)*;

NEXT: NEWLINE NEWLINE;

区分KEYSINGLE_LINE 的最佳方法是什么?

【问题讨论】:

  • 规范不明确。以“\n\na: b”结尾的提交可以将 a: b 解释为正文的最后一行或页脚的第一行。
  • 使用 ANTLR(或其他一些解析器生成器)对于这个 IMO 来说太过分了。
  • @BartKiers 我知道,例如,这可以通过超级正则表达式来解决。或者手动解析它应该不会太难。在某种程度上,我这样做是作为一种“编程套路”:)

标签: git parsing antlr4 conventional-commits


【解决方案1】:

我会做这样的事情:

ConventionalCommitsLexer.g4

lexer grammar ConventionalCommitsLexer;

options {
  caseInsensitive=true;
}

TYPE : [a-z]+;
LPAR : '(' -> pushMode(Scope);
COL  : ':' -> pushMode(Text);

fragment SPACE : [ 	];

mode Scope;

 SCOPE : ~[)]+;
 RPAR  : ')' SPACE* -> popMode;

mode Text;

 COL2    : ':' -> type(COL);
 SPACES : SPACE+ -> skip;
 WORD   : ~[: 	
]+;
 NL     : SPACE* '
'? '
' SPACE*;

常规提交 Parser.g4

parser grammar ConventionalCommitsParser;

options {
  tokenVocab=ConventionalCommitsLexer;
}

commit
 : TYPE scope? COL description ( NL NL body )? ( NL NL footer )? EOF
 ;

scope
 : LPAR SCOPE RPAR
 ;

description
 : word+
 ;

// A 'body' cannot start with `WORD COL`, hence: `WORD WORD`
body
 : WORD WORD word* ( NL word+ )*
 ;

footer
 : key_value ( NL key_value )* NL?
 ;

key_value
 : WORD COL word+
 ;

word
 : WORD
 | COL
 ;

解析输入(正文+页脚):

fix(some_module): this is a commit description
    
Some more in-depth description of what was fixed: this
can be a multi-line text, not only a one-liner.

Signed-off: john.doe@some.domain.com
Another-Key: another value with : (colon)
Some-Other-Key: some other value

结果:

解析输入(仅正文):

fix(some_module): this is a commit description
    
Some more in-depth description of what was fixed: this
can be a multi-line text, not only a one-liner.

结果:

解析输入(仅页脚):

fix(some_module): this is a commit description

Signed-off: john.doe@some.domain.com
Another-Key: another value with : (colon)
Some-Other-Key: some other value

结果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    相关资源
    最近更新 更多