Сначала хотелось бы сказать пару слов о синтаксисе Паскаля.

Как следует понимать следующую запись? nxtP^.info.cnt?

Вспомним из чего состоит узел списка. Прежде всего из информационного поля, являющегося записью.
Доступ к полям записи ведётся через оператор . - точка.
То есть info.cnt - это нахождение значения счётчика внутри информационного контейнера.
Также в узле есть два связных поля prev и next.

Однако, прежде чем доступаться к значениям, мы должны сначала доступиться к самому узлу.
Вот как раз адрес самого узла и задаётся следующим образом nxtP^ - сам узел.
Так как узел сам является записью, то доступ к его информационному полю будет таким nxtP^.info
И соответственно погружаясь далее в поле счётчика в info записи получаем nxtP^.info.cnt

В программе нам может понадобиться подпрограмма поиска по числу в счётчике пунктов.

Вот она:

Код:
(*Поиск элемента в списке по данным. Если элемент не найден, то возвращается nil.*)
function findNode(var A: listT; c: integer): linkT;
var
  nxtP,resP: linkT;
begin
(* Инициализируем результат в nil *)
  resP := nil;
(* Устанавливаем временный указатель на первый узел *)
  nxtP := A.first;
(* Траверсируем вперёд, пока не закончился список *)
  while nxtP <> nil do begin
(* Если данные счётчика достигли заданного знычения *)
    if nxtP^.info.cnt = c then begin
(* Берём этот узел как результат и выходим из подпрограммы *)
      resP := nxtP; exit;
    end;
(* Если пока не достигли траверсируем вперёд к концу списка *)
    nxtP := nxtP^.next;
  end;
(* возвращаем связь узла результата *)
  findNode := resP;
end;
А вот набросок программы меню:

Код:
program menu;
(* User types *)
type
  infoT = record
            cnt: integer;
            dat: string;
          end;

  linkT = ^nodeT;

  nodeT = record
            info: infoT;
            next: linkT;
            prev: linkT;
          end;

  listT = record
            first: linkT;
            last: linkT;
          end;

var
(* Строка меню и временная строка пункты *)
  mStr,items: string;

(* Procedures to work with list *)
procedure initList(var L: listT);
var
  nxtP, delP: linkT;
begin
  if L.first = nil then Exit;
  nxtP := L.first;
  while nxtP <> nil do begin
    delP := nxtP;
    nxtP := nxtP^.next;
    Dispose(delP);
  end;
  L.first := nil;
  L.last := nil;
end;

procedure addNode(var L: listT; tmpP: linkT);
begin
  if tmpP = nil then Exit;
  tmpP^.next := nil;
  tmpP^.prev := nil;
  if L.first = nil then begin
    L.first := tmpP;
    L.last := tmpP;
  end else begin
    L.last^.next := tmpP;
    tmpP^.prev := L.last;
    L.last := tmpP;
  end;
end;

(* Main program *)
var
  list: listT;
  A: linkT;
  i: Integer;
begin
  initList(list);
  clrscr;
  mStr := 'First Second Third Fourth Fifth';

  i := 0; items := mStr+' ';
  while pos(' ', items) <> 0 do begin
    New(A); Inc(i);
    A^.info.cnt := i;
    A^.info.dat := copy(items,1,pos(' ', items)-1);
    items := delete(items,1,pos(' ', items));
    AddNode(list, A);
  end;

  WriteLn;
  A := list.first;
  while A <> nil do begin
    Write(A^.info.cnt); Writeln('. '+A^.info.dat);
    A := A^.next;
  end;
  Writeln;
end.
Здесь оператор pos ищет первый пробел во временной строке items.
Позиция пробела без единицы и будет длиной первого пункта меню.
Именно это количество символов и заносится в поле dat созданного оператором New узла.
После чего первый пункт стирается из строки items вместе с пробелом.
Так как эти действия зациклены просматривается вся строка items до последнего пробела, который мы программно пришили к строке items. Также в цикле мы наращиваем поле счётчика, автоматически нумеруя пункты меню.

Вот результат:
Нажмите на изображение для увеличения. 

Название:	menu.png 
Просмотров:	248 
Размер:	10.0 Кб 
ID:	65636

Мне кажется, что алгоритм просто очарователен.
zen