3 条题解
-
3
这道题我们可以先写一个河童重工的计算机,然后用汇编解决。
代码如下:
#include<bits/stdc++.h> using namespace std; void toupper(string& str) { for (char& c : str)c = toupper(c); } string touppers(const string& str) { string a = str; toupper(a); return a; } class AssemblyProgram; class Tokenizer; class Compiler; class AssemblyProgram { public: enum Command { UDEF, // 0: Undefined Undefined HLT, // 1: Halt Stop the program NOP, // 2: NoOp Does nothing SET, // 3: Set Read value from <0> to <1> JMP, // 4: Jump Jump to <0> (absolute line number, begins from 1) JIF, // 5: JumpIf Jump to <0> if <1> is not zero (takes rFlag if <1> doesn't exist) CALL, // 6: Call push current linenum+1 to sAddr and jump to <0>(begins from 1) RET, // 7: Return jump to sAddr.top() and sAddr.pop() // Arithmetic operations // rVal if not exist↓ INV, // 8: Inverse <1> = -<0> ADD, // 9: Add <2> = <0> + <1> SUB, // 10: Minus <2> = <0> - <1> MULT, // 11: Multiply <2> = <0> * <1> IDIV, // 12: IntDivide <2> = <0> / <1> MOD, // 13: Modulo <2> = <0> % <1> LSFT, // 14: LeftShift <2> = <0> << <1> RSFT, // 15: RightShift <2> = <0> >> <1> BAND, // 16: BitAnd <2> = <0> & <1> BOR, // 17: BitOr <2> = <0> | <1> BXOR, // 18: BitXor <2> = <0> ^ <1> // Logical Operations // rFlag if not exist↓ LGR, // 19: Greater <2> = <0> > <1> LLS, // 20: less <2> = <0> < <1> LGE, // 21: GreaterEqual <2> = <0> >= <1> LLE, // 22: LessEqual <2> = <0> <= <1> LEQL, // 23: Equal <2> = <0> == <1> LAND, // 24: LogicalAnd <2> = <0> && <1> LOR, // 25: LogicalOr <2> = <0> || <1> // Console I/O // rVal if no exist↓ RINT, // 26: ReadInt cin >> <0> RCH, // 27: ReadChar getchar(<0>) WINT, // 28: WriteInt cout << <0> WCH // 29: WriteChar putchar(<0>) }; enum VariableType { Constant, Register, Memory, Pointer }; enum RegisterName { R1, R2, R3, R4, E1, E2, E3, E4, Flag, Val, Ret, Line }; struct arg { VariableType type; int val; AssemblyProgram *prog; int line; int* operator()() { if(type == Constant) return &val; if(type == Register) return prog->RegisterList[val]; if(type == Memory) return &(prog->mem[val]); if(type == Pointer) return &(prog->mem[*prog->RegisterList[val]]); } }; struct command { Command command; vector<arg> args; }; RegisterName getRegister(string name) { toupper(name); if(name == "R1") return R1; if(name == "R2") return R2; if(name == "R3") return R3; if(name == "R4") return R4; if(name == "E1") return E1; if(name == "E2") return E2; if(name == "E3") return E3; if(name == "E4") return E4; if(name == "FLAG") return Flag; if(name == "VAL") return Val; if(name == "RET") return Ret; if(name == "LINE") return Line; } Command getCommand(string name) { toupper(name); if(name == "UDEF") return UDEF; if(name == "HLT") return HLT; if(name == "NOP") return NOP; if(name == "SET") return SET; if(name == "JMP") return JMP; if(name == "JIF") return JIF; if(name == "CALL") return CALL; if(name == "RET") return RET; if(name == "INV") return INV; if(name == "ADD") return ADD; if(name == "SUB") return SUB; if(name == "MULT") return MULT; if(name == "IDIV") return IDIV; if(name == "MOD") return MOD; if(name == "LSFT") return LSFT; if(name == "RSFT") return RSFT; if(name == "BAND") return BAND; if(name == "BOR") return BOR; if(name == "BXOR") return BXOR; if(name == "LGR") return LGR; if(name == "LLS") return LLS; if(name == "LGE") return LGE; if(name == "LLE") return LLE; if(name == "LEQL") return LEQL; if(name == "LAND") return LAND; if(name == "LOR") return LOR; if(name == "RINT") return RINT; if(name == "RCH") return RCH; if(name == "WINT") return WINT; if(name == "WCH") return WCH; else return UDEF; } void addCommand(pair<pair<Command, int> , vector<arg> > command) { prog.push_back(command); } void addLine(int line, int rline) { while(line2rline.size() <= line) { line2rline.push_back(rline); } } int getrline(int line) { return line2rline[line]; } void l2rltest() { for(int i = 0;i < line2rline.size();i++) { printf("%d->%d\n", i, line2rline[i]); } } void run() { for(int i = 0;i < 12;i++) { *RegisterList[i] = 0; } memset(mem, 0, sizeof mem); running = true; nextptr = 0; rLine = 1; while(running) { //rLine = prog[nextptr].first.second; funcs[prog[nextptr].first.first](prog[nextptr].second); } } private: int* getRegister(enum RegisterName name) { return RegisterList[name]; } int* getMemory(int id) { return mem + id; } int rR1, rR2, rR3, rR4; int rE1, rE2, rE3, rE4; int rFlag, rVal, rRet, rLine; int *RegisterList[12] = {&rR1, &rR2, &rR3, &rR4, &rE1, &rE2, &rE3, &rE4, &rFlag, &rVal, &rRet, &rLine}; static constexpr int stackSize = 512 * 1024; stack<int> sAddr; static constexpr int memSize = 16 * 1024 * 1024; int mem[memSize]; bool running; int nextptr; vector<pair<pair<Command, int> , vector<arg> > > prog; void pushAddr(int val) { sAddr.push(val); } int topAddr() { return sAddr.top(); } void popAddr() { return sAddr.pop(); } vector<int> line2rline; #define setfunc [&](vector<arg> args) -> void #define setcalrtd(x) int *rt; if(args.size() <= x) rt = &rVal; else rt = args[x]() #define setlogrtd(x) int *rt; if(args.size() <= x) rt = &rFlag; else rt = args[x]() #define setI_Ortd(x) int *rt; if(args.size() <= x) rt = &rVal; else rt = args[x]() function<void(vector<arg>)> funcs[30] = { /*00.UDEF*/ setfunc { nextptr++; }, /*01.HLT*/ setfunc { running = false; }, /*02.NOP*/ setfunc { nextptr++; }, /*03.SET*/ setfunc { *args[1]() = *args[0](); nextptr++; }, /*04.JMP*/ setfunc { nextptr = getrline(*args[0]() + rLine); }, /*05.JIF*/ setfunc { if(args.size() <= 1) { if(rFlag) nextptr = getrline(*args[0]() + rLine); else nextptr++; } else { if(*args[1]()) nextptr = getrline(*args[0]() + rLine); else nextptr++; } }, /*06.CALL*/ setfunc { pushAddr(rLine); pushAddr(nextptr + 1) ; nextptr = getrline(*args[0]()) ; rLine = (*args[0]()) ; }, /*07.RET*/ setfunc { if(args.size() > 0) {rRet = *args[0]();} nextptr = topAddr(); popAddr(); rLine = topAddr(); popAddr(); }, /*08.INV*/ setfunc { setcalrtd(1); *rt = -(*args[0]()); nextptr++; }, /*09.ADD*/ setfunc { setcalrtd(2); *rt = (*args[0]()) + (*args[1]()); nextptr++; }, /*10.SUB*/ setfunc { setcalrtd(2); *rt = (*args[0]()) - (*args[1]()); nextptr++; }, /*11.MULT*/ setfunc { setcalrtd(2); *rt = (*args[0]()) * (*args[1]()); nextptr++; }, /*12.IDIV*/ setfunc { setcalrtd(2); *rt = (*args[0]()) / (*args[1]()); nextptr++; }, /*13.MOD*/ setfunc { setcalrtd(2); *rt = (*args[0]()) % (*args[1]()); nextptr++; }, /*14.LSFT*/ setfunc { setcalrtd(2); *rt = ((*args[0]()) << (*args[1]())); nextptr++; }, /*15.RSFT*/ setfunc { setcalrtd(2); *rt = ((*args[0]()) >> (*args[1]())); nextptr++; }, /*16.BAND*/ setfunc { setcalrtd(2); *rt = ((*args[0]()) & (*args[1]())); nextptr++; }, /*17.BOR*/ setfunc { setcalrtd(2); *rt = ((*args[0]()) | (*args[1]())); nextptr++; }, /*18.BXOR*/ setfunc { setcalrtd(2); *rt = ((*args[0]()) ^ (*args[1]())); nextptr++; }, /*19.LGR*/ setfunc { setlogrtd(2); *rt = ((*args[0]()) > (*args[1]())); nextptr++; }, /*20.LLS*/ setfunc { setlogrtd(2); *rt = ((*args[0]()) < (*args[1]())); nextptr++; }, /*21.LGE*/ setfunc { setlogrtd(2); *rt = ((*args[0]()) >= (*args[1]())); nextptr++; }, /*22.LLE*/ setfunc { setlogrtd(2); *rt = ((*args[0]()) <= (*args[1]())); nextptr++; }, /*23.LEQL*/ setfunc { setlogrtd(2); *rt = ((*args[0]()) == (*args[1]())); nextptr++; }, /*24.LAND*/ setfunc { setlogrtd(2); *rt = ((*args[0]()) && (*args[1]())); nextptr++; }, /*25.LOR*/ setfunc { setlogrtd(2); *rt = ((*args[0]()) || (*args[1]())); nextptr++; }, /*26.RINT*/ setfunc { setI_Ortd(0); scanf("%d", rt); nextptr++; }, /*27.RCH*/ setfunc { setI_Ortd(0); char c; scanf("%c", &c); *rt = c; nextptr++; }, /*28.WINT*/ setfunc { setI_Ortd(0); printf("%d", *rt); nextptr++; }, /*29.WCH*/ setfunc { setI_Ortd(0); printf("%c", (char)*rt); nextptr++; }, }; #undef setfunc #undef setrtd }; class Tokenizer { public: enum Type { Unknown, Identifier, Number, Symbol }; struct Token { Type type; string words; int line; }; void parseSource(string source) { tokens = parse(source); nextid = 0; } Token next() { if(nextid >= tokens.size()) return Token{Unknown, ""}; else return tokens[nextid++]; } /// @brief parse source code /// @param str source code /// @return parsed code static vector<Token> parse(const string &str) { vector<Token> tokens; Token buffer = {Unknown, "", 1}; int commentLayers = 0; int curline = 1; for(char c : str) { if(c == '[') { commentLayers++; } else if(c == ']') { if(commentLayers > 0) commentLayers--; } else if(commentLayers <= 0) { if(!(isblank(c) || iscntrl(c) || c == ',')) { if ((buffer.type == Number && !isdigit(c)) || (buffer.type == Identifier && (!isalnum(c) && c != '_')) || (buffer.type == Symbol && (isalnum(c) || c == '_' || c == '-'))) { //type has changed buffer.line = curline; tokens.push_back(buffer); buffer = Token{ Unknown, "" }; } if(buffer.type == Unknown) { //check new object type if(isalpha(c) || c == '_') buffer.type = Identifier; else if(isdigit(c) || c == '-') buffer.type = Number; else buffer.type = Symbol; } buffer.words.push_back(c); } else { if(buffer.type != Unknown) { buffer.line = curline; tokens.push_back(buffer); buffer = Token{Unknown, ""}; } } } if(c == '\n') { curline++; } } if(buffer.type != Unknown) { buffer.line = curline; tokens.push_back(buffer); } return tokens; } void test() { for(auto i : tokens) { cout<<i.words; } } private: vector<Token> tokens; int nextid; }; class Compiler { public: struct Command { int line; string command; vector<Tokenizer::Token> args; int rline; bool resetLine = false; }; void compile(Tokenizer &tokens) { bool ok = true; while(ok) { // 每次循环处理一条指令及其参数 Tokenizer::Token now; while(ok && (now = tokens.next()).type != Tokenizer::Identifier) { if(now.type == Tokenizer::Unknown) { ok = false; } } string command = now.words; vector<Tokenizer::Token> args; Tokenizer::Token cur; bool needPushCommand = true; while(ok && (cur = tokens.next()).words != ";") { if(cur.type == Tokenizer::Unknown) { ok = false; } else if(cur.type == Tokenizer::Symbol && cur.words == "$" && touppers(command) == "FUNCTION") { Tokenizer::Token func = tokens.next(); funcStartLines.insert(make_pair(func.words, now.line)); auto vec = Tokenizer::parse("#LINE %LINE"); for(auto &i : vec) { i.line = now.line; } commands.push_back(Command{now.line, "SET", vec, 0, true}); needPushCommand = false; } args.push_back(cur); } if(ok && needPushCommand) { commands.push_back(Command{now.line, command, args}); } } } void generateCode(AssemblyProgram &prog) { int rline = 0; for(auto &i : commands) { if(!l2rl[i.line]) l2rl[i.line] = rline; i.rline = rline; rline++; } rline = 0; for(auto i = commands.begin();i != commands.end();i++, rline++) { vector<AssemblyProgram::arg> args; string command = i->command; if(i->resetLine) rline = 0; auto j = i->args.begin(); auto nextToken = [&]() -> Tokenizer::Token { j++; if(j == i->args.end()) return Tokenizer::Token { Tokenizer::Unknown }; else return *j; }; for( ;j != i->args.end();nextToken()) { auto cur = *j; if(cur.type == Tokenizer::Number) { args.push_back(AssemblyProgram::arg{AssemblyProgram::Constant, atoi(cur.words.c_str()), &prog, i->line}); } else if(cur.type == Tokenizer::Symbol) { if(cur.words == "%") { Tokenizer::Token reg = nextToken(); args.push_back(AssemblyProgram::arg{AssemblyProgram::Register, prog.getRegister(reg.words), &prog, i->line}); } else if(cur.words == "@") { Tokenizer::Token reg = nextToken(); args.push_back(AssemblyProgram::arg{AssemblyProgram::Memory, atoi(reg.words.c_str()), &prog, i->line}); } else if(cur.words == "@%") { Tokenizer::Token reg = nextToken(); args.push_back(AssemblyProgram::arg{AssemblyProgram::Pointer, prog.getRegister(reg.words), &prog, i->line}); } else if(cur.words == "#") { Tokenizer::Token reg = nextToken(); args.push_back(AssemblyProgram::arg{AssemblyProgram::Constant, cur.line, &prog, i->line}); } else if(cur.words == "$") { command = "CALL"; Tokenizer::Token reg = nextToken(); args.push_back(AssemblyProgram::arg{AssemblyProgram::Constant, funcStartLines[reg.words], &prog, i->line}); } } } prog.addCommand(make_pair(make_pair(prog.getCommand(command), i->line), args)); } for(auto i : l2rl) { prog.addLine(i.first, i.second); } } void test() { for(auto i : l2rl) { cout << i.first << ' ' << i.second << endl; } } private: vector<Command> commands; map<string, int> funcStartLines; map<int, int> l2rl; }; AssemblyProgram prog; Tokenizer tokens; Compiler compiler; int main() { int n = 5; string str; string total = "5\nrint %r1;\nrint %r2;\nadd %r1 %r2;\nwint;\nhlt;\n"; tokens.parseSource(total); compiler.compile(tokens); compiler.generateCode(prog); prog.run(); return 0; }
信息
- ID
- 9
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 3
- 标签
- 递交数
- 3328
- 已通过
- 1674
- 上传者