Ручной вызов операции в интерпретаторе многопоточного кода (нарушение нормального потока)

Дан следующий (сокращенный) интерпретатор с поточным кодом (конечный автомат). У него есть стек операций и стек операндов. При выполнении следующая операция извлекается из стека операций и выполняется.

Есть три инструкции:

  • прибавление инструкция, которая извлекает два операнда из стека операндов, добавляет их и помещает результат в стек операндов
  • Распечатать инструкция, которая извлекает один операнд из стека операндов и выводит его
  • specialcall инструкция, которая пытается вручную вызвать прибавление Инструкция (изнутри инструкции) и должна получить результат расчета

Теперь проблема в том, что в методе specialcall требуется результат вычисления, но после вызова операции сложения в цикле команд дальнейшее выполнение просто продолжится сразу после начального специального вызова.

Один из подходов состоит в том, чтобы создать структуру операции, которая содержит а) операцию и б) адрес, на который необходимо перейти назад — при необходимости. Затем в цикле инструкций, когда структура инструкции извлечена и адрес задан, переход к этому адресу будет сделан сразу после выполнения фактической инструкции.

Есть ли другой способ решить эту проблему?

#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

Решение

У вас уже есть результат, он находится на вершине стека. После того, как код выполнен. Так что просто получите это:

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 (). Что требует способности управлять несколькими потоками инструкций, у вас нет этого соединения. Другими словами, вы не можете иметь операции а также стек переменные как глобальные переменные больше.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]