ANTLR4 语法 - 字段和扩展表达式中的“点”问题

问题描述

我有以下 ANTLR4 语法

grammar ExpressionGrammar;

parse: (expr)
     ;

expr: MIN expr
    | expr ( MUL | DIV ) expr
    | expr ( ADD | MIN ) expr
    | NUM
    | function
    | '(' expr ')'
    ;

function : ID '(' arguments? ')';

arguments: expr ( ',' expr)*;

/* Tokens */

MUL : '*';
DIV : '/';
MIN : '-';
ADD : '+';
OPEN_PAR : '(' ;
CLOSE_PAR : ')' ;

NUM : '0' | [1-9][0-9]*;
ID : [a-zA-Z_] [a-zA-Z]*;
COMMENT: '//' ~[\r\n]* -> skip;
WS: [ \t\n]+ -> skip;

我有一个这样的输入表达式:-

(Fields.V1)*(Fields.V2) + (Constants.Value1)*(Constants.Value2)

ANTLR 解析器根据上述语法生成以下文本:-

(FieldsV1)*(FieldsV2)+(Constants<missing ')'> 

如您所见,文本中缺少 Fields.V1 和 Fields.V2 中的“点”,并且还有一个

除此之外的一个问题:-

 (Var1)(Var2)    

ANTLR 没有在上面的场景中抛出错误,表达式不应该是 (Var1)(Var2)——它应该总是有运算符 (var1)*(var2) 或 (var1)+(var2) 等。解析器错误树未生成错误。应该如何修改语法以确保甚至考虑到这种情况。

解决方法

要识别 ID 之类的 Fields.V1,请将 ID 的 Lexer 规则更改为如下所示:

fragment ID_NODE: [a-zA-Z_][a-zA-Z0-9]*;
ID: ID_NODE ('.' ID_NODE)*;

请注意,由于 ID 的每个“节点”都遵循相同的规则,因此我将其制作为一个词法分析器片段,可用于组成 ID 规则。我还在片段的第二部分添加了 0-9,因为您似乎希望在 IDs

中允许数字

然后 ID 规则使用片段来构建允许 ID 中的点的词法分析器规则。

您也没有将 ID 添加为有效的 expr 替代项

要处理 (Var1)(Var2) 中错误条件的检测,您需要 Mike 的建议,将 EOF Lexer 规则添加到 parse 解析器规则的末尾。如果没有 EOF,ANTLR 将在到达可识别 expr ((Var1)) 的末尾时立即停止解析。 EOF 表示“然后您需要找到一个 EOF”,因此 ANTLR 将继续解析为 (Var2) 并给出错误。

处理您的两个示例的修订版:

grammar ExpressionGrammar;

parse: expr EOF;

expr:
    MIN expr
    | expr ( MUL | DIV) expr
    | expr ( ADD | MIN) expr
    | NUM
    | ID
    | function
    | '(' expr ')';

function: ID '(' arguments? ')';

arguments: expr ( ',' expr)*;

/* Tokens */

MUL: '*';
DIV: '/';
MIN: '-';
ADD: '+';
OPEN_PAR: '(';
CLOSE_PAR: ')';

NUM: '0' | [1-9][0-9]*;
fragment ID_NODE: [a-zA-Z_][a-zA-Z0-9]*;
ID: ID_NODE ('.' ID_NODE)*;
COMMENT: '//' ~[\r\n]* -> skip;
WS: [ \t\n]+ -> skip;

(现在我已经阅读了评论,这几乎只是应用了评论中的建议)