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

Твердыня модульных языков
Текущее время: 18 апр 2024, 13:56

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




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

Сообщения: 273
Откуда: Россия
Для многомерного константного массива в Си-исходнике служит процедура OPC.WriteConstArr, которая по структуре похожа на OPP.ConstArray, но гораздо проще, т.к. не нужны изощрённые проверки. Ведь если мы дошли до генерации программы на С, значит уже построено верное синтаксическое дерево.
Код: "OBERON"
  1. PROCEDURE WriteConstArr (VAR obj: OPT.Object; typ: OPT.Struct);
  2. (* генерация конструкция "константный массив". typ - текущий уровень массива *)
  3. VAR apar: OPT.Node; i: INTEGER;
  4.  
  5. PROCEDURE WriteElem (arr: OPT.ConstArr; i: INTEGER);
  6. (* выводит в листинг i-й элемент константного массива arr *)
  7. BEGIN
  8. WITH
  9. | arr : OPT.ConstArrOfByte DO OPM.WriteInt(arr.val[i]);
  10. | arr : OPT.ConstArrOfSInt DO OPM.WriteInt(arr.val[i]);
  11. | arr : OPT.ConstArrOfInt DO OPM.WriteInt(arr.val[i]);
  12. END;
  13. END WriteElem;
  14.  
  15. BEGIN
  16. OPM.WriteString("{"); (* скобка ( *)
  17. i := 0;
  18. IF typ^.BaseTyp^.form # 15 THEN (* массив из простых элементов *)
  19. FOR i := 0 TO typ^.n-2 DO
  20. WriteElem(obj^.conval^.arr , i+obj^.conval^.intval); OPM.WriteString(",");
  21. IF (i+1) MOD 10 = 0 THEN OPM.WriteLn; OPM.WriteString(" ") END;
  22. END;
  23. WriteElem(obj^.conval^.arr , typ^.n-1+obj^.conval^.intval); (* последний элемент *)
  24. INC(obj^.conval^.intval, typ^.n); (* учли выведенные элементы *)
  25. ELSE (* массив из массивов *)
  26. FOR i := 0 TO typ^.n-2 DO
  27. WriteConstArr (obj, typ^.BaseTyp); (* рекурсивная обработка подмассива *)
  28. OPM.WriteString(","); OPM.WriteLn;
  29. OPM.WriteString(" ");
  30. END;
  31. WriteConstArr (obj, typ^.BaseTyp); (* последний элемент *)
  32. END;
  33. OPM.WriteString("}");
  34. END WriteConstArr;
А вызывать эту процедуру будем из OPC.IdentList
Код: "OBERON"
  1. PROCEDURE IdentList (obj: OPT.Object; vis: SHORTINT);
  2. (* generate var and param lists; vis: 0 all global vars, local var, 1 exported(R) var, 2 par list, 3 scope var *)
  3. VAR base: OPT.Struct; first: BOOLEAN; lastvis: SHORTINT; i: INTEGER;
  4.  
  5.  
  6.  
  7. BEGIN
  8. base := NIL; first := TRUE;
  9. WHILE (obj # NIL) & (obj^.mode # TProc) DO
  10. IF (vis IN {0, 2}) OR ((vis = 1) & (obj^.vis # 0)) OR ((vis = 3) & ~obj^.leaf) THEN
  11. IF (obj^.typ # base) OR (obj^.vis # lastvis) OR
  12. ((obj^.conval # NIL) & (obj^.conval^.arr # NIL)) THEN (* каждый конст.массив отдельно*)
  13. (* new variable base type definition required *)
  14. IF ~first THEN EndStat END ;
  15. first := FALSE;
  16. base := obj^.typ; lastvis := obj^.vis;
  17. BegStat;
  18. IF (vis = 1) & (obj^.vis # internal) THEN OPM.WriteString(Extern)
  19. ELSIF (obj^.mnolev = 0) & (vis = 0) THEN
  20. IF (obj^.conval # NIL) & (obj^.conval^.arr # NIL) THEN (* конст.массив *)
  21. OPM.WriteString("__CONSTARR ");
  22. ELSIF obj^.vis = internal THEN OPM.WriteString(Static)
  23. ELSE OPM.WriteString(Export)
  24. END
  25. ELSIF (obj^.conval # NIL) & (obj^.conval^.arr # NIL) THEN (* конст.массив *)
  26. OPM.WriteString("__CONSTARRLOC ")
  27. END;
  28. ...
  29. ELSIF (obj^.conval # NIL) & (obj^.conval^.arr # NIL) THEN (* элементы конст.массива *)
  30. OPM.WriteString(" ="); OPM.WriteLn;
  31. OPM.WriteString(" ");
  32. obj^.conval^.intval := 0;
  33. WriteConstArr (obj, obj^.typ);
  34. END
  35. ...
Теперь
Код: "OBERON"
  1. MODULE Unsigned; (*$MAIN*)
  2. IMPORT SYSTEM;
  3. TYPE VVV= ARRAY 2 OF BYTE;
  4. TheClocks = ARRAY 3 OF VVV;
  5. CONST AnimClockData = TheClocks((41,'L'),(1, 0F2X), (CHR(0F2H),19));
  6. VAR b:VVV;
  7. BEGIN
  8. b:=AnimClockData[0];
  9. END Unsigned.
транслируется в
Код: "C"
/*  Ofront 1.2 -xtspkaem */
#include "SYSTEM.h"
 
typedef
BYTE Unsigned_VVV[2];
 
typedef
Unsigned_VVV Unsigned_TheClocks[3];
 
 
__CONSTARR Unsigned_TheClocks AnimClockData =
{{41,76},
{1,-14},
{-14,19}};
static Unsigned_VVV Unsigned_b;
 
/*============================================================================*/
 
 
export main(int argc, char **argv)
{
__INIT(argc, argv);
__REGMAIN("Unsigned", 0);
/* BEGIN */
__MOVE(AnimClockData[0], Unsigned_b, 2);
__FINI;
}
Можно ещё подумать над расположением переносов строк в С-листинге, но это уже "красоты", этим можно заняться и потом.


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

Сообщения: 273
Откуда: Россия
Добавить типы BOOLEAN и CHAR оказалось очень просто - достаточно изменить всего две строчки:
в процедуре OPB.NewArrConst
Код: "OBERON"
  1. IF typ^.form IN intSet+{Bool,Char} THEN (* массив из целых (в т.ч. BYTE) *)
и в процедуре OPP.ConstArray
Код: "OBERON"
  1. IF typ^.BaseTyp^.form IN intSet+{Bool,Char} THEN (* массив из целых (в т.ч. BYTE) *)

В Си-исходнике элементы константного массива генерируются при этом как целые числа.


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

Сообщения: 273
Откуда: Россия
А вот задание элементов массива в виде строки в кавычках требует обсуждения некоторых нюансов. Как, например, мы будем толковать последовательность в кавычках "АВС"? Как массив ARRAY 4 OF CHAR заданный (41X, 42X, 43X, 0X)?

1) Т.е. символы в кавычках ' или " означают то же самое, что символы в скобках через запятую, при этом в конец добавляется обязательный символ 0X?

Пусть так. Но нужно рассмотреть некоторые частности.

2) Если в кавычках ровно 1 символ, то это может означать либо символ, либо массив из двух символов (этот символ и нулевой) в зависимости от контекста. Но если контекст непонятен, то чему отдать предпочтение?

3)Что значит "" ? Это "массив из одного символа 0Х" или "просто символ 0Х"? Это не одно и то же, потому что массив означает переход на следующий уровень структуры (даже если эта структура имеет длину 1).

4)В примере
Код: "OBERON"
  1. TYPE Vector = ARRAY 4 OF CHAR;
  2. CONST Way = Vector(".#-");
заменим кавычки скобками и получим
Код: "OBERON"
  1. TYPE Vector = ARRAY 4 OF CHAR;
  2. CONST Way = Vector(("." , "#" , "-" , 0X));
Видим, что буквальное следование "правилу 1)" добавляет ещё один уровень и получается как будто ARRAY 1 OF ARRAY 4 OF CHAR. Т.е. на самом верхнем уровне "" на скобки не заменяются, используются те скобки, что уже есть после идентификатора типа.

5) Видим ,что мы должны предусмотреть в массиве место для обязательного 0X, даже если он нам и не нужен. Ведь мы можем задать
Код: "OBERON"
  1. TYPE Vector = ARRAY 3 OF CHAR;
  2. CONST Way = Vector("." , "#" , "-" );
Нам понадобился лишний элемент только потому, что мы захотели не писать лишние ' и запятые. Но по этой причине пришлось писать ARRAY 4, а не ARRAY 3. Проблема в том, что нет возможности простым литералом задать последовательность символов, можно задать лишь "последовательность и обязательный нулевой символ". Однако, мы можем ввести такое правило "если для обязательного нулевого символа в константном массиве нет места, то он отбрасывается". Вот только будет ли это хорошо?

6) Может ввести еще одно правило "Если в кавычках стоит меньше символов, чем размер массива, то недостающие элементы массива заполняются 0Х". Тогда мы можем писать
Код: "OBERON"
  1. TYPE MsgStr= ARRAY 3,7 OF CHAR;
  2. CONST Way = MsgStr("Hello!" , "Error" , "Try" );
и это эквивалентно
Код: "OBERON"
  1. TYPE MsgStr= ARRAY 3,7 OF CHAR;
  2. CONST Way= MsgStr(("H","e","l","l","o","!",0X) , ("E","r","r","o","r",0X,0X) , ("T","r","y",0X,0X,0X,0X) );

Следует отметить, что это касается только использования кавычек. А если элементы перечислены в скобках через запятую, то их должно быть строго заданное количество и все 0X в этом случае указываются явно.

Сравнивая 5 и 6. Ведь тем кавычки и хороши, что 0X всегда добавляется. А вдруг, в примере 6) мы ошибёмся и напишем "Hello!." или 6 вместо 7 поставим (TYPE MsgStr= ARRAY 3,6 OF CHAR;). А это не массив из символов, а именно ASCIZ-строки. А правило 5) лишний 0X просто отбросит и нас не предупредит. В результате, какая-нибудь процедура нулевой ограничитель не найдёт и залезет куда-нибудь не туда.

А ещё больше сложностей появится, если мы введём константные массивы без указания размера.


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

Сообщения: 273
Откуда: Россия
Вот здесь и проявились недостатки Оберона, касающиеся строк и символов. Кое-что уже обсуждалось на нашем форуме в теме Ответ Alone Coder'у, но было известно и ранее (http://maxandreev.narod.ru/oberon/CritiqueOberonLanguage_RUS.pdf).
Символ - это всегда одиночный символ, понятие "длина" (в том смысле как "длина строки") к нему неприменимо. Если мы хотим работать с цепочкой символов фиксированного размера, то к нашим услугам массивы (обычные, т.е. фиксированной длины, не открытые). А вот если последовательность символов может иметь переменную длину, то требуется особый тип "строка".
И это, вообще-то, три разных структуры данных. В чём-то они похожи, поэтому можно в некоторых случаях установить соответствие (скажем "символ" - "ARRAY 1 OF CHAR" - "строковая константа длины 1"), но есть и отличия, которые не позволяют говорить, что это одно и то же.

Строка - это реализация абстракции "последовательность символов переменной длины". Раз длина переменная, значит как-то нужно хранить текущую длину. Для этого существуют два основных механизма - хранить текущую длину в какой-то служебной ячейке (Pascal strings или c-addr u Форта) или помещать после последнего символа какой-то терминатор (обычно символ с кодом 0 - "нуль-терминированная строка").
Но тот или другой механизм - это именно механизм, позволяющий нам работать с символами. s[0] ТурбоПаскаля или 0X ББ в большинстве случаев от нас скрыт, потому что функционирует автоматически. Мы сталкиваемся с этим, когда либо утыкаемся в ограничения, либо работаем не с самими символами, а именно с механизмом. Например, могут возникнуть затруднения, если в ТП нам нужны строки длинней 255 символов, или если среди символов обрабатываемой строки в КП должен быть 0Х.
Также, если мы пишем процедуру для выделения в памяти буфера для строки или для передачи строки в какую-то внешнюю библиотеку (биндинг), то уже сами переходим с уровня "абстрактная последовательность символов" на уровень механизма. И тогда s[0] или завершающий символ становятся важны, потому что они становятся не скрытыми служебными, а тоже обрабатываемыми (пользовательскими). И приходится буфер выделять на 1 символ больше или вставлять завершающий 0Х и пр.
Вот и при задании константного ARRAY OF CHAR через строковые константы имеет значение, для чего именно мы вводим этот константный массив, т.е. на каком уровне мы работаем. Если нам важны только сами символы в кавычках, то автоматически добавляемый 0Х - это "лишний" символ (накладные расходы, плата за возможность задавать символы в кавычках).
Код: "OBERON"
  1. TYPE Labirint = ARRAY 3 OF ARRAY 16 OF CHAR;
  2. CONST Map = Labirint("...o..##...oo12", "...o..##...oo35", "...o..##...oo78");
Если здесь задан лабиринт 3х15, то 16-й столбец явно лишний. Он необходим лишь потому, что кавычки автоматически добавляют 0Х, который нужно куда-то девать. Другое дело, если нам требуется в программе ограничитель из нулевых символов по какой-то причине, тогда автоматическое добавление уместно.
Кстати, а как вставить символ 0Х слева? 0Х+"..000..12" не срабатывает.
А вот если массив у нас только буфер для нуль-терминированных строк, которые мы собираемся куда-то передавать, то значит мы работаем с 0Х как с полноправным символом, предполагаем его наличие и должны быть предупреждены, если в массиве для него не хватило места. Пример из предыдущего сообщения
Код: "OBERON"
  1. TYPE MsgStr= ARRAY 3,7 OF CHAR;
  2. CONST Way = MsgStr("Hello!" , "Error" , "Try" );

Поэтому предлагаю, чтобы сам программист указывал, для чего именно он хочет использовать этот константный массив - это "массив из символов фиксированного размера", где значение имеют только явно указанные символы в кавычках, или же это буфер для нультерминированных строк, где служебный завершитель тоже важен.
Указывать это можно, например, так
Код: "OBERON"
  1. TYPE Labirint = ARRAY 3 OF ARRAY 15 OF CHAR;
  2. CONST Map = Labirint$("...o..##...oo12", "...o..##...oo35", "...o..##...oo78");
В этом случае кавычки не генерируют лишний 0Х, в массив попадают только те символы, что указаны явно внутри кавычек и их должно быть ровно столько, какова длина массива по последнему измерению. Символ $ употребляется только при задании константного массива из CHAR или BYTE и влияет только на то, как следует понимать строковые константы в кавычках.
А если $ не употреблять, то предлагаю не только добавлять 0Х, но и разрешить указывать в кавычках меньше символов (недостающие заполняются нулями). Если 0Х не влезет в массив, то выдавать ошибку.
В любом случае можно использовать перечисление символов в скобках ("H","e", "l", "l","o","!",0X). И тогда в массив попадут лишь эти символы, и их должно быть указано ровно столько, какова размерность массива. И никто не будет требовать, чтобы последним символом был нулевой.
Вот только не знаю, удачно ли такое обозначение (я выбрал $, потому что в КП s$ означает "символы, находящиеся в массиве s").


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

Сообщения: 273
Откуда: Россия
Рассмотрим, какие же проблемы со строковыми константами решит введение $.
Начнём с того, что 5) и 6) решаются непосредственно, ведь именно из-за этих примеров, такая нотация и была предложена.
Цитата:
3)Что значит "" ?
Думаю, это нужно считать массивом из стольки символов 0Х, сколько необходимо для заполнения массива по этому измерению. Причём именно массивом, а не символом. Ведь символ можно задать непосредственно - 0X.
А вот с остальным не очень ясно.
Попробуем упрощённо изобразить синтаксис конструкции "одномерный константный массив из символов", ведь именно тогда приходится иметь дело со строкой, до этого уровня у нас только скобки и запятые.
Код: "OBERON"
  1. массив = ( список ) | строка | ( строка )
  2. список = элемент [ , список ]
  3. элемент = кодХ | "символ"
  4. строка = "" | "символ" | "символы"
Здесь =, [ ] и | - матасимволы, а кавычки, запятая и ( ) - терминалы.
Верно ли ,что отсутствие скобки ( в начале однозначно говорит ,что это строка?
Хотя строка здесь - это, вообще-то, "константное выражение строкового типа", но пока возможность конструировать строковую константу ограничена. Например, конкатенация не работает, поэтому если скобка и начинает константное выражение, то ей соответствует закрывающаяся в конце, а значит эти скобки вообще не нужны. Не уверен в этом на 100%, но не смог придумать константное выражение строкового типа, начинающееся со значимой скобки.
Вот если бы была конкатенация, тогда было бы можно ("пар")+"ус", например.
А вот если строка есть, то это либо список символов через запятую (тогда скобка означает начало массива), либо строка в незначащих скобках, которые тоже можно посчитать началом массива (хотя они и означают в данном случае часть константного выражения).
Итак, если скобки нет, то это строка, которую нужно прочитать, добавить возможные символы 0Х (зависит от $) и запихнуть в conval.arr.
А если скобка есть, то внутри либо строка либо список символов. Считываем первый элемент. Это будет либо однозначно CHAR, либо однозначно String, либо символ в кавычках, который можно принять за то или другое. Если возможно и то и другое, то следует читать символы дальше. Запятая покажет, что это список символов. А если это не запятая, то это либо ) либо ошибка.
Осталось разобрать случай, когда для ARRAY N OF CHAR мы прочитали что-то вроде ("с"). Если N>0, то нужно выдать либо ошибку (при наличии $), либо дополнить строку символом 0Х до длины N. А если разбираем ARRAY 1 OF CHAR и прочитали ("с"), то с - это и есть искомый единственный элемент массива.

Вот вроде бы и разобрали все случаи, но остаются некоторые вопросы. Например, почему нет конкатенации строковых констант? Её принципиально не должно быть? Ведь было бы удобно задавать, например, одну строковую константу через сцепление двух других.
Да и как, например, сделать строковую константу из спецсимволов, если 1X+2X+"А" не работает? Можно задать это через наш константный массив, но проблема в том, что константный массив - это не константа! Хотя... Хотя есть ли случаи, когда принципиально нужна "строковая константа", а константный массив (IN-параметр) не подходит? В голову приходит только построение константного массива на основе ранее заданных строковых констант.


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

Сообщения: 1019
Откуда: Днепропетровская обл.
По мере развития концепции наших константных массивов вскрылось множество интересных вопросов. Например, раз разрешается такое описание массива:
Код: "OBERON"
  1. TYPE MyHeroTyp = ARRAY 5 OF CHAR;
  2. CONST myHeroArr1 = MyHeroTyp("H", "e", "r", "o", 0X);
  3. (* А что будет если 0X задано в середине строки? *)
, то почему бы не разрешить вот такое присваивание уже неконстантого массива:
Код: "OBERON"
  1. VAR myHeroArr2: MyHeroTyp; BEGIN myHeroArr2 := MyHeroTyp("H", "e", "r", "o", 0X);
На этом можно и не останавливаться, а пойти дальше:
Код: "OBERON"
  1. n := любой_тип(значение);
А вот это мне уже не нравится. Ведь такое приведение типов взламывает нам строгую типизацию, и вовсе не зря его вынесли в SYSTEM.VAL.

Но вариант с присваиванием обычному неконстантному массиву (включая многомерные) целого блока значений на том же синтаксисе, что реализуется тобой для константного массива, но в исполняемом коде, выглядит интересно. Ведь стандарт Оберона/КП разрешает присваивание массиву блоком лишь строку, а другие типы — только поэлементно.

Интересно было бы проверить разрешает ли такое присваивание Oberon-A.

По константным массивам без указания размера. Мысль хорошая. Излишество конечно, но всё относительно. Может быть, дополнительная сложность при вычислении размера. Вот, например, задаётся массив строк без указания размера:
Код: "OBERON"
  1. TYPE Arr = ARRAY OF ARRAY OF CHAR;
  2. CONST Messages = Arr(
  3. "Сообщение 1",
  4. "А вот ещё одна строка",
  5. ... ,
  6. "Вот и всё!"
  7. );
Размер вычисляется на лету, первая мерность — количество строк, а вторая, получается, длина самой большой строки (с 0X). Но есть бонус: возможность получить размерность массива как константу (для дальнейших описаний):
Код: "OBERON"
  1. CONST Height = LEN(Messages, 0); Width = LEN(Messages, 1); (* Как в AO *)
Надеюсь, это не вызовет серьёзных трудностей в реализации.

А возможность указать размер массива даёт прекрасный контроль в случае если в массив пихается строка большей длины, чем зарезервировано.

Вопрос: а что будет если 0X задано в середине строки — это критический взгляд на механизм реализации строк в Обероне. Я вот сейчас прогнал в ББ такой код:
Код: "OBERON"
  1. MODULE A;
  2. IMPORT Log;
  3.  
  4. CONST Arr = "Arr" + 0X + 0X + 0X + 0X + "Arr";
  5.  
  6. PROCEDURE Do* ;
  7. BEGIN
  8. Log.String(Arr);
  9. Log.Int(LEN(Arr));
  10. END Do;
  11.  
  12. END A.
Результат: ArrArr 6

В исполняемом коде:
Код: "OBERON"
  1. MODULE A;
  2. IMPORT Log;
  3.  
  4. VAR arr: ARRAY 10 OF CHAR;
  5.  
  6. PROCEDURE Do* ;
  7. BEGIN
  8. arr := "Arr" + 0X + 0X + 0X + 0X + "Arr";
  9. Log.String(arr);
  10. Log.Int(LEN(arr$));
  11. END Do;
  12.  
  13. END A.
То же самое: ArrArr 6

Так что, боюсь, нам предстоят непростые решения. Есть ведь ещё механизм строк как в Oberon-07, кое-кто из моих знакомых оберонщиков считает его более совершенным.

Кстати, я не против реализовать конкатенацию (как в ББ), просто руки не дошли. Но как нам обрабатывать конкатенацию с 0X, тоже как в ББ? :)

Видимо, 0X воспринимается как пустая строка "", вот и конкатенация в итоге ничего не добавляет. Вообще это логично.

Saferoll писал(а):
По реализации. Пока возможность опускать указание размера не сделана и обрабатывается как ошибка. Для реализации нужно решить вопрос с хранением элементов. Если массив имеет фиксированный размер, то мы сначала выделяем один кусок памяти для хранения всех его элементов, а затем в процессе чтения заполняем. Если размер заранее неизвестен, то придется выделять память связанными в список кусками некоторого стандартного размера (на 100, 1024 или 4*1024 элемента, например). А если очередной кусок кончился, то выделить следующий и подсоединить его к списку. Размер куска (лучше наверно задавать его не в количестве элементов, а в КБ) можно установить в константах Ofront или даже в par-файле.
А подсмотри в исходниках компилятора AOS, как там сделано?

Saferoll писал(а):
И я правильно понимаю, что в константных массивах все строки должны быть одинаковой длины (хотя эта длина может быть явно не указана, а определяться количеством символов в кавычках)?
Да, безусловно. Иначе как к ним обращаться по индексу. При этом строки меньшей длины дополняются в массиве символами 0X до общей размерности. Так же наверное сделано и в Си.


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

Сообщения: 1019
Откуда: Днепропетровская обл.
Косметическое замечание по генерируемому коду:
Код: "C"
typedef
BYTE Unsigned_VVV[2];
 
typedef
Unsigned_VVV Unsigned_TheClocks[3];
 
 
__CONSTARR Unsigned_TheClocks AnimClockData =
{{41,76},
{1,-14},
{-14,19}};

Обрати внимание, что после typedef на следующей строчке находится табуляция, а перед нашими значениями массива — пробелы. Их нет необходимости выводить вручную. Для увеличения отступа служит вызов:
Код: "OBERON"
Ровно также как для уменьшения:
Код: "OBERON"
(процедура BegStat печатает перед каждой строкой столько табов, сколько задано в indentLevel, а процедура Indent это значение увеличивает или уменьшает).


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

Сообщения: 273
Откуда: Россия
Zorko писал(а):
Косметическое замечание по генерируемому коду:...
Обрати внимание, что после typedef на следующей строчке находится табуляция, а перед нашими значениями массива — пробелы. Их нет необходимости выводить вручную.
...(процедура BegStat печатает перед каждой строкой столько табов, сколько задано в indentLevel, а процедура Indent это значение увеличивает или уменьшает).
Спасибо, Олег. Действительно, с выводом листинга еще не разбирался.
Использовал Indent и BegStat. И правда, так лучше. Отступы соблюдаются даже во вложенной процедуре
Код: "C"
typedef
Unsigned_VVV Unsigned_TheClocks[3];
 
 
__CONSTARR Unsigned_TheClocks AnimClockData =
{{1,2,1,2,2,1,2,2,1,2,
1,2},
{3,6,1,2,2,1,2,2,1,2,
1,2},
{7,8,1,2,2,1,2,2,1,2,
1,2}};
static Unsigned_VVV Unsigned_b;
 
 
static void Unsigned_ggg (void);
 
 
/*============================================================================*/
 
typedef
BYTE VVV__3[12];
 
typedef
VVV__3 TheClocks__2[3];
 
static void Unsigned_ggg (void)
{
__CONSTARRLOC TheClocks__2 AnimClockData =
{{1,2,1,2,2,1,2,2,1,2,
1,2},
{3,6,1,2,2,1,2,2,1,2,
1,2},
{7,8,1,2,2,1,2,2,1,2,
1,2}};
}
Ещё бы, конечно, сдвинуть скобочки {{, чтобы расположить числа под числами. Но это на потом можно отложить.


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

Сообщения: 273
Откуда: Россия
Zorko писал(а):
По мере развития концепции наших константных массивов вскрылось множество интересных вопросов. Например, раз разрешается такое описание массива:
Код: "OBERON"
  1. TYPE MyHeroTyp = ARRAY 5 OF CHAR;
  2. CONST myHeroArr1 = MyHeroTyp("H", "e", "r", "o", 0X);
  3. (* А что будет если 0X задано в середине строки? *)
, то почему бы не разрешить вот такое присваивание уже неконстантого массива:
Код: "OBERON"
  1. VAR myHeroArr2: MyHeroTyp; BEGIN myHeroArr2 := MyHeroTyp("H", "e", "r", "o", 0X);
...
Но вариант с присваиванием обычному неконстантному массиву (включая многомерные) целого блока значений на том же синтаксисе, что реализуется тобой для константного массива, но в исполняемом коде, выглядит интересно. Ведь стандарт Оберона/КП разрешает присваивание массиву блоком лишь строку, а другие типы — только поэлементно.
Присвоение неконстантного не так и просто. Например,
Код: "OBERON"
  1. TYPE Arr=ARRAY 2 OF INTEGER;
  2. VAR a:Arr;
  3. ...
  4. a:=Arr(a[1],a[0]);
Как это должно толковаться? Просто ли a[0]:=a[1]; a[1]:=a[0]; или как обмен значениями a[0], a[1]? В последнем случае нужно или выяснять зависимости выражений или всегда присваивать промежуточному массиву. Всё это не просто и может оказаться неэффективно. А если выражения в массиве имеют побочные эффекты?
Операции с константным массивом - это уже проще. Это можно понимать, как анонимный массив (но не анонимного типа).
Однако, вопрос. А в Си есть такая фича? Если нет, то генерация С-кода может оказаться затруднительной.

Цитата:
По константным массивам без указания размера. Мысль хорошая. Излишество конечно, но всё относительно. Может быть, дополнительная сложность при вычислении размера.
...
Размер вычисляется на лету, первая мерность — количество строк, а вторая, получается, длина самой большой строки (с 0X).
...
Надеюсь, это не вызовет серьёзных трудностей в реализации.
Боюсь, что всё-таки вызовет трудности, и прежде всего семантические. Со строками и так многое неясно (см. предыдущие сообщения), предполагаются трудности с массивами единичной длины из-за путаницы "символ"-"строка".
Цитата:
Saferoll писал(а):
По реализации. Пока возможность опускать указание размера не сделана и обрабатывается как ошибка. Для реализации нужно решить вопрос с хранением элементов.
...
А подсмотри в исходниках компилятора AOS, как там сделано?
Что-то не могу разобраться в исходниках. Нашёл там Oberon.OPP- парсер, очень похожий на парсер Ofront. Настолько похожий, что по моим прикидкам должен выдавать ошибку на символ [ в процедуре Factor в месте
Код: "OBERON"
  1.  
  2. ELSIF sym = lbrak THEN
  3. OPS.Get(sym); err(lparen); Expression(x); CheckSym(rparen)
, которое 1 в 1 совпадает с этой строчкой в Ofront.OPP. Где происходит перехватывание [ до этого, не могу понять.


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

Сообщения: 1019
Откуда: Днепропетровская обл.
Saferoll писал(а):
Присвоение неконстантного не так и просто. Например,
Код: "OBERON"
  1. TYPE Arr=ARRAY 2 OF INTEGER;
  2. VAR a:Arr;
  3. ...
  4. a:=Arr(a[1],a[0]);
Как это должно толковаться? Просто ли a[0]:=a[1]; a[1]:=a[0]; или как обмен значениями a[0], a[1]?
Да, это сложновато получается. Но я имел ввиду скорее заполнение неконстантного массива константными значениями, т.е. так же как ты реализуешь для константного массива.

Заполнять массив неконстантными значениями Си умеет:
Код: "C"
char a = 'a'; char b = 'b'; char mas [2] = {a, b};
Но так делать я не предлагаю, уже явное излишество. Пусть бы только константами, и то хорошо.


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

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


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

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


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

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
© VEDAsoft Oberon Club