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

ANTLR4输入不匹配及函数语法未识别问题求助

问题:ANTLR4解析g(1,x);时的词法与语法错误

原始问题场景

使用Java结合ANTLR4开发f1vae,定义的Expr语法规则如下:

grammar Expr;

// parser rules
prog : ((decl_list expr_seq | expr_seq) ';' NEWLINE?)*;

decl_list : decl (decl)*;

expr_seq : expr (expr)*;

decl : DEF fun var_list '=' expr ENDEF
     | DEF fun '=' expr ENDEF
     ;

var_list : param (param)*;

expr_list : expr (',' expr)*;

expr : LET var '=' expr IN expr             # assignExpr
     | fun '()'                         # callExpr
     | fun '(' expr_list ')'            # callExpr
     | expr ('*'|'/') expr              # infixExpr
     | expr ('+'|'-') expr              # infixExpr 
     | '(' expr ')'                     # parensExpr
     | num                              # numberExpr
     | '~' expr                         # negateExpr
     | var                              # varExpr
     ;

num  : '-'? INT
     | '-'? FLOAT
     ;

fun  : STR (('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') STR)*;

var  : STR (('_' | '-') STR)*;

param : STR ('_' STR)*;

// lexer rules                    
NEWLINE: [\r\n]+ ;
INT: [0-9]+ ;          // should handle negatives
FLOAT: [0-9]+'.'[0-9]* ; // should handle signs(+/-)
WS: [ \t\r\n]+ -> skip;
DEF: 'def';
ENDEF: 'endef';
LET: 'let';
IN: 'in';
STR: [a-zA-Z]+;

输入g(1,x);时触发错误:

line 1:2 mismatched input '1' expecting {'(', '-', '~', INT, FLOAT, 'let', STR}

解析树错误地将g识别为变量,而非函数名:

(prog (expr_seq (expr (var g)) (expr ( (expr 1 ,) x ))) ; 
)

错误原因分析

  1. 函数名规则定义缺陷:原fun规则要求标识符必须包含「数字+字母」的后缀(STR (数字 STR)*),但输入的g是单纯字母组成的标识符,无法匹配fun规则,只能被识别为var,导致g(无法被解析为函数调用。
  2. 标识符规则重叠与解析优先级问题:fun和var规则均能匹配单纯字母标识符,ANTLR解析器因上下文预测不足,优先将g识别为变量,后续的(被当作独立的括号表达式起始;而括号表达式仅允许单个expr,1,x中的逗号不符合规则,触发语法错误。
  3. 数字词法规则未处理正负号:原num规则中的'-'?属于parser规则,词法分析时会将-1拆分为'-'和INT两个token,而非完整的负数。

解决方案:修改后的语法规则

grammar Expr;

// parser rules
prog : ((decl_list expr_seq | expr_seq) ';' NEWLINE?)*;

decl_list : decl+;

expr_seq : expr+;

decl : DEF ID var_list '=' expr ENDEF
     | DEF ID '=' expr ENDEF
     ;

var_list : param+;

expr_list : expr (',' expr)*;

expr : LET ID '=' expr IN expr             # assignExpr
     | ID '()'                             # callExpr
     | ID '(' expr_list ')'                # callExpr
     | expr ('*'|'/') expr                 # infixExpr
     | expr ('+'|'-') expr                 # infixExpr 
     | '(' expr ')'                        # parensExpr
     | num                                 # numberExpr
     | '~' expr                            # negateExpr
     | ID                                  # varExpr
     ;

num  : INT
     | FLOAT
     ;

param : ID;

// lexer rules                    
NEWLINE: [\r\n]+ ;
INT: '-'? [0-9]+ ;          
FLOAT: '-'? [0-9]+ '.' [0-9]* ; 
WS: [ \t\r\n]+ -> skip;
DEF: 'def';
ENDEF: 'endef';
LET: 'let';
IN: 'in';
ID: [a-zA-Z]+ ( [a-zA-Z0-9_'-]+ )*;

关键修改说明

  • 统一标识符规则:用ID词法规则替代原fun、var、param的parser规则,ID支持字母开头,后续可跟字母、数字、下划线、连字符,覆盖原函数名和变量名的所有需求。
  • 确保解析优先级:callExpr分支仍位于varExpr之前,解析器遇到ID后跟(时,会优先匹配函数调用,而非将ID单独识别为变量。
  • 修复数字词法规则:将正负号整合到INT和FLOAT的词法规则中,确保负数被识别为单个数字token。
  • 简化重复规则:将decl (decl)*改为decl+,expr (expr)*改为expr+,语义一致但语法更简洁。

修改后,输入g(1,x);会被正确解析为函数调用,解析树如下:

(prog 
  (expr_seq 
    (expr (callExpr g ( (expr_list (expr (numberExpr 1)) , (expr (varExpr x))) )) 
  ) ; 
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:35:56