如何使用Antlr4正确解析Beancount格式的注释?
Beancount格式Antlr4解析器注释解析问题
问题描述
使用Antlr4编写Beancount格式解析器时,无法正确解析注释,出现令牌识别错误。
复现语法
grammar Beancount; trStatement: tr_header NEWLINE (tr_comment NEWLINE)*; tr_header: date quoted_string; date: DATE; quoted_string: STR; tr_comment: ';' (~NEWLINE)*; fragment DIGIT: [0-9]; fragment YEAR: DIGIT DIGIT DIGIT DIGIT; fragment MONTH: DIGIT DIGIT; fragment DAY: DIGIT DIGIT; DATE: YEAR [-] MONTH [-] DAY; fragment WORD: [\p{Alnum}\-_]+; ACCOUNT: WORD (':' WORD)+; WHITESPACE: (' ' | '\t')+ -> skip; NEWLINE: ('\r' '\n'?) | '\n'; STR: '"' (~[\\"] | '\\' [\\"()])* '"';
测试文本
2019-04-14 "Cat Powder" ; Help ; Hello
错误现象
解析trStatement规则时出现:
2:4 token recognition error at: 'Help\n' 3:4 token recognition error at: 'Hello\n'
移除WORD和ACCOUNT规则后,错误变为:
2:4 token recognition error at: 'H' 2:5 token recognition error at: 'e' 2:6 token recognition error at: 'l' 2:7 token recognition error at: 'p' 3:4 token recognition error at: 'H' 3:5 token recognition error at: 'e' 3:6 token recognition error at: 'l' 3:7 token recognition error at: 'l' 3:8 token recognition error at: 'o'
解决方案
问题根源在于注释内容没有对应的词法令牌定义:原语法中tr_comment是语法规则,其中的(~NEWLINE)*无法被Antlr识别为合法令牌。将注释定义为词法规则即可解决问题,修改后的完整语法如下:
grammar Beancount; trStatement: tr_header NEWLINE (COMMENT NEWLINE)*; tr_header: date quoted_string; date: DATE; quoted_string: STR; fragment DIGIT: [0-9]; fragment YEAR: DIGIT DIGIT DIGIT DIGIT; fragment MONTH: DIGIT DIGIT; fragment DAY: DIGIT DIGIT; DATE: YEAR '-' MONTH '-' DAY; fragment WORD: [\p{Alnum}\-_]+; ACCOUNT: WORD (':' WORD)+; WHITESPACE: (' ' | '\t')+ -> skip; NEWLINE: ('\r' '\n'?) | '\n'; COMMENT: ';' ~[\r\n]*; // 将注释定义为词法规则,匹配从;到换行前的所有内容 STR: '"' (~["\\] | '\\' ["\\()])* '"'; // 替换HTML转义的"为实际双引号,符合Antlr语法规范
关键修改说明
- 将原语法规则
tr_comment替换为词法规则COMMENT,让Antlr能识别注释作为完整令牌; - 调整
STR规则中的双引号写法,移除HTML转义符,避免语法歧义; - 词法规则顺序不影响,因为
COMMENT以;开头,会优先于ACCOUNT等规则匹配。
修改后测试文本可正常解析,注释部分会被正确识别为COMMENT令牌。
内容的提问来源于stack exchange,提问作者Vishesh Handa
相关产品推荐
相关产品推荐

