You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Antlr4报mismatched input '<' expecting '<' 无词法歧义问题排查

问题背景

使用Antlr4编写语法规则时,预期语法可匹配如下输入:

i,j : bool;
setvar : set<bool>;
i > 5;
j < 10;

实际运行解析时持续报错:line 3:13 mismatched input '<' expecting '<'。初步排查时判断这类错误通常源于词法歧义,但检查语法后发现<仅在单个token规则中定义,不存在重复定义的情况。

使用的完整语法规则如下:

//// Parser Rules

grammar MLTL1;

start: block*;

block: var_list ';'
     | expr ';'
     ;

var_list: IDENTIFIER (',' IDENTIFIER)* ':' type ;

type: BASE_TYPE
    | KW_SET REL_LT BASE_TYPE REL_GT
    ;

expr: expr REL_OP expr
    | '(' expr ')'
    | IDENTIFIER 
    | INT
    ;

//// Lexical Spec

// Types
BASE_TYPE: 'bool'
         | 'int'
         | 'float'
         ;

// Keywords
KW_SET: 'set' ;

// Op groups for precedence
REL_OP: REL_EQ | REL_NEQ | REL_GT | REL_LT
      | REL_GTE | REL_LTE  ;

// Relational ops
REL_EQ: '==' ;
REL_NEQ: '!=' ;
REL_GT: '>' ;
REL_LT: '<' ;
REL_GTE: '>=' ;
REL_LTE: '<=' ; 

IDENTIFIER
  : LETTER (LETTER | DIGIT)*
  ;

INT
  : SIGN? NONZERODIGIT DIGIT*
  | '0'
  ;

fragment
SIGN
  : [+-]
  ;

fragment
DIGIT
  :  [0-9]
  ;

fragment
NONZERODIGIT
  : [1-9]
  ;

fragment
LETTER
  : [a-zA-Z_]
  ;

COMMENT : '#' ~[\r\n]* -> skip;
WS  :  [ \t\r\n]+ -> channel(HIDDEN);

为排查问题编写了如下Python测试脚本,直接输出词法分析生成的token序列:

from antlr4 import InputStream, CommonTokenStream

import MLTL1Lexer
import MLTL1Parser

input="""
  i,j : bool;
  setvar: set<bool>;
  i > 5;
  j < 10;
"""

lexer = MLTL1Lexer.MLTL1Lexer(InputStream(input))
stream = CommonTokenStream(lexer)

stream.fill()
tokens = stream.getTokens(0,100)
for t in tokens:
  print(str(t.type) + " " + t.text)

parser = MLTL1Parser.MLTL1Parser(stream)
parse_tree = parser.start()
print(parse_tree.toStringTree(recog=parser))

测试发现>和<被分配了相同的token类型值,和二者为独立定义token的预期不符。

问题成因

这是ANTLR4词法规则的机制导致的:
ANTLR4中,只有标记为fragment的词法规则才能被其他词法规则引用。如果非fragment的词法规则引用了其他非fragment词法规则,ANTLR不会保留被引用规则的独立token类型,而是会把被引用规则的匹配逻辑直接内联到当前规则中,被引用的规则本身不会生成独立的token类型。

当前语法里把REL_OP定义为非fragment的词法规则,同时引用了REL_EQ/REL_LT/REL_GT等其他非fragment词法规则,最终所有比较运算符(</>/==等)都会被统一识别为REL_OP类型的token,单独定义的REL_LT/REL_GT等规则根本不会作为独立token存在。

这也是报错信息看起来矛盾的原因:解析set<bool>这段时,parser规则期望拿到类型为REL_LT、文本为<的token,但词法实际输出的是类型为REL_OP、文本为<的token,二者类型ID不匹配,哪怕文本完全一致,ANTLR也会判定匹配失败,抛出mismatched input '<' expecting '<'的错误。

修复方案

按照ANTLR的设计规范,词法规则只负责定义最细粒度的独立token,不同token的组合逻辑要放到语法规则层实现,修改步骤如下:

  1. 删除词法规则部分的REL_OP定义,保留REL_EQ/REL_NEQ/REL_GT/REL_LT/REL_GTE/REL_LTE这些独立的比较运算符词法规则不变
  2. 在语法规则部分新增rel_op规则,作为所有比较运算符的集合:
rel_op: REL_EQ | REL_NEQ | REL_GT | REL_LT | REL_GTE | REL_LTE;
  1. 把原有expr规则中引用的REL_OP替换为新定义的语法规则rel_op:
expr: expr rel_op expr
    | '(' expr ')'
    | IDENTIFIER 
    | INT
    ;

修改后重新生成词法、语法分析器,所有比较运算符会被识别为独立的token类型,set<bool>的泛型写法和表达式中的比较运算都可以正常匹配。


内容的提问来源于stack exchange,提问作者cgjohannsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 22:06:27