【问题标题】:ANTLR4 Grammar - Issue with "dot" in fields and extended expressionsANTLR4 语法 - 字段和扩展表达式中的“点”问题
【发布时间】:2021-02-02 07:39:00
【问题描述】:

我有以下 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) 等。解析器错误树不会生成此错误。应如何修改语法以确保考虑到这种情况。

【问题讨论】:

  • 首先将EOF 添加到您的parse 规则中(并删除不必要的括号)。
  • 我不确定您期望发生什么:我在您的词法分析器中没有看到任何与 . 匹配的规则...
  • @BartKiers 没错。我想知道我应该在哪里添加该匹配。因为我的解析器实际上不应该拆分“点”。整体应该是“Fields.V1”
  • @MikeLischke EOF - 你指的是第一个解析: (expr) 吗?你想让我把它改成 expr EOF 吗?
  • "它应该是一个整体 "Fields.V1"" 然后您应该编辑您的 ID 规则,使其也包含 .。但我很困惑:这是你自己的语法,还是你在某个地方找到的?我的印象是你在没有真正了解 ANTLR 的情况下盲目地尝试事情。也许退后一步,从基本的 ANTLR 教程开始?

标签: antlr antlr4


【解决方案1】:

要像 Fields.V1 一样识别 IDs,请将 ID 的 Lexer 规则更改为如下内容:

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

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

然后ID 规则使用片段来构建允许ID 中的点的 Lexer 规则。

您也没有将 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;

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

【讨论】:

    猜你喜欢
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 2016-12-02
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多