4 条题解

  • 1
    @ 2025-7-10 20:41:14

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

    #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;\nadd %val %val;\nwint;\nwch 32;\nmult %r1 %r2;\nwint;\nhlt;\n";
    
        tokens.parseSource(total);
        compiler.compile(tokens);
        compiler.generateCode(prog);
        prog.run();
    
    
        return 0;
    }
    

    信息

    ID
    10
    时间
    1000ms
    内存
    128MiB
    难度
    5
    标签
    递交数
    1738
    已通过
    692
    上传者