我有以下语法来解析应用于图的一阶逻辑公式:
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 : [ trn]+ -> skip ;
我相信这是我语法的最终版本,所以现在我想为输入指定一些错误处理。问题是我不知道怎么做。我所知道的是,在解析输入后,我可以迭代生成的 AST,这是添加错误处理的地方。
如果解析失败,则返回解析异常;否则,我指定了以下返回错误消息的情况。
不能有 1 个量词后跟
-> condition
(这是一个公式元素),其中条件等于atom=atom
。换句话说,如果只有quantifier
那么condition
应该等于atom EQUALS assignment
。如果有 2 个量词,第一个量词应以
FOREACH
开头量词中的变量应在
condition
语句中使用表达式左侧的量词不能超过两个(因为在我正在开发的应用程序中,只有两个图形)。因此,如果量词的数量大于两个返回误差
如果有 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的哪些功能来实现错误情况?任何帮助或建议将不胜感激!
你可能希望在侦听器中与帮助程序访问者结合使用实现这些语义检查。以下是一些示例。
规则:quantifier
中的变量应在condition
中使用
实现:
- 创建一个返回指定分析树节点使用的变量的访问者。您需要覆盖
defaultResult()
和aggregateResult(T, T)
以为您完成大部分工作,然后覆盖visitNodev
和visitEdgev
以处理正在使用的特定变量。 - 在侦听器中,重写
enterFormula
方法。在此方法中,如果ctx.quantifier()
不为 null,则使用访问者获取在ctx.quantifier()
中声明的变量列表和ctx.formula()
中使用的变量列表。 - 根据这两个结果报告错误。
规则:如果有 2 个量词,那么它们应该绑定不同的变量
实现:
- 从上一个规则实现的步骤 1 中描述的访问者开始。
- 在侦听器中,重写
enterFormula
方法。在该方法中,如果ctx.quantifier()
不为 null,则需要获取ctx.formula()
返回的树下的所有其他QuantifierContext
实例的集合。您可以通过调用XPath.findAll(ctx.formula(), "//quantifier", parser)
来执行此操作。 - 使用上述访问者收集在每个链接的
QuantifierContext
实例中声明的变量列表。如果任何集合重叠,请根据需要报告错误。
规则:如果有 2 个量词,第一个量词应以FOREACH
开头
实现:
使用上一步中描述的侦听器模式查找公式包含多个quantifier
的情况。如果这些公式中的第一个ctx.quantifier().FOREACH() == null
则根据需要发出错误。
规则:不能有两个以上的量词...
实现:
更新上述第二条规则的实现,以便在quantifier
formula
中返回多个QuantifierContext
时XPath.findAll
报告错误。
规则:量词条件限制
实现:
首先,创建一个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
}
}