首页 > 解决方案 > ANTLR4 错误后正确继续解析部分

问题描述

我正在尝试为 SQL-esk 查询语言编写一些工具(验证/可能是自动完成)。但是,解析器以一种使其更难以使用的方式对无效/不完整的输入进行标记。

我已经将我的场景简化为最简单的可重现形式。这是我最小化的语法:

grammar SOQL;

WHITE_SPACE : ( ' '|'\r'|'\t'|'\n' ) -> channel(HIDDEN) ;

FROM    : 'FROM' ;
SELECT  : 'SELECT' ;

/********** SYMBOLS **********/


COMMA       : ',' ;

ID: ( 'A'..'Z' | 'a'..'z' | '_' | '$') ( 'A'..'Z' | 'a'..'z' | '_' | '$' | '0'..'9' )* ;

soql_query:    select_clause from_clause;
select_clause: SELECT field ( COMMA field )*;
from_clause:   FROM table;

field : ID;
table : ID;

当我运行以下代码时(使用antlr4ts,但它应该类似于任何其他端口):

const input = 'SELECT ID, Name, Website, Contact, FROM Account'; //invalid trailing ,
let inputStream = new ANTLRInputStream(input);
let lexer = new SOQLLexer(inputStream);
let tokenStream = new CommonTokenStream(lexer);
let parser = new SOQLParser(tokenStream);

let qry = parser.soql_query();
let select = qry.select_clause();
console.log('FIELDS: ', select.field().map(field => field.text));
console.log('FROM: ', qry.from_clause().text);

控制台日志

line 1:35 extraneous input 'FROM' expecting ID
line 1:47 mismatched input '<EOF>' expecting 'FROM'
FIELDS: Array(5) ["ID", "Name", "Website", "Contact", "FROMAccount"]
FROM:  

我收到错误(这是意料之中的),但我希望它仍然能够正确挑选出该FROM子句。

这是我的理解,因为它FROM是一个标识符,它不是一个有效的字段select_clause(也许我只是误解)?

是否有某种方法可以设置语法或解析器,以便在这种情况下继续正确识别FROM子句(以及其他常见的 WIP 查询状态)。

标签: grammarantlr4

解决方案


这是我的理解,因为 FROM 是一个标识符,它不是 select_clause 中的有效字段(也许我只是误解)?

解析器看到的只是来自词法分析器的类型化标记的离散流。解析器没有内在的方法来判断令牌是否旨在成为标识符,或者就此而言,具有任何特定的语义性质。

在设计容错语法时,将解析器计划为对语法错误相当宽容,并期望使用多个 tree-walker 来逐步识别并在可能的情况下解决语法和语义歧义。

为此特别有用的两个 ANTLR 功能包括:

1) 实现词法分析器 TokenFactory 和自定义令牌,通常扩展 CommonToken。自定义标记为标志和逻辑提供了一个方便的空间,用于识别特定标记实例的正确句法/语义使用和预期上下文。

2) 实现解析器错误策略,扩展或扩展DefaultErrorStrategy。当尝试匹配导致识别错误时,错误策略将允许对令牌流上的解析器操作进行适度修改。如果在检查周围(自定义)令牌时无法完全解决并适当修复错误,则至少可以适当地注释那些相同的自定义令牌以在随后的树遍历期间轻松解决问题。


推荐阅读