本实验为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);
}
}