如何在ANTLR4中实现错误处理

10

我需要翻译的内容是:我有以下语法来解析应用于图形上的一阶逻辑公式:


grammar Graph;


/*------------------------------------------------------------------
* PARSER RULES
*------------------------------------------------------------------*/

input
: 
formula EOF
;

formula
:
TRUE 
| FALSE 
| formula AND formula
| formula OR formula
| quantifier formula
| ST condition
;


condition
:
atom EQUALS QUOTE? (assignment | atom) QUOTE?
;

quantifier 
:
(FOREACH | EXISTS) variable IN domain
;

domain
:
(GRAPH_A | GRAPH_B)
;

atom
:
variable DOT property
;


variable
:   
(nodev | edgev)
;


nodev
:
(NODE | NODE1)
;

edgev
:
(EDGE | EDGE1)
;

property
:
(COLOR | VALUE)
;

assignment
:
(COLORTYPE | NUMBER)
;


/*------------------------------------------------------------------
* LEXER RULES
*------------------------------------------------------------------*/

TRUE : 'True' ;

FALSE : 'False' ;

AND : '&' ;

OR : '|' ;

ST : '->' ; 

EXISTS  : 'Exists' ;

FOREACH : 'Foreach' ;

NODE : 'node' ;

NODE1 : 'node1' ;

EDGE : 'edge' ;

EDGE1 : 'edge1' ;

IN : 'in' ;

GRAPH_A : 'GraphA' ;

GRAPH_B : 'GraphB' ;

EQUALS : '=' ;

DOT : '.' ;

COLOR : 'color' ;

VALUE : 'value' ;

NUMBER : ('0'..'9')+ (DOT ('0'..'9')+)? ;

QUOTE : '\'' ;

COLORTYPE : ('a'..'z')+ ;

WS : [ \t\r\n]+ -> skip ;

我相信这是我的语法的最终版本,现在我想为输入指定一些错误处理。问题是我不知道如何处理。我知道的是,在解析输入后,我可以遍历生成的AST,并在此处添加错误处理。
如果解析失败,则返回解析异常;否则,我已经指定了以下返回错误消息的情况。
  1. 不能有一个量词后跟->条件(这是一个公式元素),其中条件等于原子=原子。换句话说,如果只有量词,那么条件应该等于原子EQUALS赋值
  2. 如果有2个量词,则第一个应以FOREACH开始。
  3. 量词中的变量应在条件语句中使用
  4. 表达式左侧不能有超过两个量词(因为在我正在开发的应用程序中只有两个图)。因此,如果量词数大于2,则也会返回错误
  5. 如果有2个量词,则它们应该具有不同的绑定变量
例如,当我们有以下输入时,第一种情况应该被引发:
Exists node in GraphA -> node.color = node1.color 

因为表达式的左侧没有指定node1

第二种情况的示例输入如下:

Exists node in GraphA Exists node1 in GraphB -> node.color = node1.color

我的问题是:我是否需要在生成的解析树上实现所有的错误检查,或者我可以使用一些Java代码在语法中指定其中一些。如果错误处理应该发生在输入被解析之后,那么我可以使用ANTLR 4的哪些功能来实现错误情况?任何帮助或建议都将不胜感激!

我认为visitor类能够解决我的问题。当我遍历解析树时,我会将我感兴趣的元素添加到数据结构中(可能是HashMap或其他东西),然后应用所需的逻辑。我是否朝着正确的方向前进,还是缺少ANTLR的一些基本知识? - Wosh
1个回答

8

您可能需要在监听器中实现这些语义检查,与辅助访问者结合使用。以下是一些示例。

规则:量词中的变量应在条件中使用

实现:

  1. 创建一个访问者,返回指定解析树节点使用的变量。您需要覆盖 defaultResult()aggregateResult(T, T) 来完成大部分工作,然后覆盖 visitNodevvisitEdgev 处理使用的特定变量。
  2. 在监听器中,覆盖 enterFormula 方法。在此方法中,如果 ctx.quantifier() 不为 null,则使用您的访问者获取在 ctx.quantifier() 中声明的变量列表和在 ctx.formula() 中使用的变量列表。
  3. 根据两个结果适当地报告错误。

规则:如果有 2 个量词,则它们应该绑定不同的变量

实现:

  1. 使用上一条规则实现中描述的访问者。
  2. 在监听器中,覆盖 enterFormula 方法。在此方法中,如果 ctx.quantifier() 不为 null,则需要获取由 ctx.formula() 返回的树下所有其他 QuantifierContext 实例的集合。您可以通过调用 XPath.findAll(ctx.formula(), "//quantifier", parser) 来实现此目的。
  3. 使用上述访问者收集每个链接的 QuantifierContext 实例中声明的变量列表。如果任何集合重叠,则适当报告错误。

规则:如果有 2 个量词,则第一个应以 FOREACH 开头

实现:

使用上一步中描述的监听器模式来定位包含多个 quantifier 的公式。如果这些公式中的第一个没有 ctx.quantifier().FOREACH() == null,则适当发出错误。

规则:不能有超过两个量词...

实现:

更新上述第二个规则的实现,如果在量词的公式中XPath.findAll返回多个QuantifierContext,则报告错误。

规则:量词条件限制

实现:

首先,创建一个ParseTreePattern对象。

String patternString = "<quantifier> -> <condition>";
ParseTreePattern pattern =
    parser.compileParseTreePattern(patternString, GraphParser.RULE_formula);

然后在解析树中查找所有此模式的实例。
List<ParseTreeMatch> matches = pattern.findAll(tree, "//formula");

验证匹配结果非常简单。
for (ParseTreeMatch match : matches) {
  ConditionContext condition = (ConditionContext)match.get("condition");
  if (condition.assignment() == null) {
    // TODO: report error here
  }
}

很好的回答。你能否解释一下如何正确使用XPath?在enterFormula()中,我做的是Collection<ParseTree> q = XPath.findAll(ctx,"//quantifer",parser);,其中ctx的类型为FormulaContext,但每次都会出现NullPointerException。你有任何想法为什么会发生这种情况吗? - Wosh
你的意思是 quantifier,而不是 quantifer。你应该在 GitHub 上创建一个问题,这样我们就可以为下一个版本修复这个行为(并提供更好的错误消息):https://github.com/antlr/antlr4/issues - Sam Harwell
有没有其他方法可以查询FormulaContext以得到Quantifier元素的计数? - Wosh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接