|
|
  |
Инкрементирующийся define, c помощью препроцессор Си |
|
|
|
Jul 10 2016, 19:12
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(zltigo @ Jul 10 2016, 15:49)  Что говорит о том, что решение поставленной задачи только с помощью конечного автомата зашло в тупик  . Можно сделать завуалированный конечный автомат, без огромных перечислений enum. На стеке. Будет что-то типа задачи со своим стеком, очередное состояние - это собственно адрес. Вход в автомат - это переключение на его стек, выход (там где был break) - обратное переключение на исходный стек. Очень удобно отлаживать. Но конечно требуется некоторая дополнительная память (стек). Я так иногда делаю когда автомат получается ну очень сложным, да ещё с вложенными ветками.
|
|
|
|
|
Jul 11 2016, 08:13
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (AlexandrY @ Jul 10 2016, 14:49)  Прямо сейчас у меня в работе протокол с 41-им case в парсере. В Вашим? Да хоть 4141 case. Это ВАША РЕАЛИЗАЦИЯ некоего протокола, которая делатся через ... Попытайтесь найти спецификацию протокола в котором используется такое количество СОСТОЯНИЙ хоть на каком-то уровне. QUOTE Протоколы только отладчиком через SWD и можно детально отладить. ... поехав на край земли с "отладчиком" и сидя на столбе выяснять что это, вдруг, от того, что на противоположном конце земли кто-то, например, заапгрейдил Cisco не может связаться с Магаданом. Да, да внутрисхемный отладчик это очень "полезная" штука в таких ситуациях  .
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 11 2016, 08:14
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AlexandrY @ Jul 11 2016, 13:01)  Хоть я и не совсем понимаю о чем вы говорите, поскольку не видно кода, но могу уверенно сказать, что ваш код не линейный, а размазанный. Т.е. часть логики кода отнесена куда-то в таблицы. А это еще хуже вермишели для понимания работы. Примерно так (код вне к.автомата - там где у ТС switch; код автомата - набор case-участков состояний к.автомата): 1. Выполняется код вне к.автомата. На месте switch() ставим переключение контекста на отдельный стек (в стеке сохранён контекст задачи автомата со всеми сохранёнными регистрами и адресом возврата). SwitchContext(адрес_структуры_контекста_со_стеком). Внутри функции SwitchContext() сохраняем текущий контекст на текущем стеке, переключаемся на стек к.автомата, восстанавливаем контекст из него и осуществляем возврат в код к.автомата. В коде к.автомата, выполнив очередную ветку case, опять вызываем SwitchContext(), которая сохранит контекст к.автомата на его стеке, переключится на исходный стек задачи, вызвавшей к.автомат и восстановит контекст из него и осуществит возврат. Код к. автомата будет выглядеть: Код код //STATE_0 ... //STATE_0 SwitchContext(); //к.автомат перешёл в сост.1 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_1 ... //STATE_1 SwitchContext(); //к.автомат перешёл в сост.2 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_2 ... //STATE_2 if () { //STATE_2 SwitchContext(); //к.автомат перешёл в сост.3 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_3 ... //STATE_3 } else { SwitchContext(); //к.автомат перешёл в сост.4 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_4 ... //STATE_4 } SwitchContext(); //к.автомат перешёл в сост.5 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_5 ... //STATE_5 ... Как видите - код к.автомата получается линейным и легко читаемым даже при наличии ветвлений. А в традиционной реализации к.автомата при неск. ветвлениях по состояниям автомата уже получится малочитаемый вермишельный код. А представьте, если вдруг окажется необходимым из некоторых состояний к.автомата проходить цепочку других его состояний с возвратом потом в исходную точку: сост0 сост1 сост10 сост11 сост12 сост2 ... сост5 сост6 сост10 сост11 сост12 сост7 ... В традиционной реализации придётся ещё куда-то сохранять/восстаналивать состояния автомата. И вообще получится лес. А с переключением контекста, будет просто вызов функции.
|
|
|
|
|
Jul 11 2016, 08:34
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(zltigo @ Jul 11 2016, 14:22)  Уменьшение количества состояний чаще всего достигаеся увеличенем количества автоматов. Все сколь-нибудь вменяемые протоколы разбиты на уровни и обслуживаются на каждом уровне своими автоматоми. Если безмозгло свалить все уровни в одну кучу, то получим именно катострофический рост состояний при котором "41 case" от AlexandrY и "100" от Alt.F4 это даже еще не цветочки  Это да, можно и так. Но бывают даже относительно короткие автоматы в 10-20 состояний, но со сложной логикой ветвления, условными переходами между состояниями или необходимостью выполнения повторяющихся цепочек состояний в разных местах автомата. Я не говорю конкретно про разбор кадров протокола, вопрос был общего плана об к.автоматах.
|
|
|
|
|
Jul 11 2016, 08:48
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(x893 @ Jul 10 2016, 23:33)  Зря не смотрели в сторону http://dunkels.com/adam/pt/index.htmlи enum не нужны Protothread это не про протоколы. Поскольку там используется много неявных выходов из функции, то в сложных десериализаторах придется много кода потратить на сохранение контекста. Поскольку контекст десереализации не ограничивается только номером состояния как в Protothread. По мне лучше уж goto чем такие хитрые переходы. Цитата(jcxz @ Jul 11 2016, 11:14)  Код код //STATE_0 ... //STATE_0 SwitchContext(); //к.автомат перешёл в сост.1 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_1 ... //STATE_1 SwitchContext(); //к.автомат перешёл в сост.2 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_2 ... //STATE_2 if () { //STATE_2 SwitchContext(); //к.автомат перешёл в сост.3 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_3 ... //STATE_3 } else { SwitchContext(); //к.автомат перешёл в сост.4 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_4 ... //STATE_4 } SwitchContext(); //к.автомат перешёл в сост.5 (и вышел из контекста к.автомата вернувшись в контекст вызывающей функции) код //STATE_5 ... //STATE_5 ... В вашем псевдокоде я вижу только множественные SwitchContext() без аргументов. Это выглядит как полная бессмыслица. Стек - это в вашем понятии стековая структура данных или стек процессора? Стековые структуры обычно применяют для раскрытия рекурсии в парсерах. У меня так работают парсеры JSON, LUA и еще несколько. Но в протоколах нет рекурсий. Там есть именно разбор вариантных хидеров. Ничего лучше case для этого не придумано.
|
|
|
|
|
Jul 11 2016, 09:24
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(x893 @ Jul 11 2016, 12:09)  Смысл простой - использование __LINE__ для автогенерации switch/case Да понятен там смысл. Но влетать внутрь цикла, дескать C-и позволяет это хуже чем goto. Опять же при символьной отладке это будет выглядеть как хаотичная передача управления непонятно куда. TC же показал способ с вычисляемыми ключами. Ему Protothread никак не подойдет.
|
|
|
|
|
Jul 11 2016, 09:55
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(jcxz @ Jul 11 2016, 11:34)  Но бывают даже относительно короткие автоматы в 10-20 состояний, но со сложной логикой ветвления, условными переходами между состояниями или необходимостью выполнения повторяющихся цепочек состояний в разных местах автомата. Несомненно! По этой причине я тоже с самого начала писал, что просто не надо все всегда ТОЛЬКО на состояния автомата валить. В каждом конкретом случае надо смотреть, как разгружать собственно автомат от излишества состояний, ибо конечный автомат не есть панацея  . Совсем недавно в казалось-бы простой задаче начал в лоб писать автомат - началось погружение в пучину состояний. Разбил на два автомата - тоже не сильно понравилось, ибо такой подход нормально работает, когда протокол на уровни бьется. В результате был сделан один автомат на 13 состояний и три бита дополнительных глобальных статусов. Цитата(AlexandrY @ Jul 11 2016, 11:48)  Но в протоколах нет рекурсий... Это просто Ваши познания в протоколах невелики  . В тех же телекомуникационных протоколах в полученном фрейме может находится, или не находится, самая разнообразная информация. Причем, как относящаяся к одному объекту, так и к разным. А сам фрейм собираться из множества небольших кусочков. Вот и начинается рекурсивный разбор полей.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 11 2016, 11:11
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(zltigo @ Jul 11 2016, 12:55)  Это просто Ваши познания в протоколах невелики  . В тех же телекомуникационных протоколах в полученном фрейме может находится, или не находится, самая разнообразная информация. Причем, как относящаяся к одному объекту, так и к разным. А сам фрейм собираться из множества небольших кусочков. Вот и начинается рекурсивный разбор полей. Вы уж определитесь о чем хотите рассказать. Сначала у вас многоуровневые концепции, теперь опять рекурсивные. Фреймы из кусочков это связные списки, а не стековые структуры. Я не видел рекурсию на в TCP/IP, ни в Zigbee, ни в BLE, ни в USB... Ну ни где. А вы где усмотрели?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|