我试图为SQL的命令行客户端实现简单的自动完成。我使用antlr在应用程序的其余部分生成解析器,我想重用语法来使用自动完成。我的想法是:
- 在用户要求完成时解析不完整的语句(例如select a from
)
- 从解析器中获取他提出NoViableAltException
我想从这个令牌列表中做到: if(isreserved_word){建议完成} else {告知用户预期标识符}
这在原则上看起来是一个明智的想法(至少对我来说),我发现了这个: http://www.antlr.org/wiki/pages/viewpage.action?pageId=11567208让我确信这是可能的
然而,经过一些测试后,我意识到并没有多少令牌在state.following[state._fsp]
例如,对于create
的条目,它只包含';'
当我对这部分的语法看起来像:
root : statement? (SEMICOLON!)? EOF!;
statement : create | ...;
create : CREATE | ( TABLE table_create | USER user_create | ....);
所以我很困惑,看着生成的代码:
try {
int alt6=16;
alt6 = dfa6.predict(input);
switch (alt6) {
case 1 :
{
root_0 = (CommonTree)adaptor.nil();
pushFollow(FOLLOW_create_in_statement1088);
create8=create();
state._fsp--;
adaptor.addChild(root_0, create8.getTree());
}
break;
case 2 :
...
然后它对我有意义:解析器尝试读取下一个令牌,然后从此令牌中找到(切换案例)下一个规则。
在我的情况下,预测只是失败,因为没有下一个令牌。
所以从那里我明白我需要攻击一下antlr并查看模板并在Java.stg
我找到了这些代码片段:
/** A (...) subrule with multiple alternatives */
block(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
// <fileName>:<description>
int alt<decisionNumber>=<maxAlt>;
<decls>
<@predecision()>
<decision>
<@postdecision()>
<@prebranch()>
switch (alt<decisionNumber>) {
<alts:{a | <altSwitchCase(i,a)>}>
}
<@postbranch()>
>>
和
/** A case in a switch that jumps to an alternative given the alternative
* number. A DFA predicts the alternative and then a simple switch
* does the jump to the code that actually matches that alternative.
*/
altSwitchCase(altNum,alt) ::= <<
case <altNum> :
<@prealt()>
<alt>
break;<\n>
>>
从那里我认为我必须做的就是做自己的功能,只需在调用预测之前将所有altNum放入堆栈中。所以我尝试了: / * Yout}&gt; * /
我期待得到很好的令牌ID列表。但根本没有,我得到了不同的东西。
所以我真的迷失了,并且想知道是否有更简单的方法来提供这个自动完成功能而不必手动执行或者我如何修改模板以添加自定义堆栈来添加规则中的不同备选方案,因此我可以在引发异常后阅读它
非常感谢
答案 0 :(得分:1)
很抱歉这样说但是:不要直接使用解析器进行自动完成。如果没有在生成的解析器中进行大量的手动更改(这需要熟悉的知识),有几个原因导致它不能按预期工作:
您经常输入不完整,除非您只有一种简单的语言,否则由于解析器的回溯特性,您经常会发现自己处于意外的规则路径中。例如,如果规则中有几个alts,如果只有一个额外的令牌可用,则第一个alt将匹配,解析器将在尝试所有其他alts之前失败,然后给出完全不同的令牌或比实际需要更多的令牌
以下设置仅在错误情况下可用。但是,可能没有错误或存在错误,但处于与插入符当前位置完全不同的位置(以及用户期望自动完成框的位置)。
以下设置仅适用于您要呈现的一小组信息(即关键字)。但是,如果您在FROM子句中(假设此处使用SQL语言),通常您希望显示数据库中的可能表。您不会从解析器中获取此类信息,因为解析器没有此类上下文信息。你得到的是'标识符',它可以是表格,函数名称,变量或类似名称。
我目前针对此类问题的方法是将输入标记化并在决策树中应用领域知识。也就是说,我走输入令牌,并根据我从语法中获得的知识来决定最重要的东西。