ANTLR 解析器为 "true and or false" 语句抛出异常

ANTLR parser to throw exception for "true and or false" statement

我使用的是 ANTLR 4,语法相当复杂。我试图在这里简化...

给定如下表达式:true and or false 我想要一个解析错误,因为定义的操作数在两边都期望表达式,并且它有一个 expr 操作数操作数 expr

我的简化语法是:

grammar MappingExpression;

/* The start rule; begin parsing here.
   operator precedence is implied by the ordering in this list */


// =======================
// = PARSER RULES
// =======================

expr:
 | op=(TRUE|FALSE)                               # boolean
 | expr op=AND expr                              # logand
 | expr op=OR expr                               # logor
 ;

TRUE : 'true';
FALSE : 'false';
WS : [ \t\r\n]+ -> skip;              // ignore whitespace
AND : 'and';
OR : 'or';

然而,似乎解析器在评估 true 后停止,即使它识别了所有四个标记(例如,返回的 alt state 在解析器中变为 2)。

如果我无法获得解析异常(因为它看到我认为操作数是表达式),如果我获得了整个解析树,我可以连续抛出两个操作数的运行时异常(例如,'and' 和 'or').

最初,我只有:

expr 'and' expr #logand
expr 'or' expr #logor

这遇到了同样的解析问题(提前停止)。

如果您通过使用内置 EOF

parse
 : expr EOF
 ;

这是我在解析输入时得到的 true and or false:

查看左下角错误:

line 1:9 extraneous input 'or' expecting {'true', 'false'}
line 1:17 missing {'true', 'false'} at '<EOF>'

Bart Kiers 上面的回答是正确的。我只是想为遇到解析不完整问题的 Java 工作人员提供更多详细信息。

我有一个相当复杂的 g4 文件,它将 expr 定义为一系列与标签关联的 OR'ed 规则(例如,在 # 之后成为 ExpressionsVisitor 中的方法名称)。虽然这似乎有效,但在某些情况下我预计会出现解析错误但收到 none。我也遇到过这样的情况,即只有解析器输入的一部分被解释,因此无法处理整个输入语句。

我修复g4文件如下(完整版为here):

// =======================
// = PARSER RULES
// =======================

expr_to_eof : expr EOF ;

expr:
   ID                                                     # id
 | '*'                                                    # field_values
 | DESCEND                                                # descendant
 | DOLLAR                                                 # context_ref
 | ROOT                                                   # root_path
 | ARR_OPEN exprOrSeqList? ARR_CLOSE                      # array_constructor
 | OBJ_OPEN fieldList? OBJ_CLOSE                          # object_constructor
 | expr '.' expr                                          # path
 | expr ARR_OPEN ARR_CLOSE                                # to_array
 | expr ARR_OPEN expr ARR_CLOSE                           # array
 | expr OBJ_OPEN fieldList? OBJ_CLOSE                     # object
 | VAR_ID (emptyValues | exprValues)                      # function_call
 | FUNCTIONID varList '{' exprList? '}'                   # function_decl
 | VAR_ID ASSIGN (expr | (FUNCTIONID varList '{' exprList? '}'))                   # var_assign
 | (FUNCTIONID varList '{' exprList? '}') exprValues                               # function_exec
 | op=(TRUE|FALSE)                                        # boolean
 | op='-' expr                                            # unary_op
 | expr op=('*'|'/'|'%') expr                             # muldiv_op
 | expr op=('+'|'-') expr                                 # addsub_op
 | expr op='&' expr                                       # concat_op
 | expr op=('<'|'<='|'>'|'>='|'!='|'=') expr              # comp_op
 | expr 'in' expr                                         # membership
 | expr 'and' expr                                        #logand
 | expr 'or' expr                                         # logor
 | expr '?' expr (':' expr)?                              # conditional
 | expr CHAIN expr                                        # fct_chain
 | '(' (expr (';' (expr)?)*)? ')'                         # parens
 | VAR_ID                                                 # var_recall
 | NUMBER                                                 # number
 | STRING                                                 # string
 | 'null'                                                 # null
 ;

根据 Bart 的建议,我为 expr_to_eof 添加了最高规则,导致该方法被添加到 MappingExpressionParser。因此,在我的表达式 class 中,在我调用 tree = parser.expr(); 之前,我现在需要调用 tree = parser.expr_to_eof();,这导致了一个包含 Token.EOF 的最后一个子节点的 ParseTree。 =16=]

因为我的代码需要检查执行的第一步和最后一步的一些条件,所以我最容易添加以下内容以删除 <EOF> 并取回 ParseTree(ExprContext 而不是 Expr_to_eofContext) 我一直在使用添加这条语句:

newTree = ((Expr_to_eofContext)tree).expr();

因此,总的来说,只需在 .g4 文件中添加新规则并更改解析器以便解析到结尾,就可以很容易地修复一个长期存在的错误(以及我推迟解决的其他错误) file() 然后提取整个被解析的表达式。

我希望这将使我能够向 JSONata4Java 添加更多的功能以匹配 JavaScript 版本 jsonata.js

再次感谢巴特!