Оберон-клуб «ВЄДАsoft»

Твердыня модульных языков
Текущее время: 24 ноя 2017, 20:35

Часовой пояс: UTC + 2 часа




Начать новую тему Ответить на тему  [ Сообщений: 69 ]  На страницу Пред.  1 ... 3, 4, 5, 6, 7
Автор Сообщение
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 09 май 2015, 19:03 
Не в сети
Администратор
Аватара пользователя

Сообщения: 237
Откуда: Россия
Saferoll писал(а):
И вот какая появилась еще идея.
Константные массивы трактуются как входные параметры IN, что на мой взгляд удобнее просто констант.
Но может быть дополнительно к этому сделать, чтобы элемент константного массива, у которого все индексы заданы константой, считался константой.
...
Мы как бы вводим новый тип константного выражения - "взятие по индексу". Причём в этой операции наряду с константами (индексами) участвует и неконстанта - сам массив.
В качестве индексов можно задавать даже константное выражение, что сулит дополнительные удобства. В том числе, например, для реализации беззнаковой арифметики.

А вот сделать это оказалось не так и сложно. Достаточно внести изменения в модуль OPB.
Нужно изменить процедуру Index, которая как раз и добавляет в дерево операцию "индексация":
Код: "OBERON"
  1. PROCEDURE Index*(VAR x: OPT.Node; y: OPT.Node);
  2. VAR f: SHORTINT; typ: OPT.Struct;
  3. BEGIN
  4. f := y^.typ^.form;
  5. IF x^.class >= Nconst THEN err(79)
  6. ELSIF ~(f IN intSet) OR (y^.class IN {Nproc, Ntype}) THEN err(80); y^.typ := OPT.inttyp END ;
  7. IF x^.typ^.comp = Array THEN typ := x^.typ^.BaseTyp;
  8. IF (y^.class = Nconst) & ((y^.conval^.intval < 0) OR (y^.conval^.intval >= x^.typ^.n)) THEN err(81) END
  9. ELSIF x^.typ^.comp = DynArr THEN typ := x^.typ^.BaseTyp;
  10. IF (y^.class = Nconst) & (y^.conval^.intval < 0) THEN err(81) END
  11. ELSE err(82); typ := OPT.undftyp
  12. END ;
  13. BindNodes(Nindex, typ, x, y); x^.readonly := x^.left^.readonly;
  14.  
  15. IF (x^.right^.class = Nconst) & (* индекс является константой *)
  16. (x^.right^.conval^.intval >= 0) &(x^.right^.conval^.intval < x^.left^.typ^.n)& (* притом правильной *)
  17. ( (x^.left^.class = Nindex) & (x^.left^.subcl = Nconst ) OR (* и применяется к элементу конст.массива *)
  18. (* или к самому конст.массиву *)
  19. (x^.left^.obj#NIL)&(x^.left^.obj^.conval # NIL) & (x^.left^.obj^.conval^.arr # NIL)) THEN
  20. IF x^.typ^.comp = Basic THEN (* заменить обращение к элементу его значением *)
  21. FoldConstArrElem(x)
  22. ELSE
  23. x^.subcl := Nconst (* пометить потенциальный элемент - константу *)
  24. END
  25. END;
  26. END Index;
  27.  

А где-то выше (можно после процедуры NewArrConst) необходимо добавить новую процедуру
Код: "OBERON"
  1. PROCEDURE FoldConstArrElem(VAR x:OPT.Node);
  2. (* заменяет элемент константного массива его значением *)
  3. VAR k, i : INTEGER;
  4. y: OPT.Node;
  5. arr: OPT.ConstArr;
  6. BEGIN
  7. k := 1;
  8. i := 0;
  9. y := x;
  10. (* найдем индекс элемента в одномерном куске памяти*)
  11. WHILE y^.class = Nindex DO
  12. i := i+k*y^.right^.conval^.intval; (* индекс *)
  13. y := y^.left;
  14. k:=k*y^.typ^.n;
  15. END;
  16. (* создадим константу, соответствующую этому элементу *)
  17. arr := y^.obj^.conval^.arr;
  18. WITH
  19. | arr : OPT.ConstArrOfByte DO y := NewIntConst(arr.val[i]);
  20. | arr : OPT.ConstArrOfSInt DO y := NewIntConst(arr.val[i]);
  21. | arr : OPT.ConstArrOfInt DO y := NewIntConst(arr.val[i]);
  22. END;
  23. (* коррекция типа константы *)
  24. CASE x^.typ^.form OF
  25. | Bool: y := NewBoolConst(y^.conval^.intval = 1);
  26. | Char: y^.typ := OPT.chartyp;
  27. | Byte: y^.typ := OPT.bytetyp;
  28. ELSE (* для целого типа все уже сделано *)
  29. END;
  30. (* заменим элемент константного массива константой *)
  31. x := y;
  32. END FoldConstArrElem;
  33.  
  34.  

В результате обращение к элементу константного массива будет уже на этапе построения дерева заменено константой.
Например
Код: "OBERON"
  1. TYPE Labirint = ARRAY 2 OF ARRAY 3,3 OF INTEGER;
  2. CONST Map = Labirint(((1,2,3),(4,5,6),(7,8,9)), ((11,12,13),(14,15,16),(17,18,19)));
  3. VAR I:INTEGER;
  4. BEGIN
  5. I:=Map[1,2,2];
  6. ...
В Си-исходнике оператор I:=Map[1,2,2]; превращается в Unsigned_I = 17;
Причем это именно константа. Можно написать, например
Код: "OBERON"
  1. FOR I := 60 TO 120 BY Map[1,0,2] DO

и это эквивалентно
Код: "OBERON"
  1. FOR I := 60 TO 120 BY 13 DO


Вернуться к началу
 Профиль  
Ответить с цитатой  
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 09 май 2015, 21:44 
Не в сети
Администратор
Аватара пользователя

Сообщения: 237
Откуда: Россия
Заметим, что в константу превращаются таким образом только неструктурные типы (BYTE, CHAR, BOOLEAN и целые). Если задано
Код: "OBERON"
  1. TYPE MsgStr= ARRAY 3,7 OF CHAR;
  2. CONST Msg= MsgStr("Hello!" , "Error" , "Try" );
  3.  
то Msg[0] это не константа, это массив из символов. А вот Msg[0,0] это константа символьного типа.
Но при этом вдруг выяснилось, что строки в константных массивах оказались несовместимы по присваиванию:
Код: "OBERON"
  1. TYPE MsgStr= ARRAY 3,7 OF CHAR;
  2. CONST Msg= MsgStr("Hello!" , "Error" , "Try" );
  3. Msg2="asdfgh";
  4. VAR
  5. S:ARRAY 7 OF CHAR;
  6. BEGIN
  7. S:=Msg[0]; (* выдает ошибку "incompatible assignment"*)
  8. S:=Msg2; (* допустимо*)
  9.  


Вернуться к началу
 Профиль  
Ответить с цитатой  
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 10 май 2015, 13:00 
Не в сети
Аватара пользователя

Сообщения: 843
Откуда: Днепропетровская обл.
Saferoll писал(а):
Небольшой патч, призванный устранить вылет по ТРАП при нарушении синтаксиса в описании константных массивов.
Патч добавил, Олежек.

Saferoll писал(а):
1) Константные массивы не экспортируется, даже если помечены звездочкой. Это означает, что к ним нельзя обращаться из другого модуля, а можно только из того, где они описаны.
Досадная проблема, но для её решения скорее всего понадобится изменить формат символьных файлов. Вообще говоря, это уже и так назревает, т.к. оказалось, что в символьных файлах хранится машинно-ориентированная информация (размер записей в байтах), из-за чего для правильной генерации 64-битных программ пришлось ввести в WinDev второй набор символьных файлов Sym64. Это быстрое заплаточное решение, но оно акцентирует дальнейшие исследования на изучение различий в 32-битных и 64-битных символьных файлах. И, видимо, слить их опять в один набор получится только после не такой уж тривиальной переделки Ofront'а, чем я пока тоже не планирую заниматься.

Saferoll писал(а):
2) SDCC неправильно работает со строками константного массива, хотя они и верно генерируются в Си-исходнике. При этом под константный массив выделяется место, с которым и работают все операции. Но сами значения задаются в другом месте, откуда, видимо, какой-то код инициализации должен бы их перекинуть в зарезервированную область. Но этот код отсутствует или не срабатывает.
Этот код на самом деле должен находиться в crt0, откуда я его вырезал для экономии памяти. Решить сию трудность будет не так трудно, достаточно просто вернуть в ctr0 участок кода, ответственный за инициализацию статических структур (или даже иметь несколько вариантов crt0, из которых при сборке выберется нужный). Грустно другое. То, что SDCC работает с констатнтыми массивами не так уж эффективно. Но и здесь есть надежда, что ситуация силами сообщества SDCC со временем улучшится.


Вернуться к началу
 Профиль  
Ответить с цитатой  
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 16 май 2015, 02:05 
Не в сети
Аватара пользователя

Сообщения: 843
Откуда: Днепропетровская обл.
Я тут подумал, что пляски с crt0 — по сути уже вторичное решение. Проблема заключается в том, что SDCC не должен дублировать данные константных массивов. А зачем он это делает? Чтобы иметь возможность переброской исходных данных в массив восстановить его исходное состояние, что актуально только для обычных проинициализированных массивов (в Обероне таких массивов быть не может), но никак не для константных. Но для константных код всё равно генерируется с дублированием данных.

Я не поленился и написал о проблеме сообществу разработчиков SDCC. Посмотрим, что ответят.

А экспорт константных массивов предстоит сделать нам. Меня только смущает вот что. Как быть с отображением таких массивов при просмотре интерфейса? Показывать ли все данные экспортированного массива? Для небольших массивов это вроде бы и полезно. А вот если массивы будут огромные, то может получиться мега-простыня из цифр. Олежек, интересует твоё мнение.


Вернуться к началу
 Профиль  
Ответить с цитатой  
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 16 май 2015, 17:06 
Не в сети
Администратор
Аватара пользователя

Сообщения: 237
Откуда: Россия
Zorko писал(а):
А экспорт константных массивов предстоит сделать нам. Меня только смущает вот что. Как быть с отображением таких массивов при просмотре интерфейса? Показывать ли все данные экспортированного массива? Для небольших массивов это вроде бы и полезно. А вот если массивы будут огромные, то может получиться мега-простыня из цифр. Олежек, интересует твоё мнение.
Я всё ещё плохо представляю механизм экспорта. Может быть можно сделать так, чтобы небольшие массивы выводились прямо, а у больших выводить только структуру и ссылку, по которой открывался бы просмотр элементов в отдельном окне?
Zorko писал(а):
Я не поленился и написал о проблеме сообществу разработчиков SDCC. Посмотрим, что ответят.
Там уже кое-что ответили. Philipp Krause предложил использовать конструкцию, наподобие такой
Код: "C"
const char Msg[3][7] =
{{72,101,108,108,111,33,0},
{69,114,114,111,114,0,0},
{84,114,121,0,0,0,0}};
Действительно, если внести такие изменения в С-исходник, то генерируется код
Код: "ASM"
_Msg:
.db #0x48 ; 72 'H'
.db #0x65 ; 101 'e'
.db #0x6C ; 108 'l'
.db #0x6C ; 108 'l'
.db #0x6F ; 111 'o'
.db #0x21 ; 33
.db #0x00 ; 0
.db #0x45 ; 69 'E'
.db #0x72 ; 114 'r'
.db #0x72 ; 114 'r'
.db #0x6F ; 111 'o'
.db #0x72 ; 114 'r'
.db #0x00 ; 0
.db #0x00 ; 0
.db #0x54 ; 84 'T'
.db #0x72 ; 114 'r'
.db #0x79 ; 121 'y'
.db #0x00 ; 0
.db #0x00 ; 0
.db #0x00 ; 0
.db #0x00 ; 0
без всяких инициализаций. Это, в принципе, то, что нам и нужно (?).
Аналогичный результат получается ,если написать
Код: "C"
typedef
CHAR const MsgStr[3][7];
MsgStr Msg =
{{72,101,108,108,111,33,0},
{69,114,114,111,114,0,0},
{84,114,121,0,0,0,0}};

Можно было бы переделать кодогенерацию. Но здесь есть сложность - придется вставлять слово const внутрь typedef. Можно завести для этого два разных типа
Код: "C"
typedef
CHAR MsgStr[3][7];/* для обычных массивов */
typedef
CHAR const _const_MsgStr[3][7];/* для константных массивов */

А может даже лучше употреблять модификатор const два раза:
Код: "C"
typedef
CHAR const MsgStr[3][7];
const MsgStr Msg =
{{72,101,108,108,111,33,0},
{69,114,114,111,114,0,0},
{84,114,121,0,0,0,0}};
чтобы
1)идентификатор Msg всегда указывал на одну и ту же область памяти (адрес, связанный с идентификатором Msg, - константа)
2)сами значения в этой области нельзя было изменить.
Вот, только вопрос, будет ли при этом совместимость по присваиванию и прочее, ведь константные массивы в Оберон-коде у нас толкуются как IN-параметры.

Впрочем, разработчики SDCC признали наличие ошибки, так что немного подождем. Возможно, SDCC и для первоначального варианта (с __CONSTARR) будет генерировать правильный ASM-код.


Вернуться к началу
 Профиль  
Ответить с цитатой  
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 16 май 2015, 23:41 
Не в сети
Аватара пользователя

Сообщения: 843
Откуда: Днепропетровская обл.
Да, походу они выкопали, что const в выражении "const char Msg[3][7]" относится и к элементам массива тоже. Ну что же, я так и предполагал. Так что твой код для генерации массива корректен, нам остаётся только подождать исправления этой ошибки в SDCC.

Вывод при просмотре интерфейса только структуры массива и ссылки, по которой откроется просмотр элементов в отдельном окне, будет трудновато вписать в существующее устроение браузера. Наверное. В любом случае, для начала предлагаю реализовать полный вывод всего массива, а там посмотрим, может им и ограничимся.


Вернуться к началу
 Профиль  
Ответить с цитатой  
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 17 май 2015, 07:40 
Не в сети
Администратор
Аватара пользователя

Сообщения: 237
Откуда: Россия
Zorko писал(а):
Вывод при просмотре интерфейса только структуры массива и ссылки, по которой откроется просмотр элементов в отдельном окне, будет трудновато вписать в существующее устроение браузера. Наверное. В любом случае, для начала предлагаю реализовать полный вывод всего массива, а там посмотрим, может им и ограничимся.
К сожалению, я пока занимался только Ofront-ом и плохо представляю внутренности ББ. Но вот, скажем, в ТРАП-окне можно щелкнуть по ромбику и откроется отдельное окно с переменными. Можно, наверно, там подсмотреть реализацию: для массива выводится несколько первых элементов и многоточие (если элементов много), по щелчку на многоточии в отдельном окне выводится весь массив целиком. Но это в идеале, а пока можно выводить все элементы (или часть с простым неактивным многоточием).


Вернуться к началу
 Профиль  
Ответить с цитатой  
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 09 июн 2017, 21:21 
Не в сети
Администратор
Аватара пользователя

Сообщения: 237
Откуда: Россия
Попробуем исправить проблему с несовместимостью строк. Для этого можно внести такие исправления в процедуру OPB.CheckAssign:
Код: "OBERON"
  1. PROCEDURE CheckAssign(x: OPT.Struct; ynode: OPT.Node); (* x := y *)
  2. VAR f, g: SHORTINT; y, p, q: OPT.Struct;
  3. BEGIN
  4. ...
  5. | Comp:
  6. x^.pvused := TRUE; (* idfp of y guarantees assignment compatibility with x *)
  7. IF x^.comp = Array THEN
  8. IF (ynode^.class = Nconst) & (g = Char) THEN CharToString(ynode); y := ynode^.typ; g := String END ;
  9. IF x = y THEN (* ok *)
  10. ELSIF (g = String) & (x^.BaseTyp = OPT.chartyp) THEN (*check length of string*)
  11. IF ynode^.conval^.intval2 > x^.n THEN err(114) END ;
  12. (* массиву из символов присваивается массив из символов *)
  13. ELSIF (g=Comp) & (y^.comp = Array) & (y^.BaseTyp = OPT.chartyp)
  14. & (x^.BaseTyp = OPT.chartyp) & (ynode^.left # NIL) & (ynode^.left^.obj # NIL)
  15. & (ynode^.left^.obj^.conval # NIL) & (ynode^.left^.obj^.conval^.arr # NIL) THEN
  16. IF y^.n > x^.n THEN err(114) END ;
  17. ELSE err(113)
  18. END
  19. ...
  20.  
После такого исправления программа
Код: "OBERON"
  1. MODULE arrstr; (*$MAIN*)
  2. TYPE MsgStr= ARRAY 3,6 OF CHAR;
  3. CONST Msg= MsgStr("Hello" , "Error" , "Try" );
  4. Msg2="asdfgh";
  5. VAR
  6. S:ARRAY 7 OF CHAR;
  7. BEGIN
  8. S:=Msg[0]; (* выдавало ошибку "incompatible assignment"*)
  9. S:=Msg2; (* допустимо*)
  10. END arrstr.

Успешно пройдет компиляцию в С-код:
Код: "C"
/* Ofront+ 0.9 -sm */
#include "SYSTEM.h"
typedef
CHAR arrstr_MsgStr[3][6];
__CONSTARR arrstr_MsgStr Msg =
{{72,101,108,108,111,0},
{69,114,114,111,114,0},
{84,114,121,0,0,0}};
static CHAR arrstr_S[7];
/*============================================================================*/
int main(int argc, char **argv)
{
__INIT(argc, argv);
__REGMAIN("arrstr", 0);
/* BEGIN */
__MOVE(Msg[0], arrstr_S, 6);
__MOVE("asdfgh", arrstr_S, 7);
__FINI;
}
Компиляция будет успешной, если изменить длину массива:
Код: "OBERON"
  1. TYPE MsgStr= ARRAY 3,7 OF CHAR;
  2. CONST Msg= MsgStr("Hello!" , "Error" , "Try" );
Если же поставить TYPE MsgStr= ARRAY 3,8 OF CHAR; , то будет ошибка 114 ("string too long"). Если изменить тип константного массива на TYPE MsgStr= ARRAY 3,7 OF BYTE; , то опять будет ошибка о несовместимом присваивании.
Обратим внимание на сложное условие. Если там убрать
Код: "OBERON"
  1. (ynode^.left#NIL) & (ynode^.left^.obj#NIL) & (ynode^.left^.obj^.conval # NIL) & (ynode^.left^.obj^.conval^.arr # NIL)
то присваивание будет разрешено не только для константных, но и для любых символьных массивов. А если еще больше ослабить условие и оставить только
Код: "OBERON"
  1. ELSIF (g=Comp) & (y^.comp = Array) & (y^.BaseTyp = x^.BaseTyp)
то присваивать друг другу можно будет не только символьные, но и вообще любые массивы, лишь бы совпадал тип элементов и элементов в источнике не было бы больше (меньше можно).
Но до какой степени полезно ослаблять это условие? Какие правила совместимости по присваиванию введем для массивов (константных массивов)?


Вернуться к началу
 Профиль  
Ответить с цитатой  
 Заголовок сообщения: Re: Константные массивы
СообщениеДобавлено: 13 июн 2017, 01:06 
Не в сети
Аватара пользователя

Сообщения: 843
Откуда: Днепропетровская обл.
Олежек, предложенное исправление внедрил. Правда, пока что без ослабления строгости присваиваний. В Обероне есть тонкость, благодаря которой, мне кажется, нам ничего ослаблять не потребуется:
Код: "OBERON"
  1. MODULE ArrTest; (*$MAIN*)
  2. TYPE
  3. ArrType = ARRAY 7 OF INTEGER;
  4. CONST
  5. S0 = ArrType( 1, 2, 3, 4, 5, 6, 7 );
  6. VAR
  7. S1, S2: ARRAY 7 OF INTEGER;
  8. S3: ARRAY 7 OF INTEGER;
  9. S4: ArrType;
  10. BEGIN
  11. S1 := S2;
  12. S1 := S3; (* incompatible assignment *)
  13. S1 := S0; (* incompatible assignment *)
  14. S4 := S0;
  15. END ArrTest.
Первое присваивание — это присваивание между массивами S1 и S2, которые объявлены вместе, и поэтому считаются совместимыми.

Второе присваивание, строго говоря, фактически между массивами того же типа, но объявленными раздельно, а такие массивы в Обероне-2 совместимыми не считаются (в КП тоже — только что проверил в BlackBox).

Следуя букве строгой типизации, мы объявили массив S4 того же типа, что и константный S0 — типа ArrType. И, о чудо! Они совместимы по присваиванию! И ничего не ослаблено! :-)

Это действительно не слишком очевидная тонкость — объявлять массивы, которые планируется копировать, вместе. Либо же через заранее описанный тип. Ведь типы ARRAY 7 OF INTEGER и ArrType, как в данном примере, не считаются одним и тем же типом. В духе Оберона. :-)

Благодарю тебя за проделанную работу! Ценно.


Вернуться к началу
 Профиль  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 69 ]  На страницу Пред.  1 ... 3, 4, 5, 6, 7

Часовой пояс: UTC + 2 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Тех.поддержка phpBB