【P4911】Java题解
Gralerfics · · 题解
啊这,貌似是第一份 JavaAC 欸。
一遍过(是数据太水了大概咳咳)
虽然好像评论区说数据有些指令没有然而还是都写了,没看到没空行所以空行也处理了一下。
我怀疑有 bug 但数据测试不出来(小声
(嗯,这次 O2 又是会逆向优化)
是刚学了 Java 用来巩固写的 emm ,所以也做了奇怪的封装什么的,也没有注重代码长度和效率,写长点多爽啊(暴论
后半部分写得比较肿,主要是看不清了要。
具体嘛就是假装词法分析一下(见 public void Compiler.Lexer()
)。这里面是先割词,然后识别到标识符再向前归纳和可能存在的 %, @ 之类的合并起来变成变量。
按词分好,按行分好,然后执行(见 public void Interpreter.run() )。
运行前还要处理一下函数地址(见 public void Interpreter.loadup() )。
为了体现面向对象各种结构都定义了对应的类( CPU, Memory, Compiler, Interpreter, Stream, IStream, OStream )。
sAddr 栈和各种寄存器在 CPU 类里,内存就是内存。
class IStream extends Stream 和 class OStream extends Stream 分别模拟输入输出流。
各自成员变量都设为 private 做了封装(自虐)。
所以 main 函数看起来很舒服咳咳。
所以全收起来之后比较清晰:
import java.util.*;
// 内存
class Memory {...}
// 处理器
class CPU {...}
// 流
class Stream {...}
// 输入流 extends 流
class IStream extends Stream {...}
// 输出流 extends 流
class OStream extends Stream {...}
// 编译器(伪
class Compiler {...}
// 解释器(伪
class Interpreter {...}
public class Main {
public static void main(String[] args) {...}
}
最后贴上代码,写了不少注释:
import java.util.*;
// 内存
class Memory {
// 0 - 1677216
private int[] data = new int[16777300];
// 构造函数
Memory() {
Arrays.fill(data, 0);
}
// 调取和设置方法
public int getAddr(int _a) {
return data[_a];
}
public void setAddr(int _a, int _d) {
data[_a] = _d;
}
}
// 处理器
class CPU {
// 栈元素
private class Tsta {
int next;
int line;
Tsta(int next, int line) {
this.next = next;
this.line = line;
}
}
// 栈
private Stack<Tsta> sAddr = new Stack<>();
// 寄存器
private int R1 = 0, R2 = 0, R3 = 0, R4 = 0;
private int E1 = 0, E2 = 0, E3 = 0, E4 = 0;
private int Flag = 0, Val = 0, Ret = 0, Line = 0;
// 调取和设置方法
public int Get(String name) {
switch (name) {
case "r1": return R1;
case "r2": return R2;
case "r3": return R3;
case "r4": return R4;
case "e1": return E1;
case "e2": return E2;
case "e3": return E3;
case "e4": return E4;
case "flag": return Flag;
case "val": return Val;
case "ret": return Ret;
case "line": return Line;
}
return 0;
}
public void Set(String name, int t) {
switch (name) {
case "r1": R1 = t; break;
case "r2": R2 = t; break;
case "r3": R3 = t; break;
case "r4": R4 = t; break;
case "e1": E1 = t; break;
case "e2": E2 = t; break;
case "e3": E3 = t; break;
case "e4": E4 = t; break;
case "flag": Flag = t; break;
case "val": Val = t; break;
case "ret": Ret = t; break;
case "line": Line = t; break;
}
}
public void push(int next, int line) {
sAddr.push(new Tsta(next, line));
}
public int pop() {
// 弹栈返回目标行,并复位%Line
Tsta t = sAddr.pop();
Line = t.line;
return t.next;
}
}
// 流
class Stream {
// 数据
private ArrayList<String> data = new ArrayList<>();
// 调取和设置方法
public ArrayList<String> get() {
return data;
}
public void add(String s) {
data.add(s);
}
}
// 输入流 extends 流
class IStream extends Stream {
// 指针
private int current = 0;
// 是否为空白符
private boolean isWhite(char _peek) {
return _peek == ' ' || _peek == '\t';
}
// 构造函数,按空白符划词
IStream() {}
IStream(Stream _in) {
for (String _line : _in.get()) {
int len = _line.length();
int j = 0;
for (int i = 1; i < len; i++) {
// 词尾
if (isWhite(_line.charAt(i)) && !isWhite(_line.charAt(i - 1))) {
add(_line.substring(j, i));
}
// 词头,头指针更新
if (!isWhite(_line.charAt(i)) && isWhite(_line.charAt(i - 1))) {
j = i;
}
}
// 行末 -> 词尾
add(_line.substring(j));
}
}
// 按序读取
public String getNext() {
return get().get(current++);
}
}
// 输出流 extends 流
class OStream extends Stream {
// 输出
public void output() {
for (String _l : get()) {
System.out.print(_l);
}
}
}
// 编译器(伪
class Compiler {
// 词
private class Ttoken {
// 词类型
private int type = 0;
// 词属性
private String property;
// 构词法
Ttoken(int type, String property) {
this.type = type;
this.property = property;
}
// 调取和设置方法
public int getT() {
return type;
}
public void setT(int type) {
this.type = type;
}
public String getP() {
return property;
}
public void setP(String property) {
this.property = property;
}
}
// 词表
private ArrayList<Ttoken> tokens = new ArrayList<>();
// 句首词表
private ArrayList<Integer> cmds = new ArrayList<>();
// 是否为空白符
private boolean isWhite(char _peek) {
return _peek == ' ' || _peek == '\t';
}
// 是否为标识符字符
private boolean isLetter(char _peek) {
return _peek >= 'A' && _peek <= 'z' || _peek >= '0' && _peek <= '9';
}
// 词法分析,并记录句首词
public void Lexer(Stream _code) {
int anno = 0;
cmds.add(0); // 行号从1开始标记
for (String _line : _code.get()) {
cmds.add(tokens.size());
int len = _line.length();
for (int i = 0; i < len; i++) {
char _peek = _line.charAt(i);
// 空白、注释处理
if (_peek == '[') {
anno++;
continue;
}
if (_peek == ']') {
anno--;
continue;
}
if (anno != 0 || isWhite(_peek)) continue;
// 特殊符号
if (_peek == '%') {
tokens.add(new Ttoken(-1, ""));
continue;
}
if (_peek == '@') {
tokens.add(new Ttoken(-2, ""));
continue;
}
if (_peek == '#') {
tokens.add(new Ttoken(-3, ""));
continue;
}
if (_peek == '$') {
tokens.add(new Ttoken(-4, ""));
continue;
}
if (_peek == ';') {
tokens.add(new Ttoken(-5, ""));
continue;
}
// 标识符
tokens.add(new Ttoken(1,"" + _peek));
if (i < len - 1) {
_peek = _line.charAt(++i);
while (i < len && isLetter(_peek)) {
tokens.get(tokens.size() - 1).property += _peek;
_peek = _line.charAt(++i);
}
i--;
}
// 标识符向前归纳
if (tokens.size() <= 2) continue;
Ttoken A = tokens.get(tokens.size() - 3);
Ttoken B = tokens.get(tokens.size() - 2);
Ttoken C = tokens.get(tokens.size() - 1);
if (A.type == -2 && B.type == -1) {
A.type = 4;
A.property = C.property;
tokens.remove(tokens.size() - 1);
tokens.remove(tokens.size() - 1);
continue;
} // @%... -> 4
if (B.type == -1) {
B.type = 2;
B.property = C.property;
tokens.remove(tokens.size() - 1);
continue;
} // %... -> 2
if (B.type == -2) {
B.type = 3;
B.property = C.property;
tokens.remove(tokens.size() - 1);
continue;
} // @... -> 3
if (B.type == -3) {
B.type = 5;
B.property = C.property;
tokens.remove(tokens.size() - 1);
continue;
} // #... -> 5
if (B.type == -4) {
B.type = 6;
B.property = C.property;
tokens.remove(tokens.size() - 1);
// continue;
} // $... -> 6
}
}
cmds.add(cmds.get(cmds.size() - 1) + 1); // 结尾加空行防止ptr+1溢出
}
// 获取第_n行句首词编号
public Integer getCmd(int _n) {
return cmds.get(_n);
}
// 获取第_n个词
public int GetT(int _n) {
return tokens.get(_n).type;
}
public String GetP(int _n) {
return tokens.get(_n).property;
}
}
// 解释器(伪
class Interpreter {
// 处理器
private CPU cpu = new CPU();
// 内存
private Memory mem = new Memory();
// 当前执行行号,即#Line
private int ptr;
// 函数头行号记录
private HashMap<String, Integer> func = new HashMap<>();
// 函数加载器
public void loadup(int _n, Compiler com) {
for (int i = 1; i <= _n; i++) {
if (com.getCmd(i + 1).equals(com.getCmd(i))) continue;
int num = com.getCmd(i);
if (com.GetP(num).contains("function")) {
func.put(com.GetP(num + 1), i); // 关联函数名与行号
}
}
}
// 获取变量值
public int FET(int ty0, String pr0) {
switch (ty0) {
case -1: return (int)pr0.charAt(0);
case 1: return Integer.parseInt(pr0);
case 2: return cpu.Get(pr0);
case 3: return mem.getAddr(Integer.parseInt(pr0));
case 4: return mem.getAddr(cpu.Get(pr0));
case 5: return ptr;
case 6: return func.get(pr0);
}
return 0;
}
// SET操作
public void SET(int ty0, String pr0, int ty1, String pr1) {
int arg0 = FET(ty0, pr0);
switch (ty1) {
case 2: cpu.Set(pr1, arg0); break;
case 3: mem.setAddr(Integer.parseInt(pr1), arg0); break;
case 4: mem.setAddr(cpu.Get(pr1), arg0); break;
}
}
// 运行
public void run(Compiler com, IStream in, OStream out) {
ptr = 1;
while (true) {
if (com.getCmd(ptr + 1).equals(com.getCmd(ptr))) {
ptr++;
continue;
}
if (com.GetP(com.getCmd(ptr)).contains("hlt")) {
break;
} else if (com.GetP(com.getCmd(ptr)).contains("set")) {
SET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1),
com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
} else if (com.GetP(com.getCmd(ptr)).contains("jmp")) {
ptr = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
+ cpu.Get("line");
continue;
} else if (com.GetP(com.getCmd(ptr)).contains("jif")) {
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 3) {
if (cpu.Get("flag") == 1) {
ptr = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
+ cpu.Get("line");
continue;
}
} else {
if (FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)) != 0) {
ptr = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
+ cpu.Get("line");
continue;
}
}
} else if (com.GetP(com.getCmd(ptr)).contains("call")) {
cpu.push(ptr + 1, cpu.Get("line")); // 压栈
ptr = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1)); // 跳转至函数
cpu.Set("line", ptr); // 设置当前函数头
continue;
} else if (com.GetP(com.getCmd(ptr)).contains("ret")) {
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 3) {
cpu.Set("ret", FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))); // 返回值
}
ptr = cpu.pop(); // 弹栈并跳回,同时复位%Line
continue;
} else if (com.GetP(com.getCmd(ptr)).contains("inv")) {
int t = - FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 3) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
}
} else if (com.GetP(com.getCmd(ptr)).contains("add")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
+ FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("sub")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
- FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("mult")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
* FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("idiv")) {
int t = (int)Math.floor(1.0d * FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
/ FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("mod")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
% FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("lsft")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
<< FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("rsft")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
>> FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("band")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
& FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("bor")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
| FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("bxor")) {
int t = FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
^ FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2));
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("val", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("lgr")) {
int t = (FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
> FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)))?1:0;
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("flag", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("lls")) {
int t = (FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
< FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)))?1:0;
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("flag", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("lge")) {
int t = (FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
>= FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)))?1:0;
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("flag", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("lle")) {
int t = (FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
<= FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)))?1:0;
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("flag", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("leql")) {
int t = (FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))
== FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)))?1:0;
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("flag", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("land")) {
int t = (FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1)) == 1
&& FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)) == 1)?1:0;
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("flag", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("lor")) {
int t = (FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1)) == 0
&& FET(com.GetT(com.getCmd(ptr) + 2), com.GetP(com.getCmd(ptr) + 2)) == 0)?0:1;
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 4) {
cpu.Set("flag", t);
} else {
SET(1, ((Integer)t).toString(), com.GetT(com.getCmd(ptr) + 3), com.GetP(com.getCmd(ptr) + 3));
}
} else if (com.GetP(com.getCmd(ptr)).contains("rint")) {
SET(1, in.getNext(), com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1));
} else if (com.GetP(com.getCmd(ptr)).contains("rch")) {
SET(-1, in.getNext(), com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1));
} else if (com.GetP(com.getCmd(ptr)).contains("wint")) {
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 2) {
out.add(((Integer) cpu.Get("val")).toString());
} else {
out.add(((Integer) FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1))).toString());
}
} else if (com.GetP(com.getCmd(ptr)).contains("wch")) {
if (com.getCmd(ptr + 1) - com.getCmd(ptr) == 2) {
out.add("" + (char)cpu.Get("val"));
} else {
out.add("" + (char)FET(com.GetT(com.getCmd(ptr) + 1), com.GetP(com.getCmd(ptr) + 1)));
}
}
ptr++; // 除跳转语句外,行号指针默认+1
}
}
}
public class Main {
public static void main(String[] args) {
// 创建Scanner对象
Scanner scanner = new Scanner(System.in);
// 读入程序
Stream code = new Stream();
int totalLines = scanner.nextInt();
scanner.nextLine();
for (int i = 0; i < totalLines; i++) {
code.add(scanner.nextLine());
}
// 读入输入并加载至输入流
Stream input = new Stream();
while (scanner.hasNextLine()) {
input.add(scanner.nextLine());
}
IStream in = new IStream(input);
// 编译,数据保证无编译错误
Compiler compiler = new Compiler();
compiler.Lexer(code);
// 解释,数据保证无运行时错误
Interpreter interpreter = new Interpreter();
OStream out = new OStream();
interpreter.loadup(totalLines, compiler);
interpreter.run(compiler, in, out);
// 输出
out.output();
}
}