微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ANTLR4 中的贪婪子规则

如何解决ANTLR4 中的贪婪子规则

我正在研究一种解析器语法,它应该允许尾随表达式而不包含符号。以下是证明该问题的简化版本:

grammar Example;

root: expression EOF;

expression: binaryExpression;

binaryExpression
    : binaryExpression 'and' binaryExpression
    | binaryExpression 'or' binaryExpression
    | quantifier
    | '(' expression ')'
    | OPERAND
;

quantifier
    : 'no' ID 'in' ID 'satisfies' expression
;

OPERAND: 'true' | 'false';
ID: [a-z]+;
WS: (' ' | '\r' | '\t')+ -> channel(HIDDEN);

如果您尝试解析以下表达式,您会注意到,虽然解析正确识别输入,但它报告了歧义:

true or false and no x in y satisfies true or false

Ambiguity

错误报告按预期工作(稍后会详细介绍):

Error recovery

line 1:1 token recognition error at: '1'
line 1:2 mismatched input '<EOF>' expecting {'(','no',OPERAND}

我正在寻找某种方法来明确告诉解析器 quantifier 应该是贪婪的:右侧的所有内容都应该明确地消耗,直到表达式结束。

我尝试重构规则以仅允许在二进制表达式的 RHS 上使用 quantifier。虽然它有效,但错误恢复机制变得无法识别大多数表达式:

grammar Example;

root: expression EOF;

expression: quantifier | booleanExpression;

quantifier
    : 'no' ID 'in' ID 'satisfies' expression
;

booleanExpression
    : orExpression ('or' (quantifier | andQuantifier))?
    | andQuantifier
;

andQuantifier: andExpression 'and' quantifier;

orExpression
    : orExpression 'or' orExpression
    | andExpression
;

andExpression
    : andExpression 'and' andExpression
    | '(' expression ')'
    | OPERAND
;

OPERAND: 'true' | 'false';
ID: [a-z]+;
WS: (' ' | '\r' | '\t')+ -> channel(HIDDEN);

如您所见,问题消失了:

Unambiguous parse tree

但它的代价是语法更加复杂,并且无法识别错误输入,例如 (1

Error recovery

line 1:1 token recognition error at: '1'
line 1:2 no viable alternative at input '('

还有其他人对如何修复它有任何其他想法吗?

解决方法

这是我的做法,使用 Antlr4 的内置算法优先解决歧义(因为语法肯定是歧义的)。为了使优先算法起作用,将限定符视为具有低优先级的一元运算符很有用,这就是为什么下面的 quantifier 只是“运算符”而不是完整表达式的原因。大概在真正的语法中,您会有其他量词,并且很可能有更高优先级的一元运算符,例如 not

grammar Example;

root: expression EOF;

expression
    : expression 'and' expression
    | expression 'or' expression
    | quantifier expression
    | operand
    | '(' expression ')'
;

quantifier
    : 'no' ID 'in' ID 'satisfies'
;

operand: BOOLEAN | ID;

BOOLEAN: 'true' | 'false';
ID: [a-zA-Z]+;
WHITE_SPACE: (' ' | '\r' | '\n' | '\t')+ -> channel(HIDDEN);

这与您帖子中的示例不太一样,因为您修改了问题的第一个版本中的一些小细节。但我认为这是指示性的。

出于显而易见的原因,我无法尝试使用 (1(我认为输入对应于另一个版本,其中整数是操作数),但是使用 (true 时它给了我看起来像的错误您正在寻找的报告。我不是真正的 ANTLR4 专家,所以我不知道如何预测错误恢复的细节。

,

好的,经过多次来回,我想我终于明白您要寻找的是关联性。试试:

grammar Example;

root: expression EOF;

expression
    : '(' expression ')'                            # parenExpr
    | <assoc=right>expression (AND | OR) quantifier # quantifierExpr
    | expression AND expression                     # andExpr
    | expression OR expression                      # orExpr
    | OPERAND                                       # operandExpr
;

quantifier
    :  'no' ID 'in' ID 'satisfies' expression
;

AND: 'and';
OR: 'or';
OPERAND: 'true' | 'false';
ID: [a-z]+;
WS: (' ' | '\r' | '\t')+ -> channel(HIDDEN);

(我冒昧地为您的备选方案添加标签并简化表达式规则。)。标签将在您的代码中非常方便,因为您需要单独处理每个选项。标签将为您提供单独的功能以在您的听众/访问者中覆盖(以及特定于该替代方案的 Context 类)

true and false or false and no x in y satisfies true or false 

enter image description here

true and false or false or no x in y satisfies true or false

enter image description here

true and false or false and no x in y satisfies true or false

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。