каюсь, я списки ниасилил(
Вид для печати
каюсь, я списки ниасилил(
По настоящему, там огромные неувязки с терминологией.
И очень много знаний по-умолчанию (что есть необходимость, но как их добывать?)
Это - напрочь дырявит мозг.
Например прямой перевод Звено - Link.
При описании Списков, логика ОТСУТСТВУЕТ, так как звенья в цепи связываются самостоятельно, а в списках нужны сцепки!
Но прямой перевод Сцепка - Coupler.
Вот, как раз, вагонная сцепка (prev, next) и должна называться fCoup, bCoup.
Я бы хотел описывать списки как поезд - очень подходит!
Есть универсальная тележка(node) [нужно указывать её тип, так как бывает простой вагон, а бывает пульмановский], есть Контейнер(infoItem)[указываем тип - сухогруз или цистерна], есть передняя и задняя сцепка(next, prev), есть тягач и толкач (first , last).
ВСЁ!
Это всё лучше смотреть в картинках.
Их много в Инете, но редко можно найти что-либо кузявое.
Вот одна картинка похожая на нашу структуру:
Вложение 65765
Опять-таки, я только в МГУшных статьях нарыл, какие-то приемлемые сведения...
Ну и борьбу принцыпов тоже никто не исключал.
Одни яростно любят низкоуровневое программирование и доступаются до списков без фиктивных указателей (звеньев, которые содержат только указательные поля, но надо знать, что в них присутствуют и поля данных, просто незаполненные...). Другие, (как я) любят простоту программирования и вовсю используют фиктивные звенья.
ВСЁ ВОЗМОЖНО ДЛЯ ТОГО, КТО ВЕРИТ!
zen
Вообще говоря, чем дальше я забираюсь в Паскаль, тем мне больше нравится Никлаус Вирт.
Не зря он Нобелевский лауреат и автор Модулы2 и Ады, кроме Паскаля, разумеется.
Просто, прежде чем писать языки он последовательно трудился над философией языка.
ДА! Можно в какой-то степени говорить и о философии Си, но так вышло, что Ритчи и Керниган, всё же не Вирт и не швейцарцы.
Значит так, в саге о двусвязных списках я упустил важнейшую и единую для Паскаля вещь.
Попытаюсь сейчас исправить ситуацию...
Прежде всего мы со списками работаем только На Куче.
Однако, работа с ЛЮБОЙ динамической переменной ЕДИНООБРАЗНА для всего Паскаля!!!
1. Создаём ТИП УКАЗАТЕЛЯ, чтобы ссылаться не ещё неописанный объект.
2. Описываем ТИП объекта любой сложности, на имя которого и ссылается указатель.
3. Создаём данный объект на куче, выделяя для него память и инициализируя компоненты
4. ЗАТО обращаемся к объекту С ПОМОШЬЮ ПЕРЕМЕННОЙ, создаваемой в статической области программы и имеющей наш описанный ранее указательный тип.
5. Кроме этого мы всегда должны адресоваться к ТИПУ. Системный тип pointer не даст нам никакого доступа к зфпрашиваемому объекту.
Только к начальному адресу.
Давайте пройдёмся вдоль алгоритма:
То есть, получается некое разделение труда.Код:const
maxC = 40; maxR = 24;
type
SAVMSC = ^scrT;
scrT = array[1..maxR] of array[1..maxC] of byte;
var
scr: SAVMSC absolute $58;
- Сам указатель нетипизирован никак, лишь обозначен как указатель.
- Типизация объекта добавляет указателю тип этого объекта
- Создав переменную такого же типа мы из Паскаля с полным правом работаем с этой переменной как с типизированным объектом.
Из-за строгой типизации данных в Паскале совсем не тривиально создать такой объект, как байтовый буфер.
Сделаем это на Куче, и сделаем это с массивом байт.
Однако придётся вспомнить, что массив байт в Паскале всегда должен иметь РАЗМЕРНОСТЬ, как же быть, если массив наш динамический и размерности его мы не знаем?
Тогда вдумайтесь о чём я пытался сказать ранее: Мы создаём void указатель и типизируем его типом наших данных. ПРИ ЭТОМ ОБЪЕКТ НА КУЧЕ НЕ СОЗДАН! Просто компилятору уже известны НЕКОТОРЫЕ его атрибуты.
Переменная для доступа к объекту уже будет иметь эти атрибуты, а также те, которые мы дополнительно придадим при создании объекта.
zenКод:const
(* Пусть это от балды будет размером нашего буфера *)
(* Или Width*Heigth без разницы это определяется динамически в рантайме*)
bytes = 960;
type
arrP = ^arrT; (* Тип Указателя на массив *)
(* Тип Статического массива из одного байта *)
arrT = array[1..1] of byte;
var
(* Переменная, пригодная для работы с одноразмерными массивами *)
(* Размерность здесь существенна, а размер в байтах нет, так как массив на Куче НЕ СОЗДАН. *)
A: arrP;
begin
(* Создаём на Куче массив байтов нужного размера *)
getmem(A, sizeof(byte)*bytes);
... (* Работаем с ним *)
(* Освобождаем память *)
freemem(A, sizeof(byte)*bytes;
end.
Ещё и автор языка Оберон, который породил Оберон-2 и Компонентный Паскаль, а потом Оберон-07. Тоже очень интересные языки, я сейчас с ними плотно работаю. А Модула-2 породила Модулу-3 и Modula-2 R10, а также Objective Modula-2.
Поправлю: Вирт лауреат премии Тьюринга, а не Нобелевской, что не уменьшает его заслуг. Также он не участвовал в разработке Ады (это язык, разработанный Жаном Ишбиа и большим комитетом, но без Вирта). В основу разработки Оберона лёг девиз Эйнштейна: «Делай просто, насколько возможно, но не проще этого». Ишбиа же сказал: «Вирт верит в простые решения сложных проблем. Я не верю в такие чудеса. Сложные проблемы требуют сложных решений».
Олег,
Я, просто, столкнулся по настоящему с ТЕОРЕТИКАМИ языков программирования начиная с языка Лиспа.
МакКарти занимался ЧИСТО теоретическими проблемами и даже ПРЕДСТАВИТЬ не мог, что он на острие Оккама. Это его френд запрограммировал ЛИСП (На чём - не важно. Может на Ассемблере, может просто в машкодах)
Цитата из Оккама - "Не плоди сущности сверх необходимости". (Получше, Айнстайна, правда?)
Я почувствовал, что теория Языков важна!, но не понимал смысла...
...
И теперь я вижу, что Вы отметили существенные вещи:
- PL65 не попрёт из-за эклектичности. Нужно быть ЯВУ! Слишком низкоуровневый. Библиотеки не спасут.
- Си не догонит никогда даже ACTION! По скорости, по очевидности, для тех кто знает Атари.
- LISP не использует возможности машин, сделанных после него.
Ну, в общем, нам мало остаётся. Паскаль. Он УЧИТ учить, но САМ ЯЗЫК СЛОЖНО учить!
Так как он ОРГАНИЗОВАН Правильно для ВСЕХ машин, а не Си (Я, кстати, Си люлю!)
Си правильно ВЗАИМОДЕЙСТВУЕТ со всеми машинами. И шо це нам дало?
Всё взаимодействие идёт по законам Си.
Но, здесь о Паскале. Тем более, не об уродливом. (А их в Атарьском мире таких, даже, много!)
Я даже рад, кстати, что Вирт лауреат Тьюринговой премии. Оба думали об одном и том же...
Как организовать нам машину!
Сделали же... А УРОД Нобель, промёрзши во льдах, убил даже понятие ПРЕМИЯ!
Теперь Нобелевка - это проституирование на ... далее по списку.
zen
Шынни, Action! они рассматривали ТОЖЕ как только ПОДХОД к языку.
Невозможно в ЯВУ программировать, вычисляя машкоды вручную, хотя, при желании - это тоже - не проблема...
Невозможно таскать с собой рантаймы везде. От этого сдохло ещё полдесятка языков для Атари.
Они же пробовали ДАЖЕ всунуть рантаймы в ДОС. И шо?
Язык работает реально О-о-очень быстро, но ГДЕ ОН? (Это - DVC C компилятор...)
Разумеется, никакой переносимости В НАТУРЕ!
НАФИГА ЭТО НУЖНО,ТОВАРИЩИ?
Честно, кроме CLSN, я не вижу других языков. Даже бросил PL65, который разлюбил.
Просто, посмотри коды... Учти, кроме этого, что это - СТАНДАРТНЫЕ средства языка.
Никаких трюков.
Я и сам балдею от запретов жесткой типизации переменных Паскаля, но я уже понял ДЛЯ ЧЕГО она нужна.
Для ПРОГРАММИСТА, а не для программы! (И для компилятора ТОЖЕ, но это вторично.)
Я, когда-нибудь напишу что-то вроде оконной(терминал) библиотеки для Паскаля.
НО Я - НЕ ПРОГРАММИСТ.
Уже половина готова. (Я с CLSN знаком только полгода... С Паскалем не знаком. Документации по Паскалю нет...)
Нужно алгоритмы выбирать, а я не умею. Пытаюсь.
Удачи, zen.
Я тут на две недели пропал, так как не мог с лёгкостью, присущей PL65 возиться с байтами.
Это - та самая типизация в Паскале!
Сейчас я многое узнал.
Доступ к значениям в Паскале контролируется и Вы не сможете доступиться НИ ДО ЧЕГО, кроме начального адреса при помощи void указателя.
В общем, с трудом написал блочные функции для работы с окнами.
Как Вы помните, - это сохранить блок экрана и затем восстановить его из Кучи. В pl65 не было кучи.
Каждый блок экрана занимал ОЗУ. Только CLSN даёт нам эту возможность!
Я честно пробовал CLSN средства, но это было НЕВЕРОЯТНО медленно. Побайтовый вызов и всё через стек...
Сейчас - всё равно через стек, но только по числу вызова строк. Строки прорисовываются машинными кодами встроенных программ.
Вот код:
Привет ВСЕМ! zen.Код:(* Block procedures for CLSN Pascal*)
const
Описали доступные границы. Паскаль будет за ними следить и при случае даст ошибку.
maxC = 40; maxR = 24;
type
Описываем экран как массив строк, состоящих из массива колонок экранных байтов.
scrT = array[1..maxR] of array[1..maxC] of byte;
Описываем системный ярлык Атари как указатель на экран типа scrT
SAVMSC = ^scrT;
Описываем буфер как одномерный массив из одного байта.
Идея в том, что нам далее понадобится адрес начала этого массива, создаваемого на Куче.
bufT = array[1..1] of byte;
Так как мы работаем в динамической области памяти, мы можем пользоваться ТОЛЬКО указателями.
Описываем указатель на буфер как сущность способную работать с типом bufT, то есть с массивом байт.
bufP = ^bufT;
Доступ к Куче ведётся через переменные и ТОЛЬКО. Это - указательные переменные!
var
Создали указательную статическую переменную для доступа к абсолютному системному адресу - SAVMSC.
scr: SAVMSC absolute $58;
Создали указатнльную переменную доступа к массиву.
buf: bufP;
Создали глобальные
(вообще говоря, для блочных функций нужны локальные, или нужно создать хендл, передающий данные)
переменные координат блока.
x,y,w,h: byte;
Создали счётчики по координатам.
i,j,k: integer;
Создали управляющую переменную для просмотра состояний программы.
ch: char;
Предполагается, что мы в динамической области создадим место для помещения туда части экрана.
Так как переменная buf для нас постоянный указатель на буфер, мы считаем её константой и нам
нужна временная переменная b для доступа к буферу... Нельзя рубить сук, на котором сидишь!
x,y,w,h - координатно-размерные переменные
(* Save Block to Buffer *)
procedure saveBlk(var x,y,w,h: byte);
var
j,k: integer; b: bufP;
begin
getmem(b, sizeof(byte)*w*h);
k := 1; b := buf; (*начальные значения*)
for j := 0 to h-1 do begin(*по строкам*)
move(scr^[y+j][x], b^[k], w); (*копируем строку в буфер*)
fillchar(scr^[y+j][x], w, 128); (*для индексации заменяем её инверсными пробелами*)
k := k+w; (* переходим к следующей строке в буфере *)
Здесь важно понять, что доступ к объекту ведётся ТОЛЬКО в соостветствии с его типом!
То есть Паскаль не даёт нам права обращаться к массиву буфера просто указателями,
только указателями типа bufP, для буфера!!!
end;
end;
(* Restore Block from Buffer *)
procedure restBlk(var x,y,w,h: byte);
var
j,k: integer; b: bufP;
begin
k := 1; b := buf;
for j:=0 to h-1 do begin
move(b^[k], scr^[y+j][x], w); (* Взяли и поменяли источник и приёмник. Вуаля! *)
k := k+w;
end;
freemem(b, sizeof(byte)*w*h); (*будьте честными. верните арендованное!*)
end;
(* Main program *)
var
B: bufP;
begin
x:=3; y:=3; w:=12; h:=6;
ch := readkey;
saveBlk(x,y,w,h);
ch := readkey;
restBlk(x,y,w,h);
ch := readkey;
end.
ezswift, Ваше усердие достойно уважения.
Вы тоже, Шынни заняты нужным делом.
ВСЯКОЕ! Всякое усердие достойно уважения.
Разница между попугаем и человеком в том, что человек усерден.
Попугай рыщет за жрачём, ищет за попугаехой, и... ВСЁ!
А мы пробавляемся как можем.
Нерадостно, но достойно.