OberonCore https://forum.oberoncore.ru/ |
|
Как изменить тип записи во время исполнения программы? https://forum.oberoncore.ru/viewtopic.php?f=2&t=2835 |
Страница 1 из 1 |
Автор: | Alexander Shiryaev [ Суббота, 11 Сентябрь, 2010 14:22 ] |
Заголовок сообщения: | Как изменить тип записи во время исполнения программы? |
Код: MODULE M; IMPORT SYSTEM; TYPE Msg* = ABSTRACT RECORD END; MsgA* = RECORD (Msg) a-, b-: INTEGER END; MsgB* = RECORD (Msg) x-, y-, z-: SHORTREAL END; MsgHandler* = POINTER TO ABSTRACT RECORD END; PROCEDURE (h: MsgHandler) Handle- (IN msg: Msg), NEW, ABSTRACT; PROCEDURE DataToMsg (type: INTEGER; IN a: ARRAY OF BYTE; len: INTEGER; VAR msg: ANYREC); BEGIN SetType(msg, type); (* как это сделать? *) SYSTEM.MOVE( SYSTEM.ADR(a), SYSTEM.ADR(msg), len ) END DataToMsg; PROCEDURE DataReceived* (id: BYTE; IN a: ARRAY OF BYTE; len: INTEGER; h: MsgHandler); TYPE MsgX = RECORD (Msg) END; VAR ok: BOOLEAN; type: INTEGER; msg: MsgX; BEGIN ok := FALSE; CASE id OF 10H: IF len = SIZE(MsgA) THEN ok := TRUE; type := GetType(MsgA) (* как это сделать? *) END | 11H: IF len = SIZE(MsgB) THEN ok := TRUE; type := GetType(MsgB) (* как это сделать? *) END ELSE END; IF ok THEN DataToMsg(type, a, len, msg); h.Handle(msg) END END DataReceived; END M. MODULE M1; IMPORT M, StdLog; TYPE MsgHandler = POINTER TO RECORD (M.MsgHandler) END; PROCEDURE (h: MsgHandler) Handler (IN msg: Msg); BEGIN WITH msg: M.MsgA DO StdLog.String("A:"); StdLog.Int(msg.a); StdLog.Int(msg.b); StdLog.Ln | msg: M.MsgB DO StdLog.String("B:"); StdLog.Real(msg.x); StdLog.Real(msg.y); StdLog.Real(msg.z); StdLog.Ln END END Handler; PROCEDURE Test*; VAR a: ARRAY 8 OF BYTE; h: MsgHandler; BEGIN a[0] := 1; a[1] := 1; a[2] := 0; a[3] := 0; a[4] := 2; a[5] := 1; a[6] := 0; a[7] := 0; NEW(h); M.DataReceived(10H, a, 8, h) END Test; END M1. Желательно с помощью Kernel. |
Автор: | Иван Кузьмицкий [ Суббота, 11 Сентябрь, 2010 14:48 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Зачем такое нужно? |
Автор: | Alexander Shiryaev [ Суббота, 11 Сентябрь, 2010 14:59 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Хочу реализовать обмен "сообщениями" между 2-мя компьютерами. Обрабатывать сообщения удобно таким способом: Код: PROCEDURE (h: Handler) MsgReceived (IN msg: Msg); BEGIN WITH msg: MsgA DO ... | msg: MsgB DO ... ... END END MsgReceived; а не таким: Код: PROCEDURE MsgReceived (id: INTEGER; IN data: ARRAY OF BYTE; len: INTEGER);
BEGIN CASE id OF 00H: ... | 01H: ... ... END END MsgReceived; |
Автор: | Пётр Кушнир [ Суббота, 11 Сентябрь, 2010 16:15 ] | ||
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? | ||
Обмен сообщениями между компами я организовал через джаббер, с использованием базового сообщения абстрактного типа. код примерно такой, постараюсь удалить весь джабер и оставить суть: Код: IMPORT SYSTEM, Kernel, Meta
TYPE MsgPtr* = POINTER TO Message; Message* = ABSTRACT RECORD (AbfBus.Message) END; Alien* = POINTER TO RECORD (Message) data* : Items.Item; END; Converter* = POINTER TO ABSTRACT RECORD END; PROCEDURE (c : Converter) ItemToMsg*(item : Items.Item; VAR msg : MsgPtr; res : INTEGER), NEW, ABSTRACT; PROCEDURE (c : Converter) MsgToItem*(VAR msg : Message; OUT item : Items.Item), NEW, ABSTRACT; StdConv = POINTER TO RECORD(Bus.Converter) END; PROCEDURE LookupItem (VAR r: ANYREC; OUT i: Meta.Item); VAR type: Kernel.Type; mod: Kernel.Module; attr: Kernel.ItemAttr; BEGIN (* create a meta item for a global variable passed as VAR parameter *) attr.obj := Meta.varObj; attr.typ := Meta.recTyp; attr.vis := Meta.exported; attr.adr := SYSTEM.ADR(r); attr.mod := NIL; attr.desc := SYSTEM.VAL(Kernel.Type, SYSTEM.TYP(r)); attr.ptr := NIL; attr.ext := NIL; attr.mod := NIL; Meta.GetThisItem(attr, i) END LookupItem; PROCEDURE (c : StdConv) ItemToMsg(item : Items.Item; VAR msg : Bus.MsgPtr; res : INTEGER); VAR name, summ : ARRAY 127 OF CHAR; this : Meta.Item; x : ANYPTR; hash : SternMd5.Hash; i : INTEGER; fnum, fp : ARRAY 127 OF CHAR; al : Bus.Alien; sp : Bus.Special; BEGIN name:=item.GetParam(Const.type)$; Meta.LookupPath(name, this); IF this.Valid() THEN x:=this.New(); ASSERT(x#NIL); msg:=x(Bus.MsgPtr); LookupItem(msg, this); i:=0; Inc(fnum); ELSE NEW(al); al.data:=item; msg:=al; END; END ItemToMsg;
|
Автор: | Пётр Кушнир [ Суббота, 11 Сентябрь, 2010 16:21 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
В общем, суть в том, что мы наследуем тип сообщения от абстрактного типа, реализовываем нужный нам тип сообщения, затем передаём его произвольным образом на другой комп, при этом передаём тип сообщения(я передаю название типа например "MyModule.MyMsg"), если на другом компе имеется модуль с тем же самым типом сообщения, создаём новый экземпляр нужного типа(x:=this.New()) и сразу подключаем к нему Meta-элемент(LookupItem) и заполняем его из полученных данных. |
Автор: | Пётр Кушнир [ Суббота, 11 Сентябрь, 2010 16:24 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Тип сообщения наследуется от абстрактного типа межможульной шины сообщений http://forum.oberoncore.ru/viewtopic.php?f=47&t=269&start=0&hilit=Advanced+BlackBox+Framework - AbfBus.Message с целью дальнейшего распространения полученных из сети сообщений по шине, не отходя от кассы, так сказать |
Автор: | Alexander Shiryaev [ Суббота, 11 Сентябрь, 2010 18:13 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
В итоге сделал так: Код: MODULE TmpM3; IMPORT SYSTEM, Kernel; TYPE Msg* = POINTER TO ABSTRACT RECORD END; MsgHandler* = POINTER TO ABSTRACT RECORD END; Table* = POINTER TO ABSTRACT RECORD END; PROCEDURE (h: MsgHandler) Handle- (msg: Msg), NEW, ABSTRACT; PROCEDURE (t: Table) Lookup- (id: BYTE; OUT len: BYTE; OUT type: INTEGER; OUT ok: BOOLEAN), NEW, ABSTRACT; PROCEDURE DataReceived* (id: BYTE; IN a: ARRAY OF BYTE; len: BYTE; h: MsgHandler; table: Table); VAR type: INTEGER; len1: BYTE; ok: BOOLEAN; msg: Msg; BEGIN table.Lookup(id, len1, type, ok); IF ok & (len = len1) THEN Kernel.NewObj( msg, SYSTEM.VAL( Kernel.Type, type) ); SYSTEM.MOVE( SYSTEM.ADR(a), SYSTEM.ADR(msg^), len ); ASSERT(msg # NIL); h.Handle(msg) END END DataReceived; END TmpM3. Код: MODULE TmpM4; (* этот модуль должен создаваться автоматически *) IMPORT SYSTEM, TmpM3; TYPE MsgA* = POINTER TO MsgADesc; MsgADesc* = RECORD (TmpM3.Msg) a-, b-: INTEGER END; MsgB* = POINTER TO MsgBDesc; MsgBDesc* = RECORD (TmpM3.Msg) x-, y-, z-: SHORTREAL END; Table = POINTER TO RECORD (TmpM3.Table) END; VAR table-: Table; PROCEDURE (t: Table) Lookup (id: BYTE; OUT len: BYTE; OUT type: INTEGER; OUT ok: BOOLEAN); BEGIN CASE id OF 10H: len := SIZE(MsgADesc); type := SYSTEM.TYP(MsgADesc); ok := TRUE | 11H: len := SIZE(MsgBDesc); type := SYSTEM.TYP(MsgBDesc); ok := TRUE ELSE ok := FALSE END END Lookup; BEGIN NEW(table) END TmpM4. Код: MODULE TmpM5;
IMPORT TmpM3, TmpM4, StdLog; TYPE MsgHandler = POINTER TO RECORD (TmpM3.MsgHandler) END; PROCEDURE (h: MsgHandler) Handle (msg: TmpM3.Msg); BEGIN WITH msg: TmpM4.MsgA DO StdLog.String("A:"); StdLog.Int(msg.a); StdLog.Int(msg.b); StdLog.Ln | msg: TmpM4.MsgB DO StdLog.String("B:"); StdLog.Real(msg.x); StdLog.Real(msg.y); StdLog.Real(msg.z); StdLog.Ln END END Handle; PROCEDURE Test*; VAR h: MsgHandler; a: ARRAY 12 OF BYTE; BEGIN a[0] := 1; a[1] := 1; a[2] := 0; a[3] := 0; a[4] := 2; a[5] := 1; a[6] := 0; a[7] := 0; NEW(h); TmpM3.DataReceived(10H, a, 8, h, TmpM4.table) END Test; END TmpM5. !(Q)TmpM5.Test |
Автор: | Илья Ермаков [ Воскресенье, 12 Сентябрь, 2010 21:41 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Ваша сетевая библиотеке в Блэкбоксе получателе должна вызывать какой-то обработчик, передавая ему запись нужного типа. Чтобы привести байтовый буфер к нужному типу, можете использовать функцию SYSTEM.THISRECORD. Она недокументирована, пример можно увидеть в Meta: Код: PROCEDURE (VAR rec: Item) CallWith* (proc: PROCEDURE(VAR rec, par: ANYREC); VAR par: ANYREC), NEW;
BEGIN ASSERT(rec.ext = NIL, 31); ASSERT(rec.ptr # NIL, 20); ASSERT(rec.typ = recTyp, 21); ASSERT(rec.obj = varObj, 22); ASSERT((rec.mod = NIL) OR (rec.mod.refcnt >= 0), 23); proc(SYSTEM.THISRECORD(rec.adr, SYSTEM.VAL(INTEGER, rec.desc)), par) END CallWith; |
Автор: | Alexander Shiryaev [ Понедельник, 13 Сентябрь, 2010 11:29 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Спасибо! Как раз то, что нужно. Код: MODULE TmpM3;
IMPORT SYSTEM; TYPE Msg* = ABSTRACT RECORD END; MsgHandler* = POINTER TO ABSTRACT RECORD END; Table* = POINTER TO ABSTRACT RECORD END; PROCEDURE (h: MsgHandler) Handle- (IN msg: Msg), NEW, ABSTRACT; PROCEDURE (t: Table) Lookup- (id: BYTE; OUT len: BYTE; OUT type: INTEGER; OUT ok: BOOLEAN), NEW, ABSTRACT; PROCEDURE DataReceived* (id: BYTE; IN a: ARRAY OF BYTE; len: BYTE; h: MsgHandler; table: Table); VAR type: INTEGER; len1: BYTE; ok: BOOLEAN; BEGIN table.Lookup(id, len1, type, ok); IF ok & (len = len1) THEN h.Handle( SYSTEM.THISRECORD( SYSTEM.ADR(a), type ) ) END END DataReceived; END TmpM3. |
Автор: | Пётр Кушнир [ Понедельник, 13 Сентябрь, 2010 14:47 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
мегахак!!! а я то, огород городил... |
Автор: | Иван Кузьмицкий [ Пятница, 06 Январь, 2012 14:50 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Не нашёл лучшего места, чем тут, чтобы зафиксировать концептуальный примерчик. Задача: необходимо рассылать уведомления по шине (здесь считаем, что это статическая RECORD без полей), зная только имя типа уведомления в виде цепочки символов. Код: MODULE TestMeta;
(** project = "TestMeta" organization = "" contributors = "" version = "System/Rsrc/About" copyright = "Kuzmitskiy Ivan Alexandrovich" license = "Docu/BB-License" purpose = "Лабораторный образец, демонстрирующий один из способов создания переменной, тип который задан цепочкой символов" changes = " - 20120106, kia, автогенерация заголовка " issues = "" **) IMPORT Log := StdLog, Meta; TYPE Message* = ABSTRACT RECORD END; PMessage* = POINTER TO Message; NotifyMsg* = RECORD (Message) END; NotifyMsg1* = RECORD (Message) END; NotifyMsg2* = RECORD (Message) END; PROCEDURE Handle (VAR msg: Message); BEGIN WITH msg: NotifyMsg DO Log.String('TestMeta, обработка NotifyMsg'); Log.Ln | msg: NotifyMsg1 DO Log.String('TestMeta, обработка NotifyMsg1'); Log.Ln | msg: NotifyMsg2 DO Log.String('TestMeta, обработка NotifyMsg2'); Log.Ln ELSE END END Handle; PROCEDURE Do* (s: ARRAY OF CHAR); VAR this: Meta.Item; x: ANYPTR; pn: PMessage; n: NotifyMsg; BEGIN Meta.LookupPath(s, this); IF this.Valid() THEN x := this.New(); ASSERT(x # NIL, 60); Handle(x(PMessage)) ELSE Log.String('TestMeta: Тип не найден!'); Log.Ln; END; END Do; END TestMeta. ^Q"TestMeta.Do('')" ^Q"TestMeta.Do('TestMeta.NotifyMsg')" ^Q"TestMeta.Do('TestMeta.NotifyMsg1')" ^Q"TestMeta.Do('TestMeta.NotifyMsg2')" |
Автор: | Илья Ермаков [ Понедельник, 09 Январь, 2012 10:13 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Хороший пример, но у него есть важный изъян: порождается динамический экземпляр. Для прикладного программирования это можно стерпеть, но вообще, каждый раз, когда я такое вижу, мне обидно за то, что мы скатываемся к стилю Явы/Шарпов - плодить мусор там, где Оберон, с его полиморфизмом для записей на стеке, позволяет этого не делать... В вашем случае, чтобы "не плодить", можно сделать модулёк, которая внутри решает эту проблему (подстановку пустого экземпляра записи по имени) через SYSTEM... Самый простой способ - использовать THISREC. Если без SYSTEM - то можно сделать такой модулёк, который хранит по одному экземпляру записей по их имени и отдаёт нужную. Это как дополнение к Вашему примеру. В нагруженных приложениях это важно. |
Автор: | Иван Кузьмицкий [ Понедельник, 09 Январь, 2012 14:53 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Я ещё не понял, как пользоваться SYSTEM.THISRECORD |
Автор: | Александр Ильин [ Понедельник, 09 Январь, 2012 15:03 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Илья Ермаков писал(а): Самый простой способ - использовать THISREC. Чего?В документации не нашёл такого. |
Автор: | Евгений Темиргалеев [ Понедельник, 09 Январь, 2012 15:07 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
В документации её и нету. Была выкопана в исходниках компилятора и затем обнаружена в коде модуля Meta. |
Автор: | Роман М. [ Вторник, 10 Январь, 2012 18:59 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Илья Ермаков писал(а): Самый простой способ - использовать THISREC. То есть использовать недокументированную функциональность? |
Автор: | Info21 [ Среда, 11 Январь, 2012 12:53 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Заразная какая болезнь. |
Автор: | Иван Кузьмицкий [ Среда, 11 Январь, 2012 13:35 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Это не болезнь, а поиск средств для обмена сообщениями между экземплярами BlackBox. Всем известно, что экземпляры BlackBox функционируют в чужеродной, "не-оберон"-среде , поэтому просто так сообщение не передашь! Надо его, это сообщение, обязательно завернуть в полиэтиленовый пакет в целях инфекционной безопасности, да сургучом залить, а при получении распечатать |
Автор: | Info21 [ Среда, 11 Январь, 2012 15:33 ] |
Заголовок сообщения: | Re: Как изменить тип записи во время исполнения программы? |
Иван Кузьмицкий писал(а): Это не болезнь, а поиск средств для обмена сообщениями между экземплярами BlackBox. Ну, пусть.
|
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |