在隐藏通道中迭代令牌



我目前正在为自定义的,非常类似于lua的脚本语言MobTalkerScript(MTS)创建一个IDE,它为我提供了一个ANTLR4词法分析器。由于 MTS 语言文件中的规范将注释放入HIDDEN_CHANNEL通道中,因此我需要告诉词法分析器实际从HIDDEN_CHANNEL通道读取。这就是我试图做到这一点的方式。

Mts3Lexer lexer = new Mts3Lexer(new ANTLRInputStream("<replace this with the input>"));
lexer.setTokenFactory(new CommonTokenFactory(false));
lexer.setChannel(Token.HIDDEN_CHANNEL);
Token token = lexer.emit();
int type = token.getType();
do {
    switch(type) {
        case Mts3Lexer.LINE_COMMENT:
        case Mts3Lexer.COMMENT:
            System.out.println("token "+token.getText()+" is a comment");
        default:
            System.out.println("token "+token.getText()+" is not a comment");
    }
} while((token = lexer.nextToken()) != null && (type = token.getType()) != Token.EOF);

现在,如果我在以下输入中使用此代码,则只会将token ... is not a comment打印到控制台。

function foo()
    -- this should be a single-line comment
    something = "blah"
    --[[ this should
         be a multi-line
         comment ]]--
end

但是,包含注释的令牌永远不会显示。所以我搜索了这个问题的根源,并在ANTLR4 Lexer类中找到了以下方法:

/** Return a token from this source; i.e., match a token on the char
 *  stream.
 */
@Override
public Token nextToken() {
    if (_input == null) {
        throw new IllegalStateException("nextToken requires a non-null input stream.");
    }
    // Mark start location in char stream so unbuffered streams are
    // guaranteed at least have text of current token
    int tokenStartMarker = _input.mark();
    try{
        outer:
        while (true) {
            if (_hitEOF) {
                emitEOF();
                return _token;
            }
            _token = null;
            _channel = Token.DEFAULT_CHANNEL;
            _tokenStartCharIndex = _input.index();
            _tokenStartCharPositionInLine = getInterpreter().getCharPositionInLine();
            _tokenStartLine = getInterpreter().getLine();
            _text = null;
            do {
                _type = Token.INVALID_TYPE;
                // System.out.println("nextToken line "+tokenStartLine+" at "+((char)input.LA(1))+
                // " in mode "+mode+
                // " at index "+input.index());
                int ttype;
                try {
                    ttype = getInterpreter().match(_input, _mode);
                }
                catch (LexerNoViableAltException e) {
                    notifyListeners(e);     // report error
                    recover(e);
                    ttype = SKIP;
                }
                if ( _input.LA(1)==IntStream.EOF ) {
                    _hitEOF = true;
                }
                if ( _type == Token.INVALID_TYPE ) _type = ttype;
                if ( _type ==SKIP ) {
                    continue outer;
                }
            } while ( _type ==MORE );
            if ( _token == null ) emit();
            return _token;
        }
    }
    finally {
        // make sure we release marker after match or
        // unbuffered char stream will keep buffering
        _input.release(tokenStartMarker);
    }
}

引起我注意的台词如下。

_channel = Token.DEFAULT_CHANNEL;

我对 ANTLR 了解不多,但显然这条线将词法分析器保持在DEFAULT_CHANNEL通道中。

我尝试从HIDDEN_CHANNEL通道读取的方式是否正确,还是不能将nextToken()与隐藏通道一起使用?

我发现了为什么词法分析器没有给我任何包含注释的标记 - 我似乎错过了语法文件跳过注释而不是将它们放入隐藏通道。联系了作者,更改了语法文件,现在可以工作了。

注意

自己:多注意你读到的内容。

对于 Go (golang),这个片段对我有用:

import (
    "github.com/antlr/antlr4/runtime/Go/antlr"
)
type antlrparser interface {
    GetParser() antlr.Parser
}
func fullText(prc antlr.ParserRuleContext) string {
    p := prc.(antlrparser).GetParser()
    ts := p.GetTokenStream()
    tx := ts.GetTextFromTokens(prc.GetStart(), prc.GetStop())
    return tx
}

只需将您的ctx.GetSomething()传递到fullText.当然,如上图所示,空格必须转到*.g4文件中的隐藏通道:

WS: [ trn] -> channel(HIDDEN);

最新更新