4

次の (短縮された) スレッド化されたコード インタープリター (有限状態マシン) が与えられます。オペレーション スタックとオペランド スタックがあります。実行時に、次の操作が操作スタックからポップされて実行されます。

次の 3 つの指示があります。

  • オペランド スタックから 2 つのオペランドをポップする加算命令は、それらを加算し、結果をオペランド スタックにプッシュします
  • オペランド スタックから 1 つのオペランドをポップして出力する印刷命令
  • 加算命令を (命令内から)手動で呼び出そうとし、計算結果を取得する必要があるspecialcall命令

ここでの問題は、specialcall メソッドでは計算の結果が必要ですが、命令ループで加算演算が呼び出された後、最初の specialcall の直後にさらに実行が継続することです。

1 つのアプローチは、a) 操作と b) 必要に応じてジャンプするアドレスを含む操作構造体を作成することです。次に、命令ループで、命令構造体がポップされてアドレスが設定されると、実際の命令の実行直後にこのアドレスへのジャンプが行われます。

この問題を解決する他の方法はありますか?

#include <stdint.h>
#include <iostream>
#include <deque>

const uint32_t operation_addition = 1;
const uint32_t operation_print = 2;
const uint32_t operation_specialcall = 3;

std::deque<uint32_t> operations;
std::deque<uint32_t> stack;

void specialcall() {
    std::cout << "specialcall" << std::endl;

    // Manually create the call
    stack.push_back(52);
    stack.push_back(25);
    operations.push_back(operation_addition);

    // "place to jump back"

    // Need result of calculation here!
    ...
}

void addition() {
    std::cout << "addition" << std::endl;

    uint32_t operandA = stack.back();
    stack.pop_back();
    uint32_t operandB = stack.back();
    stack.pop_back();

    uint32_t result = operandA + operandB;
    stack.push_back(result);
}

void print() {
    std::cout << "print" << std::endl;

    uint32_t result = stack.back();
    stack.pop_back();

    std::cout << result << std::endl;
}

void start() {
    while (!operations.empty()) {
        uint32_t op = operations.back();
        operations.pop_back();

        switch (op) {
        case operation_specialcall:
            specialcall();
            break;
        case operation_print:
            print();
            break;
        case operation_addition:
            addition();
            break;
        }
    }
}

int main() {
    stack.push_front(25);
    stack.push_front(53);
    operations.push_front(operation_addition);
    operations.push_front(operation_print);
    operations.push_front(operation_specialcall);
    start();

    std::cout << "execution finished" << std::endl;
}
4

1 に答える 1

2

あなたはすでに結果を持っています。それはスタックの一番上にあります。コードが実行された後。だからそれを取得するだけです:

int main() {
    stack.push_front(25);
    stack.push_front(53);
    operations.push_front(operation_addition);
    operations.push_front(operation_print);
    operations.push_front(operation_specialcall);
    start();

    uint32_t result = stack.back();
    stack.pop_back();
    std::cout << result << std::endl;
}

operation_specialcall() 関数内で結果が必要な場合は、その関数が結果をどのように使用するかについて深く考える必要があります。任意に、それを印刷できます:

void specialcall() {
    stack.push_back(52);
    stack.push_back(25);
    operations.push_back(operation_addition);
    operations.push_back(operation_print);
}

どちらのアプローチもまったく同じことを達成します。ここで重要なのは、コンパイル時と実行時を区別することです。それらを混同しないようにしてください。これには、インタープリターの大幅な拡張が必要です。eval() 関数に相当するものを実装する必要があります。これには、複数の命令ストリームを管理できる必要がありますが、その配管が整っていません。つまり、オペレーションスタック変数をグローバル変数として持つことはできなくなりました。

于 2013-10-05T12:37:45.980 に答える