3 条题解

  • 3
    @ 2025-7-10 20:33:20

    这道题我们可以先写一个河童重工的计算机,然后用汇编解决。

    代码如下:

    #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
    上传者