Н. Вирт - Программирование на языке Модула-2 (1160777), страница 13
Текст из файла (страница 13)
Ошибочные присваиваниямежду элементами разных классов могут, следовательно, быть обнаружены простым просмотромтекста программы без ее выполнения. Пусть имеются такие описания:VAR b: BOOLEAN;i: INTEGER;с: CARDINAL;64в этом случае присваивание b := i невозможно, поскольку типы переменных Ь и iнесовместимы. Два типа называются совместимыми.
если они описаны как равные либоудовлетворяют определенным правилам совместимости, которые будут обсуждаться далее.Важным исключением из этих правил являются типы INTEGER и CARDINAL. По этой причинеприсваивание i := с допустимо.Для демонстрации правил совместимости рассмотрим следующие описания:TYPE А = ARRAY [0..99] OF CHAR;В = ARRAY [0..99] OF CHAR;С=АВ этом случае переменные типа А можно присваивать переменным типа С (и наоборот), ноне переменным типа В. Однако допустимо присваивание b[i] := a[i], поскольку обе переменныеимеют один тип CHAR.16. ПЕРЕЧИСЛИМЫЕ ТИПЫМожно описать новый неструктурированный тип перечисление или перечислимый тип,явно выписав все множество значений, которые принадлежат этому типу. Объявление типаТ = (cl,c2,...,сn)вводит новый, неструктурированный тип Т, для значений которого используются nидентификаторов-констант c1, c2.....cN.
Только эти идентификаторы входят в значения данноготипа. Синтаксис описания перечислимого типа следующий:$Перечисление = "(" СписИдент ")".Операции над величинами такого типа должны описываться программистом какпроцедуры. Кроме операций присваивания возможны еще сравнения этих величин. Величиныупорядочены: c1 -наименьшая, сп - наибольшая. Вот примеры перечислимых типов:TYPE цвет - (красный,оранжевый,желтый,зеленый, голубой,синий,Фиолетовый);ДеньНедели = (пн,вт,ср,чт,пт,сб,вс);месяц = (янв.Февр,март,апр,май,июнь,июль, авг, сект,окт,нояб,дек)Порядковый номер константы ci можно получить, воспользовавшись стандартнойФункцией ORD(ci): ее значение i-1. Например,ORD(красный) = 0, ORD(чт) = 3, ORD(дек) = 11.Стандартный тип BOOLEAN - тоже перечислимый тип. Можно считать, что он имеетописаниеBOOLEAN = (FALSE,TRUE)Стандартные процедуры INC(x) и DEC(x) служат для присваивания переменной хсоответственно следующего и предыдущего значения по сравнению с ее текущим значением.17.
ТИП ДИАПАЗОНЕсли известно (или предполагается), что переменная будет принимать значения тольковнутри некоторого определенного диапазона величин, то этот Факт можно выразить, описав так65называемый тип диапазон. Допустим, например, что переменная ш принимает значения только издиапазона от 1 до N включительно. Запишем следующие описания:TYPE S = [1..N]VAR i: S(которые можно сократить до VAR i: [1..N] ).Каждый диапазон имеет некоторый базовый тип - тип его значений.
Все операции,определенные для базового типа, применимы также и к его диапазону. Единственное ограничениекасается величин, которые могут быть присвоены переменным типа диапазон.Синтаксис описания диапазона:$$ТипДиапазон = [КвалИдент]"[" КонстВыражение ".." КонстВыражение "]".где выражения обозначают границы диапазона и должны содержать только константы.Приведем примеры описаний диапазонов.ЛатБуква = ["А".."Z"]Цифра - ["0"..."9"]Индекс = INTEGER [1.. 100]РабочийДень = [пн..пт]Идентификатор, который может стоять перед квадратными скобками, указывает базовыйтип диапазона. Этот идентификатор опускается, если базовый тип очевиден по виду границ.
Нодля целых это не всегда возможно. Если же идентификатор опущен в случае целых констант, тособлюдается следующее правило: если нижняя граница диапазона отрицательна, то базовымтипом считается INTEGER, иначе CARDINAL. Отметим еще, что нельзя определять диапазон длятипа REAL.Тип диапазон имеет то преимущество, что дает дополнительную гарантию противнекорректных присваиваний и может, следовательно, помочь в обнаружении ошибок. Следует,однако, указать, что проверки принадлежности величины диапазону происходят во времявыполнения программы, поскольку такие ошибки не могут быть обнаружены лишь проверкойтекста программы.18. ТИП МНОЖЕСТВОКаждый тип данных определяет некоторое множество значений. В том случае, когда тип Sявляется типом множество (множественный тип), то область его значений - набор всевозможныхмножеств, составленных из элементов некоторого определенного базового типа В.
Например, еслибазовый тип В - диапазонВ = [0..1]и тип S описан какS = SET OF Вто величинами типа S будут множества {}, {0},{1},{0,1}. Если базовый тип принимает празличных значений, то тип множество для него будет иметь 2^N различных значений.Обозначение О соответствует пустому множеству. В предшествующем разделе нам ужевстречался стандартный множественный тип BITSET. Он определяется как66BITSET = SET OF [0..W-1]где W - длина слова используемой ЭВМ. Операции объединения, пересечения и вычитаниямножеств, а также операция IN (определения принадлежности множеству) применимы не только ктипу BITSET, а ко всем множественным типам. Для указания типа константного множества передсписком элементов, заключенным в Фигурные скобки, должен стоять соответствующийидентификатор типа.
Он может быть опущен в случае стандартного типа BITSET. Синтаксисописания множественного типа:$ТипМножество = "SET" "OF" ПростойТип.Синтаксис представления множеств как операндов выражений был приведен в разделе,посвященном стандартному типу BITSET. Напомним, что операнды множественного типаобразуются посредством заключения списка элементов в Фигурные скобки, перед которыми стоитидентификатор, указывающий тип множества (в случае типа BITSET он может быть опущен).Базовый тип множества должен быть или перечислением, или диапазоном. Кроме того,реализации Модулы ограничивают число элементов базового типа для множества длиной словаили некоторым небольшим числом, кратным ей.
Обычно это число равно 16 или 32.Хотя эти правила и ограничивают общность понятия "множество", тем не менее типмножество - мощное средство, позволяющее выразить операции над отдельными битами операндана высоком уровне абстракции, основанном на хорошо знакомом математическом понятии. Дляработы с множествами предлагаются две стандартные процедуры (они разворачиваютсякомпилятором непосредственно в последовательность команд, без использования вызова); здесь sдолжна быть переменной, ах- выражением базового типа для s.INCL(s,x) включить элемент х в множество sEXCL(s,x) исключить элемент х из множества sВ заключение этой главы опишем одно приложение типа BITSET, не отражающеенепосредственно понятие множества, но ставшее тем не менее очень важным и полезным.
Онокасается представления информации о растре сканирующего дисплея. Эта информация называетсябитовой картой экрана, поскольку каждая отдельная точка экрана представляется отдельнымбитом в памяти ЭВМ, причем 1 обозначает черный, 0 - белый цвет (или наоборот). Такое битовоепредставление удобно описывается как массив элементов типа BITSET. Предположим теперь, чтомы должны представить в машине с длиной слова W экран дисплея с М строками, каждая изкоторых содержит N точек.
(Мы также считаем, что N кратно W). Тогда соответствующееописание будет выглядеть так:VAR КартаБитов: ARRAY [0..M*(N DIV W)-l] OF BITSETЗакрашивание точки (элемента изображения) с координатами х, у можно теперь выразитьследующей процедурой:PROCEDURE ЗакраситьЧерным(х,у: CARDINAL);BEGININCL(KapтaБитов[(N*y + х) DIV W],x MOD W)END ЗакраситьЧернымПроцедура ЗакраситьБелым просто использовала бы EXCL вместо INCL. Мыпредполагаем, что число N кратно W и что 0 <= х < N и 0 <= у < М.
Если этого нельзягарантировать, то в процедуру нужно включить соответствующие проверки. Очистка экранаэффективно реализуется присваиванием всем элементам массива пустого множества, вместо тогочтобы оперировать с отдельными битами.FOR i := 0 ТО M*(N DIV W)-l DO КартаБитов[1] := {} END6719. ТИП ЗАПИСЬВсе элементы массива имеют один и тот же тип. Запись же, в отличие от массива,предоставляет возможность описать совокупность элементов как один объект, даже в случае ихразличных типов. Следующие примеры - это типичные случаи, которым хорошо подходитструктуризация данных с помощью записей. Дата состоит из трех элементов: день, месяц, год.Описание некоторого человека может состоять из его имени, пола, идентифицирующего номера идаты рождения.
Это выражается следующими описаниями типа:Дата = RECORD день: [1..31];мес: месяц;год: CARDINALENDЧеловек = RECORDФамилия,Имя,Отчество:ARRAY [0..23] OF CHAR;Мужчина: BOOLEAN;ИдентНомер: CARDINAL;Родился: Дата ENDЗапись дает возможность обращаться к ней и как к целому, и к ее отдельным элементам.Элементы записи называются также ее компонентами (или полями), а их имена называютсяидентификаторами компонент. Подобно массиву, где мы обозначаем i-й элемент массива а череза[i] (т.е. идентификатором массива, за которым следует индекс), компоненту f записи r мы будемобозначать через r.f, (т.е. после идентификатора записи через точку следует имя компоненты).Пусть даны переменныеd1,d2: Дата;p1,р2: Человек;Студент: ARRAY [0. .99] OF ЧеловекДля них можно построить следующие обозначения:dl.деньd2.месpi.Фамилияpi.Родился68Эти примеры показывают, что поля в свою очередь могут быть структурированы.Аналогичным образом, записи сами могут быть элементами массива или компонентами другойзаписи, т.е.
существует возможность строить иерархию структур. Следовательно, селекторыэлементов могут образовывать последовательность, как это видно из дальнейших примеров.Многомерный массив, обсуждавшийся в разделе, посвященном массивам, теперь оказываетсяпросто частным случаем структурной иерархии.р1.0тчество[7]р2.Рождения.годСтудент[23].ИдентНомерСтудент[k].Фамилия[0]На первый взгляд может показаться, что запись - обобщение массива, поскольку снятотребование совпадения типов всех элементов.
Однако, с другой стороны, запись и болееограниченна, чем массив, поскольку компонента записи выбирается в соответствии сФиксированным идентификатором компоненты, а индекс, выбирающий элемент массива, можетбыть выражением, т.е. результатом предшествующих вычислений.Важно отметить, что значение записи может представлять собой произвольнуюкомбинацию значений ее компонент. Поэтому для типа Дата значение "день =31" можетсосуществовать с "мес = Февр", хотя это значение и не является настоящей датой.Синтаксис описания записи$ТипЗапись = "RECORD" ПослСписковКомпонент "END".$ПослСписковКомпонент =$$$СписокКомпонент {":" СписокКомпонент}.СписокКомпонент = [СписИдёнт ":" Тип |ВариантныйСписокКомпонент].Синтаксис обозначения:$Обозначение = КвалИдент {Селектор).$Селектор = "." Идентификатор |$"[" СписВыражений "]" | "^".Примечание: Вариантные списки компонент и селектор ^ будут обсуждаться далее.Чтобы выразить в удобном виде обработку элементов массива, был введен оператор цикла спараметром.