Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 21.12.2015, 14:50   #1
fanlis
Пользователь
 
Регистрация: 13.05.2007
Сообщений: 60
Вопрос Собственный стек процедур или выход посреди процедуры

Здравствуйте, господа. Структура моей программы такова, что имеется набор процедур (я их называю события), в которых выполняются определенные действия - расчеты, вывод результатов, нажатие кнопок, вызов других событий и проч. Короче все что угодно. Программа состоит из вызова событий. Такая структура задана изначально и изменению не подлежит. Смысл весь в том, что одно событие должно размещаться в одной процедуре.
Допустим есть событие, которое реализует следующую последовательность действий:

- Вывод начальной информации
- Нажатие кнопки на форме, которая задает переменную Q
- Если Q=1, то вызов другого события и после его выполнения возврат в это событие
- Если Q=0, то дальше
- Нажатие другой кнопки на форме.
- Вывод чего-нибудь
- выход

Т.е. фактически процедура должна прерываться (в середине процедуры происходить выход из нее (чтобы сделать какие-то действия на форме, например, нажать кнопку), а затем снова возвращаться в процедуру с того места, где было прерывание.

Я реализовал данную схему следующим образом. Сделал собственный стек, в который я добавляю вызываемые события, точку в самом событии и какие-нибудь данные:
Код:
type
  ProcEvent = procedure;
  
  TStack = record //стек процедур
    P: ProcEvent; //событие
    S: byte; //точка в событии
    Param1: integer; //дополнительный параметр 1
    Param2: integer; //дополнительный параметр 2
 end;

var 
  Nst: integer; //номер текущего события в стеке
Далее добавление события в стек:
Код:
procedure TForm1.Call(Proc: ProcEvent; Stage: byte; Param1: integer = 0; Param2: integer = 0);
begin
  inc(Stack[Nst].S);
  inc(Nst);
  Stack[Nst].P:=Proc;
  Stack[Nst].S:=Stage;
  Stack[Nst].Param1:=Param1;
  Stack[Nst].Param2:=Param2;
  Timer_Stack.Enabled:=true;
end;
Завершение события:
Код:
procedure TForm1.Ret;
begin
  Stack[Nst].P:=nil;
  Stack[Nst].S:=0;
  Stack[Nst].Param1:=0;
  Stack[Nst].Param2:=0;
  dec(Nst);
  if Nst>=0 then
  begin
    PlayStack;
  end
  else ShowMessage('В стеке нет процедур');
end;
И запуск текущего события из стека:
Код:
procedure TForm1.PlayStack;
begin
  Timer_Stack.Enabled:=true;
end;


procedure TForm1.Timer_StackTimer(Sender: TObject);
begin
  Timer_Stack.Enabled:=false;
  Stack[Nst].P; //вызов процедуры-события
end;
Само событие имеет следующую структуру (сразу с примером):
Код:
procedure Event1;
begin
  case Stack[Nst].S of
    1: begin
      вывод сообщения: нажмите кнопку 1       
    end;

    2: begin
      if Q=1 then Form1.Call(Event2,1)
      else
      begin
        inc(Stack[Nst].S);
        Form1.PlayStack;
    end;

    3: Form1.Ret;
  end;//case
end;
При нажатии любой кнопки, после необходимых действий, в конце происходит следующее:
Код:
 inc(Stack[Nst].S);
 Form1.PlayStack;
Таким образом с помощью точек в событии (case) происходит "временный" выход из события. В п.1 (case 1 просят нажать кнопку, далее происходит выход из события и можно спокойно что-то делать на форме, в том числе и нажать кнопку. После нажатия кнопки и выполнения действий (установки переменной Q, например), происходит вызов события снова из стека со следующей точки, т.е п.2 (case 2. В п.2 происходит вызов другого события, но не прямой, а сначала добавление его в стек, далее выход из события 1 и запуск события 2 через таймер. И вот здесь есть одно НО, которое мне очень не нравится - таймер. Он сделан для того, чтобы был выход из события, потому что если я его не сделаю, то не получу доступ к форме.
Наверное это извращенный метод, но другого ничего придумать не смог. В принципе я сделал что-то наподобие обычного ассемблерного стека (когда-то давно на древнем компе (не IBM PC даже) я что-то писал на ассемблере). Может можно как-то это все сделать по-другому, проще или хотя бы избавиться от таймера. Может даже можно на ассемблере? (Знания ассемблера у меня меньше минимальных)
fanlis вне форума Ответить с цитированием
Старый 23.12.2015, 15:36   #2
fanlis
Пользователь
 
Регистрация: 13.05.2007
Сообщений: 60
По умолчанию

Ответов нет... Интересно, это невозможно сделать или просто никто не знает?..
fanlis вне форума Ответить с цитированием
Старый 23.12.2015, 16:03   #3
FaTaL
Участник клуба
 
Аватар для FaTaL
 
Регистрация: 09.11.2007
Сообщений: 1,759
По умолчанию

А зачем не реализовать это с помощью обычных процедур и функций?
FaTaL вне форума Ответить с цитированием
Старый 23.12.2015, 19:06   #4
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,442
По умолчанию

Подозреваю, то попытка изобрести собственный интерпретатор, пока что он программный и без переменных и функций и прочего.

Чтобы передать управление другому потому т.е. визуальному, первый надо либо на паузу поставить:
поток1:
команда
команда
вызов виз. интерфейса ва потоке 2:
пауза потоку 1
команда
конец виз. интервейса
возобновление потока1
смерть потоку 2
команда
команда
....

либо залочить его в какой-то бесконечный loop пока работает интерфейс,

поток1:
это вызов виз. интерфейса? - нет
команда
это вызов виз. интерфейса? - нет
команда
это вызов виз. интерфейса? - да
пока не выпал из него
если выпал на выход иначе
команда в интерфейсе
;
это вызов виз. интерфейса? - нет
команда
это вызов виз. интерфейса? - нет
команда
...


и не понятно что вы там за затею удумали.

Последний раз редактировалось Человек_Борща; 23.12.2015 в 19:08.
Человек_Борща вне форума Ответить с цитированием
Старый 23.12.2015, 19:20   #5
taras-proger
Подтвердите свой е-майл
 
Регистрация: 12.11.2014
Сообщений: 470
По умолчанию

Нда. Интерпретатор процедурного языка без переменных - это очень круто. А чего бы не пойти с того конца, откуда все делают? То есть сначала переменные, а потом уже развитие от алгоритмического к процедурному.
taras-proger вне форума Ответить с цитированием
Старый 23.12.2015, 19:46   #6
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,442
По умолчанию

Цитата:
Нда. Интерпретатор процедурного языка без переменных - это очень круто. А чего бы не пойти с того конца, откуда все делают? То есть сначала переменные, а потом уже развитие от алгоритмического к процедурному.
Нда. Вот бы ещё люди посты целиком читали, и не писали на его основе уже странных осуждений автора топика.

Я предположил что это интерпретатор, т.к. кое-где с, как мне кажется, похожим работаю.
Человек_Борща вне форума Ответить с цитированием
Старый 23.12.2015, 20:08   #7
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,792
По умолчанию

Цитата:
А чего бы не пойти с того конца, откуда все делают? То есть сначала переменные, а потом уже развитие от алгоритмического к процедурному.
Ой держите меня семеро - лопну со смеху
Ай да улыбатель )))
Яб плюсанул
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 23.12.2015, 21:13   #8
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

fanlis
Лично я не понял к вопроса. Просто начали об одном, а спрашиваете про другое.

Бывает так, что хочется:
- менять граф переходов;
- управлять очерёдность исполнения функций;
- контролировать стек;
- контролировать локальные переменные
и т.п.

Я это называю иерархической парадигмой программирования.
В самом Delphi такое не предусмотрено. Для этого нужен интерпретируемый язык программирования.

1. Отсюда первое решение делать интерпретатор.
2. Второе решение разбить программу на процедуры с единообразным набором параметров и запретить внутренние вызовы себе подобных.
3. Использовать ассемблер для навешивания крюков(Hook). Наложения заплаток и изменения кода как говориться на лету.
4. Использовать отладчик для остановки посреди команд. Можно написать отладчик который будет отлаживать сам себя.

Всё остальное это пожалуй комбинации подходов.
----------------------------------------------------

Цитата:
запуск события 2 через таймер. И вот здесь есть одно НО, которое мне очень не нравится - таймер. Он сделан для того, чтобы был выход из события, потому что если я его не сделаю, то не получу доступ к форме.
А что тут не так? Таймер вещь хорошая. Но нужен он для другого.
Что касается получить доступ так вам никто не запрещает. А если вам надо ещё реагировать на действия пользователя. Так отделите свой код от формы. К примеру сделайте его параллельным.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .

Последний раз редактировалось Pavia; 23.12.2015 в 21:18.
Pavia вне форума Ответить с цитированием
Старый 24.12.2015, 00:43   #9
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,859
По умолчанию

Цитата:
Сообщение от fanlis Посмотреть сообщение
Ответов нет... Интересно, это невозможно сделать или просто никто не знает?..
Просто никто не понимает нафига это нужно?

В очередной раз задан только конкретный вопрос, но не озвучена сама задача.

Последний раз редактировалось BDA; 24.12.2015 в 03:31.
northener вне форума Ответить с цитированием
Старый 25.12.2015, 08:55   #10
fanlis
Пользователь
 
Регистрация: 13.05.2007
Сообщений: 60
По умолчанию

Цитата:
В очередной раз задан только конкретный вопрос, но не озвучена сама задача.
Вот что касается этой фразы: я понимаю, что пишу сюда, потому что не знаю как сделать и спрашиваю об этом умных людей, у которых возможно опыта больше моего. Но как правило, к моменту задания вопроса я уже изучил разные подходы (конечно не все) и определил направление пути развития программы - т.е. методы реализации, но в чем-то застрял, поэтому и спрашиваю. И спрашиваю естественно конкретно о том, на чем застрял. Люди же все разные и думают по-разному, поэтому у каждого свой подход и предлагают обычно не решение конкретной задачи, а изменение всей системы проекта, ну другими словами другой подход к реализации задачи. Это не плохо, это даже очень хорошо - иметь несколько взглядов на проблему и выбрать лучший, но несколько выбивает из колеи, потому что я-то думаю в своем направлении.
Ну да ладно, я отвлекся. Просто передо мной поставлена жесткая задача: имеющееся событие реализовывать в одной процедуре. Таких событий... ну на данный момент штук 500, у каждого есть свой номер. И каждое событие должно быть оформлено как одна процедура, как единый блок, чтобы не было путаницы. Такая задача. Будут у нее параметры или нет - не важно, главное чтобы все процедуры были одного типа (все без переменных, или все с двумя переменными и т.д.). Но так получается, что событие предусматривает работу с интерфейсом программы, т.е. должно прерывать свою работу, чтобы получить данные от пользователя (например, нажатие кнопки). Я поэтому и выбрал такой метод - прерывание процедуры и возврат в нее. Да, получается наверно что-то вроде интерпретатора (хотя я не знаю, что это такое, только догадываюсь). Ну а как еще это сделать?

Разбивать одну процедуру на несколько не очень хорошо:
- будет очень много процедур, порой даже с одной командой;
- целиковое событие размазывается по программе, что ведет к путанице;
- не понятно какую процедуру вызывать после того, как закончилась первая (требующая нажатия кнопки), и пользователь нажал кнопку (т.к. допустим эта кнопка используется во многих событиях).
- ну и требование делать все в одной процедуре (хотя конечно это можно оспорить и доказать невозможность такого подхода, но неизвестно к чему это приведет).

Был у меня еще один мысль (как предлагалось здесь): программа просит нажать кнопку и переходит в бесконечный цикл с Application.ProcessMessages, который ждет нажатия. Но это ведь занимает процессор, а это плохо.

А таймер мне не нравится тем, что как показала практика, переходов между частями события может быть много и между самими событиями и ощутимы задержки в программе. А какую поставить задержку на таймере тоже не понятно (вдруг на моем компе она успеет отработать, а на другом, допустим более медленном или быстром, нет?).

У меня была задумка работать со стеком (не с моим, а с обычным), как-то добавлять самому туда адреса процедур или что-то подменять, но я это не умею делать.

Для начала я бы попытался решить поставленную задачу, т.е. прерывать работу процедуры и возвращаться в нее. И сделать то же, что я уже сделал, но с обычным стеком (просто не знаю как), поэтому и спросил конкретно. Если не получится, тогда поменять метод, не через стек, а как-то еще. Ну а если уж и это никак, тогда придется как-то менять весь подход и доказывать, что поставленная задача нерешаема (что не хотелось бы).
fanlis вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Refresh() формы, или собственный MessageBox timao C++ Builder 2 29.11.2013 17:56
Выход из главной процедуры VictorM Microsoft Office Excel 6 26.11.2012 11:52
Принудительный выход из процедуры kardinal94 Общие вопросы Delphi 8 12.07.2011 03:55
Выход из процедуры mactepmac Общие вопросы Delphi 1 28.06.2011 06:56
Не работает выход во внешнию среду из процедуры!!! Hacker19_90 Паскаль, Turbo Pascal, PascalABC.NET 1 10.11.2008 19:31