Skip to content

Добавление комментариев для QHsm #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions compiler/library/default/qhsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

#include <stddef.h>

// стандартные события
const QEvt standard_events[] = {
// сигнал для кодирования пустых действий
{(QSignal)(QEP_EMPTY_SIG_)},
// сигнал для кодирования действий входа
{(QSignal)(Q_ENTRY_SIG)},
// сигнал для кодирования действий выхода
{(QSignal)(Q_EXIT_SIG)},
// сигнал для кодирования вложенных начальных переходоов
{(QSignal)(Q_INIT_SIG)},
};

Expand All @@ -17,19 +22,33 @@ QState QHsm_top(void *const me, const QEvt *const event)
return (QState)(Q_RET_IGNORED);
}

/*
Совершить преобразование (переход) внутри иерархической машины состояния.

После этого процесса, текущее (current) состояние становится равным родительскому (effective) состоянию, а целевое (target) состояние пропадает (NULL)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может быть, предположение о том, что effective - родительское состояние, является ложным? Потому что проверка source == effective == target выглядит очень странно

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Думаю, стоит поглубже это покопать

*/
static void do_transition(QHsm *me)
{
QStateHandler source = me->current_;
QStateHandler effective = me->effective_;
QStateHandler target = me->target_;

/*
Текущее состояние (source) вызывается со стандартными событиями Q_EXIT_SIG и QEP_EMPTY_SIG_.
Похоже, что эти вызовы могут повлиять на машину состояний me, таким образом, что его родительское состояние (effective) меняется
(иначе не понятно, зачем идёт сравнение source с effective, если в конце source = me->effective_)
*/
while (source != effective) {
source(me, &standard_events[Q_EXIT_SIG]);
source(me, &standard_events[QEP_EMPTY_SIG_]);
source = me->effective_;
}

if (source == target) {
/*
Предыдущий блок кода гарантирует, что source == effective, следовательно
source == effective == target
*/
source(me, &standard_events[Q_EXIT_SIG]);
target(me, &standard_events[Q_ENTRY_SIG]);

Expand All @@ -39,12 +58,22 @@ static void do_transition(QHsm *me)
return;
}

// Поиск пути от target до source

QStateHandler path[Q_MAX_DEPTH];
// текущее расстояние от target
ptrdiff_t top = 0;
// длина пути от target до source (LCA = lowest (least) common ancestor, наименьший общий предок)
ptrdiff_t lca = -1;

path[0] = target;

/*
Обход и передача сигналов EP_EMPTY_SIG_ target и его предкам.

Цикл выполняется до тех пор, пока не будет достигнута вершина машины состояния,
либо до тех пор пока не будет найден номер вершины, на которой находится source, относительно target.
*/
while (target != &QHsm_top) {
target(me, &standard_events[QEP_EMPTY_SIG_]);
target = me->effective_;
Expand All @@ -56,11 +85,21 @@ static void do_transition(QHsm *me)
}
}

/*
Обход и передача сигналов Q_EXIT_SIG и EP_EMPTY_SIG_ source и его предкам.

Цикл выполняется только в том случае, если на предыдущем шаге не удалось определить
расстояние от target до source.

Значение top в этом случае должно равняться расстоянию от изначального значения target до QHsm_top.
*/
while (lca == -1) {
source(me, &standard_events[Q_EXIT_SIG]);
source(me, &standard_events[QEP_EMPTY_SIG_]);
source = me->effective_;

/*
Проверка наличия source на пути от target до QHsm_top.
*/
for (ptrdiff_t i = 0; i <= top; ++i) {
if (path[i] == source) {
lca = i;
Expand All @@ -70,7 +109,7 @@ static void do_transition(QHsm *me)
}

target = path[lca];

// передача всем предшествующим до target состояниям сигнала Q_ENTRY_SIG
for (ptrdiff_t i = lca - 1; i >= 0; --i) {
target = path[i];
target(me, &standard_events[Q_ENTRY_SIG]);
Expand Down
38 changes: 37 additions & 1 deletion compiler/library/default/qhsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,75 +22,111 @@

#include <stdint.h>

// максимальная глубина состояний относительно вверха (top)
#define Q_MAX_DEPTH 8

// сигнал
typedef int QSignal;
// состояние
typedef int QState;

// событие
typedef struct
{
QSignal sig;
} QEvt;

// обработка состояния
typedef QState (*QStateHandler)(void *const me, const QEvt *const event);

// сигналы
enum
{
// пустой сигнал
QEP_EMPTY_SIG_ = 0,
// сигнал входа
Q_ENTRY_SIG,
// сигнал выхода
Q_EXIT_SIG,
// начальный сигнал
Q_INIT_SIG,
Q_VERTEX_SIG,
// пользовательский сигнал
Q_USER_SIG,
};

// возращаемые сигналы (RETurn)
enum
{
// ?
Q_RET_SUPER,
// необработано
Q_RET_UNHANDLED,
// обработано
Q_RET_HANDLED,
// проигнорировано
Q_RET_IGNORED,
// трансформировано (переходное состояние)
Q_RET_TRAN,
};

// структура, обозначающая иерархическую машину состояний
typedef struct
{
// текущее состояние
QStateHandler current_;
// родительское состояние (?)
QStateHandler effective_;
// цель для перехода
QStateHandler target_;
} QHsm;

// создание указателя из более конкретного типа к более общему QHsm (upcast)
// позволяет убедиться, что в коде не используются лишние, конкретные свойства, что будет мешать в будущем обобщить код
#define Q_MSM_UPCAST(me) ((QHsm *)(me))
// преобразование объекта handler в тип QStateHandler
#define Q_STATE_CAST(handler) ((QStateHandler)(handler))

// макрос, который приводит Q_RET_UNHANDLED к типу QState
#define Q_UNHANDLED() ((QState)(Q_RET_UNHANDLED))
// макрос, который приводит Q_RET_HANDLED к типу QState
#define Q_HANDLED() ((QState)(Q_RET_HANDLED))

// преобразование
#define Q_TRAN(target) \
((Q_MSM_UPCAST(me))->target_ = Q_STATE_CAST(target), \
(QState)(Q_RET_TRAN))
#define Q_SUPER(super) \
((Q_MSM_UPCAST(me))->effective_ = Q_STATE_CAST(super), \
(QState)(Q_RET_SUPER))

// инициализация преобразования машины состояния (me) через событие (event)
#define QMSM_INIT(me, event) (QMsm_init(me, event))
// отправка события (event) в QHsm (me)
#define QMSM_DISPATCH(me, event) (QMsm_dispatch(me, event))

// макрос для простой отправки вызовов только посредством сигналов, которые оканчиваются на _SIG.
#define SIMPLE_DISPATCH(me_, sig_) \
do { QEvt e_; e_.sig = sig_##_SIG; QMSM_DISPATCH(me_, &e_); } while (0) // Macro to simple dispatch calls with signal only
// макрос для простой отправки вызовов только посредством сигналов
#define SIGNAL_DISPATCH(me_, sig_) \
do { QEvt e_; e_.sig = sig_; QMSM_DISPATCH(me_, &e_); } while (0) // Macro to simple dispatch calls with signal only
// отправить событие в _obj
#define PASS_EVENT_TO(obj_) \
do { QMSM_DISPATCH(obj_, e); } while (0) // Macro with clear name

#ifdef __cplusplus
extern "C" {
#endif

// Глобальное состояние по умолчанию
QState QHsm_top(void *const me, const QEvt *const event);

// конструктор QHsm
void QHsm_ctor(QHsm *const me, QStateHandler initial);

// инициализация преобразования машины состояния (me) через событие (event)
void QMsm_init(QHsm *me, const QEvt *const event);
// отправка события (event) в QHsm (me)
QState QMsm_dispatch(QHsm *me, const QEvt *const event);

#ifdef __cplusplus
Expand Down
Loading