ANTLR语法规则优先级配置:将<<word>>识别为特殊令牌而非普通字面量
解决ANTLR语法中<>与的识别问题
我来帮你搞定这个ANTLR语法的问题,核心在于理解ANTLR词法规则的匹配优先级——先定义的规则优先,且总是尝试最长匹配,你的原语法里因为规则顺序和令牌范围的问题,导致无法区分特殊的<<word>>和普通的<word>,下面是调整后的完整方案:
调整后的完整语法
grammar test; // 语法规则 doc: item+ ; item: func | atom ; func: OPEN_FUNC WORD CLOSE_FUNC ; atom: PUNCT+ #punctAtom | NEWLINE+ #newlineAtom | WORD #wordAtom | SINGLE_LT #ltAtom // 单个<作为普通原子处理 | SINGLE_GT #gtAtom; // 单个>作为普通原子处理 // 词法规则 - 关键:特殊复合令牌必须放在最前面 OPEN_FUNC: '<<'; CLOSE_FUNC: '>>'; SINGLE_LT: '<'; // 仅当无法匹配OPEN_FUNC时,才会匹配单个< SINGLE_GT: '>'; // 仅当无法匹配CLOSE_FUNC时,才会匹配单个> NEWLINE : [\n\r]+ ; PUNCT : [.,?!]+ ; WORD : (LETTER | DIGIT | SYMB)+ ; // 排除<、>和标点,避免和其他规则冲突 // 片段规则(仅用于辅助定义,不会生成令牌) fragment LETTER : [a-zA-Z] ; fragment DIGIT : [0-9] ; fragment SYMB : [-_@#$%^&*()+=/\\|{}[\]~`] ; // 自定义符号,不含<、>和标点
关键调整说明
词法规则顺序是核心
ANTLR的词法分析器会按规则定义的顺序尝试匹配,且优先选择最长的匹配结果。所以我们把<<和>>这两个复合令牌放在最前面,确保遇到<<时,不会被拆成两个单独的<令牌。拆分单个<和>的匹配
新增SINGLE_LT和SINGLE_GT规则匹配单个的<和>,这样当出现<word>时,会被拆成「单个< + WORD + 单个>」,全部归为普通原子项,符合你的需求。修正WORD的范围
原语法中WORD包含了PUNCT字符,会导致PUNCT规则永远无法触发(因为WORD先定义,会优先匹配标点字符)。现在我们让WORD排除<、>和标点,确保每个规则的职责清晰,不会互相抢占匹配权。
简化版可选方案
如果你不需要单独处理单个<和>,可以把它们合并到PUNCT规则里,这样语法会更简洁:
grammar test; doc: item+ ; item: func | atom ; func: OPEN_FUNC WORD CLOSE_FUNC ; atom: PUNCT+ #punctAtom | NEWLINE+ #newlineAtom | WORD #wordAtom ; OPEN_FUNC: '<<'; CLOSE_FUNC: '>>'; NEWLINE : [\n\r]+ ; PUNCT : [<>.,?!]+ ; // 把单个<、>合并到标点规则里 WORD : (LETTER | DIGIT | SYMB)+ ; fragment LETTER : [a-zA-Z] ; fragment DIGIT : [0-9] ; fragment SYMB : [-_@#$%^&*()+=/\\|{}[\]~`] ;
这种情况下,<word>会被拆成「PUNCT(<) + WORD + PUNCT(>)」,同样会被识别为普通字面量。
ANTLR词法规则排序的核心原则
记住这两点,以后遇到类似问题就不会踩坑:
- 特殊/复合令牌优先:多字符的特殊令牌(比如
<<、>>、关键字)一定要放在单个字符或通用令牌的前面。 - 通用规则靠后:像WORD、PUNCT这类通用的令牌,要放在所有特殊规则之后,避免它们抢占特殊令牌的匹配机会。
内容的提问来源于stack exchange,提问作者skrilmps
相关产品推荐
相关产品推荐

