钾肥喵的窝

我在 CODING 部署的 Hexo 博客

0%

题解-【P4911】-河童重工的计算机

题面

P4911 河童重工的计算机

另外一组样例

样例来自题面中的汇编教程附带示例, 删去了空行, 懒得编数据了, 所以就没有写读入数据部分.

样例看不懂也没关系, 下面是用C++的语句转换的程序, 为了方便对应行号, 转换后的样例删去了第一个空行, 同时每条语句前加上了操作码.

架构设计

写大模拟应该做什么?
当然是跑路啊, 不跑路还留下来秃头吗?
当然是先分析需求, 设计基本架构啊.

首先观察指令格式, 可以发现一个操作至多只有三个变量(开个数组就完事了).

再来观察变量, 一些类型的变量需要读写寄存器或者内存, 存个指针就可以了, 另一些变量是常量, 标记一下即可.

接下来观察内存和栈, 根据文档可知, 直接开个数组模拟即可.

如何将指令与操作联系起来呢? 我们只要给每种指令编号, 用编号去访问不同的函数就可以了, 开个map<string, int> 就可以了.

读入预处理

首先我们先预处理一下所有指令, 统一转换成小写字母.

1
transform(line.begin(), line.end(), line.begin(), ::tolower);

接下来我们处理注释, 并且给语句分行(应对一行多条语句的情况, 虽然测试数据中貌似并没有这种情况), 顺便还能处理一下变量间可能出现的逗号.

对于注释很简单, 根据未配对的中括号个数就能很容易的判断在不在注释里, 用erase()删除即可, 需要注意的是删除之后迭代器要减一, 否则无法遍历所有字符.

分号代表语句的结束, 利用stringstream的特性, 这里我们把它换成’\n’.

逗号很简单, 换成空格即可.

读入指令

预处理完之后, 我们就获得一个便于处理的string了, 首先存入stringstream, 然后每次读取一行, 就获得了一条指令, 需要注意的是这里可能获得空行, 应该加以判断.

对于每条指令, 操作是必然存在的, 直接无脑读即可, 但是变量个数可能是不确定的, 这里继续利用stringstream的特性来处理.

对于一个变量, 如果它不是常量, 我们直接储存对应指针, 如果是常量, 存储它的值. 具体的处理逻辑在data结构体中的init()函数中.

因为代码太长了, 所以请看完整代码中的对应部分.

函数指针数组

把操作码当作下标访问对应的函数即可.

1
2
3
4
5
6
7
8
void (*fun[])(const op &a, int &index) = {
fun0, fun1, fun2, fun3, fun4, fun5, fun6, fun7, fun8, fun9,
fun10, fun11, fun12, fun13, fun14, fun15, fun16, fun17, fun18, fun19,
fun20, fun21, fun22, fun23, fun24, fun25, fun26, fun27, fun28, fun29,
fun30, fun31
};
//example
fun[ops[i].op](ops[i], i);

对应函数

按照题意模拟即可

完整代码