Browse Source

Исправлен пропуск литеры после откр. скобки в комментариях; Написаны модули для испытаний

Arthur Yefimov 2 years ago
parent
commit
cc79a918c6

+ 1 - 5
src/Autodoc/AutodocParser.Mod

@@ -467,7 +467,7 @@ BEGIN
             tmp := writingDoc;
             ReadComment(FALSE);
             writingDoc := tmp
-          ELSE WriteDoc('('); Read
+          ELSE WriteDoc('(')
           END
         ELSE WriteDoc(c); Read
         END
@@ -1023,10 +1023,6 @@ VAR x: CHAR;
   RETURN ok & (s[0] # 0X) END IsInt;
 
 BEGIN
-  Out.String('CHECK ORDINAL [');
-  Out.String(C.value);
-  Out.String(']');
-  Out.Ln;
   IF ~C.isOrdinal THEN x := C.value[0];
     (* Literal char 'x' or "x" *)
     IF ((x = '"') OR (x = "'")) & (C.value[1] # 0X) & (C.value[2] = x) THEN

+ 53 - 0
src/Autodoc/Test/Bananas.Mod

@@ -0,0 +1,53 @@
+MODULE Bananas;
+(** Модуль содержит тип Banana -- расширение класса Fruits.Fruit *)
+IMPORT Fr := Fruits, S := Strings, Int;
+
+CONST
+  (** Цвета бананов **)
+  yellow* = 1; (** Желтый *)
+  red*    = 2; (** Красный *)
+  brown*  = 0; (** Коричневый *)
+
+TYPE
+  Banana* = POINTER TO BananaDesc; (** Банан *)
+  BananaDesc* = RECORD(Fr.FruitDesc) (** Запись-банан *)
+    color*: INTEGER (** Цвет банана, см. Цвета бананов *)
+  END;
+
+PROCEDURE GetNameHandler(o: Banana; VAR s: Fr.Name);
+BEGIN
+  s := 'Банан "'; S.Append(o.name, s); S.Append('" ', s);
+  IF o.color = yellow THEN S.Append('жёлтого', s)
+  ELSIF o.color = red THEN S.Append('красного', s)
+  ELSIF o.color = brown THEN S.Append('коричневого', s)
+  ELSE S.Append('непонятного', s)
+  END;
+  S.Append(' цвета', s)
+END GetNameHandler;
+
+(** Обработчик сообщений. Обрабатывает некоторые сообщения,
+    остальныче передаёт в Fruits.FruitHandler.
+    
+    Вызывается процедурой Fruits.Handle через f.do(f, ...) *)
+PROCEDURE BananaHandler*(f: Fr.Fruit; VAR msg: Fr.Message);
+BEGIN
+  IF msg IS Fr.GetNameMsg THEN
+    GetNameHandler(f(Banana), msg(Fr.GetNameMsg).s)
+  ELSE Fr.FruitHandler(f, msg)
+  END
+END BananaHandler;
+
+(** Инициалиазтор. Задаёт начальные значения банану.
+    Вызывается конструктором NewBanana.
+     Обработчик handle устанавливается в BananaHandler *)
+PROCEDURE InitBanana*(o: Banana; name: Fr.Name; color: INTEGER);
+BEGIN Fr.InitFruit(o, name); o.color := color; o.handle := BananaHandler
+END InitBanana;
+
+(** Конструктор *)
+PROCEDURE NewBanana*(name: Fr.Name; color: INTEGER): Banana;
+VAR o: Banana;
+BEGIN NEW(o); InitBanana(o, name, color)
+RETURN o END NewBanana;
+
+END Bananas.

+ 128 - 1
src/Autodoc/Test/Fruits.Mod

@@ -1,4 +1,131 @@
 MODULE Fruits;
+(** Здесь объявлен абстрактный тип данных (класс) Fruit, который можно
+    расширять с помощью обработчика сообщений в поле Fruit.handle
+    (см., например, модули Oranges и Bananas), список фруктов List
+    и процедуры к ним. *)
+IMPORT Strings, Out;
+CONST nameLen* = 64; (** Длина строки для названия фрукта *)
 TYPE
-  Fruit* = RECORD END;
+  Name* = ARRAY nameLen OF CHAR; (** Тип-строка для имени фрукта *)
+
+  (** Фрукт **)
+
+  Fruit* = POINTER TO FruitDesc; (** Фрукт *)
+  Message* = RECORD END; (** Абстрактное сообщение. Обрабатывается в Handler *)
+  Handler* = PROCEDURE (f: Fruit; VAR msg: Message);
+
+  (** Фрукт **)
+  FruitDesc* = RECORD (** Фрукт *)
+    next*: Fruit;
+    x*, y*: INTEGER; (** Координаты *)
+    name*: Name;
+    handle*: Handler (** Обработчик события *)
+  END;
+
+  (** Список фруктов **)
+  List* = POINTER TO ListDesc;
+  ListDesc* = RECORD
+    first*, last*: Fruit
+  END;
+
+  (** Сообщения для обработчика **)
+
+  (** Напечатать в консоли приветствие фрукта и его X, Y *)
+  PrintMsg* = RECORD(Message) END;
+
+  (** Получть приветствие фрутка, т. е. наименование и имя *)
+  GetNameMsg* = RECORD(Message) s*: Name END;
+
+(** ООП Фруктов **)
+
+(** Обработать сообщение фрукта *)
+PROCEDURE Handle*(f: Fruit; VAR msg: Message);
+BEGIN f.handle(f, msg)
+END Handle;
+
+(** Печать фрукта.
+     Печатаются наименование фрукта (в расширениях типа Fruit может быть
+    переопределено через GetNameMsg) и его координаты. Строка переносится *)
+PROCEDURE Print*(f: Fruit);
+VAR M: PrintMsg;
+BEGIN f.handle(f, M)
+END Print;
+
+(** Получить наименование фрукта *)
+PROCEDURE GetName*(f: Fruit; VAR s: ARRAY OF CHAR);
+VAR M: GetNameMsg;
+BEGIN f.handle(f, M); Strings.Copy(M.s, s)
+END GetName;
+
+(** Обработчик сообщения печати. Извне вызывается через процедуру Print *)
+PROCEDURE PrintHandler(f: Fruit);
+VAR M: GetNameMsg;
+BEGIN
+  f.handle(f, M);
+  Out.String(M.s);
+  Out.String(' X:'); Out.Int(f.x, 0);
+  Out.String(' Y:'); Out.Int(f.y, 0); Out.Ln
+END PrintHandler;
+
+(** Обработчик сообщения "получить наименование".
+     Пишет в s вид фрукта и его имя.
+     В расширениях может выводить и другую информацию. *)
+PROCEDURE GetNameHandler(f: Fruit; VAR s: Name);
+BEGIN
+  s := 'Фрукт "';
+  Strings.Append(f.name, s);
+  Strings.Append('"', s)
+END GetNameHandler;
+
+(** Обработчик сообщений. Вызывается процедурой Handle через f.do(f, ...),
+    а также обработчиками в расширениях типа Fruit. *)
+PROCEDURE FruitHandler*(f: Fruit; VAR msg: Message);
+BEGIN
+  IF msg IS PrintMsg THEN PrintHandler(f)
+  ELSIF msg IS GetNameMsg THEN GetNameHandler(f, msg(GetNameMsg).s)
+  END
+END FruitHandler;
+
+(** Инициалиазтор. Задаёт начальные значения фрукту. Вызывается
+    конструктором NewFruit и инициализаторами всех расширений типа Fruit.
+     Обработчик handle устанавливается в FruitHandler *)
+PROCEDURE InitFruit*(f: Fruit; name: Name);
+BEGIN f.x := 0; f.y := 0; f.handle := FruitHandler; Strings.Copy(name, f.name)
+END InitFruit;
+
+(** Конструктор *)
+PROCEDURE NewFruit*(name: Name): Fruit;
+VAR f: Fruit;
+BEGIN NEW(f); InitFruit(f, name)
+RETURN f END NewFruit;
+
+(** Список фруктов **)
+
+(** Создаёт и возвращает новый пустой список *)
+PROCEDURE NewList*(): List;
+VAR L: List;
+BEGIN NEW(L)
+RETURN L END NewList;
+
+(** Опустошает список *)
+PROCEDURE Clear*(L: List);
+BEGIN L.first := NIL; L.last := NIL
+END Clear;
+
+(** Добавляет фрукт f в конец списка L.
+     f.next получает значение NIL *)
+PROCEDURE Append*(L: List; f: Fruit);
+BEGIN
+  IF L.last = NIL THEN L.first := f ELSE L.last.next := f END;
+  L.last := f; f.next := NIL
+END Append;
+
+(** Каждому фрукту из списка L передаёт сообщение msg *)
+PROCEDURE Broadcast*(L: List; VAR msg: Message);
+VAR f: Fruit;
+BEGIN
+  f := L.first;
+  WHILE f # NIL DO Handle(f, msg); f := f.next END
+END Broadcast;
+
 END Fruits.

+ 44 - 0
src/Autodoc/Test/Oranges.Mod

@@ -0,0 +1,44 @@
+MODULE Oranges;
+(** Модуль содержит тип Orange -- расширение класса Fruits.Fruit *)
+IMPORT Fruits, Strings, Int;
+
+TYPE
+  Orange* = POINTER TO OrangeDesc; (** Апельсин *)
+  OrangeDesc* = RECORD(Fruits.FruitDesc) (** Запись-апельсин *)
+    size*: INTEGER (** Диаметр апельсина в сантиметрах *)
+  END;
+
+PROCEDURE GetNameHandler(o: Orange; VAR s: Fruits.Name);
+BEGIN
+  s := 'Апельсин "';
+  Strings.Append(o.name, s);
+  Strings.Append('" размера ', s);
+  Int.Append(o.size, s)
+END GetNameHandler;
+
+(** Обработчик сообщений. Обрабатывает некоторые сообщения,
+    остальныче передаёт в Fruits.FruitHandler.
+    
+    Вызывается процедурой Fruits.Handle через f.do(f, ...) *)
+PROCEDURE OrangeHandler*(f: Fruits.Fruit; VAR msg: Fruits.Message);
+BEGIN
+  IF msg IS Fruits.GetNameMsg THEN
+    GetNameHandler(f(Orange), msg(Fruits.GetNameMsg).s)
+  ELSE Fruits.FruitHandler(f, msg)
+  END
+END OrangeHandler;
+
+(** Инициалиазтор. Задаёт начальные значения банану.
+    Вызывается конструктором NewOrange.
+     Обработчик handle устанавливается в OrangeHandler *)
+PROCEDURE InitOrange*(o: Orange; name: Fruits.Name; size: INTEGER);
+BEGIN Fruits.InitFruit(o, name); o.size := size; o.handle := OrangeHandler
+END InitOrange;
+
+(** Конструктор *)
+PROCEDURE NewOrange*(name: Fruits.Name; size: INTEGER): Orange;
+VAR o: Orange;
+BEGIN NEW(o); InitOrange(o, name, size)
+RETURN o END NewOrange;
+
+END Oranges.

+ 30 - 0
src/Autodoc/Test/TestFruits.Mod

@@ -0,0 +1,30 @@
+MODULE TestFruits;
+IMPORT Fruits, Oranges, B := Bananas, Out;
+VAR F: Fruits.Fruit;
+  s: Fruits.Name;
+  L: Fruits.List;
+  pmsg: Fruits.PrintMsg;
+BEGIN
+  L := Fruits.NewList();
+
+  F := Fruits.NewFruit('Взморье');
+  Fruits.Print(F);
+  Fruits.GetName(F, s);
+  Out.String('Имя: '); Out.String(s); Out.Ln; Out.Ln;
+  Fruits.Append(L, F);
+
+  F := Oranges.NewOrange('Деревенский', 15);
+  Fruits.Print(F);
+  Fruits.GetName(F, s);
+  Out.String('Имя: '); Out.String(s); Out.Ln; Out.Ln;
+  Fruits.Append(L, F);
+
+  F := B.NewBanana('Эквадорский', B.red);
+  Fruits.Print(F);
+  Fruits.GetName(F, s);
+  Out.String('Имя: '); Out.String(s); Out.Ln; Out.Ln;
+  Fruits.Append(L, F);
+
+  Out.String('Список:'); Out.Ln;
+  Fruits.Broadcast(L, pmsg)
+END TestFruits.