[antlr-interest] What to expect next

Jan van der Ven jhvdven at xs4all.nl
Wed Feb 27 11:16:48 PST 2008


Dear list,



I am a contributor to an eclipse plugin 
(http://sourceforge.net/projects/quantum). I am responsible for the SQL 
Editor and want to increase user experience by offering content assist. 
We use antlr 2.7.x to check valid syntax. That works reasonably fine, 
but I would like to have more information on incomplete statements.

Using actions I have divided a SQL statement into several parts and have 
managed to have content assist based on that. But this is not as 
fine-grained as I want it to be. What I would really like is that the 
syntax check would tell us what it expects next: a column definition,  a 
keyword, a table and so on. The content assist would then be able to 
show just those assists. The problem is of course that the syntax that 
the user is entering is wrong, so will cause an error. Somehow I do not 
get as many  "expected <this> found 'null'" errors as I expected (if you 
get my expectation;-)).

I have added exception handling around my entry rule, hoping to achieve 
that if one statement does not compile, the next one might. So I consume 
everything up to and including the next SEMI. I think that my 
implementation somehow hides the errors I want to catch.

sql_script:
     sql_stmt 
(s:SEMICOLON!{currentStatement.setLength(#s.getColumn()-currentStatement.getOffset());} 
(sql_stmt)?)*
    {
        ##=#([SQL_SCRIPT,"script"], #sql_script);
    }
;
exception
catch [MismatchedTokenException mce]
{
     QError e = new QError();
   // .... omitted for brevity
    errors.add(e);
    if(LA(1)==SEMICOLON)
    {
        consume();
        returnAST = sql_script_AST;
        sql_stmt();
        return;
    }
    consume();
    while (LA(1) != Token.EOF_TYPE && (LA(1)!=SEMICOLON)) {
        consume();
    }
    if(LA(1)==SEMICOLON){
        consume();
    }
    returnAST = sql_script_AST;
    sql_stmt();
    return;
}
catch [NoViableAltException nvae]
{
    QError e = new QError();
   // .... omitted for brevity
    errors.add(e);
      if(LA(1)==SEMICOLON)
    {
        consume();
        sql_stmt();
        return;
    }
    consume();
    while (LA(1) != Token.EOF_TYPE && (LA(1)!=SEMICOLON)) {
        consume();
    }
    if(LA(1)==SEMICOLON){
        consume();
    }
    if(LA(1)!=EOF){
        sql_script();
    }
    return;
}
catch [RecognitionException re]
{
    QError e = new QError();
   // .... omitted for brevity
    errors.add(e);
    if(LA(1)==SEMICOLON)
    {
        consume();
        returnAST = sql_script_AST;
        sql_stmt();
        return;
    }
    consume();
    while (LA(1) != Token.EOF_TYPE && (LA(1)!=SEMICOLON)) {
        consume();
    }
    if(LA(1)==SEMICOLON){
        consume();
    }
    returnAST = sql_script_AST;
    sql_stmt();
    return;
}

I have a similar exception handling block around the sql_stmt rule. (The 
stuff I am doing to the returnAST is also sub-optimal.)
sql_stmt
:
      sql_data_stmt 
{statements.put(currentStatement.getStatementNumber(), 
currentStatement);}// this statement had correct syntax.
    | sql_schema_stmt 
{statements.put(currentStatement.getStatementNumber(), currentStatement);}
    | sql_transaction_stmt
    |
    ( options {generateAmbigWarnings=false;}:
         // Keeping this order avoids the clash of the "set" statements
     // due to the linear approximation of the lookahead
        sql_session_stmt     // LA(1) is surely "set"
      | sql_connection_stmt
    )
    | sql_dyn_stmt
    | system_descriptor_stmt
    | get_diag_stmt
    | declare_cursor
    | temporary_table_decl
;
exception
catch [MismatchedTokenException mce]
{
... see above...


So my questions are:
1) Can antlr offer a list of things it expects next? So if the statement 
is: SELECT * FROM, can antlr then tell me it expects a table definition. 
Whether that would be a table, view or subquery depends on the grammar, 
I think. I would like all three alternatives, and the grammar for 
completed statements does support all three.
2) In what order should I catch the exceptions? I want as much info on 
the error as possible. Do I need one catch [Exception e] and then handle 
the subtypes in the catch block? Which rule should I call in the 
exception block: sql_script or sql_stmt?
3) Am I taking the correct approach here?


Any suggestions would be greatly appreciated.

Kind regards,


Jan



More information about the antlr-interest mailing list