如何使 NetBeans LexerInput 适应 ANTLR 的 CharStream。我有下一个实现,但效果不佳。我想通过 ANTLR 词法分析器向 NetBeans 平台添加一种新语言。

Lexer 只发出 EOF,但 token 类型没问题,我不明白。

import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.misc.Interval;
import org.netbeans.spi.lexer.LexerInput;

/**
 * @author jonny
 */
public class AntlrCharStream implements CharStream {


    private class CharStreamState {
        int index;
        int line;
        int charPositionInLine;
    }

    private int line = 1;
    private int charPositionInLine = 0;
    private LexerInput input;
    private String name;
    private int index = 0;
    private List<CharStreamState> markers;
    private int markDepth = 0;
    private int lastMarker;

    public AntlrCharStream(LexerInput input, String name) {
        this.input = input;
        this.name = name;
    }

    @Override
    public String getText(Interval intrvl) {
        return input.readText().toString();
    }

    public String substring(int start, int stop) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public int LT(int i) {
        return LA(i);
    }

    public int getLine() {
        return line;
    }

    public void setLine(int line) {
        this.line = line;
    }

    public void setCharPositionInLine(int pos) {
        this.charPositionInLine = pos;
    }

    public int getCharPositionInLine() {
        return charPositionInLine;
    }

    public void consume() {
        int c = input.read();
        index++;
        charPositionInLine++;

        if (c == '\n') {
            line++;
            charPositionInLine = 0;
        }
    }

    public int LA(int i) {
        if (i == 0) {
            return 0; // undefined
        }

        int c = 0;
        for (int j = 0; j < i; j++) {
            c = read();
        }
        backup(i);
        return c;
    }

    public int mark() {
        if (markers == null) {
            markers = new ArrayList<CharStreamState>();
            markers.add(null); // depth 0 means no backtracking, leave blank
        }
        markDepth++;
        CharStreamState state = null;
        if (markDepth >= markers.size()) {
            state = new CharStreamState();
            markers.add(state);
        } else {
            state = (CharStreamState) markers.get(markDepth);
        }
        state.index = index;
        state.line = line;
        state.charPositionInLine = charPositionInLine;
        lastMarker = markDepth;

        return markDepth;
    }

    public void rewind() {
        rewind(lastMarker);
    }

    public void rewind(int marker) {
        CharStreamState state = (CharStreamState) markers.get(marker);
        // restore stream state
        seek(state.index);
        line = state.line;
        charPositionInLine = state.charPositionInLine;
        release(marker);
    }

    public void release(int marker) {
        // unwind any other markers made after m and release m
        markDepth = marker;
        // release this marker
        markDepth--;
    }

    public void seek(int index) {
        if (index < this.index) {
            backup(this.index - index);
            this.index = index; // just jump; don't update stream state (line, ...)
            return;
        }

        // seek forward, consume until p hits index
        while (this.index < index) {
            consume();
        }
    }

    public int index() {
        return index;
    }

    public int size() {
        return -1; //unknown...
    }

    public String getSourceName() {
        return name;
    }

    private int read() {
        int result = input.read();
        if (result == LexerInput.EOF) {
            result = CharStream.EOF;
        }

        return result;
    }

    private void backup(int count) {
        input.backup(count);
    }
}
'[@-1,6:6='<EOF>',<1>,2:2]'
'[@-1,7:7='<EOF>',<1>,2:3]'
'[@-1,8:15='<EOF>',<9>,2:4]'
'[@-1,16:16='<EOF>',<1>,2:12]'
'[@-1,17:23='<EOF>',<8>,2:13]'
'[@-1,24:24='<EOF>',<1>,2:20]'
'[@-1,25:25='<EOF>',<2>,2:21]'
'[@-1,26:26='<EOF>',<1>,3:0]'
'[@-1,27:27='<EOF>',<1>,3:1]'
'[@-1,28:28='<EOF>',<1>,3:2]'
'[@-1,29:29='<EOF>',<1>,3:3]'
'[@-1,30:37='<EOF>',<4>,3:4]'
'[@-1,38:38='<EOF>',<1>,3:12]'
'[@-1,39:43='<EOF>',<5>,3:13]'
'[@-1,44:44='<EOF>',<1>,3:18]'
'[@-1,45:48='<EOF>',<9>,3:19]'
'[@-1,49:49='<EOF>',<1>,3:23]'
'[@-1,50:53='<EOF>',<7>,3:24]'
'[@-1,54:54='<EOF>',<1>,3:28]'
'[@-1,55:56='<EOF>',<6>,3:29]'
'[@-1,57:57='<EOF>',<2>,3:31]'
'[@-1,58:57='<EOF>',<-1>,4:32]'

最佳答案

我也在尝试使用 ANTLR 4 制作一个 NetBeans 插件。这是我从 that tutorial 修改 AntlrCharStream 后想到的。到目前为止,它对我有用。

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.misc.Interval;
import org.netbeans.spi.lexer.LexerInput;

public class AntlrCharStream implements CharStream {

    private final LexerInput input;
    private final String name;
    private int index = 0;
    private int markDepth = 0;

    public AntlrCharStream(LexerInput input, String name) {
        this.input = input;
        this.name = name;
    }

    @Override
    public String getText(Interval interval) {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public void consume() {
        int character = read();
        if (character == EOF) {
            backup(1);
            throw new IllegalStateException("Attempting to consume EOF");
        }
        index++;
    }

    @Override
    public int LA(int lookaheadAmount) {
        if (lookaheadAmount < 0) {
            return lookBack(-lookaheadAmount);
        } else if (lookaheadAmount > 0) {
            return lookAhead(lookaheadAmount);
        } else {
            return 0; //Behaviour is undefined when lookaheadAmount == 0
        }
    }

    private int lookBack(int amount) {
        backup(amount);
        int character = read();
        for (int i = 1; i < amount; i++) {
            read();
        }
        return character;
    }

    private int lookAhead(int amount) {
        int character = 0;
        for (int i = 0; i < amount; i++) {
            character = read();
        }
        backup(amount);
        return character;
    }

    @Override
    public int mark() {
        return ++markDepth;
    }

    @Override
    public void release(int marker) {
        // unwind any other markers made after m and release m
        markDepth = marker;
        // release this marker
        markDepth--;
    }

    @Override
    public void seek(int index) {
        if (index < 0) {
            throw new IllegalArgumentException(String.format("Invalid index (%s < 0)", index));
        }

        if (index < this.index) {
            backup(this.index - index);
            this.index = index;
            return;
        }

        // seek forward, consume until p hits index
        while (this.index < index) {
            consume();
        }
    }

    @Override
    public int index() {
        return index;
    }

    @Override
    public int size() {
        throw new UnsupportedOperationException("Stream size unknown");
    }

    @Override
    public String getSourceName() {
        return name;
    }

    private int read() {
        int result = input.read();
        if (result == LexerInput.EOF) {
            return EOF;
        } else {
            return result;
        }
    }

    private void backup(int count) {
        input.backup(count);
    }
}

关于antlr - NetBeans 平台语言和 ANTLR 词法分析器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16152666/

10-17 02:08