xtext如何容忍解析错误?

时间:2013-09-14 04:00:50

标签: antlr xtext

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

USE foo;
SELECT * FROM bar;

但我输入

US foo;
SELECT * FROM bar;

默认行为是Antlr将停止解析,我丢失了语法高亮和大纲视图。 错误消息为Missing EOF at 'US'。我将IParser重新绑定到RuntimeModule中的自定义解析器

@Override
public Class<? extends org.eclipse.xtext.parser.IParser> bindIParser() {
    return CustomCqlParser.class;
}

覆盖createParser

中的Parser方法
@Override
protected InternalCqlParser createParser(XtextTokenStream stream) {
    return new CustomInternalCqlParser(stream, getGrammarAccess());
}

并覆盖方法句柄此部分recoverFromMismatchedToken以使用所有标记直到分号

@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;
}
在此matchedSymbolSELECT之后

,但语法高亮显示仍然消失,并且antlr停止解析。我怎样才能实现目标?

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

我将super.recoverFromMismatchToken复制到我的自定义类,并从原始源代码中添加它。

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;
}

如果令牌错误不是在开始时发生而不是no viable alternative异常,那么这将保持语法突出显示。但它仍然会认为它仍然使用相同的解析规则,而不是开始一个新的规则。此外,如果我在开头输入了错误的标记,那么预期的标记将是EOF。这将使我“消耗所有代币直到分号”也失败了。

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

跟踪InternalCqlParser.java,我发现错误发生在第一个关键字语句中,它会得到一个ID并返回。我在那之后添加了一个代码片段

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

解析确实继续,语法突出显示在错误语句后仍然存在。但是,错误行没有任何错误标记,我在该行之后丢失了内容辅助。触发内容辅助的类是Statement,但它将不再起作用。

1 个答案:

答案 0 :(得分:0)

一般情况下,基于词法分析器的解析器(如Antlr / Xtext生成的解析器)不能很好地支持您所要求的内容,因为词法分析器必须决定生成哪个令牌而不了解令牌可能匹配的解析器规则。

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

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

  • 如果您想要更好的语法错误消息,可以customize

  • 如果您的用例在输入时支持用户,则自定义Auto Edit Strategy Provider可能是正确的。

  • 如果您想支持现有查询中的用户修复错误,Quick Fixes可能是要走的路(可以与语法错误消息结合使用,参见上面的链接)。

只有当这些都不是一个选项,并且你真的想允许这种错误的语法时,你应该尝试在语法级别修复它。 我想你正在谈论Cassandra的CQL的语法,我想有不止一种语句(例如选择,插入等),所以涉及被解释为关键字的标识符的黑客不具备资格由于语法模糊(除了他们的丑陋;-))。 所以我想你必须列出你愿意接受的所有单词作为替代。 在这种情况下,我建议为每个关键字的错误变体创建Data Type Rule,为标识符创建另一个数据类型规则,包括错误的变体,因为我猜你不想禁止&# 34; US&#34;作为标识符。 E.g:

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;