Antlr xtext如何容忍解析错误?

Antlr xtext如何容忍解析错误?,antlr,xtext,Antlr,Xtext,我正在编写一种类似SQL的语言。假设正确的语法是 USE foo; SELECT * FROM bar; 但是我把它打到 US foo; SELECT * FROM bar; 默认行为是Antlr将停止解析,并且我丢失了语法高亮显示和大纲视图。 错误消息是“US”处缺少EOF。我将IParser重新绑定到RuntimeModule中的自定义解析器 @Override public Class<? extends org.eclipse.xtext.parser.IParser>

我正在编写一种类似SQL的语言。假设正确的语法是

USE foo;
SELECT * FROM bar;
但是我把它打到

US foo;
SELECT * FROM bar;
默认行为是Antlr将停止解析,并且我丢失了语法高亮显示和大纲视图。 错误消息是“US”处缺少EOF。我将IParser重新绑定到RuntimeModule中的自定义解析器

@Override
public Class<? extends org.eclipse.xtext.parser.IParser> bindIParser() {
    return CustomCqlParser.class;
}
并重写方法handle this part
recoverfrommatchedtoken
以使用所有令牌直到分号

@Override
protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) throws RecognitionException {
    Object out = super.recoverFromMismatchedToken(input, ttype, follow);

    if (out == null) {

        beginResync();
        consumeUntil(input, RULE_T_SEMICOLON);
        input.consume();
        endResync();

        Object matchedSymbol = getCurrentInputSymbol(input);
        System.out.println(matchedSymbol);
        return matchedSymbol;
    }
    return out;
}
在此之后,
matchedSymbol
SELECT
,但语法突出显示仍然消失,antlr停止解析。我怎样才能实现我的目标

================编辑==================================

我将
super.recoverfrommaschtoken
复制到我的自定义类中,并将其添加到原始源代码中

if (ttype != EOF) {
    beginResync();
    consumeUntil(input, RULE_T_SEMICOLON);
    input.consume();
    endResync();

    Object matchedSymbol = getCurrentInputSymbol(input);
    input.consume(); // move past ttype token as if all were ok
    return matchedSymbol;
}
如果令牌错误不是在开始时发生,也不是
无可行的替代
异常,这将保持语法高亮显示。但是它仍然认为它仍然使用相同的解析规则,而不是开始一个新的规则。此外,如果我在开始时输入了错误的令牌,那么预期的令牌将是
EOF
。这将使我的“使用所有令牌直到分号”也失败

==================================编辑========================================

跟踪
InternalCqlParser.java
,我发现如果输入错误发生在语句的第一个关键字中,它将获得一个
ID
并返回。我在这之后添加了一个代码片段

if (LA1_0 == RULE_IDENT) {
    beginResync();
    consumeUntil(input, RULE_T_SEMICOLON);
    input.consume();
    endResync();
    continue;
}

解析将继续,并且语法高亮显示将保留在错误语句之后。但是,错误行没有任何错误标记,并且在该行之后我丢失了内容辅助功能。触发内容辅助的类是
语句
,但它将不再工作。

基于lexer的解析器(如Antlr/Xtext生成的解析器)通常不支持您所请求的内容,因为lexer必须在不知道令牌可能匹配的解析器规则的情况下决定生成哪个令牌

在任何情况下,我都不建议尝试在Antlr级别解决这个问题,因为您必须在Xtext工具中进行大量定制

如果可能的话,我建议考虑一些根本不涉及语法的替代解决方案:

  • 如果您想要更好的语法错误消息,可以使用它们

  • 如果您的用例在输入时支持用户,那么定制可能是正确的

  • 如果您想支持用户修复现有查询中的错误,可以这样做(可以与语法错误消息结合使用,参见上面的链接)

只有当这两个选项都不是选项,并且您确实希望允许这种类型错误的语法时,才应该尝试在语法级别修复它。
当我假设您正在谈论Cassandra的CQL语法时,我猜有不止一种类型的语句(例如select、insert等),因此涉及解释为关键字的标识符的黑客由于语法歧义(除了它们的丑陋;-)而不合格。 所以我想你必须列出所有你愿意接受的词语作为替代。 在这种情况下,我建议为每个关键字的错误类型变体创建一个数据类型规则,并为标识符(包括错误类型变体)创建另一个数据类型规则,因为我想您不想禁止将“US”作为标识符。 例如:


我想你说的是Cassandra CQL——你是想让解析器真正接受像“US mykeyspace;”这样的语句作为有效的USE语句,还是只是想改进错误消息,使其不涉及EOF,并希望最终拒绝该语句?嗨,我不再从事这个项目了。当时,我想保持语法高亮显示和其他IDE功能可用,但在错误的语句下有一个错误标记。在最初的情况下,如果我输入了单个字符,由于解析失败,整个文本编辑区域将变为灰色。
if (LA1_0 == RULE_IDENT) {
    beginResync();
    consumeUntil(input, RULE_T_SEMICOLON);
    input.consume();
    endResync();
    continue;
}
Use:
  ('USE' | MistypedUseKeyword) keyspaceName=Identifier ';';

CreateTable: 

MistypedUseKeyword:
  'US' | 'USW' | 'USEE';

MistypedCreateKeyword:
  'CREAT' | 'CREATW' | 'CERATE' | 'CRATE';

MistypedTableKeyword:
  'TABL' | 'TALBE' | 'TBLE' | 'TBALE' | 'TABEL';

MistypedKeyword:
  MistypedUseKeyword | MistypedCreateKeyword | MistypedTableKeyword;

Identifier:
  ID | MistypedKeyword;