Разное

Goto pascal: Операторы goto, break, continue и прекращения программы

GOTO — Lurkmore

10 SIN
20 GOTO HELL

10

Сферичнее только 10 GOTO 10

GOTO (гоу ту, бдлкдр. гото) — слитное написание английского go to, что переводится как «иди к…» либо «иди на…», оператор безусловного перехода к указанной после него метке/строке программы. Причина лютых срачей между программистами. Споры на тему «дозволено ли GOTO или нет» (можно ли ТАКОЕ употреблять в программах) идут с самого начала существования структурного программирования.

При ненадлежащем использовании в коде этот самый код становится непонятен даже создателю. При годном использовании может СИЛЬНО облегчить код и исключить использование более сложных конструкций. Собственно срач подразумевает первый случай использования.

Содержание

  • 1 10
  • 2 20 GOTO 60
  • 3 30 Срач
  • 4 40 На самом деле
  • 5 50 GOTO 80
  • 6 60 Суть
  • 7 70 GOTO 30
  • 8 80 См. также
  • 9 90 Ссылки
  • 10 100 END ELSE GOTO 10

20 GOTO 60

30 Срач

Как пользоваться оператором GOTO? Подскажите, пожалуйста. А то друг подарил книгу — самоучитель С++, а страница с goto — вырвана.

Вы удивитесь, но первый троллинг GOTO возник ещё в 1968 году, когда Эдсгер Дейкстра написал высер «Go To Statement Considered Harmful» («Оператор GOTO считается опасным», точнее «О вреде оператора GOTO», ещё точнее — «взгляд на GOTO, как на вредный оператор», а изначально — «A Case Against the Goto Statement», заменённое редактором журнала Communications of the ACM Никлаусом Виртом на название с популярным уже тогда «Considered Harmful». Оба названия можно перевести как «Доводы против оператора GOTO»; в них самих не ненависть или утверждение о всеобщей нелюбви к GOTO, а только указание на то, что в статье будет критика). Прочесть его крайне рекомендуется — там тонны лулзов (несмотря на то, что переводил явно надмозг). Чего только стоит первое же предложение: «За многие годы я утвердился во мнении о том, что квалификация программистов — функция, обратно зависящая от частоты появления операторов go to в их программах».

Еще более доставляет тот факт, что фраза «Considered Harmful» сама по себе стала мемом. Так, ответ на статью Дейкстры назывался «’GOTO Considered Harmful’ Considered Harmful», ответ на неё назывался «’„GOTO Considered Harmful“ Considered Harmful’ Considered Harmful?» и так далее (всего 78 (!) статей с данной фразой).

Вообще, в двух словах критика GOTO выражается очень просто: «Хуй поймешь, в каком порядке выполняется этот код». Отладка кода, щедро усыпанного GOTO, напоминает распутывание клубка ниток, причем состоящего из разных кусочков ниток, которые надо собрать в определенном порядке. Кстати, согласно этому оператору, данную статью следует читать начиная с первого раздела, а потом перейти к шестому, и если вы это читаете, не прочтя шестой, то вы ламер, лол.(пруф линк)(факты=}лузлы)goto…


Кстати, если хотите на своем опыте понять проблему GOTO, попробуйте добавить в эту статью новый раздел, сохранив корректность всех GOTO-ссылок.

Так вот, упомянутый во втором разделе язык Basic подвергался отдельной критике Дейкстры: «Студентов, ранее изучавших Бейсик, практически невозможно обучить хорошему программированию. Как потенциальные программисты они подверглись необратимой умственной деградации». А ещё он назвал копирования отечественными компостроителями архитектуры IBM «Величайшей диверсией Запада против СССР», и, ЧСХ, отчасти оказался прав!

Вернемся к GOTO. Любопытный факт: несмотря на массовую нелюбовь, он есть в большинстве современных языков программирования. И выстрелить себе в ногу с его помощью могут многие, под здоровый смех более просветленных быдлокодеров. Но, что интересно, оператор GOTO имеется в исходниках весьма популярных программ, вроде ядра линукса или гугловского «Андроида», более того, сам Линус одобряет использование GOTO в языках программирования не таких дурацких, как Pascal. Почему? Потому что существуют редкие случаи, когда его использование несколько упрощает код. Другое дело, что использование его вне этих случаев немедленно приводит к полному пиздецу. Впрочем, случаи этого в последнее время не так уж часты — вероятно, по той причине, что многие ньюфаги, не знавшие раннего Бейсика, просто

не знают о том, что такой оператор существует (для PHP-быдла он, как правило, и не нужен, потому что там редко встретишь сколь-либо сложные алгоритмы).

Все это, однако, не мешает периодически выходить новым статьям, доказывающим или опровергающим то, о чем Дейкстра и его оппоненты написали полвека назад. Под любой такой статьей немедленно начинается спор между GOTO-фагами и GOTO-ненавистниками. Вторые обычно аргументируют «GOTO нельзя, потому что GOTO нельзя, и вообще можно ту же задачу решить без него», а первые осторожно замечают, что иногда это все-таки можно (если не прыгать вверх по программе), к тому же в некоторых языках не хватает адекватных заменителей, а на этих языках по-прежнему пишется код. Например, выход из многовложенных циклов на Си — можно извращаться с return-ами или делать флаги выхода, но, бля… А можно и не извращаться: по правилам структурного программирования break и вложенные циклы строго запрещены, потому что это сводит читаемость кода (и, как следствие, его работоспособность) к нулю. Про бесконечный цикл while(true) вообще молчим. Правильный вариант — использование функций, возвращающих false в случае, если нужно срочно выйти из цикла.

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

Но надо сказать, что современные языки с GOTO все-таки стараются ограничить его применение — так, обычно нельзя так просто прыгать между функциями. Так что GOTO уже не тот, что был раньше. Но мы помним!

40 На самом деле

На самом деле, GOTO — это единственный оператор, который используется для управления выполнением кода этими вашими центральными процессорами. Для всякого ЦП есть в сущности два способа управлять кодом: условный оператор (если да, то выполнить следующую команду, иначе выполнить послеследующую) и перейти на другой участок кода (GOTO). Всё. А что вы хотели, машина Поста, десу! И все эти ваши процедурное программирование, функциональное программирование, ООП, ААП, замыкания, циклы и прочая синтаксическая ересь — после компиляции превращается в сотни, тысячи, миллионы GOTO (а точнее, в JMP, JE, JLE, JGE, JNE, etc.), я гарантирую это! Несогласные goto 30

50 GOTO 80

60 Суть

Последствия использования

Оператор GOTO — древнейший оператор. Используется он для безусловного перехода из одной точки кода в другую. До появления процедур и функций был по сути единственным способом запустить один и тот же код несколько раз. В x86-ом ассемблере этому оператору соответствует JMP.

Люди, начинавшие программировать на раннем Basic’е, безусловно помнят, что каждая строчка на нем нумеровалась (10, 20 и т. д.). Соответственно, написав GOTO 10, можно было скакнуть в самое начало программы. Или ещё куда-нибудь. Многие ранние версии Бейсика позволяли вычисляемый GOTO (хоть от функции RND или INPUT), а иногда в таком лапидарном виде:10 RUN. В более современных языках появились символьные метки, так что стало возможным писать goto nahuy;

или ещё что-то в этом роде.

70 GOTO 30

80 См. также

  • Рекурсия
  • Пункт А
  • Пункт Б
  • Григорий Зельднер

90 Ссылки

  • GoTo ЖиВ!

100 END ELSE GOTO 10

Языки программирования

  • ++i + ++i
  • AJAX
  • BrainFuck
  • C Sharp
  • C++
  • Dummy mode
  • Erlang
  • Forth
  • FUBAR
  • God is real, unless explicitly declared as integer
  • GOTO
  • Haskell
  • Ifconfig
  • Java
  • JavaScript
  • LISP
  • My other car
  • Oracle
  • Pascal
  • Perl
  • PHP
  • Prolog
  • Pure C
  • Python
  • RegExp
  • Reverse Engineering
  • Ruby
  • SAP
  • SICP
  • Tcl
  • TeX
  • Xyzzy
  • Анти-паттерн
  • Ассемблер
  • Быдлокодер
  • Выстрелить себе в ногу
  • Грязный хак
  • Дискета
  • ЕГГОГ
  • Индусский код
  • Инжалид дежице
  • Капча
  • КОИ-8
  • Костыль
  • Лог
  • Метод научного тыка
  • Очередь
  • Помолясь
  • Проблема 2000
  • Программист
  • Процент эс
  • Рекурсия
  • Свистелки и перделки
  • Спортивное программирование
  • СУБД
  • Тестировщик
  • Умение разбираться в чужом коде
  • Фаза Луны
  • Фортран
  • Хакер
  • Языки программирования

Почему Go To Considered Harmful? / Хабр

Некоторое время назад мне понадобилось процитировать известное письмо Дейкстры 1968 года, и я воспользовался случаем, чтобы таки внимательно прочитать его. В наши дни «споры о goto» уже неактуальны, поскольку в большинстве современных языков команды goto либо нет вообще, либо используется она редко, и стало быть, обсуждать особо нечего. Однако мне была интересна аргументация. В нашей области масса «фольклорного знания», которое на поверку не всегда оказывается точным (что хорошо показано в книге Боссавита), так что оценить логику Дейкстры с позиции сегодняшнего дня не помешает. Надо сказать, что его формулировки не всегда легко понять, поэтому я решил изложить их несколько более простым языком, потратив немного больше места.

Письма в редакцию

Для начала отметим, что жанр «Go To Statement Considered Harmful» — это письмо в редакцию журнала Communications of the ACM. То есть перед нами не научная статья, и особых требований к строгости здесь не предъявляется. Большинство писем — это краткие сообщения об интересных находках (в том числе фрагменты кода), реакция на другие письма, сообщения об ошибках в статьях и тому подобное. Некоторые из них читать довольно забавно. Например, один автор в том же 1968 году выражает недовольство шестнадцатеричными цифрами. Дескать, если в числе нет символов A-F, то непонятно, десятичное это число или шестнадцатеричное. В качестве решения он предлагает свой собственный набор цифр, который выглядит так:

Думаю, я ещё полистаю секцию писем на досуге, но пока что давайте вернёмся к основной теме.

Вопросы пространства и времени

Первое наблюдение Дейкстры состоит в том, что программа существует в пространстве и во времени. Когда мы пишем код, мы видим его как текст, занимающий некое пространство экрана. В процессе же выполнения пространственная структура уходит на второй план: порядок выполнения инструкций лишь отчасти соответствует исходной организации текста. Далее, автор отмечает, что отслеживать последовательность выполнении инструкций во времени — задача нетривиальная, и хорошо бы стремиться к сокращению «концептуального расстояния» между мирами «кода в пространстве» и «кода во времени».

О трассировке

Теперь обсудим небольшой фрагмент кода, выполняющийся ровно в том порядке, в котором он изначально записан («в пространстве»):

a = 5
b = 15
c = a + b # мы здесь
print(c)

Предположим, я выполняю код по шагам в отладчике, и прямо сейчас собираюсь запустить третью строку. Как много информации требуется, чтобы воспроизвести эту ситуацию заново, если мне понадобится перезапустить программу?

Очевидно, что в данном конкретном случае достаточно поставить точку останова на третью строку, и после повторного запуска мы снова окажемся в том же самом состоянии. Иными словами, для воспроизведения состояния достаточно указать некоторую позицию в коде.

Ветвления никак не меняют эту картину. Чтобы дойти до вызова print() в следующем примере, я могу просто поставить точку останова и перезапустить отладчик:

a = 5
b = 15
c = a + b
if c == 20:
    print(c) # мы здесь
else:
    pass

Ситуация меняется, как только в программе появляются вызовы функций. Рассмотрим следующий фрагмент:

def f(a):
    c = 5 + a
    print(c) # мы здесь
f(5)
f(7)

Здесь уже недостаточно знать, что текущей инструкцией является print(). Нам нужно ещё понять, какой из двух вызовов f() сейчас выполняется. Таким образом, нам нужно располагать полным стеком вызовов.

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

Почему использовать go to плохо

К этому моменту должно быть понятно, что перечисленные элементы (указатели текущей строки, стеки вызовов, счётчики итераций) необходимы для понимания того, что именно происходит в программе во время выполнения. Дейкстра подчёркивает, что их значения находятся за пределами нашего влияния. Скажем, мы можем написать функцию или не писать её, но если уж функция написана, она будет использоваться в самых различных контекстах. Таким образом, следует просто принять к сведению наличие указанных координат (именно это слово, а не «элементы», используется в исходной статье) и научиться отслеживать их значения.

Следующий шаг в рассуждениях сделать уже просто: «становится ужасно трудно найти осмысленный набор координат, с помощью которых можно было бы описать ход выполнения процесса». Иначе говоря, сложно понять, каким именно образом предполагается отслеживать логику выполнения программы, если go to постоянно передаёт управление в разные части системы.

Не сказал бы, что приведённый аргумент базируется на твёрдой научной основе, но, вероятно, в этом и нет необходимости. Даже если требуемый «набор координат» существует в теории, найти его непросто и, по всей видимости, непросто и использовать. Вывод самого Дейкстры состоит в том, что конструкция go to «попросту слишком примитивна»: мы можем разумным образом перемещаться по чему-либо, имеющему структуру, а возможность мгновенно «телепортироваться» куда угодно эту структуру разрушает. Поэтому go to использовать не следует.

Аргумент против оператора GOTO – Pascal для небольших машин

EDW215

Дело против инструкции GO TO.

Эдсгер В. Дейкстра
Технологический университет
Эйндховен, Нидерланды

Уже несколько лет я знаком с наблюдением, что качество программистов является убывающей функцией плотности от до операторов в создаваемых ими программах. Позже я обнаружил, почему использование числа 9Оператор 0015 go to имеет такие катастрофические последствия, и я убедился, что оператор go to должен быть упразднен во всех языках программирования «высокого уровня» (то есть во всех, кроме — возможно — простого машинного кода). В то время я не придал слишком большого значения этому открытию; Теперь я представляю свои соображения для публикации, потому что в самых недавних дискуссиях, в которых поднималась эта тема, меня призвали сделать это.

Мое первое замечание состоит в том, что, хотя деятельность программиста заканчивается, когда он построил правильную программу, подлинным предметом его деятельности является процесс, протекающий под управлением его программы, ибо именно этот процесс должен привести к желаемому результату. эффект, именно этот процесс в своем динамическом поведении должен удовлетворять желаемым спецификациям. Тем не менее, как только программа создана, «создание» соответствующего процесса делегируется машине.

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

Давайте теперь рассмотрим, как мы можем охарактеризовать ход процесса. (Вы можете подумать об этом вопросе очень конкретно: предположим, что процесс, рассматриваемый как последовательность действий во времени, останавливается после произвольного действия, какие данные мы должны исправить, чтобы мы могли повторить процесс до тех пор, пока та же самая точка?) Если текст программы представляет собой чистую конкатенацию, скажем, операторов присваивания (в целях данного обсуждения рассматриваемых как описания отдельных действий), то достаточно указать в тексте программы точку между двумя последовательными действиями. описания. (при отсутствии перейти к операторам Я могу позволить себе синтаксическую двусмысленность в последних трех словах предыдущего предложения: если мы разбираем их как «последовательные (описания действий)», мы имеем в виду последовательные в текстовом пространстве, если мы анализируем как «(последовательные действия) описания» мы имеем в виду последовательные во времени.) Назовем такой указатель на подходящее место в тексте «текстовым указателем».

Когда мы включаем условные предложения ( if B then A ), альтернативные предложения ( , если B , затем A 1 иначе A 2), оговорки о выборе, введенные C.A.R.Hoare ( дело [i] из 9 0016 ( А 1, А 2, ….., An )) или условные выражения, введенные Дж. Маккарти ( B 1 → E 1, B 2 → E 2,….., Bn EN ), факт остается фактом: ход процесса по-прежнему характеризуется единым текстовым индексом.

Как только мы включаем в наш язык процедуры, мы должны признать, что одного текстового индекса уже недостаточно: в случае, когда текстовый индекс указывает на внутреннюю часть тела процедуры, динамический прогресс характеризуется только тогда, когда мы также даем на какой вызов процедуры мы ссылаемся. При включении процедур ход процесса можно характеризовать последовательностью текстовых индексов, длина этой последовательности равна динамической глубине вызова процедуры.

Теперь давайте рассмотрим повторяющиеся предложения (например, while B Repeat A или Repeat A до B 9 0032). С логической точки зрения такие предложения теперь излишни, потому что мы можем выразить повторение с помощью рекурсивных процедур. Из соображений реализма я не хочу их исключать: с одной стороны, предложения о повторении могут быть вполне удобно реализованы с помощью современного конечного оборудования, с другой стороны, модель рассуждения, известная как «индукция», дает нам хорошие возможности для сохранения наших интеллектуальных способностей. понять процессы, порожденные предложениями повторения. С включением предложений повторения текстовых индексов уже недостаточно для описания динамического хода процесса. Однако с каждой записью в предложениях повторения мы можем связать так называемый «динамический индекс», неумолимо подсчитывая порядковый номер соответствующего текущего повторения. Поскольку предложения повторения (как и вызовы процедур) могут применяться вложенно, мы обнаруживаем, что теперь ход процесса всегда можно однозначно охарактеризовать (смешанной) последовательностью текстовых и/или динамических индексов.

Суть в том, что значения этих индексов находятся вне контроля программиста: они генерируются (либо при написании его программы, либо при динамическом развитии процесса), хочет он того или нет. Они обеспечивают независимые координаты для описания хода процесса.

Зачем нужны такие независимые координаты? Причина в том — и это, по-видимому, присуще последовательным процессам, — что мы можем интерпретировать значение переменной только в отношении хода процесса. Если мы хотим сосчитать число, n , скажем, людей в изначально пустой комнате, мы можем добиться этого, увеличив n на 1 всякий раз, когда мы видим, что кто-то входит в комнату; в промежуточный момент, когда мы заметили, что кто-то входит в комнату, но еще не выполнили последующее увеличение n , его значение равно числу людей в комнате минус один!

Безудержное использование оператора go to приводит к тому, что становится ужасно трудно найти осмысленный набор координат для описания хода процесса. Обычно люди также принимают во внимание значения некоторых хорошо выбранных переменных, но об этом не может быть и речи, потому что понимание значения этих значений зависит от прогресса! С перейти к оператору можно, конечно, по-прежнему однозначно описывать прогресс с помощью счетчика, подсчитывающего количество действий, выполненных с момента запуска программы (т. е. своего рода нормализованные часы). Трудность в том, что такая координата хоть и уникальна, но совершенно бесполезна: в такой системе координат чрезвычайно сложно определить все те точки хода, где, скажем, n равно числу людей в комнате минус один. !

Оператор go to в его нынешнем виде слишком примитивен, это слишком приглашение испортить программу. Можно рассматривать и ценить положения, которые считаются ограничивающими его использование. Я не утверждаю, что упомянутые пункты являются исчерпывающими в том смысле, что они удовлетворят все потребности; но какие бы пункты ни предлагались (например, пункты об абортах), они должны удовлетворять требованию, что может поддерживаться независимая от программиста система координат для описания процесса полезным и управляемым способом.

Трудно закончить эту статью справедливым признанием: могу ли я судить, кто повлиял на мое мышление? Совершенно очевидно, что на меня повлияли Питер Лэндин и Кристофер Стрейчи, и я не сожалею об их влиянии на меня. Наконец, я хотел бы отметить (насколько я помню это совершенно отчетливо), как Хайнц Земанек на собрании перед ALGOL в начале 1959 года в Копенгагене весьма недвусмысленно выразил свое сомнение в том, что оператор go to следует рассматривать на равной синтаксической основе с присваиванием заявление. В некоторой степени я виню себя за то, что не понял последствий его замечания.

Замечание о нежелательности оператора go to далеко не ново. Я помню, что читал явную рекомендацию ограничить использование оператора go to аварийными выходами, но я не смог отследить его; предположительно, это было сделано C.A.R. Хор. В [1, гл. 3.2.1] Вирт и Хоар вместе делают замечание в том же направлении, мотивируя построение падежа: «Как и условный оператор, он отражает динамическую структуру программы более четко, чем переходят на операторов и переключателей, что избавляет от необходимости вводить в программу большое количество меток».

В [2] Джузеппе [так в оригинале] Якопини, похоже, доказал (логическую) ненужность оператора go to . Однако упражнение по более или менее механическому переводу произвольной блок-схемы в бесступенчатую не рекомендуется. Тогда нельзя ожидать, что полученная блок-схема будет более прозрачной, чем исходная.

НОМЕРА:

  1. Вирт, Никлаус и Хоар, C. A.R. Вклад в развитие Алгола. Комм. ACM 9 (июнь 1966 г.), 413–432.
  2. Бём, Коррадо, и Якопини, Джузеппе. Блок-схемы, машины Тьюринга и языки всего с двумя правилами построения. Комм. ACM 9 (май 1966 г.), 366–371.

РЕСТРУКТУРИЗАЦИЯ ПРОГРАММ PASCAL, СОДЕРЖАЩИХ ОПЕРАТОРЫ GOTO. — Heriot-Watt Research Portal

Помимо плохого влияния на стиль программирования, наличие операторов goto в программе может значительно усложнить задачу механического перевода на другой язык программирования. Ввиду этого представлен алгоритм, который реструктурирует любую программу на Паскале, содержащую операторы goto, для создания эквивалентной программы без операторов goto. Система, использующая этот алгоритм, была разработана на Прологе.

90 150 Количество страниц
Язык оригинала Английский
Страницы (от-до) 134-137
4
Журнал Компьютерный журнал
Объем 28
Номер выпуска 2
Статус публикации Опубликовано — май 1985 г.

  • АПА
  • Автор
  • БИБТЕКС
  • Гарвард
  • Стандарт
  • РИС
  • Ванкувер

Уильямс, Х. и Чен, Г. (1985). РЕСТРУКТУРИЗАЦИЯ ПРОГРАММ НА PASCAL, СОДЕРЖАЩИХ ОПЕРАТОРЫ GOTO. Компьютерный журнал , 28 (2), 134-137.

@article{63437316cde34ebfa1336f7c592b2f00,

title = «РЕСТРУКТУРИЗАЦИЯ ПРОГРАММ НА PASCAL, СОДЕРЖАЩИХ ОПЕРАТОРЫ GOTO.»,

abstract = «Помимо их плохого влияния на стиль программирования, присутствие операторов goto в программе может значительно упрощают проблему механического перевода на другой язык программирования. Ввиду этого представлен алгоритм, который реструктурирует любую программу на Паскале, содержащую операторы goto, для создания эквивалентной программы без операторов goto. Система, использующая этот алгоритм, была разработана на Прологе».0003

автор = «Говард Уильямс и Г. Чен»,

год = «1985»,

месяц = ​​май,

язык = «английский»,

том = «28»,

страницы = «134- -137 «,

Journal =» Computer Journal «,

ISSN =» 0010-4620 «,

Publisher =» Oxford University Press «,

Number =» 2 «,

}

Williams, H & Чен, Г. 1985, «РЕСТРУКТУРИЗАЦИЯ ПРОГРАММ PASCAL, СОДЕРЖАЩИХ ОПЕРАТОРЫ GOTO», Компьютерный журнал , том. 28, нет. 2, стр. 134-137.

РЕСТРУКТУРИЗАЦИЯ ПРОГРАММ НА PASCAL, СОДЕРЖАЩИХ КОМАНДЫ GOTO. / Уильямс, Ховард; Чен, Г.

В: Computer Journal, Vol. 28, № 2, 05.1985, с. 134-137.

Результат исследования: Вклад в журнал › Статья › рецензирование

TY – JOUR

T1 – РЕСТРУКТУРИЗАЦИЯ ПРОГРАММ PASCAL, СОДЕРЖАЩИХ ОПЕРАТОРЫ GOTO.

AU — Williams, Howard

AU — Chen, G.

PY — 1985/5

Y1 — 1985/5

N2 — Помимо плохого влияния на стиль программирования, наличие операторов goto в программе может значительно усложнить задачу механического перевода на другой язык программирования. Ввиду этого представлен алгоритм, который реструктурирует любую программу на Паскале, содержащую операторы goto, для создания эквивалентной программы без операторов goto. Система, использующая этот алгоритм, была разработана на Прологе.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *