#P2324. 第1题-汇编作业
-
ID: 1538
Tried: 2104
Accepted: 628
Difficulty: 3
所属公司 :
华为
时间 :2024年5月8日-暑期实习
第1题-汇编作业
题面解释:
这道题要求我们设计一个简单的虚拟机解释器,能够解析和执行一系列虚拟指令。虚拟机包含32个32位的整形寄存器(a0到a31),并且只使用寄存器和立即数进行计算。指令可以分为几种类型:MOV dst src
用于将源(src)赋值给目标寄存器(dst);ADD dst src0 src1
将两个源相加;SUB dst src0 src1
将第一个源减去第二个源;MUL dst src0 src1
将两个源相乘;DIV dst src0 src1
将第一个源除以第二个源并向下取整;PRINT dst
用于输出目标寄存器的值。输入为若干行指令,输出为对每条PRINT指令的寄存器值。
思路
模拟题,根据题意模拟即可。
需要注意的几个点:
- 题目并未事先确定输入的行数,所以需要读到末尾 EOF 为止
- 在进行 ADD 和 SUB 操作时,并不知道两个数是以寄存器形式还是立即数形式给出,所以需要判断出来,然后获取到对应的数值进行计算即可
- 除法操作下取整,C++ 的除法是向零取整,需要自行处理成向下取整
时间复杂度:O(n) ,n 为输入的行数
题解
本题要求我们实现一个简单的虚拟机解释器,能够解析和执行一系列指令。虚拟机的核心在于32个整形寄存器(a0到a31),我们可以使用寄存器和立即数进行计算。指令包括移动数据、加法、减法、乘法、除法以及打印寄存器的值。我们的任务是根据输入的指令,正确地修改寄存器的值,并在遇到PRINT指令时输出相应的寄存器值。
主要操作说明
- MOV 指令:将源的值(寄存器或立即数)赋给目标寄存器。
- ADD、SUB、MUL、DIV 指令:分别执行加法、减法、乘法和除法操作,结果存入目标寄存器。特别地,DIV指令需要向下取整,确保结果正确。
- PRINT 指令:打印指定寄存器的值。
输入输出
- 输入:程序通过标准输入逐行读取指令,直到EOF为止。
- 输出:对于每条PRINT指令,输出目标寄存器的当前值。
特殊情况处理
- 在进行加法、减法、乘法和除法操作时,源值可能是寄存器或立即数,因此需要判断并获取正确的值。
- 为了实现向下取整的除法,需要使用
floor
函数来处理整除。
代码
C++
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
// 获取寄存器或立即数的ID(从字符串的第二个字符开始转为整数)
int getIds(string dstSrc) {
return stoi(dstSrc.substr(1));
}
// 从源字符串中获取值
int getValueFromSrcStr(string src, int dst[]) {
// 如果来源是寄存器(以字母'a'开头)
if (src[0] == 'a') {
return dst[getIds(src)]; // 返回对应寄存器的值
}
// 如果来源是立即数,直接转为整数返回
return stoi(src); // 将字符串转为整数
}
// 寄存器数组,全局变量,初始化为0
int dst[32];
int main() {
// 读取用户输入
string op; // 用于存储当前指令
// 将寄存器数组初始化为0
memset(dst, 0, sizeof(dst));
// 循环读取指令直到输入结束
while (cin >> op) { // 读取每一条指令
if (op == "MOV") {
// MOV指令,获取目标寄存器和源值
string dstStr, src; // 目标寄存器和源值字符串
cin >> dstStr >> src; // 读取目标寄存器和源
dst[getIds(dstStr)] = getValueFromSrcStr(src, dst); // 执行赋值操作
} else if (op == "ADD") {
// ADD指令,获取目标寄存器和两个源值
string dstStr, src0, src1; // 目标寄存器和两个源
cin >> dstStr >> src0 >> src1; // 读取数据
dst[getIds(dstStr)] = getValueFromSrcStr(src0, dst) + getValueFromSrcStr(src1, dst); // 执行加法
} else if (op == "SUB") {
// SUB指令,获取目标寄存器和两个源值
string dstStr, src0, src1; // 目标寄存器和两个源
cin >> dstStr >> src0 >> src1; // 读取数据
dst[getIds(dstStr)] = getValueFromSrcStr(src0, dst) - getValueFromSrcStr(src1, dst); // 执行减法
} else if (op == "MUL") {
// MUL指令,获取目标寄存器和两个源值
string dstStr, src0, src1; // 目标寄存器和两个源
cin >> dstStr >> src0 >> src1; // 读取数据
dst[getIds(dstStr)] = getValueFromSrcStr(src0, dst) * getValueFromSrcStr(src1, dst); // 执行乘法
} else if (op == "DIV") {
// DIV指令,获取目标寄存器和两个源值,并进行整除
string dstStr, src0, src1; // 目标寄存器和两个源
cin >> dstStr >> src0 >> src1; // 读取数据
dst[getIds(dstStr)] = (int)floor((double)getValueFromSrcStr(src0, dst) / getValueFromSrcStr(src1, dst)); // 执行向下取整的除法
} else {
// PRINT指令,打印目标寄存器的值
string dstStr; // 目标寄存器
cin >> dstStr; // 读取目标寄存器
cout << dst[getIds(dstStr)] << endl; // 输出寄存器的值
}
}
return 0; // 程序结束
}
Python
def get_ids(dst_src):
# 提取寄存器编号
return int(dst_src[1:])
def get_value_from_src_str(src):
# 来源是寄存器
if src[0] == 'a':
return dst[get_ids(src)]
# 来源是立即数
return int(src)
dst = [0] * 32 # 初始化寄存器数组
def main():
import sys
input = sys.stdin.read
data = input().strip().split("\n")
for line in data:
parts = line.split()
op = parts[0] # 操作码
if op == "MOV":
dst_str, src = parts[1], parts[2]
# 将 src 的值移动到目标寄存器
dst[get_ids(dst_str)] = get_value_from_src_str(src)
elif op == "ADD":
dst_str, src0, src1 = parts[1], parts[2], parts[3]
# 执行加法运算
dst[get_ids(dst_str)] = get_value_from_src_str(src0) + get_value_from_src_str(src1)
elif op == "SUB":
dst_str, src0, src1 = parts[1], parts[2], parts[3]
# 执行减法运算
dst[get_ids(dst_str)] = get_value_from_src_str(src0) - get_value_from_src_str(src1)
elif op == "MUL":
dst_str, src0, src1 = parts[1], parts[2], parts[3]
# 执行乘法运算
dst[get_ids(dst_str)] = get_value_from_src_str(src0) * get_value_from_src_str(src1)
elif op == "DIV":
dst_str, src0, src1 = parts[1], parts[2], parts[3]
# 执行除法运算,向下取整
dst[get_ids(dst_str)] = get_value_from_src_str(src0) // get_value_from_src_str(src1)
else:
dst_str = parts[1]
# 输出寄存器的值
print(dst[get_ids(dst_str)])
if __name__ == "__main__":
main()
Java
import java.util.Arrays; // 导入数组工具类
import java.util.Scanner; // 导入扫描器类用于输入
public class Main {
// 从寄存器或立即数字符串中获取寄存器的索引
private static int getIds(String dstSrc) {
return Integer.parseInt(dstSrc.substring(1)); // 将字符串从第二个字符开始转换为整数
}
// 根据源字符串获取对应的值
private static int getValueFromSrcStr(String src) {
// 如果来源是寄存器(以字母'a'开头)
if (src.charAt(0) == 'a') {
return dst[getIds(src)]; // 返回对应寄存器的值
}
// 如果来源是立即数,直接转为整数返回
return Integer.parseInt(src); // 将字符串转为整数
}
// 定义全局的寄存器数组,长度为32
static int[] dst = new int[32];
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // 创建扫描器对象用于输入
Arrays.fill(dst, 0); // 将寄存器数组初始化为0
// 循环读取输入直到结束
while (scanner.hasNext()) {
String op = scanner.next(); // 读取当前指令
if (op.equals("MOV")) { // 如果是MOV指令
String dstStr = scanner.next(); // 读取目标寄存器
String src = scanner.next(); // 读取源值
dst[getIds(dstStr)] = getValueFromSrcStr(src); // 将源值赋给目标寄存器
} else if (op.equals("ADD")) { // 如果是ADD指令
String dstStr = scanner.next(); // 读取目标寄存器
String src0 = scanner.next(); // 读取第一个源值
String src1 = scanner.next(); // 读取第二个源值
// 执行加法操作并将结果存入目标寄存器
dst[getIds(dstStr)] = getValueFromSrcStr(src0) + getValueFromSrcStr(src1);
} else if (op.equals("SUB")) { // 如果是SUB指令
String dstStr = scanner.next(); // 读取目标寄存器
String src0 = scanner.next(); // 读取第一个源值
String src1 = scanner.next(); // 读取第二个源值
// 执行减法操作并将结果存入目标寄存器
dst[getIds(dstStr)] = getValueFromSrcStr(src0) - getValueFromSrcStr(src1);
} else if (op.equals("MUL")) { // 如果是MUL指令
String dstStr = scanner.next(); // 读取目标寄存器
String src0 = scanner.next(); // 读取第一个源值
String src1 = scanner.next(); // 读取第二个源值
// 执行乘法操作并将结果存入目标寄存器
dst[getIds(dstStr)] = getValueFromSrcStr(src0) * getValueFromSrcStr(src1);
} else if (op.equals("DIV")) { // 如果是DIV指令
String dstStr = scanner.next(); // 读取目标寄存器
String src0 = scanner.next(); // 读取第一个源值
String src1 = scanner.next(); // 读取第二个源值
// 执行除法操作,向下取整并将结果存入目标寄存器
dst[getIds(dstStr)] = (int)Math.floor((double) getValueFromSrcStr(src0) / getValueFromSrcStr(src1));
} else { // 如果是PRINT指令
String dstStr = scanner.next(); // 读取目标寄存器
System.out.println(dst[getIds(dstStr)]); // 输出寄存器的值
}
}
scanner.close(); // 关闭扫描器
}
}
javaScript
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
let dst = new Array(32).fill(0); // 32个寄存器,初始化为0
// 从寄存器或立即数字符串中获取寄存器索引
function getIds(dstSrc) {
return parseInt(dstSrc.substring(1)); // 截取寄存器编号并转换为整数
}
// 获取寄存器的值或立即数
function getValueFromSrcStr(src) {
return src[0] === 'a' ? dst[getIds(src)] : parseInt(src);
}
// 处理指令
while (true) {
let line = await readline();
if (!line) break;
let parts = line.split(" ");
let op = parts[0]; // 指令名
if (op === "MOV") {
let dstStr = parts[1], src = parts[2];
dst[getIds(dstStr)] = getValueFromSrcStr(src);
} else if (op === "ADD") {
let dstStr = parts[1], src0 = parts[2], src1 = parts[3];
dst[getIds(dstStr)] = getValueFromSrcStr(src0) + getValueFromSrcStr(src1);
} else if (op === "SUB") {
let dstStr = parts[1], src0 = parts[2], src1 = parts[3];
dst[getIds(dstStr)] = getValueFromSrcStr(src0) - getValueFromSrcStr(src1);
} else if (op === "MUL") {
let dstStr = parts[1], src0 = parts[2], src1 = parts[3];
dst[getIds(dstStr)] = getValueFromSrcStr(src0) * getValueFromSrcStr(src1);
} else if (op === "DIV") {
let dstStr = parts[1], src0 = parts[2], src1 = parts[3];
dst[getIds(dstStr)] = Math.floor(getValueFromSrcStr(src0) / getValueFromSrcStr(src1));
} else if (op === "PRINT") {
let dstStr = parts[1];
console.log(dst[getIds(dstStr)]);
}
}
rl.close();
})();
题目描述
小明这学期有一门专业必修课,叫做汇编语言,这不准备结课了嘛,老师布置了一个大作业,要求设计一种虚拟机解释器,能解析并执行以下虚拟指令。
虚拟机约定:32位的整形寄存器有a0,a1,..a31,共32个寄存器;
整个虚拟机只有寄存器和立即数参与计算。
规则集(dst一定为寄存器,src为寄存器或十进制正整数,运算结果存在负数场景):
(1)MOV dst src含义:dst = src
(2)ADD dst src0 src1含义:dst = src0 + src1
(3)SUB dst src0 src1含义:dst = src0 - src1
(4)MUL dst src0 src1含义:dst = src0 * src1
(5)DIV dst src0 src1含义:dst = src0 / src1(结果向下取整)
(6)PRINT dst含义:打印dst寄存器值
规定:不用考虑计算溢出(用例保证),指令数最多100条,至少一条PRINT指令,寄存器保证先赋值再引用。不用考虑小数以及除0错误。
输入描述
若干行,每行一条指令
输出描述
对输入的每行指令,若为PRINT指令,则输出打印一行,该行中包括一个整数,表示寄存器的值
样例一
输入
MOV a1 100
MOV a2 200
ADD a3 a1 100
SUB a4 a3 a2
PRINT a4
输出
0
解释
a1=100
a2=200
a3=a1(100)+100=200a4=a3(200)-a2(200)=0
样例二
输入
MOV a1 100
MOV a2 200
PRINT a1
ADD a3 a1 100
SUB a4 a3 a2
PRINT a4
输出
100
0
Limitation
1s, 1024KiB for each test case.