3

我正在编写一种类似 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;
}

在此之后,但语法高亮仍然消失并且 antlr 停止解析matchedSymbolSELECT我怎样才能实现我的目标?

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

我复制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 ,但它不再起作用。

4

1 回答 1

0

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

无论如何,我不建议尝试在 Antlr 级别解决这个问题,因为您将不得不在 Xtext 工具中进行大量自定义。

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

  • 如果您想要更好的语法错误消息,您可以自定义它们。

  • 如果您的用例在输入时支持用户,则自定义自动编辑策略提供程序可能是正确的。

  • 如果您想支持用户修复现有查询中的错误,快速修复可能是一种方法(可以结合语法错误消息,参见上面的链接)。

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

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;
于 2016-11-15T13:45:02.240 回答