2011-11-07 16 views
7

Escribo un plugin de Eclipse/Xtext para CoffeeScript, y me di cuenta de que probablemente necesite escribir un lexer manualmente. El analizador de CoffeeScript también usa un hand-written lexer para manejar sangrías y otros trucos en la gramática.Escribiendo un lexer Xtext/ANTLR personalizado sin un archivo de gramática

Xtext genera una clase que se extiende org.eclipse.xtext.parser.antlr.Lexer que a su vez se extiende org.antlr.runtime.Lexer. Entonces supongo que tendré que extenderlo. Puedo ver dos formas de hacerlo

  • Anular mTokens(). Esto se hace mediante el código generado, cambiando el estado interno.
  • Sobrescribe nextToken() que parece un enfoque natural, pero tendré que hacer un seguimiento del estado interno.

No he podido encontrar ningún ejemplo de cómo escribir incluso un simple lexer para ANTLR sin un archivo de gramática. Entonces la respuesta más fácil sería un puntero a uno.

Una respuesta a Xtext: grammar for language with significant/semantic whitespace se refiere a todotext que maneja el problema de la sangría al cambiar los tokens en el flujo de entrada subyacente. No quiero ir por ese camino, porque sería difícil manejar otros trucos de la gramática del coffeescript.

ACTUALIZACIÓN:

me di cuenta de que, mientras tanto, mi pregunta era en parte xtext específica.

+0

Solo necesita implementar 'ITokenSource' - y haga lo que tenga que hacer en el método' nextToken'. ¿Has comprobado http://stackoverflow.com/questions/4414166/antlr-parser-with-manlier-lexer? Hay ejemplos sobre el manejo de sangrías (en Python, por ejemplo) en la Referencia definitiva de Antlr. – Jimmy

Respuesta

7

Esto es lo que hice, y funciona.

public class MyLexer extends myprj.parser.antlr.internal.InternalMylangLexer { 
    private SomeExternalLexer externalLexer; 

    public Lexer(CharStream in) { 
    super(in); 
    externalLexer = new SomeExternalLexer(in); 
    } 

    @Override 
    public Token nextToken() { 
    Token token = null; 
    ExternalToken extToken = null; 
    try { 
     extToken = externalLexer.nextToken(); 
     if (extToken == null) { 
     token = CommonToken.INVALID_TOKEN; 
     } 
     else { 
     token = mapExternalToken(extToken); 
     } 
    } 
    catch (Exception e) { 
     token = CommonToken.INVALID_TOKEN; 
    } 
    return token; 
    } 

    protected Token mapExternalToken(ExternalToken extToken) { 
    // ... 
    } 
} 

entonces tengo un analizador ligeramente personalizada que contiene:

public class BetterParser extends MylangParser { 
    @Override 
    protected TokenSource createLexer(CharStream stream) { 
    MyLexer lexer = new MyLexer(stream); 
    return lexer; 
    } 
} 

También tuve que cambiar mi MylangRuntimeModule.java que contienen este método

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

Y eso es todo.

+0

Genial, gracias por compartir. –

5

Otra forma (sin la necesidad de crear un analizador personalizado) es crear un analizador léxico personalizada mediante la ampliación de léxico xtext (org.eclipse.xtext.parser.antlr.Lexer) de la siguiente manera:

public class CustomSTLexer extends Lexer { 

    @Override 
    public void mTokens() { 
     // implement lexer here 
    } 
} 

Entonces que ates en su módulo:

@Override 
public void configureRuntimeLexer(Binder binder) { 
    binder.bind(Lexer.class) 
       .annotatedWith(Names.named(LexerBindings.RUNTIME)) 
       .to(CustomSTLexer.class); 
} 

Si quieres echar un vistazo a un ejemplo completo, he implementado un analizador léxico personalizada para un editor basado en xtext para StringTemplate llamados hastee.

Cuestiones relacionadas