ANTLR4 错误后正确继续解析部分
ANTLR4 Correctly continuing to parse sections after error
我正在尝试为 SQL-esk 查询语言编写一些工具(validation/possibly 自动完成)。但是,解析器正在以一种使其更难处理的方式标记 invalid/incomplete 输入。
我已将场景简化为最简单的可重现形式。这是我最小化的语法:
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
中的有效字段(也许我只是误会了)?
是否有某种方法可以设置语法或解析器,以便在这种情况下(以及其他常见的 WIP 查询状态)继续正确识别 FROM
子句。
It was my understanding since FROM is a identifier, it's not a valid
field in the select_clause (maybe I'm just misunderstanding)?
解析器看到的只是来自词法分析器的离散类型标记流。解析器没有内在的方式来判断一个标记是否打算成为一个标识符,或者就此而言,是否具有任何特定的语义性质。
在设计容错语法时,计划解析器对语法错误相当宽容,并期望使用多个树遍历器来逐步识别并在可能的情况下解决语法和语义歧义。
为此目的特别有用的两个 ANTLR 功能包括:
1) 实现词法分析器 TokenFactory 和自定义令牌,通常扩展 CommonToken。自定义令牌提供了方便的 space 标志和逻辑,用于识别特定令牌实例的正确 syntactic/semantic 使用和预期上下文。
2) 实施解析器错误策略,扩展或扩展 DefaultErrorStrategy。当尝试匹配导致识别错误时,错误策略将允许对令牌流上的解析器操作进行适度修改。如果在检查周围的(自定义)标记时无法完全解决和适当修复错误,至少可以适当地注释那些相同的自定义标记,以便在随后的树遍历过程中轻松解决问题。
我正在尝试为 SQL-esk 查询语言编写一些工具(validation/possibly 自动完成)。但是,解析器正在以一种使其更难处理的方式标记 invalid/incomplete 输入。
我已将场景简化为最简单的可重现形式。这是我最小化的语法:
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
中的有效字段(也许我只是误会了)?
是否有某种方法可以设置语法或解析器,以便在这种情况下(以及其他常见的 WIP 查询状态)继续正确识别 FROM
子句。
It was my understanding since FROM is a identifier, it's not a valid field in the select_clause (maybe I'm just misunderstanding)?
解析器看到的只是来自词法分析器的离散类型标记流。解析器没有内在的方式来判断一个标记是否打算成为一个标识符,或者就此而言,是否具有任何特定的语义性质。
在设计容错语法时,计划解析器对语法错误相当宽容,并期望使用多个树遍历器来逐步识别并在可能的情况下解决语法和语义歧义。
为此目的特别有用的两个 ANTLR 功能包括:
1) 实现词法分析器 TokenFactory 和自定义令牌,通常扩展 CommonToken。自定义令牌提供了方便的 space 标志和逻辑,用于识别特定令牌实例的正确 syntactic/semantic 使用和预期上下文。
2) 实施解析器错误策略,扩展或扩展 DefaultErrorStrategy。当尝试匹配导致识别错误时,错误策略将允许对令牌流上的解析器操作进行适度修改。如果在检查周围的(自定义)标记时无法完全解决和适当修复错误,至少可以适当地注释那些相同的自定义标记,以便在随后的树遍历过程中轻松解决问题。