1 条题解

  • 0
    @ 2025-8-24 22:05:11

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Edgaru089
    **

    搬运于2025-08-24 22:05:11,当前版本为作者最后更新于2018-10-05 08:44:02,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    完整的阅读体验见 https://blog.edgaru089.ml/index.php/oi/problem/luogu-p4911-ktx-65-solution/

    作为出题人,我有责任写一篇题解(逃

    这题的初衷就是一个庞大的大模拟,刚刚见到未来程序改这道题有着一种自然的熟悉感呢(笑)

    但是不像那道题,这道题没有什么语义树之类的高深的东西呢,只有对代码能力的考察,像我这种初中三年荒废在搞项目的人,代码功底还可以说是十分扎实的呢(笑)

    关心一下注释的格式:

    注释是可以嵌套的,像 [[] putchar 65; ] 这样的根本不会有什么输出呢

    标程中,我是用std::function存下每一个指令对应的处理函数,然后解释调用

    第一步,先把程序分拆成tokens,去掉注释,记录行号和function定义位置,替换为set指令 第二步,把tokens转换成指令和数据源,同时替换callfunc为call指令

    最后别忘了,call和ret时栈中要压入调用处指令地址和当前的%line寄存器的值这两个值呢

    以下是标程(八月就定稿了

    /* Ktx-65 Assembly Language Interpreter */
    /* Ktx-65 汇编语言解释器 */
    /* Copyright (c) Kawasiro Nitori & Moriya Suwano of Kappa Heavy Industries Co.,Ltd. */
    /* 版权所有 河童重工业会社 河城荷取 洩矢诹访子 */
    
    /* 版本:审议稿 */
    /* 平成三十年 八月 十一日 */
    
    
    #include <cstdlib>
    #include <iostream>
    #include <stack>
    #include <functional>
    #include <map>
    #include <vector>
    #include <initializer_list>
    #include <string>
    #include <fstream>
    #include <cstring>
    using namespace std;
    
    
    bool compileErrorLevel = false;
    void compileError(int line, string message) {
        // TODO Compile Error
        cout << "[ERROR] Interpreter encountered a Compile Error on line " << line << endl;
        cout << "    Message: " << message << endl;
        compileErrorLevel = true;
    }
    
    #define compileAssert(line, statement, message) \
    (!!(statement) || [](int l, string state, string m)->bool {compileError(l, "Compile Assertation Failed: " + m + ", Statement: " + state); return false; }(line, #statement, message))
    
    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 {
    public:
    
        enum Command {
            Undefined = 0,  // Undefined
            Halt = 1,       // Stops the program
            NoOp,           // Does nothing
            // Memory Access
            Set,            // Read value from <0> into <1>
            // Streamline control
            Jump,           // Jump to <0>(absolute line number, begins from 1)
            JumpIf,         // Jump to <0> if <1> is not zero (takes rFlag if <1> doesn't exist)
            Call,           // push current linenum+1 to sAddr and jump to <0>(begins from 1)
            Return,         // jump to sAddr.top() and sAddr.pop()
            // Arithmetic operations
            // rVal if not exist↓
            Inverse,        // <1> = -<0>
            Add,            // <2> = <0> + <1>
            Minus,          // <2> = <0> - <1>
            Multiply,       // <2> = <0> * <1>
            IntDivide,      // <2> = <0> / <1>
            Modulo,         // <2> = <0> % <1>
            LeftShift,      // <2> = <0> << <1>
            RightShift,     // <2> = <0> >> <1>
            BitAnd,         // <2> = <0> & <1>
            BitOr,          // <2> = <0> | <1>
            BitXor,         // <2> = <0> ^ <1>
            // Logical Operations
            // rFlag if not exist↓
            Greater,        //  <2> = <0> > <1>
            Less,           //  <2> = <0> < <1>
            GreaterEqual,   //  <2> = <0> >= <1>
            LessEqual,      //  <2> = <0> <= <1>
            Equal,          //  <2> = <0> == <1>
            LogicalAnd,     //  <2> = <0> && <1>
            LogicalOr,      //  <2> = <0> || <1>
            // Console I/O
            //        rVal if not exist ¡ý
            ReadInt,        //  cin >> <0>
            ReadChar,       // getchar(<0>)
            WriteInt,       // cout << <0>
            WriteChar,      // putchar(<0>)
            // Keep at last - command count
            CommandCount
        };
    
        enum VariableType {
            Constant,
            Pointer,
            Memory
        };
    
        struct DataSource {
            int* valptr;
            int valconst;
            int* valmemidptr;
            AssemblyProgram* prog;
            VariableType type;
            int& operator ()() {
                if (type == Constant)
                    return valconst;
                else if (type == Pointer)
                    return *valptr;
                else {
                    int id = *valmemidptr;
                    if (id >= memsize || id < 0) {
                        prog->runtimeError("Memory acess out of range");
                        valconst = 0;
                        return valconst;
                    }
                    return prog->mem[id];
                }
            }
        };
    
        void halt() {
            // TODO Halt
            running = false;
        }
    
        void runtimeError(string message) {
            // TODO Runtime Error
            cout << "[ERROR] Interpreter encountered a Runtime Error on instruction " << nextptr + 1 << ", clock cycle " << clockCounter << endl;
            cout << "    Message: " << message << endl;
            running = false;
        }
    
    private:
        // Exception-Safe Wrappers
        void pushAddr(int val) { if (sAddr.size() >= stackSize)runtimeError("sAddr Stack Overflow"); sAddr.push(val); }
        int topAddr() { if (sAddr.size() <= 0) { runtimeError("sAddr Access Error(size = 0)"); return 0; } else return sAddr.top(); }
        void popAddr() { if (sAddr.size() <= 0)runtimeError("sAddr Stack Underflow"); else sAddr.pop(); }
        int popAddrRet() { if (sAddr.size() <= 0) { runtimeError("sAddr Stack Underflow"); return 0; } else { int val = sAddr.top(); sAddr.pop(); return val; } }
        int readMem(int id) { if (id >= memsize || id < 0) { runtimeError("Memory Access Error(Read)"); return 0; } else return mem[id]; }
        void writeMem(int id, int val) { if (id >= memsize || id < 0)runtimeError("Memory Access Error(Write)"); else mem[id] = val; }
        int lineProgramId(int line) { auto i = commandLines.find(line); if (i == commandLines.end()) { runtimeError("Jump Line Number Invalid"); return 0; } else return i->second; }
    
    private:
        // Command Handlers
        void funcSet(vector<DataSource>& l) { l[1]() = l[0](); nextptr++; }
        void funcJmp(vector<DataSource>& l) { nextptr = lineProgramId(l[0]() + rLine); }
        void funcJIf(vector<DataSource>& l) { if (l.size() <= 1) { if (rFlag)nextptr = l[0]() + lineProgramId(rLine); else nextptr++; } else { if (l[1]())nextptr = l[0]() + lineProgramId(rLine); else nextptr++; } }
        void funcCall(vector<DataSource>& l) { pushAddr(rLine); pushAddr(nextptr + 1); nextptr = lineProgramId(l[0]()); }
        void funcRet(vector<DataSource>& l) { if (l.size() > 0)rRet = l[0](); nextptr = popAddrRet(); rLine = popAddrRet(); }
        void funcInv(vector<DataSource>& l) { int* p;  if (l.size() <= 1)p = &rVal; else p = &l[1](); (*p) = -l[0](); nextptr++; }
        void funcAdd(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() + l[1](); nextptr++; }
        void funcSub(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() - l[1](); nextptr++; }
        void funcMult(vector<DataSource>& l) { int* p; if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() * l[1](); nextptr++; }
        void funcIDiv(vector<DataSource>& l) { int* p; if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() / l[1](); nextptr++; }
        void funcMod(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() % l[1](); nextptr++; }
        void funcLSft(vector<DataSource>& l) { int* p; if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() << l[1](); nextptr++; }
        void funcRSft(vector<DataSource>& l) { int* p; if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() >> l[1](); nextptr++; }
        void funcBAnd(vector<DataSource>& l) { int* p; if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() & l[1](); nextptr++; }
        void funcBOr(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() | l[1](); nextptr++; }
        void funcBXor(vector<DataSource>& l) { int* p; if (l.size() <= 2)p = &rVal; else p = &l[2](); (*p) = l[0]() ^ l[1](); nextptr++; }
        void funcLGr(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rFlag; else p = &l[2](); (*p) = l[0]() > l[1](); nextptr++; }
        void funcLLs(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rFlag; else p = &l[2](); (*p) = l[0]() < l[1](); nextptr++; }
        void funcLGE(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rFlag; else p = &l[2](); (*p) = l[0]() >= l[1](); nextptr++; }
        void funcLLE(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rFlag; else p = &l[2](); (*p) = l[0]() <= l[1](); nextptr++; }
        void funcLEql(vector<DataSource>& l) { int* p; if (l.size() <= 2)p = &rFlag; else p = &l[2](); (*p) = l[0]() == l[1](); nextptr++; }
        void funcLAnd(vector<DataSource>& l) { int* p; if (l.size() <= 2)p = &rFlag; else p = &l[2](); (*p) = l[0]() && l[1](); nextptr++; }
        void funcLOr(vector<DataSource>& l) { int* p;  if (l.size() <= 2)p = &rFlag; else p = &l[2](); (*p) = l[0]() || l[1](); nextptr++; }
        void funcRInt(vector<DataSource>& l) { if (l.size() <= 0)cin >> rVal; else cin >> l[0](); nextptr++; }
        void funcRCh(vector<DataSource>& l) { if (l.size() <= 0)rVal = getchar(); else l[0]() = getchar(); nextptr++; }
        void funcWInt(vector<DataSource>& l) { if (l.size() <= 0)cout << rVal; else cout << l[0](); nextptr++; }
        void funcWCh(vector<DataSource>& l) { if (l.size() <= 0)putchar(rVal); else putchar(l[0]()); nextptr++; }
    
    public:
        void initalaize() {
    #define REGISTER_RAW(command, name) \
    commands[name] = command; names[command] = name
    #define REGISTER_HANDLER(command, handler, minParamCount, name)    \
    handlers[command] = [this](vector<DataSource>& l) {if (l.size() < minParamCount)runtimeError("Paramater Count Mismatch"); else handler(l); }; \
    /*handlers[command] = bind(&AssemblyProgram::handler, this, placeholders::_1);*/ \
    commands[name] = command; names[command] = name
            REGISTER_RAW(Undefined, "UDEF");
            handlers[Undefined] = [this](vector<DataSource>&) { runtimeError("Undefined Command Called"); };
            REGISTER_RAW(Halt, "HLT");
            handlers[Halt] = [this](vector<DataSource>&) { halt(); };
            REGISTER_RAW(NoOp, "NOP");
            handlers[NoOp] = [this](vector<DataSource>&) {};
            REGISTER_HANDLER(Set, funcSet, 2, "SET");
            REGISTER_HANDLER(Jump, funcJmp, 1, "JMP");
            REGISTER_HANDLER(JumpIf, funcJIf, 1, "JIF");
            REGISTER_HANDLER(Call, funcCall, 1, "CALL");
            REGISTER_HANDLER(Return, funcRet, 0, "RET");
            REGISTER_HANDLER(Inverse, funcInv, 1, "INV");
            REGISTER_HANDLER(Add, funcAdd, 2, "ADD");
            REGISTER_HANDLER(Minus, funcSub, 2, "SUB");
            REGISTER_HANDLER(Multiply, funcMult, 2, "MULT");
            REGISTER_HANDLER(IntDivide, funcIDiv, 2, "IDIV");
            REGISTER_HANDLER(Modulo, funcMod, 2, "MOD");
            REGISTER_HANDLER(LeftShift, funcLSft, 2, "LSFT");
            REGISTER_HANDLER(RightShift, funcRSft, 2, "RSFT");
            REGISTER_HANDLER(BitAnd, funcBAnd, 2, "BAND");
            REGISTER_HANDLER(BitOr, funcBOr, 2, "BOR");
            REGISTER_HANDLER(BitXor, funcBXor, 2, "BXOR");
            REGISTER_HANDLER(Greater, funcLGr, 2, "LGR");
            REGISTER_HANDLER(Less, funcLLs, 2, "LLS");
            REGISTER_HANDLER(GreaterEqual, funcLGE, 2, "LGE");
            REGISTER_HANDLER(LessEqual, funcLLE, 2, "LLE");
            REGISTER_HANDLER(Equal, funcLEql, 2, "LEQL");
            REGISTER_HANDLER(LogicalAnd, funcLAnd, 2, "LAND");
            REGISTER_HANDLER(LogicalOr, funcLOr, 2, "LOR");
            REGISTER_HANDLER(ReadInt, funcRInt, 0, "RINT");
            REGISTER_HANDLER(ReadChar, funcRCh, 0, "RCH");
            REGISTER_HANDLER(WriteInt, funcWInt, 0, "WINT");
            REGISTER_HANDLER(WriteChar, funcWCh, 0, "WCH");
    #undef REGISTER_RAW
    #undef REGISTER_HANDLER
            program.clear();
            nextptr = 0;
        }
    
        bool pushCommand(int fileline, string name, vector<DataSource> param) {
            toupper(name);
            auto i = commands.find(name);
            if (i == commands.end()) {
                compileError(fileline, "Invaild command \"" + name + "\"");
                return false;
            }
            else {
                program.push_back(make_pair(i->second, param));
                if (commandLines.find(fileline) == commandLines.end())
                    commandLines[fileline] = program.size() - 1;
                return true;
            }
        }
    
        int* getRegister(int fileline, string name) {
            toupper(name);
            if (name == "R1")
                return &rR1;
            else if (name == "R2")
                return &rR2;
            else if (name == "R3")
                return &rR3;
            else if (name == "R4")
                return &rR4;
            else if (name == "E1")
                return &rE1;
            else if (name == "E2")
                return &rE2;
            else if (name == "E3")
                return &rE3;
            else if (name == "E4")
                return &rE4;
            else if (name == "FLAG")
                return &rFlag;
            else if (name == "VAL")
                return &rVal;
            else if (name == "RET")
                return &rRet;
            else if (name == "LINE")
                return &rLine;
            else {
                compileError(fileline, "Invaild register name \"" + name + '\"');
                return nullptr;
            }
        }
    
        int* getMemory(int fileline, int id) {
            if (id >= memsize || id < 0) {
                compileError(fileline, "Memory access statically out of range");
                return 0;
            }
            else return mem + id;
        }
    
        void run() {
            rR1 = rR2 = rR3 = rR4 = rE1 = rE2 = rE3 = rE4 = rFlag = rVal = rRet = rLine = 0;
            memset(mem, 0, sizeof(mem));
            while (!sAddr.empty())
                sAddr.pop();
    
            clockCounter = 0;
            nextptr = 0;
            running = true;
            while (running) {
                if (nextptr >= program.size() || nextptr < 0)
                    runtimeError("Program Pointer Invaild");
                else
                    handlers[program[nextptr].first](program[nextptr].second);
                clockCounter++;
            }
        }
    
        int getClock() { return clockCounter; }
    
        bool valid;
    private:
    
        friend class Compiler;
    
        int rR1, rR2, rR3, rR4;
        int rE1, rE2, rE3, rE4;
        int rFlag, rVal, rRet, rLine;
        static constexpr int stackSize = 512 * 1024;
        stack<int> /*sVal,*/ sAddr;
    
        vector<pair<Command, vector<DataSource>>> program;
        int nextptr;
        static constexpr int memsize = 16 * 1024 * 1024;
        int mem[memsize];
    
        int clockCounter;
        bool running;
    
        function<void(vector<DataSource>&)> handlers[CommandCount];
        map<int, int> commandLines;
        map<string, Command> commands;
        string names[CommandCount];
    };
    
    
    class Tokenizer {
    public:
        enum Type {
            Unknown,
            Identifier,
            Number,
            Symbol
        };
    
        struct Token {
            Type type;
            string word;
            int line;
        };
    
        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 == '-'))) {
                            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.word.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);
                buffer = Token{ Unknown, "" };
            }
            return tokens;
        }
    
        void parseTotal(string total) {
            tokens = parse(total);
            nextid = 0;
        }
    
        void parse(istream& in) {
            int c;
            string str;
            while (c = in.get()) {
                if (in.eof())
                    break;
                str.push_back(c);
            }
            parseTotal(str);
        }
    
        Token next() {
            if (nextid >= tokens.size())
                return Token{ Unknown, "" };
            else
                return tokens[nextid++];
        }
    
        Token offset(int offset) {
            int id = nextid - 1 + offset;
            if (id >= tokens.size() || id < 1)
                return Token{ Unknown };
            else
                return tokens[id];
        }
    
    private:
        vector<Token> tokens;
        int nextid;
    };
    
    /*
    Basic Syntax
    COMMAND %Register @Address Value @%AddrAtRegister;
    */
    class Compiler {
    public:
    
        struct Command {
            int line;
            string command;
            vector<Tokenizer::Token> sources;
        };
    
    
        void compile(Tokenizer& tokens) {
            valid = false;
            bool ok = true;
            while (ok) {
                Tokenizer::Token commt;
                while (ok && (commt = tokens.next()).type != Tokenizer::Identifier)
                    if (commt.type == Tokenizer::Unknown)
                        ok = false;
                string command = commt.word;
                vector<Tokenizer::Token> sources;
                Tokenizer::Token cur;
                bool pushCommand = true;
                while (ok && (cur = tokens.next()).word != ";") {
                    if (cur.type == Tokenizer::Unknown)
                        ok = false;
                    //if (cur.type == Tokenizer::Identifier&&tokens.offset(-1).type != Tokenizer::Symbol)
                    //    compileError(cur.line, "\";\" expected before a new identifier");
                    else if (cur.type == Tokenizer::Symbol&&cur.word == "$"&&touppers(command) == "FUNCTION") {
                        Tokenizer::Token func = tokens.next();
                        compileAssert(func.line, func.type == Tokenizer::Identifier, "\"function $\" not followed by a identifier as function name");
                        compileAssert(func.line, funcStartLines.find(func.word) == funcStartLines.end(), "Redefinition of function \"" + func.word + "\"");
                        funcStartLines.insert(make_pair(func.word, commt.line));
    
                        auto vec = Tokenizer::parse("#LINE %LINE");
                        for (auto& i : vec) { i.line = commt.line; }
                        commands.push_back(Command{ commt.line, "SET", vec });
                        pushCommand = false;
                    }
                    sources.push_back(cur);
                }
                if (compileErrorLevel)
                    break;
                if (ok&&pushCommand)
                    commands.push_back(Command{ commt.line, command, sources });
            }
            if (compileErrorLevel) {
                compileErrorLevel = false;
                valid = false;
            }
            else
                valid = true;
        }
    
        void generateCode(AssemblyProgram& prog) {
            if (!valid)
                return;
            prog.initalaize();
            prog.valid = false;
    
            bool ok = true;
    
            for (auto i = commands.begin(); ok&&i != commands.end(); i++) {
                string& command = i->command;
                vector<AssemblyProgram::DataSource> sources;
                bool pushCommand = true;
    
                auto j = i->sources.begin();
                auto nextToken = [&]()->Tokenizer::Token {
                    j++;
                    if (j == i->sources.end())
                        return Tokenizer::Token{ Tokenizer::Unknown };
                    else
                        return *j;
                };
                for (; ok&&j != i->sources.end(); nextToken()) {
                    auto& cur = *j;
                    if (cur.type == Tokenizer::Number)
                        sources.push_back(AssemblyProgram::DataSource{ nullptr, atoi(cur.word.c_str()), nullptr, nullptr, AssemblyProgram::Constant });
                    else if (cur.type == Tokenizer::Symbol) {
                        if (cur.word == "%") {
                            Tokenizer::Token reg = nextToken();
                            compileAssert(reg.line, reg.type == Tokenizer::Identifier, "% not followed by identifier");
                            sources.push_back(AssemblyProgram::DataSource{ prog.getRegister(reg.line, reg.word), 0, nullptr, nullptr, AssemblyProgram::Pointer });
                        }
                        else if (cur.word == "@") {
                            Tokenizer::Token val = nextToken();
                            compileAssert(val.line, val.type == Tokenizer::Number, "@ not followed by a number");
                            sources.push_back(AssemblyProgram::DataSource{ prog.getMemory(val.line, atoi(val.word.c_str())), 0, nullptr, nullptr, AssemblyProgram::Pointer });
                        }
                        else if (cur.word == "@%") {
                            Tokenizer::Token reg = nextToken();
                            compileAssert(reg.line, reg.type == Tokenizer::Identifier, "@% not followed by identifier");
                            sources.push_back(AssemblyProgram::DataSource{ nullptr, 0, prog.getRegister(reg.line, reg.word), &prog, AssemblyProgram::Memory });
                        }
                        else if (cur.word == "#") {
                            Tokenizer::Token def = nextToken();
                            compileAssert(def.line, def.type == Tokenizer::Identifier, "# not followed by identifier");
                            toupper(def.word);
                            if (def.word == "LINE")
                                sources.push_back(AssemblyProgram::DataSource{ nullptr, def.line, nullptr, nullptr, AssemblyProgram::Constant });
                            else
                                compileError(def.line, "Compile-time constant identifier \"" + def.word + "\" undefined");
                        }
                        else if (cur.word == "$") {
                            if (command == "callfunc") {
                                Tokenizer::Token func = nextToken();
                                compileAssert(func.line, func.type == Tokenizer::Identifier, "\"callfunc $\" not followed by a identifier as function name");
                                auto it = funcStartLines.find(func.word);
                                if (it == funcStartLines.end())
                                    compileError(func.line, "Function \"" + func.word + "\" undefined");
                                else {
                                    prog.pushCommand(i->line, "CALL", {
                                        AssemblyProgram::DataSource{ nullptr, it->second, nullptr, nullptr, AssemblyProgram::Constant }
                                                     });
                                }
                                pushCommand = false;
                            }
                            else
                                compileError(cur.line, "$ not preceeded by keyword \"function\" or \"callfunc\"");
    
                        }
                    }
                    if (compileErrorLevel)
                        ok = false;
                }
                if (ok&&pushCommand)
                    prog.pushCommand(i->line, i->command, sources);
            }
    
            if (compileErrorLevel) {
                compileErrorLevel = false;
                prog.valid = false;
            }
            else
                prog.valid = true;
        }
    
    private:
    
        vector<Command> commands;
        map<string, int> funcStartLines;
        bool valid;
    
    
    };
    
    
    AssemblyProgram prog;
    Tokenizer tokens;
    Compiler compiler;
    
    
    int main(int argc, char* argv[]) {
    
        int n;
        cin >> n;
    
        string str;
        string total;
        while (n > 0 && getline(cin, str)) {
            if (str == "")
                continue;
            n--;
            total += str + '\n';
        }
    
        tokens.parseTotal(total);
        compiler.compile(tokens);
        compiler.generateCode(prog);
        prog.run();
    
        return 0;
    }
    

    话又说回来,要是像未来程序改那样的题真的出现在了省选里,又有多少人会做出来呢……

    • 1

    信息

    ID
    3914
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者