Дано хотелось эту статью написать. Только сейчас сподобился...
Программная реализация простого конечного автомата предполагает одну переменную для хранения его состояния и бесконечный цикл множественного выбора действий по значению этой переменной.
Код:
1 CONSTANT Случай1
2 CONSTANT Случай2
3 CONSTANT Случай3
Случай1 VALUE Состояние
: КАвтомат
Состояние Случай1 = IF Действие1 Случай3 TO Состояние THEN
Состояние Случай2 = IF Действие2 Случай1 TO Состояние THEN
Состояние Случай3 = IF Действие3 Случай2 TO Состояние THEN
;
: КА-Цикл BEGIN
КАвтомат
AGAIN ;
Возможны оптимизации, вид изменится, но принцип такой. Анализируем состояние - выполняем действие - устанавливаем новое состояние.
Если
КАвтомат запускать не в цикле
КА-Цикл, а во внешнем, то в нем получится "многозадачность" и КА будет работать "параллельно" с другими частями системы.
Почему это возможно? Потому что, независимо от состояний, управление
всегда проходит через одну точку -
КАвтомат. Разрыв в этой одной точке позволяет легко добавить программе дополнительные "параллельные" ветви.
Далее читаем
Броуди и видим, что мы устанавливаем Флаг (переменную
Состояние), который потом проверяем. Это сложно. Надо устанавливать значение. А какое значение?
Самое лучшее - сразу устанавливать код, который дожен быть выполнен в следующем состоянии! Делаем следующий шаг и
сразу выполняем этот код!
Код:
\ язык CLCF - на нем это видно проще. В обычном Форте посложнее, но тоже можно.
: КА-Цикл \ множественные точки входа, имя - просто метка, адрес в коде
: Действие1 ( действия Действие1 ) Действие3 ; \ переход на соотв. слово
: Действие2 ( действия Действие2 ) Действие1 ;
: Действие3 ( действия Действие3 ) Действие2 ;
Получается Форт-программа,
эквивалентная коду конечного автомата, но
проще! Нет лишних сущностей, не надо придумывать лишних имен!
Единственная проблема - для получения "многозадачности"
КА-цикл надо где-то разорвать.
Но теперь нельзя выделить
одну точку, через которую управление проходит при любых состояниях.
(Аналогичная ситуация на уровне слов - нет одной точки для перехвата управления - возникает и при использовании распределенных адресных интерпретаторов, и при использовании нативного кода=>трудно сделать переключение задач на этом уровне)
Что же должен делать такой разрыв?
Он может позволять выполнять еще какой-то код. Тогда он может выглядеть просто как вызов слова.
Он может вернуть управление вызвавшей программе. Но тогда ему надо как-то сохранить свое состояние. Сохранение состояния в стеке возвратов позволит вызвавшей программе продолжить выполнение
КА-Цикл с прерванного места просто возвратом. Но это не получится повторить несколько раз...
Значит, только переменная, в которой будет сохраняться адрес продолжения. Этот вариант больше похож на первоначальный код.
В каких же местах он должен быть?
Добавлять его прийдется либо во все действия
ДействияN , либо только в те, которые выполняются долго (это должен знать разработчик) - формального правила, по-видимому, нет...
Эта же проблема возникнет и при реализации кооперативной многозадачности в рамках одной программы. Где разрывать? Можно ли придумать хорошее формальное правило для таких разрывов?
Что вы думаете по этому поводу?
Есть еще один вариант - оставить код как есть, а реализацию многозадачности пусть выполняет внешняя программа - менеджер задач. Тогда она должна обеспечить сохранение и восстановление контекста этой нашей задачи.
Сам я пока склоняюсь к выборочной вставке выхода с сохранением контекста.