本实验为NJU编译原理实验1

实验要求

  • 通过标准错误输出(stderr, 如System.err 等), 打印程序的所有运行结果。
  • 对于包含词法错误的文件,需要打印所有错误信息,格式为:Error type A at Line [lineNo]:[errorMessage]
  • 对于没有任何词法错误的文件,打印所有识别到的Tokens信息

.g4文件编写

按照SysY词法规则来编写即可,这里不再赘述。

代码实现

在Main.java中,我们需要实现main函数,读取文件,进行词法分析,并输出结果。

//通过标准错误输出(stderr, 如System.err 等), 打印程序的 所有 运行结果。
if (args.length < 1) {
    System.err.println("input path is required");
}
String source = args[0];
CharStream input = CharStreams.fromFileName(source);
SysYLexer sysYLexer = new SysYLexer(input);

接下来实现打印错误信息,需要重写org.antlr.v4.runtime.BaseErrorListener中的syntaxError函数,并实现printLexerErrorInformation函数。

public class MyErrorListener extends BaseErrorListener {
    private final List<String> errorInformation = new ArrayList<>();
    private boolean hasError = false;

    @Override
    public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
        hasError = true;

        errorInformation.add("Error type A at Line " + line + ":" + msg);

    }

    public boolean hasError() {
        return hasError;
    }

    public void printLexerErrorInformation() {
        // 你需要打印所有错误信息,
        // 格式为:Error type A at Line [lineNo]:[errorMessage],
        // 其中lineNo为出错的token首个字符所在行的行号,errorMessage可自行定义,
        // 本实验不做要求,只要冒号前的信息正确即可。;

        for (String s : errorInformation) {
            System.err.println(s);
        }

    }

}

接下来,我们需要实现printSysYTokenInformation函数,用于打印所有识别到的Tokens信息。

private static void printSysYTokenInformation(Token t) {


    String tokenName = SysYLexer.VOCABULARY.getSymbolicName(t.getType());
    String tokenText = t.getText();
    int line = t.getLine();

    //特别要求:输出时忽略所有注释,对十六进制和八进制数字常量输出token文本时需输出其十进制的值
    if (tokenName.equals("INTEGER_CONST")) {
        if (tokenText.startsWith("0x")) {
            tokenText = String.valueOf(Integer.parseInt(tokenText.substring(2), 16));
        } else if (tokenText.startsWith("0")) {
            tokenText = String.valueOf(Integer.parseInt(tokenText, 8));
        }
    }

    System.err.println(tokenName + " " + tokenText + " at Line " + line + ".");
}

最后,我们需要实现main函数的剩余部分。

MyErrorListener myErrorListener = new MyErrorListener();
sysYLexer.removeErrorListeners();
sysYLexer.addErrorListener(myErrorListener);
var myTokens = sysYLexer.getAllTokens();
if (myErrorListener.hasError()) {
    myErrorListener.printLexerErrorInformation();
} else {
    for (var t : myTokens) {
        printSysYTokenInformation(t);
    }
}