ANTLR4解析器词法上下文问题:WOOL语言语法解析解决方案咨询
WOOL语言ANTLR4词法歧义问题解决
问题背景
WOOL语言允许以下三种结构:
[[ text | NodeName ]] [[ NodeName ]] [[ text | NodeName | text ]]
其中:
text需保留输入原样(包含空格,仅排除|和])NodeName是符合规则的标识符(格式为[a-zA-Z_][a-zA-Z_0-9]*或标识符.标识符)
核心问题:词法分析器无法区分[[后的内容是文本还是NodeName标识符,将nodeName规则中的CHAR替换为ID时,会触发语法错误:
line 1:21 no viable alternative at input '[this is some text. | NodeName '
现有最小化语法
WParser.g4
parser grammar WParser; options { tokenVocab=WLexer;} // 语法起始规则 program: replies EOF ; // 回复列表最多包含一个特殊回复 replies : reply* specialreply? reply* ; // 普通回复包含1或2个管道符,必须包含nodeName reply : LBOX CHAR PIPE nodeName RBOX | LBOX CHAR PIPE nodeName PIPE CHAR RBOX ; // 特殊回复仅包含nodeName specialreply : LBOX nodeName RBOX ; // NodeName格式 nodeName : CHAR | CHAR DOT CHAR;
WLexer.g4(原始版本)
lexer grammar WLexer; COMMENT_TXT : '//' ~( '\r' | '\n' )* -> skip ; WS: [\n\r\f]+ -> skip ; // 此模式下空格不被跳过 LBOX : '[' ; RBOX : ']' ; PIPE : '|' ; DOT : '.' ; ID: [a-zA-Z_][a-zA-Z_0-9]* ; CHAR : ~( '\f' | '\n' | '\r' | '[' | ']' | '>' | '|' | '<' | '/' | '=' | '$' )+ ;
问题根源
原始词法规则中,CHAR的匹配范围完全覆盖了ID的字符集,而ANTLR4词法分析遵循「最长匹配+先定义优先」原则,导致本该被识别为ID的NodeName被优先匹配成CHAR,最终触发解析错误。
解决方法:使用词法模式(Lexer Modes)
通过切换词法模式,在进入[[后启动专属处理模式,明确区分文本、NodeName和分隔符:
修改后的WLexer.g4
lexer grammar WLexer; COMMENT_TXT : '//' ~( '\r' | '\n' )* -> skip ; WS: [\n\r\f]+ -> skip ; // 全局模式仅匹配[[起始标记,切换到内容模式 LBOX_START : '[[' -> pushMode(BOX_CONTENT); // 定义括号内内容的专属词法模式 mode BOX_CONTENT; // 匹配闭合标记并退出当前模式 RBOX_END : ']]' -> popMode; // 分隔符标记 PIPE : '|'; DOT : '.'; // 优先识别NodeName标识符 ID: [a-zA-Z_][a-zA-Z_0-9]* ; // 匹配文本:除]]和|之外的所有字符(包含空格) TEXT : ~(']'|'|')+ ; // 单独的]不属于闭合标记,归为文本 UNMATCHED_BRACKET : ']' -> type(TEXT);
修改后的WParser.g4
parser grammar WParser; options { tokenVocab=WLexer;} program: replies EOF ; replies : reply* specialreply? reply* ; // 普通回复的两种格式 reply : LBOX_START TEXT PIPE nodeName RBOX_END | LBOX_START TEXT PIPE nodeName PIPE TEXT RBOX_END ; // 特殊回复格式 specialreply : LBOX_START nodeName RBOX_END ; nodeName : ID | ID DOT ID;
原理说明
- 模式切换:匹配到
[[后进入BOX_CONTENT模式,仅处理括号内的内容,避免全局规则干扰。 - 优先级明确:在内容模式下,
ID的定义优先于TEXT,确保NodeName被正确识别为标识符。 - 文本精准匹配:
TEXT仅排除]]和|两个关键分隔符,既保留了文本的原始格式,又不会误匹配分隔标记。
内容的提问来源于stack exchange,提问作者rieks op den akker
相关产品推荐
相关产品推荐

