В C / C ++ вы можете реализовать прямой потоковый интерпретатор с массив указателей на функции. Массив представляет вашу программу - массив операций. Каждая из функций операции должна заканчиваться вызовом следующей функции в массиве, например:
void op_plus(size_t pc, uint8_t* data) {
*data += 1;
BytecodeArray[pc+1](pc+1, data); //call the next operation in the array
}
BytecodeArray - это массив указателей на функции. Если бы у нас был массив этих операций op_plus, длина массива определяла бы, как часто мы будем увеличивать содержимое данных. (конечно, вам нужно добавить некую завершающую операцию как последнюю операцию в массиве).
Как можно реализовать что-то подобное в OCaml? Возможно, я пытаюсь перевести этот код слишком буквально: я использовал массив функций OCaml, как в C ++. Проблема в том, что я продолжаю получать что-то вроде:
let op_plus pc data = Printf.printf "pc: %d, data_i: %d \n" pc data;
let f = (op_array.(pc+1)) in
f (pc+1) (data+1) ;;
где op_array - это массив, определенный в области выше, а затем переопределить его позже, чтобы он был заполнен кучей функций op_plus ... однако, функция op_plus использует предыдущее определение op_array. Это проблема курицы и яйца.
Еще один вариант (если размер заранее известен) - изначально заполнить массив пустыми инструкциями:
let op_array = Array.create size (fun _ _ -> assert false)
let op_plus = ...
let () = op_array.(0) <- op_plus; ...
Вы не должны переопределять op_array
, вы должны заполнить его инструкциями, изменив его на месте так, чтобы он был тем же op_array
, который уже используется в ваших функциях. Ссылаться на. К сожалению, в OCaml нельзя динамически изменять размер массива.
Я вижу два решения:
1) если не нужно менять последовательность "инструкций", определить их во взаимной рекурсии с массивом op_array
. OCaml позволяет определять взаимно рекурсивные функции и значения, которые начинаются с применения конструктора. Что-то вроде:
let rec op_plus pc data = ...
and op_array = [| ... |]
2) Или используйте дополнительную косвенность: сделайте op_array
ссылкой на массив инструкций и обратитесь в функциях к (!op_array).(pc+1). Позже, после того как вы определили все инструкции, вы можете сделать так, чтобы op_array
указывал на массив нужного размера, полный необходимых инструкций.
let op_array = ref [| |] ;;
let op_plus pc data = ... ;;
op_array := [| ... |] ;;