2011-11-07 12 views
7

Sto scrivendo un plugin Eclipse/Xtext per CoffeeScript e ho capito che probabilmente avrò bisogno di scrivere un lexer a mano. Il parser di CoffeeScript utilizza anche un hand-written lexer per gestire il rientro e altri trucchi nella grammatica.Scrivere un lexer Xtext/ANTLR personalizzato senza un file di grammatica

Xtext genera una classe che estende org.eclipse.xtext.parser.antlr.Lexer che a sua volta estende org.antlr.runtime.Lexer. Quindi suppongo che lo proverò. Posso vedere due modi per farlo

  • Ignora mTokens(). Questo viene fatto dal codice generato, cambiando lo stato interno.
  • Override nextToken() che sembra un approccio naturale, ma poi dovrò tenere traccia dello stato interno.

Non ho trovato alcun esempio su come scrivere anche un semplice lexer per ANTLR senza un file di grammatica. Quindi la risposta più semplice sarebbe un puntatore a uno.

Una risposta a Xtext: grammar for language with significant/semantic whitespace si riferisce a todotext che gestisce il problema di indentazione modificando i token nel flusso di input sottostante. Non voglio andare in quel modo, perché sarebbe difficile gestire altri trucchi della grammatica del coffeescript.

UPDATE:

mi sono reso conto, nel frattempo che la mia domanda era in parte xtext specifica.

+0

Devi solo implementare 'ITokenSource' e fare tutto ciò che devi fare nel metodo' nextToken'. Hai controllato http://stackoverflow.com/questions/4414166/antlr-parser-with-manual-lexer. Esistono degli esempi sulla gestione dei rientri (in Python, ad esempio) nel Riferimento antlr definitivo. – Jimmy

risposta

7

Ecco cosa ho fatto - e funziona.

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) { 
    // ... 
    } 
} 

poi ho un parser leggermente personalizzata contenente:

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

ho anche dovuto cambiare il mio MylangRuntimeModule.java per contenere questo metodo

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

E questo è tutto.

+0

Fantastico, grazie per la condivisione. –

5

Un altro modo (senza la necessità di creare un parser personalizzato) è quello di creare un lexer personalizzata estendendo lexer di xtext (org.eclipse.xtext.parser.antlr.Lexer) come segue:

public class CustomSTLexer extends Lexer { 

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

Poi si associa nel vostro modulo:

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

Se si vuole avere uno sguardo a un esempio completo, ho implementato un lexer personalizzato per un editore xtext-based per StringTemplate chiamato hastee.