Java VMTranslator Part II

news2024/11/28 6:53:00

用Java写一个翻译器,将Java的字节码翻译成汇编语言 

目录

程序控制流开发

基本思路

核心代码

实验结果,使用例子进行验证

函数调用

基本思路

核心代码

实验结果,使用例子进行验证

 Parser

CodeWriter

Main


程序控制流开发

基本思路

在project7的基础上将带有控制流的vm字节码翻译成asm汇编文件,既然是翻译,那就是字符串替换问题,在第一部分的程序控制流实现中,我们要做的就是用asm汇编语言实现goto、if-goto和label。

首先是label,这个非常简单,就直接换成(label)就完了。

然后是goto label,这个也简单,拿到label的值直接跳转就行。

最后是if-goto,这个我们首先要搞懂它是什么意思?从课件上可以知道,if-goto的效果是当栈顶元素不为0时发生跳转,并且弹栈。

因此我们首先将栈顶元素取出来,然后栈指针自减,当栈顶元素不为0时跳转。

核心代码

首先是parser类的修改,在代码调试的时候发现这次的vm字节码文件出现了有连续空格的情况,之前的parser没有对这种情况的处理,这次更新一下,增加将连续空格变成单个空格的处理。

然后是parser判断vm指令类型的函数需要增加对label、goto和if-goto指令类型的判断。

然后最主要的就是codeWriter的功能增加,增加了对label、goto和if-goto指令字符串的替换。

然后主函数就是增加对label、goto和if-goto情况的判断即可。

实验结果,使用例子进行验证

首先是BasicLoop的测试,如下图所示,成功通过测试。

然后是斐波那契的测试,如下图所示,成功通过测试,可见控制流的实现通过了。

函数调用

基本思路

首先解决call,这个比较复杂,这个主要是保存在调用函数之前当前程序的状态,主要是LCL、ARG、THIS和THAT,还有函数调用者的返回地址。

接下来我们分别一部分一部分的讲解每一个应该怎么操作。

Push retAddrLabel比较简单,就是将调用者当前的地址保存下来,将调用返回地址压入栈中,当然这个地址需要处理一下,因为我们要区分开每一次调用的label。

对于push LCL/ARG/THIS/THAT的操作是一样的,都是类似于project7中push pointer的操作,即拿到对应的字段值,把它压进栈即可。

对于ARG=SP-5-nArgs,直接翻译,让ARG的值为SP-5-nArgs。

LCL=SP这个也好翻译,而goto functionName就直接跳过去就行了,但是要记得把调用返回地址标号写在后面,因为调用完函数之后要回来。

对于函数定义function functionName nVars,根据课件可知我们需要进行nVars次push constant 0的操作。

因此只需要写上function名字的label后调用nVars次我们之前在project7写的push constant 0的翻译就行了。

对于return而言,基本上就是做的call的反操作,把call时期保存的函数调用者的状态给还原,其中主要的就是拿到函数返回地址以及把之前压入栈的字段值恢复。

因为这个return涉及到的操作很多,我们还是需要一个部分一个部分的讲解。

首先需要一个局部变量拿到我们函数调用之前写入LCL的栈指针的值。

然后根据这个调用前的栈指针的值我们可以拿到之前压入栈的函数返回地址。

然后把函数返回值写入ARG,这里是project7的pop argument 0的操作。

然后是恢复函数调用者时期SP的值。

恢复THAT/THIS/ARG/LCL字段的值。

最后回到函数调用者的地址。

然后是最后两个测试程序需要调用它们的启动函数。

启动函数就是初始化栈指针的值为256,然后调用它们写好的Sys.init函数。

还有根据最后一个测试StaticTest的调试结果可以知道不同vm文件的static字段应该是不一样的,难怪需要setFileName函数的存在,因为我没有这个函数就一直跑不对。

核心代码

parser判断vm指令类型的函数需要增加对call、function和return指令类型的判断。

然后最主要的就是codeWriter的功能增加,增加了对call、function和return指令字符串的替换,其中call和return就一一写入相应的字符串,call还需要区分开每一次调用的地址,因此调用label需要加入序号。

而function的处理,则重复调用project7写的push constant 0进行翻译。

然后主函数就是增加对label、goto和if-goto情况的判断即可。

还有调用启动函数的编写。

因为这里出现了多个vm文件,因此我们需要在主函数里对输入文件路径做一些处理,我们首先创建一个文件容器,先判断这个文件路径是否是单个文件还是一个文件夹,如果是单个文件,把这个文件装进容器。如果是一个文件夹,那么把这个文件夹目录下所有vm文件装进容器。

然后对于容器里的每一个文件都生成一个parser解析器就行解析翻译。

实验结果,使用例子进行验证

SimpleFunction先注释掉我们启动的初始化函数,因为它已经包含了启动函数,测试结果如下图所示,测试成功。

然后是这个非常非常长的斐波那契测试,这里包括了两个vm文件,同时我们启用写好的调用启动函数代码,测试结果如下图所示,成功通过。

然后是最后的考验StaticTest,第一次测试其实是失败的,为什么吗,因为一开始我没有搞懂为什么有个setFileName函数要写,于是我就没写,然后就在这里调试的时候发现,对于不同的vm文件需要不同的static字段,后来重写了project7的pop和push函数,加上了区分不同vm文件的static函数。

然后就终于搞定了。

 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();
            command = command.replaceAll("\\s+", " "); //将连续的空格替换成单个空格
            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 if (Objects.equals(cmd0, "label")) {
            return "C_LABEL";
        } else if (Objects.equals(cmd0, "goto")) {
            return "C_GOTO";
        } else if (Objects.equals(cmd0, "if-goto")) {
            return "C_IF";
        } else if (Objects.equals(cmd0, "call")) {
            return "C_CALL";
        } else if (Objects.equals(cmd0, "function")) {
            return "C_FUNCTION";
        } else if (Objects.equals(cmd0, "return")) {
            return "C_RETURN";
        } else {
            cmd1 = cmd0;
            return "C_ARITHMETIC";
        }
    }

    public String arg1() {
        return cmd1;
    }

    public int arg2() {
        return cmd2;
    }

    public void close() {
        scanner.close();
    }

}

CodeWriter

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 String fileName="";
    private final HashMap<String, String> vmToAsm = new HashMap<>();
    private int jump = 0;

    public CodeWriter(File file) throws IOException {
        asm = new FileWriter(file);
        String fetch = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\n";
        vmToAsm.put("add", fetch + "M=M+D\n");
        vmToAsm.put("sub", fetch + "M=M-D\n");
        vmToAsm.put("and", fetch + "M=M&D\n");
        vmToAsm.put("or", fetch + "M=M|D\n");
        vmToAsm.put("gt", fetch + "D=M-D\n@TRUE\nD;JGT\n@SP\nA=M-1\nM=0\n@END\n0;JMP\n(TRUE)\n@SP\nA=M-1\nM=-1\n(END)\n");
        vmToAsm.put("eq", fetch + "D=M-D\n@TRUE\nD;JEQ\n@SP\nA=M-1\nM=0\n@END\n0;JMP\n(TRUE)\n@SP\nA=M-1\nM=-1\n(END)\n");
        vmToAsm.put("lt", fetch + "D=M-D\n@TRUE\nD;JLT\n@SP\nA=M-1\nM=0\n@END\n0;JMP\n(TRUE)\n@SP\nA=M-1\nM=-1\n(END)\n");
        vmToAsm.put("neg", "D=0\n@SP\nA=M-1\nM=D-M\n");
        vmToAsm.put("not", "@SP\nA=M-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 + "\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
            } else if (Objects.equals(segment, "local")) {
                asmCommand = "@LCL\nD=M\n@" + index + "\nA=D+A\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
            } else if (Objects.equals(segment, "argument")) {
                asmCommand = "@ARG\nD=M\n@" + index + "\nA=D+A\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
            } else if (Objects.equals(segment, "this")) {
                asmCommand = "@THIS\nD=M\n@" + index + "\nA=D+A\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
            } else if (Objects.equals(segment, "that")) {
                asmCommand = "@THAT\nD=M\n@" + index + "\nA=D+A\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
            } else if (Objects.equals(segment, "temp")) {
                asmCommand = "@" + (5 + index) + "\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
            } else if (Objects.equals(segment, "pointer")) {
                if (index == 0) {
                    asmCommand = "@THIS\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
                } else {
                    asmCommand = "@THAT\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
                }
            } else if (Objects.equals(segment, "static")) {
                asmCommand = "@" + fileName+ index + "\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n";
            }
        } else {
            if (Objects.equals(segment, "local")) {
                asmCommand = "@LCL\nD=M\n@" + index + "\nD=D+A\n@255\nM=D\n@SP\nM=M-1\nA=M\nD=M\n@255\nA=M\nM=D\n";
            } else if (Objects.equals(segment, "argument")) {
                asmCommand = "@ARG\nD=M\n@" + index + "\nD=D+A\n@255\nM=D\n@SP\nM=M-1\nA=M\nD=M\n@255\nA=M\nM=D\n";
            } else if (Objects.equals(segment, "this")) {
                asmCommand = "@THIS\nD=M\n@" + index + "\nD=D+A\n@255\nM=D\n@SP\nM=M-1\nA=M\nD=M\n@255\nA=M\nM=D\n";
            } else if (Objects.equals(segment, "that")) {
                asmCommand = "@THAT\nD=M\n@" + index + "\nD=D+A\n@255\nM=D\n@SP\nM=M-1\nA=M\nD=M\n@255\nA=M\nM=D\n";
            } else if (Objects.equals(segment, "temp")) {
                asmCommand = "@SP\nM=M-1\nA=M\nD=M\n@" + (5 + index) + "\nM=D\n";
            } else if (Objects.equals(segment, "pointer")) {
                if (index == 0) {
                    asmCommand = "@SP\nM=M-1\nA=M\nD=M\n@THIS\nM=D\n";
                } else {
                    asmCommand = "@SP\nM=M-1\nA=M\nD=M\n@THAT\nM=D\n";
                }
            } else if (Objects.equals(segment, "static")) {
                asmCommand = "@SP\nM=M-1\nA=M\nD=M\n@" + fileName+ index + "\nM=D\n";
            }
        }
        asm.write(asmCommand);
    }

    public void writeLabel(String label) throws IOException {
        asm.write("(" + label + ")\n");
    }

    public void writeGoto(String label) throws IOException {
        asm.write("@" + label + "\n0;JMP\n");
    }

    public void writeIf(String label) throws IOException {
        asm.write("@SP\nM=M-1\nA=M\nD=M\n@" + label + "\nD;JNE\n");
    }

    public void writeCall(String functionName, int nArgs) throws IOException {
        asm.write("@Caller" + jump + "\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n");
        asm.write("@LCL\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n");
        asm.write("@ARG\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n");
        asm.write("@THIS\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n");
        asm.write("@THAT\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n");
        asm.write("@SP\nD=M\n@5\nD=D-A\n@" + nArgs + "\nD=D-A\n@ARG\nM=D\n");
        asm.write("@SP\nD=M\n@LCL\nM=D\n");
        asm.write("@" + functionName + "\n0;JMP\n(Caller" + jump + ")\n");
        jump++;
    }

    public void writeReturn() throws IOException {
        asm.write("@LCL\nD=M\n@FRAME\nM=D\n");
        asm.write("@5\nA=D-A\nD=M\n@RET\nM=D\n");
        asm.write("@ARG\nD=M\n@0\nD=D+A\n@255\nM=D\n@SP\nM=M-1\nA=M\nD=M\n@255\nA=M\nM=D\n");
        asm.write("@ARG\nD=M\n@SP\nM=D+1\n");
        asm.write("@FRAME\nD=M-1\nAM=D\nD=M\n@THAT\nM=D\n");
        asm.write("@FRAME\nD=M-1\nAM=D\nD=M\n@THIS\nM=D\n");
        asm.write("@FRAME\nD=M-1\nAM=D\nD=M\n@ARG\nM=D\n");
        asm.write("@FRAME\nD=M-1\nAM=D\nD=M\n@LCL\nM=D\n");
        asm.write("@RET\nA=M\n0;JMP\n");
    }

    public void writeFunction(String functionName, int nArgs) throws IOException {
        asm.write("(" + functionName + ")\n");
        for (int i = 0; i < nArgs; i++) {
            writePushPop("C_PUSH", "constant", 0);
        }
    }

    public void writeInit() throws IOException {
        asm.write("@256\nD=A\n@SP\nM=D\n");
        writeCall("Sys.init", 0);
    }

    public void close() throws IOException {
        asm.close();
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }
}

Main

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Objects;

public class Main {
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\Yezi\\Desktop\\Java程序设计\\nand2tetris\\projects\\08\\FunctionCalls\\StaticsTest");
        ArrayList<File> vm = new ArrayList<>();
        CodeWriter codeWriter = new CodeWriter(new File("C:\\Users\\Yezi\\Desktop\\Java程序设计\\nand2tetris\\projects\\08\\FunctionCalls\\StaticsTest\\StaticsTest.asm"));
        codeWriter.writeInit();
        if (file.isFile()) {
            vm.add(file);
        } else {
            for (File one : Objects.requireNonNull(file.listFiles())) {
                if (one.getName().endsWith(".vm")) {
                    vm.add(one);
                }
            }
        }
        for (File one : vm) {
            Parser parser = new Parser(one);
            codeWriter.setFileName(one.getName());
            while (parser.hasMoreCommands()) {
                parser.advance();
                if (Objects.equals(parser.commandType(), "C_ARITHMETIC")) {
                    codeWriter.writeArithmetic(parser.arg1());
                } else if (Objects.equals(parser.commandType(), "C_LABEL")) {
                    codeWriter.writeLabel(parser.arg1());
                } else if (Objects.equals(parser.commandType(), "C_GOTO")) {
                    codeWriter.writeGoto(parser.arg1());
                } else if (Objects.equals(parser.commandType(), "C_IF")) {
                    codeWriter.writeIf(parser.arg1());
                } else if (Objects.equals(parser.commandType(), "C_FUNCTION")) {
                    codeWriter.writeFunction(parser.arg1(), parser.arg2());
                } else if (Objects.equals(parser.commandType(), "C_RETURN")) {
                    codeWriter.writeReturn();
                } else if (Objects.equals(parser.commandType(), "C_CALL")) {
                    codeWriter.writeCall(parser.arg1(), parser.arg2());
                } else {
                    codeWriter.writePushPop(parser.commandType(), parser.arg1(), parser.arg2());
                }
            }
            parser.close();
        }
        codeWriter.close();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1175094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Activiti监听器

文章目录 学习链接任务监听器 TaskListener监听器监听的事件监听器委托类DelegateTask任务监听实现方式 — 类class绘制流程图自定义任务监听器SiteReportUserTaskListener 测试 监听实现方式 — 表达式expression绘制流程图自定义 TaskListenerExpression测试spring表达式 执行…

【MySQL事务篇】MySQL锁机制

MySQL锁机制 文章目录 MySQL锁机制1. 概述2. MySQL并发事务访问相同记录2.1 读-读情况2.2 写-写情况2.3 读-写或写-读情况2.4 并发问题的解决方案 3. 锁的不同角度分类3.1 从数据操作的类型划分&#xff1a;读锁、写锁1. 锁定读2. 写操作 3.2 从数据操作的粒度划分&#xff1a;…

前端框架Vue学习 ——(五)前端工程化Vue-cli脚手架

文章目录 Vue-cliVue项目-创建Vue项目-目录结构Vue项目-启动Vue项目-配置端口Vue项目开发流程 Vue-cli 介绍&#xff1a;Vue-cli 是 Vue 官方提供的一个脚手架&#xff0c;用于快速生成一个 Vue 的项目模版 安装 NodeJS安装 Vue-cli npm install -g vue/cliVue项目-创建 图…

简易线程池开发流程

简易线程池开发 线程池基本结构 #include"threadpool.h" //任务队列 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<strings.h> typedef struct Task {void(*function)(void* arg);void*arg; }Task; //线程池结构体 …

1.UML面向对象类图和关系

文章目录 4种静态结构图类图类的表示类与类之间的关系依赖关系(Dependency)关联关系(Association)聚合(Aggregation)组合(Composition)实现(Realization)继承/泛化(Inheritance/Generalization)常用的UML工具reference欢迎访问个人网络日志🌹🌹知行空间🌹🌹 4种静态结构…

力扣 141.环形链表和142.环形链表2

目录 1.环形链表Ⅰ解题思路2.环形链表Ⅰ代码实现3.环形链表Ⅱ解题思路4.环形链表Ⅱ代码实现 1.环形链表Ⅰ解题思路 利用快慢指针&#xff0c;快指针一次走两个&#xff0c;慢指针一次走一个&#xff0c;如果出现了快指针为空或者快指针的next为空的现象则说明不带环&#xff0…

2023年亚太杯APMCM数学建模大赛ABC题辅导及组队

2023年亚太杯APMCM数学建模大赛 ABC题 一元线性回归分析类 回归分析&#xff08;Regression Analysis)是确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。   – 按涉及变量个数划分   • 一元回归分析   • 多元回归分析   – 按自变量和因变量之间关…

【Python从入门到进阶】41、有关requests代理的使用

接上篇《40、requests的基本使用》 上一篇我们介绍了requests库的基本使用&#xff0c;本篇我们来学习requests的代理。 一、引言 在网络爬虫和数据抓取的过程中&#xff0c;我们经常需要发送HTTP请求来获取网页内容或与远程服务器进行通信。然而&#xff0c;在某些情况下&…

【SpringSecurity6.x】会话管理

只需在两个浏览器中用同一个账号登录就会发现,到目前为止,系统尚未有任何会话并发限制。一个账户能多处同时登录可不是一个好的策略。事实上,Spring Security已经为我们提供了完善的会话管理功能,包括会话固定攻击、会话超时检测以及会话并发控制。 理解会话 会话(sessi…

白标软件:时间与金钱的双赢助手

白标的好处是你不需要从零开始构建一个应用程序。供应商提供软件解决方案&#xff0c;而你提供品牌&#xff0c;并将应用程序包装、市场推广和盈利。 白标软件帮助节省时间和金钱的六种方式&#xff1a; 1、不需要招募软件开发组织或专业人员 传统上&#xff0c;软件开发需要…

腾讯云CVM服务器标准型S5、SA3、S6详细介绍

腾讯云CVM服务器标准型实例的各项性能参数平衡&#xff0c;标准型云服务器适用于大多数常规业务&#xff0c;例如&#xff1a;web网站及中间件等&#xff0c;常见的标准型云服务器有CVM标准型S5、S6、SA3、SR1、S5se等规格&#xff0c;腾讯云服务器网txyfwq.com来详细说下云服务…

腾讯云服务器CVM S5服务器CPU性能测评和优惠价格表

腾讯云服务器CVM标准型S5有活动&#xff0c;CVM 2核2G S5优惠价280.8元一年自带1M带宽&#xff0c;15个月313.2元、2核4G配置748.2元15个月、4核8G配置1437.24元15个月、8核16G优惠价3048.48元15个月&#xff0c;公网带宽可选1M、3M、5M或10M&#xff0c;腾讯云服务器网txyfwq.…

喜讯!极限科技成功签约中国一汽搜索数据库三年许可订阅合同!

中标喜讯&#xff01;极限科技 INFINI Easysearch 成功签约中国第一汽车股份有限公司三年订阅合同&#xff01; 一汽集团作为国内汽车行业龙头企业&#xff0c;数字化转型伴随业务发展不断深化&#xff0c;非结构化数据日益成为各类组织数据的增长主力&#xff0c;逐渐成为数据…

.NET Framework中自带的泛型委托Func

Func<>是.NET Framework中自带的泛型委托&#xff0c;可以接收一个或多个输入参数&#xff0c;并且有返回值&#xff0c;和Action类似&#xff0c;.NET基类库也提供了多达16个输入参数的Func委托&#xff0c;输出参数只有1个。 1、Func泛型委托 .NET Framework为我们提…

C#学习中关于Visual Studio中ctrl+D快捷键(快速复制当前行)失效的解决办法

1、进入VisualStudio主界面点击工具——>再点击选项 2、进入选项界面后点击环境——>再点击键盘&#xff0c;我们可用看到右边的界面的映射方案是VisualC#2005 3、 最后点击下拉框&#xff0c;选择默认值&#xff0c;点击之后确定即可恢复ctrlD的快捷键功能 4、此时可以正…

有限域的Fast Multiplication和Modular Reduction算法实现

1. 引言 关于有限域的基础知识&#xff0c;可参考&#xff1a; RISC Zero团队2022年11月视频 Intro to Finite Fields: RISC Zero Study Club 有限域几乎是密码学中所有数学的基础。 ZKP证明系统中的所有运算都是基于有限域的&#xff1a; 使用布尔运算的数字电路&#xf…

基于单片机的养殖场温度控制系统设计

博主主页&#xff1a;单片机辅导设计 博主简介&#xff1a;专注单片机技术领域和毕业设计项目。 主要内容&#xff1a;毕业设计、简历模板、学习资料、技术咨询。 文章目录 主要介绍一、控制系统设计二、系统方案设计2.1 系统运行方案设计2.1.1 羊舍环境温度的确定 三、 系统仿…

在Windows或Mac上安装并运行LLAMA2

LLAMA2在不同系统上运行的结果 LLAMA2 在windows 上运行的结果 LLAMA2 在Mac上运行的结果 安装Llama2的不同方法 方法一&#xff1a; 编译 llama.cpp 克隆 llama.cpp git clone https://github.com/ggerganov/llama.cpp.git 通过conda 创建或者venv. 下面是通过conda 创建…

基于ssm车位租赁系统+vue(2023年☆全网唯一)【附开发文档|表结构|万字文档(LW)和搭建文档】

主要功能 前台登录&#xff1a; 注册用户&#xff1a;用户账号、密码、姓名、手机号、身份证号、性别、邮箱 用户&#xff1a; ①首页、车位展示、公告展示、查看更多 ②车位类型、车位介绍、车位收藏、留言、我要租赁、公告、留言板 ③个人中心、车位收藏、车位租赁订单、已到…

由于找不到msvcr110.dll,无法继续执行代码。重新安装程序可能会解决此问题,解决方法分享

MSVCR110.dll是Microsoft Visual C 2012 Redistributable的一个组件&#xff0c;它包含了许多运行库文件&#xff0c;这些文件是许多应用程序和游戏所必需的。当您在运行某些程序或游戏时&#xff0c;可能会遇到“msvcr110.dll丢失”的错误提示。这是因为您的计算机上缺少了MSV…