企业网站策划大纲模板,松江网站开发公司,网站建设 要维护么,凡科快图免费版商用目录
堆栈运算命令
基本思路
核心代码
Parser
Code Writer
Main
实验结果#xff0c;使用SimpleAdd、StackTest进行验证
内存访问命令
基本思路
核心代码
Parser
Code Writer
Main
实验结果#xff0c;使用进行验证。对比生成的二进制代码文件。 用Java写一个翻…目录
堆栈运算命令
基本思路
核心代码
Parser
Code Writer
Main
实验结果使用SimpleAdd、StackTest进行验证
内存访问命令
基本思路
核心代码
Parser
Code Writer
Main
实验结果使用进行验证。对比生成的二进制代码文件。 用Java写一个翻译器将Java的字节码翻译成汇编语言
堆栈运算命令 基本思路
主要写两个类一个解析器类Parser负责处理输入的vm文件解析vm指令一个类CodeWriter负责将经过Parser解析过的vm指令翻译成汇编指令输出asm文件。 首先编写类Parser有六个成员函数包含构造函数负责打开文件流并准备读取vm指令hasMoreCommands函数判断是否还有指令advance函数负责将vm指令处理干净去掉空白和注释commandType函数判断vm指令的类型arg1和arg2函数负责返回指令的组成部分。 然后编写CodeWriter类构造函数打开一个文件准备写入asm指令writeArithmetic函数写入算术逻辑运算asm指令writerPushPop函数写入push和pop的asm指令。 然后最关键的地方来了如何从vm指令到asm指令
我们首先从算术逻辑运算指令来看以二元运算为例计算的两个数是放在栈上的位于栈指针SP上面两个位置而我们只有M和D两个寄存器可以用来计算在A寄存器保存栈指针地址的情况下。 因此对于所有二元运算我们首先要把参与计算的两个数放在M和D寄存器上具体操作是栈指针SP自减把M的值赋给D然后再将栈指针上移。 然后再执行二元运算这样就比较简单了。 对于一元运算比较简单直接栈指针自减对M进行操作即可。 而对于gt、eq和lt这样比较指令则比较复杂因为涉及到跳转同样是二元运算因此我们需要先按照上述方法先将参与计算的两个数拿出来放在M和D寄存器然后计算M和D的差通过比较差和0的大小来跳转。 而对于push constant x指令将一个常数压入栈就比较简单了。 拿到常数的值后将它写入栈指针执行的内存然后栈指针自增就行了。 核心代码
Parser
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Objects;
import java.util.Scanner;public class Parser {private String command null;private Scanner scanner null;private String cmd0 null;private String cmd1 null;private int cmd2;public Parser(File file) throws FileNotFoundException {scanner new Scanner(new FileReader(file));}public boolean hasMoreCommands() {boolean hasMore false;while (scanner.hasNextLine()) {command scanner.nextLine();if (!Objects.equals(command, ) command.charAt(0) ! /) { //去掉空白行和注释String[] pure command.split(/);command pure[0];hasMore true;break;}}return hasMore;}public void advance() {String[] cmd command.split( );cmd0 cmd[0];if (cmd.length 1) {cmd1 cmd[1];if (cmd.length 2) {cmd2 Integer.parseInt(cmd[2]);}}}public String commandType() {if (Objects.equals(cmd0, push)) {return C_PUSH;} else {return C_ARITHMETIC;}}public String arg1() {if (Objects.equals(commandType(), C_ARITHMETIC))return cmd0;return cmd1;}public int arg2() {return cmd2;}public void close(){scanner.close();}}Code Writer
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Objects;public class CodeWriter {private FileWriter asm null;private String asmCommand;private final HashMapString, String vmToAsm new HashMap();private int jump0;public CodeWriter(File file) throws IOException {asm new FileWriter(file);String fetch SP\nMM-1\nAM\nDM\nAA-1\n;vmToAsm.put(add, fetch MMD\n);vmToAsm.put(sub, fetch MM-D\n);vmToAsm.put(and, fetch MMD\n);vmToAsm.put(or, fetch MM|D\n);vmToAsm.put(gt, fetch DM-D\nTRUE\nD;JGT\nSP\nAM-1\nM0\nEND\n0;JMP\n(TRUE)\nSP\nAM-1\nM-1\n(END)\n);vmToAsm.put(eq, fetch DM-D\nTRUE\nD;JEQ\nSP\nAM-1\nM0\nEND\n0;JMP\n(TRUE)\nSP\nAM-1\nM-1\n(END)\n);vmToAsm.put(lt, fetch DM-D\nTRUE\nD;JLT\nSP\nAM-1\nM0\nEND\n0;JMP\n(TRUE)\nSP\nAM-1\nM-1\n(END)\n);vmToAsm.put(neg, D0\nSP\nAM-1\nMD-M\n);vmToAsm.put(not, SP\nAM-1\nM!M\n);}public void writeArithmetic(String vmCommand) throws IOException {asmCommandvmToAsm.get(vmCommand);if(Objects.equals(vmCommand, gt) || Objects.equals(vmCommand, eq) || Objects.equals(vmCommand, lt)){asmCommandasmCommand.replaceAll(TRUE,TRUEInteger.toString(jump));asmCommandasmCommand.replaceAll(END,ENDInteger.toString(jump));jump;}asm.write(asmCommand);}public void writePushPop(String cmd, String segment, int index) throws IOException {if (Objects.equals(cmd, C_PUSH)) {if (Objects.equals(segment, constant)) {asmCommand Integer.toString(index) \nDA\nSP\nAM\nMD\nSP\nMM1\n;}}asm.write(asmCommand);}public void close() throws IOException {asm.close();}
}Main
import java.io.File;
import java.io.IOException;
import java.util.Objects;public class Main {public static void main(String[] args) throws IOException {Parser parsernew Parser(new File(C:\\Users\\Yezi\\Desktop\\Java程序设计\\nand2tetris\\projects\\07\\StackArithmetic\\StackTest\\StackTest.vm));CodeWriter codeWriternew CodeWriter(new File(C:\\Users\\Yezi\\Desktop\\Java程序设计\\nand2tetris\\projects\\07\\StackArithmetic\\StackTest\\StackTest.asm));while(parser.hasMoreCommands()){parser.advance();if(Objects.equals(parser.commandType(), C_ARITHMETIC)){codeWriter.writeArithmetic(parser.arg1());}else{codeWriter.writePushPop(parser.commandType(), parser.arg1(), parser.arg2());}}codeWriter.close();parser.close();}
}
实验结果使用SimpleAdd、StackTest进行验证
我们用CPU Emulator装载.tst文件用运行程序得到的.out文件和所给的.cmp文件进行比较其中SimpleAdd比较结果如下图所示可见成功翻译 StackTest的结果如下图所示可见第一阶段翻译成功。 内存访问命令 基本思路
首先要搞明白的是push操作是将内存上的数值压入栈中而pop操作是将栈中的数值弹出来到内存中。 对于constant段我们第一阶段已经解决了。
对于local、argument、this和that字段就是从它们相应的内存地址上读取或写入数据。 Push的话先拿到segmenti的地址所指向的数值然后将这个数值压入栈中栈指针自增。 Pop的话要复杂一些因为我们只有A、M和D寄存器可以用而pop我们首先要拿到segmenti的地址所以我们要先找一个地方存下来原本的R系列寄存器在这里已经被字段占用了所以我们这里取地址255的内存空间暂存一下地址。 而temp字段的push和pop操作相对而言要简单许多。 此时读写的地址为5i。 对于pointer字段其实就是把this和that的数值压入栈或者弹栈的数值到this和that中。 当参数为0时对this进行操作当参数为1时对that进行操作在this和that的地址上进行读写数据。 而对于static字段与前面的字段相比不过就是换了运算的地址空间而已。 Asm代码基本和前面的操作一样就是运算的地址变成了16开始的地址。 核心代码
Parser
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Objects;
import java.util.Scanner;public class Parser {private String command null;private final Scanner scanner;private String cmd0 null;private String cmd1 null;private int cmd2;public Parser(File file) throws FileNotFoundException {scanner new Scanner(new FileReader(file));}public boolean hasMoreCommands() {boolean hasMore false;while (scanner.hasNextLine()) {command scanner.nextLine();if (!Objects.equals(command, ) command.charAt(0) ! /) { //去掉空白行和注释String[] pure command.split(/);command pure[0];hasMore true;break;}}return hasMore;}public void advance() {String[] cmd command.split( );cmd0 cmd[0];if (cmd.length 1) {cmd1 cmd[1];if (cmd.length 2) {cmd2 Integer.parseInt(cmd[2]);}}}public String commandType() {if (Objects.equals(cmd0, push)) {return C_PUSH;} else if (Objects.equals(cmd0, pop)) {return C_POP;} else {return C_ARITHMETIC;}}public String arg1() {if (Objects.equals(commandType(), C_ARITHMETIC))return cmd0;return cmd1;}public int arg2() {return cmd2;}public void close() {scanner.close();}}Code Writer
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Objects;public class CodeWriter {private final FileWriter asm;private String asmCommand;private final HashMapString, String vmToAsm new HashMap();private int jump 0;public CodeWriter(File file) throws IOException {asm new FileWriter(file);String fetch SP\nMM-1\nAM\nDM\nAA-1\n;vmToAsm.put(add, fetch MMD\n);vmToAsm.put(sub, fetch MM-D\n);vmToAsm.put(and, fetch MMD\n);vmToAsm.put(or, fetch MM|D\n);vmToAsm.put(gt, fetch DM-D\nTRUE\nD;JGT\nSP\nAM-1\nM0\nEND\n0;JMP\n(TRUE)\nSP\nAM-1\nM-1\n(END)\n);vmToAsm.put(eq, fetch DM-D\nTRUE\nD;JEQ\nSP\nAM-1\nM0\nEND\n0;JMP\n(TRUE)\nSP\nAM-1\nM-1\n(END)\n);vmToAsm.put(lt, fetch DM-D\nTRUE\nD;JLT\nSP\nAM-1\nM0\nEND\n0;JMP\n(TRUE)\nSP\nAM-1\nM-1\n(END)\n);vmToAsm.put(neg, D0\nSP\nAM-1\nMD-M\n);vmToAsm.put(not, SP\nAM-1\nM!M\n);}public void writeArithmetic(String vmCommand) throws IOException {asmCommand vmToAsm.get(vmCommand);if (Objects.equals(vmCommand, gt) || Objects.equals(vmCommand, eq) || Objects.equals(vmCommand, lt)) {asmCommand asmCommand.replaceAll(TRUE, TRUE jump);asmCommand asmCommand.replaceAll(END, END jump);jump;}asm.write(asmCommand);}public void writePushPop(String cmd, String segment, int index) throws IOException {if (Objects.equals(cmd, C_PUSH)) {if (Objects.equals(segment, constant)) {asmCommand index \nDA\nSP\nAM\nMD\nSP\nMM1\n;} else if (Objects.equals(segment, local)) {asmCommand LCL\nDM\n index \nADA\nDM\nSP\nAM\nMD\nSP\nMM1\n;} else if (Objects.equals(segment, argument)) {asmCommand ARG\nDM\n index \nADA\nDM\nSP\nAM\nMD\nSP\nMM1\n;} else if (Objects.equals(segment, this)) {asmCommand THIS\nDM\n index \nADA\nDM\nSP\nAM\nMD\nSP\nMM1\n;} else if (Objects.equals(segment, that)) {asmCommand THAT\nDM\n index \nADA\nDM\nSP\nAM\nMD\nSP\nMM1\n;} else if (Objects.equals(segment, temp)) {asmCommand (5 index) \nDM\nSP\nAM\nMD\nSP\nMM1\n;} else if (Objects.equals(segment, pointer)) {if (index 0) {asmCommand THIS\nDM\nSP\nAM\nMD\nSP\nMM1\n;} else {asmCommand THAT\nDM\nSP\nAM\nMD\nSP\nMM1\n;}} else if (Objects.equals(segment, static)) {asmCommand (16 index) \nDM\nSP\nAM\nMD\nSP\nMM1\n;}} else {if (Objects.equals(segment, local)) {asmCommand LCL\nDM\n index \nDDA\n255\nMD\nSP\nMM-1\nAM\nDM\n255\nAM\nMD\n;} else if (Objects.equals(segment, argument)) {asmCommand ARG\nDM\n index \nDDA\n255\nMD\nSP\nMM-1\nAM\nDM\n255\nAM\nMD\n;} else if (Objects.equals(segment, this)) {asmCommand THIS\nDM\n index \nDDA\n255\nMD\nSP\nMM-1\nAM\nDM\n255\nAM\nMD\n;} else if (Objects.equals(segment, that)) {asmCommand THAT\nDM\n index \nDDA\n255\nMD\nSP\nMM-1\nAM\nDM\n255\nAM\nMD\n;} else if (Objects.equals(segment, temp)) {asmCommand SP\nMM-1\nAM\nDM\n (5 index) \nMD\n;} else if (Objects.equals(segment, pointer)) {if (index 0) {asmCommand SP\nMM-1\nAM\nDM\nTHIS\nMD\n;} else {asmCommand SP\nMM-1\nAM\nDM\nTHAT\nMD\n;}} else if (Objects.equals(segment, static)) {asmCommand SP\nMM-1\nAM\nDM\n (16 index) \nMD\n;}}asm.write(asmCommand);}public void close() throws IOException {asm.close();}
}Main
main函数没变
实验结果使用进行验证。对比生成的二进制代码文件。 我们用CPU Emulator装载.tst文件用运行程序得到的.out文件和所给的.cmp文件进行比较其中BasicTest的比较结果如下图所示可见成功翻译。 PointerTest的比较结果如下图所示可见成功翻译 StaticTest的结果如下图所示可见第二阶段翻译成功。