KRIEGSSPIELE!
Вы хотите отреагировать на этот пост ? Создайте аккаунт всего в несколько кликов или войдите на форум.

02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Сб Дек 09, 2017 10:26 am

ГЛАВА ВТОРАЯ. МАЛЕВИЧ, ГОВОРИТЕ?

Конечно, разнообразные языки разработкти создавались и раньше:

СЕПУЛЕНИЕ СЕПУЛЕК

Общие места из документа "Система структурного документирования CWEB (Версия 3.0), 1994, Дональд Э.Кнут и Сильвио Леви. Перевод на русский язык: Сергей Короп - 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10PS, 0.3Мб02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10.
***

ВВЕДЕНИЕ. Суть философии CWEB в том, что программисты, желающие снабдить свою программу наилучшей документацией, должны одновременно пользоваться языком, подобным TeX, для подготовки документации и языком, подобным C, для программирования. Ни тот, ни другой сам по себе не предоставляет всего необходимого, но будучи должным образом объединены, оказываются куда более полезными, чем порознь.

Структура компьютерной программы может быть представлена, как "сеть" ("web" - "паутина"), состоящая из множества взаимно зависимых частей. Чтобы документировать такую программу, необходимо описать каждую такую часть и ее взаимоотношения с другими. Средства обработки текстов, предоставляемые TeX, позволяют нам описать локальную структуру каждой части программы, а средства программирования языка С - формально и однозначно специфицировать алгоритмы. Объединив их, мы получаем стиль программирования, максимально способствующий пониманию структуры сложных программ, и одновременно - хорошо документированные программы, для которых автоматически обеспечивается взаимное соответствие программы и документации.

Система CWEB состоит из двух программ, названных CWEAVE и CTANGLE. При программировании в системе CWEB программа на языке C и документация к ней объединены в одном файле, называемом CWEB-файл, с именем вроде something.w. Команда 'cweave something' создает файл something.tex, который с помощью TeX превращается в красиво оформленную ("pretty printed") версию something.w, которая соблюдает все типографские соглашения, такие как дизайн страницы, использование отступов, курсивных и жирных шрифтов, математических символов. Дополнительно автоматически строится система перекрестных ссылок. Аналогично, команда 'ctangle something' порождает программу на языке C something.c, которая может быть откомпилирована в исполнимый код.

Помимо предоставления удобного средства документирования, CWEB расширяет язык C возможностью менять местами части текста программы, так что большие программные системы могут быть восприняты целиком в терминах небольших секций и их локальных взаимосвязей. Программа CTANGLE названа так потому, что она расставляет секции web-структуры в порядке, требуемом C; преимуществом программирования в CWEB является то, что алгоритмы могут быть выражены в "развернутой" форме, в которой каждая секция объясняется отдельно от других. Программа CWEAVE, в соответствии своему названию, "сплетает" содержащиеся в каждой секции TeX- и C-части в структурированный документ. Возможно, не случайно немецким эквивалентом "weave" является "wele", а соответствующий им латинский императив - "texe"!

Пользователь CWEB должен быть хороню знаком с языком С. Минимальное знакомство с TeX также желательно, но фактически может быть получено уже в процессе работы с CWEB, поскольку простой текст подготавливается в TeX практически без какого-либо знания его языка. Тем, кто хорошо знаком с обеими системами потребуются совсем небольшие усилия, чтобы изучить команды CWEB.

ОБЗОР. Содержимым файлов CWEB может быть TeX-текст и С-текст. CWEB-программист должен четко представлять все происходящее с ними как в процессе генерации документации, так и программы, т.е. знать суть всех тех действий, которые будут производиться над CWEB-файлом программами CWEAVE и CTANGLE. Текст в формате TeX полностью копируется программой CWEAVE и игнорируется CTANGLE, это "чистая документация". С другой стороны, C-программа форматируется CWEAVE и преобразуется CTANGLE...

CWEB-файл содержит секции, которые более или менее самодостаточны. Каждая секция состоит из трех частей:

- TeX-часть, содержащая материал, разъясняющий суть содержимого секции.
- Промежуточная (middle) часть содержит макроопределения, служащие сокращениями для C-конструкций, которые неудобно выписывать каждый раз заново. Они преобразуются CTANGLE в макросы препроцессора.
- C-часть, содержащая часть программы, генерируемой CTANGLE. Длина C-части в идеале не должна превышать дюжины строчек, чтобы она составляла законченный фрагмент программы и была легко понимаемой.

Три части каждой секции должны располагаться в этом порядке, т.е. TeX-комментарий должен следовать первым, затем промежуточная часть и, наконец, С-код. Любая из этих частей может быть пустой.

CWEB-файл может содержать произвольный текст, располагающийся перед началом первой секции и не входящий ни в одну из секций. Подобный текст далее будем именовать "преамбулой" ("in limbo"), он игнорируется CTANGLE и полностью копируется CWEAVE, так что его назначение состоит в определении произвольных инструкций TeX'a. Как правило, эти инструкции загружают требуемые шрифты, определяют макросы, изменяют размеры страницы и/или генерируют титульный лист.

Секции нумеруются последовательно, начиная с 1. Эти номера появляются в начале каждой секции в TeX-документе, полученном CWEAVE, а также в комментариях, отмечающих начало и конец каждой секции в С-программе, сгенерированной CTANGLE.

ИМЕНА СЕКЦИЙ. К счастью, нет никакой надобности нумеровать секции вручную... их номера будут сгенерированы CWEAVE и CTANGLE автоматически. При необходимости секции может быть присвоено имя вместо номера... Для наглядности имя секции должно быть хорошим описанием содержимого секции, т.е. пояснять абстракцию, представленную секцией. Впоследствии секция может быть "встроена" в другие секции так, что малозначимые детали ее реализации окажутся скрытыми. Имя секции, следовательно, должно быть достаточно длинным, чтобы выразить при этом ее суть.

К сожалению, утомительно и чревато ошибками писать длинное имя секции снова и снова. Поэтому CTANGLE и CWEAVE позволяют использовать сокращения...

ЧТО ДЕЛАЕТ CTANGLE? Конструкция ... имя ... может появиться в теле С-секции произвольное количество раз: последующие ссылки на имя означают его "использование", а не "объявление", т.е. что именованная секция, определенная где-либо еще, должна быть вставлена в это место C-программы. Действительно, основная идея CTANGLE - создать программу, объединив некоторое количество именованных и неименованных секций. Точные правила такого объединения таковы: вначале все макроопределения... преобразуются в инструкции препроцессора и собираются в начале файла. Далее туда копируются неименованные C-секции. Так образуется первое приближение текста программы (должна существовать хотя бы одна неименованная секция). Затем все имена секций, найденные в полученном тексте, заменяются C-частями соответствующих секций и этот процесс подстановки продолжается до разрешения всех ссылок. Все комментарии удаляются, поскольку полученная программа на С не предназначается для чтения человеком. Если одно и то же имя было дано более чем одной секции, С-фрагмент получается объединением C-частей всех таких секций. Это оказывается полезным, например, если имеется секция с именем 'Global variables', в которой будут собраны все глобальные переменные, где бы они ни были объявлены. Когда несколько секций имеют одинаковое имя, CWEAVE полагает номер первой из них номером, соответствующим этому имени, и она вставляет в конец секции ссылку: 'See also sections ...' ("См. также секции ..."), в которой перечислены номера всех остальных секций, имеющих это же имя.

Когда CTANGLE начинает и оканчивает обработку секции, она вставляет в выходной файл директивы препроцессора #line, так что номера строк в сообщениях об ошибках и при отладке программы будут ссылаться на исходный CWEB-файл. Благодаря этому, в большинстве случаев о получаемом С-файле можно просто забыть.

ЧТО ДЕЛАЕТ CWEAVE? Общая идея CWEAVE - создать из файла CWEB файл .tex таким образом: первая строка получаемого файла .tex указывает TeX'y загрузить файл макроопределений, описывающих формат CWEB-документов. Далее в tex-файл копируется текст преамбулы, расположенный перед первой секцией. Затем следует по очереди вывод каждой секции, возможно вперемешку с командами окончания страницы. Наконец, CWEAVE генерирует систему перекрестных ссылок: для каждого C-идентификатора указываются номера всех секций, в которых он используется, а также строится алфавитный список всех имен секций, а также оглавление, содержащее номера страниц и секций для всех "заглавных" секций.

Вы спросите, что такое "заглавная" секция...? Секции, которые ... обозначают начало новой группы секций. Такие группы в документе TeX всегда начинают новую страницу, и их имя используется в колонтитуле всех последующих страниц до появления очередной заглавной секции. Имя группы также заносится в оглавление и печатается в начале секции жирным шрифтом.

TeX-файл, полученный с помощью CWEAVE, для каждой секции содержит следующее: во-первых, номер секции - Далее следует TeX-часть секции, скопированная почти дословно... Вслед за этим идут промежуточная и C-части секции, разделенные небольшим промежутком, если они обе непустые. Эти две части получены вставкой множества затейливых TeX-макросов в C-программу. Эти макросы управляют типографскими подробностями, такими, как шрифты, правильная расстановка пробелов в математических формулах, разбиение на строки и отступы.
...

***

Почему я обозвал эту прелесть "сепульками"?

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

Именно так и выглядит (и работает - тоже) текстовая (пусть и красиво отформатированная-оформленная) документация на программу, изготовленная подобным способом. Это называется "Литературным программированием" (изначально, это ошибка перевода: "literate" - грамотное).
Если интересно, посмотрите написанное похожим образом описание самой системы TeX - 500 страниц математически-строгой программистской красотищи. Пожалуй, единственная целиком структурно написанная сложная программа, исходники которой я видел.
Однако, я совершенно не уверен, что такое может написать "обычный программист". Или, даже, прочесть-разобраться. Дело в том, что все 500 страниц написаны на честном Pascal (конечно, хорошо откомментированном), не вводится никакого проблемно-ориентированного лексикона, который бы позволил нам описывать суть программы краткими словами. Постоянно же перепрыгивать с уровня абстракций на "елочки if-ов" и обратно (с заходом на поиск "сепулек")... для этого надо быть воистину "структурным программистом".
Почему "дерево перекрестных ссылок" удалено из процесса разработки и появляется только как часть выходной документации? Что произойдет с TeX-частями в процессе отладки программы? Насколько правка TeX-макросов будет способна порушить код программы? Нет, прав был Брукс: "Я пользуюсь практическим правилом, согласно которому программный продукт (а именно его создание и подразумевает "литературное программирование") стоит, по меньшей мере, втрое дороже, чем просто отлаженная программа с такой же функциональностью".
Воспринимать этот метод, как способ облегчить жизнь программиста, нельзя.
***

Если вы хотите попробовать понять, насколько управляем CWEB-код, посмотрите код приключенческой игры - 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10TXT, 0.2Мб02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10. Конечно, для чтения предназначен только распечатанный TeX-документ, но писать-то предлагается в CWEB...
***

Говоря же о "текстовом программировании", поставим еще одну галочку:
- программа = промежуточная запись кода и документации => код + документация;
возможны, ведь, и другие варианты:
- программа = код и документирующие комментарии в нем;
- программа = код обычный и код, выдающий документацию;
- программа = код, написанный на естественно-понятном (проблемно-ориентированном) языке...
а нас в этой части заметок более всего интересует "плавное" превращение документации в код...
- программа = код и документация на то, что еще не в коде...


Последний раз редактировалось: Gudleifr (Ср Мар 25, 2020 2:10 pm), всего редактировалось 4 раз(а)
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Сб Дек 09, 2017 10:36 am

Т.к. мой инструментарий не располагает к подобным красивостям, вернемся в древние времена:

О.В.ЖУКОВ / ГЕНЕРАЦИЯ ПРОГРАММ ОБРАБОТКИ ДАННЫХ / 1976
Основополагающие огрызки:
***

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

В книге описаны пакеты простой и сложной структуры. Большое внимание уделено пакетам программ, обеспечивающим формирование и использование базы данных, и пакету генерации программных комплексов (ГПК). Это объясняется тем, что на использовании базы данных основана работа всех пакетов, а пакет ГПК обеспечивает выполнение всех функций пакетов программ (простой структуры) преобразований информационных массивов, редактирования и печати выходных ведомостей.

Программный комплекс (ПРК) - система программ (сегментов), выполнение которых в определенной последовательности необходимо для реализации требуемого алгоритма обработки данных; один из этих сегментов является головным...

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

На входном языке пакета ГПК описывается программный комплекс - составляется проблемная программа. По этой программе процессором пакета формируются и записываются в библиотеку программного комплекса рабочие программы, среди которых особое место занимает программа, управляющая работой программного комплекса (УППК). Существуют средства расширения входного языка пакета ГПК, которые позволяют пользователям производить развитие ГПК в нужном для них направлении. В то время как большинство программ пакетов простой структуры являются генераторами интерпретирующего типа, пакет ГПК содержит в качестве своего процессора генераторы-компиляторы.

Генератор-интерпретатор при формировании рабочей программы модифицирует свое тело в соответствии c входными параметрами, и сформированная программа сразу же исполняется (без записи в библиотеку). Поэтому рабочая программа перед выполнением каждый раз формируется в оперативной памяти. Генератор-компилятор по заданным параметрам формирует рабочую программу, которая записывается в библиотеку программ и может многократно использоваться при обработке данных. Генераторы-интерпретаторы могут составить основу оперативно настраиваемых комплексов решения типовых задач АСУ (например, информационно-справочных задач). Эта гибкость обеспечивается тем, что каждый раз при выполнении некоторой процедуры осуществляется генерация рабочей программы. Этот недостаток отсутствует при использовании генераторов-компиляторов, но имеет место другой - рабочая программа жестко настроена в соответствии с заданными параметрами. При построении ГПК принято компромиссное решение: в формируемых рабочих программах существуют средства модификации этих программ с тем, чтобы была возможность использовать программный комплекс при решении задачи для различных однородных объектов. Модификация программ осуществляется путем автоматической замены имен массивов, магнитных лент (МЛ), нестандартных блоков пользователя, подключаемых к программам обработки данных.

Блоки формирования базы данных обеспечивают ввод описаний данных в систему, оформление их виде специальных массивов - "каталогов описаний". Эти описания используются для настройки стандартных процедур обработки информационных массивов.

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

Управляющая программа программного комплекса (УППК) организует поочередное выполнение программ обработки данных; она определяет имя очередной обрабатывающей программы, загружает ее и передает на нее управление. Обрабатывающие программы могут представлять собой стандартные программы обработки данных, внешние программы к некоторым стандартным программам, специально разработанные нестандартные программы обработки конкретных данных. Такое разделение функций в программном комплексе позволяет унифицировать его составные части, а в дальнейшем автоматически формировать их.

Стандартные программы собраны в библиотеку и используются в блоках формирования и обслуживания базы данных, в блоках вывода результатов, в программном комплексе решения конкретных задач.

ПРК может иметь различную степень обобщенности (приспособленности) к обработке информации для различных объектов. При смене объектов может появиться необходимость в программах ПРК менять имена массивов, МЛ, программ обработки, этапов обработки, нестандартных блоков пользователя (БЛПО), подключаемых к стандартным программам, а также структуру ПРК, т.е. состав и взаимосвязи входящих в него программ обработки информационных массивов. Рассмотрим возможные степени (уровни) обобщенности ПРК.

ПЕРВАЯ СТЕПЕНЬ ОБОБЩЕННОСТИ. Такой ПРК служит для решения типовой задачи только для одного объекта. Подобные ПРК могут быть применены для решения задач на другом объекте, если имена и структуры используемых информационных массивов на обоих объектах одинаковы. Каталоги описаний данных при работе ПРК не используются.

ВТОРАЯ СТЕПЕНЬ ОБОБЩЕННОСТИ. ПРК решения типовой задачи для группы однородных объектов. При использовании такого ПРК для конкретного объекта настройка осуществляется путем указания Оператором с ПМ (пишущей машинки) обозначения данного объекта, которое используется для модификации имен массивов, МЛ и БЛПО. Имеются два варианта реализации.

А. При работе программ обработки массивов осуществляется модификация имен массивов и магнитных лент в рабочих описаниях массивов (РОМ), программ обработки и имен БЛПО. В этом случае структуры записей, длины зон массивов, соответствующих всем объектам, должны быть строго идентичны; каталоги при работе ПРК не используются.

Б. При работе программ обработки массивов осуществляется модификация имен массивов в РОМ программ обработки и имен БЛПО, а из каталога с использованием модифицированных имен массивов считываются постоянные описания массивов (ПОМ) соответствующих массивов. В этом случае требования к идентичности структур массивов, относящихся к различным объектам, снижаются: длина записей и зон может быть различна, но величины (реквизиты) записей, использованные в обработке, должны иметь одинаковое внутреннее представление и положение внутри записей.

ТРЕТЬЯ СТЕПЕНЬ ОБОБЩЕННОСТИ. ПРК решения типовой задачи для группы объектов, для которых соответствующие массивы могут иметь различную структуру, но имена величин, использованных в обработке, должны быть во всех массивах одинаковыми. В этом случае может производиться модификация имен массивов, МЛ и БЛПО, требуется использование каталогов описаний, а программы обработки работают как генераторы-интерпретаторы, которые включаются в работу внешними программами, загружаемыми управляющей программой ПРК. Внешние программы для генераторов-интерпретаторов или для обобщенных программ, реализующих типовые алгоритмы обработки данных, формируются с обеспечением выполнения всех требований, предъявляемых к программам ПРК решения задач для группы однородных объектов (см. выше). ПРК третьей степени обобщенности могут быть построены из программ пакетов простой структуры.

Таким образом, программный комплекс, имеющий средства адаптации, позволяющие использовать этот ПРК для решения типовой задачи на многих объектах, является пакетом программ сложной структуры. А поэтому средство, которое служит для автоматического формирования таких ПРК, является генератором пакетов программ решения типовых задач АСУ.

УППК выполняет следующие основные функции:

- управляет последовательностью выполнения этапов обработки;
- принимает с ПМ имя очередного этапа обработки;
- автоматически определяет имя очередного этапа обработки, проверяя заданные условия;
- организует загрузку программы ОБМЕН требуемой модификации;
- принимает с ПМ имя объекта, для которого необходимо проводить обработку;
- запускает программу очередного этапа решения задачи (загрузка программы, передача на нее управления);
- информирует оператора о ходе выполнения этапов обработки, в том числе о некоторых аварийных ситуациях;
- резервирует на МЛ содержимое области ООБ при прекращении выполнения ПРК.

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

Выполнение ПРК разбито на отдельные этапы. Содержанием этапа могут быть ввод, вывод, контроль, сортировка, слияние, выборка, арифметические преобразования и т.п. информационных массивов. Кроме того, как указывалось выше, отдельным этапом может быть выполнение сложного вычислительного процесса, управляемого собственной управляющей программой. Такой этап МЫ будем называть составным. После выполнения этапа может быть необходима проверка с целью определения очередного этапа. Если необходимо определить, который этап (ЭТАП2 или ЭТАП3) выполнять после завершения этапа ЭТАП1, осуществляется проверка в блоке проверки условия УСЛ1. Блок УСЛ1 входит в состав этапа ЭТАП1.

Если же необходимо определить очередной этап из трех возможных: ЭТАП2, ЭТАП4, ЭТАП5, то проверка осуществляется в два приема: в блоке УСЛ2 и в блоке УСЛ3. Блок УСЛ2 входит в состав этапа ЭТАП1, а блок УСЛ3 - в состав этапа ЭТАП3.

В начале выполнения каждой УППК на пишущую машинку (ПМ) выводится некоторый "начальный текст", являющийся кратким содержанием вычислительного процесса или его названием. В конце выполнения ПРК на ПМ выводится "конечный текст", который информирует Оператора о прекращении выполнения вычислительного процесса.

Каждая программа обработки информационных массивов состоит из настраивающей части и динамической части. Основная функция первой части - подготовить все необходимые таблицы и константы, загрузить необходимые программы, модифицировать названия массивов, МЛ, БЛПО, ввести в ОЗУ из каталога описания массивов, распределить динамическую область для полей обмена с МЛ, открыть массивы для записи и для чтения, считать в ОЗУ первые зоны входных массивов. Динамическая часть программы содержит блоки, выполняющие следующие функции: определение действительных адресов всех величин, участвующих в процессе обработки, выполнение собственно процесса обработки, определение адресов очередных записей в полях обмена, анализ состояния обработки с целью определения конца работы, завершение работы (закрытие массивов, перемотка МЛ и т.п.).

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

Обмен информацией между УППК и программами обработки осуществляется через общую область.

Программы обработки информационных массивов:

- Сортировка массива
- Сортировка массива с уплотнением
- Сортировка массива с суммированием и уплотнением
- Слияние массивов
- Слияние массивов с суммированием и уплотнением
- Слияние упорядоченных массивов с исключением
- Разделение массива записей на несколько массивов по заданным условиям
- Обьединение записей двух одинакого упорядоченных массивов
- Контроль значений ключевых признаков записей массива по словарю значений
- Корректировка информационных массивов
- Пересечение двух массивов с умножением числа записей
- Корректировка значений отдельных величин записей
- Корректировка значений величин на заданную дельту
- Формирование массивов из входных массивов
- Преобразование записей массива, удовлетворяющих условию
- Вычисление нарастающего итога
- Вычисление ступенчатого итога
- Уплотнение упорядоченного массива с подсчетом одинаковых записей и формированием выходной записи по формату, определенному в описании записи
- Уплотнение массива с суммированием заданных величин (без перемены формата)
- Присоединение массивов
- Уплотнение массива с преобразованием данных из "уплотненных" записей по условию
- Редактирование результирующего массива для вывода выходных ведомостей на АЦПУ

...

***

Далее в книге подробно расписаны язык УППК, форматы всех необходимых таблиц, перфокарт и бланков. Практически все, кроме машинного кода системы.
Но, интересно, наверное, другое:

- Неочевидность позиции программиста по отношению к программному комплексу. Это совершенно неприемлемо для большинства современных программистов, "точно знающих" свое место в разработке сложнейшего аппаратно-программного комплекса, который занимает, по словам босса, 90% рынка компьютерных услуг. А тут - и системотехник, и быдлокодер, и пользователь - в одном лице, и, возможно, даже в течение одного рабочего дня.
- Второе - роль Оператора в комплексе. Не в смысле: Оператор нужен, т.к. мало денег дали интерфейс-дизайнеру; а в смысле: так проще и удобнее, в т.ч. и пользователю.
- Третье - мы видим, что, чем законченнее и совершеннее система, тем естественнее оставление в ней "дыр" для добавления пользовательского кода.
- Наконец, четвертое - что благополучно "побежденная" языками программирования высокого уровня проблема "структуризации, объектирования и прочиего абстрагирования данных" опять вылезает, как только мы начинаем делать что-то реальное. Все эти "степени обобщенности" нам придется прочувствовать.

И стоит ли так сильно отходить от привычного: "Написал ровно то, что прописано в Техническом Задании"?
Зачем? Скажу за себя.
Готов потратить на написание этих записок год-два и получить простое средство быстро и удобно сделать то, что мне надо, но не готов обновлять каждый год до конца жизни свое железо и программы. Не готов, вместо написания чего-то своего, изучать, опять же перманентно, один монструознее другого модные-патентованные способы сделать это по-чайниковски (или профессионально, что в наше время одно и то же).
***

С другой стороны, мы видим: то, что было в те далекие годы технически-вынужденной необходимостью, стало привычной парадигмой. Имеется в виду сращивание интерфейса с системой управления. В древние времена участие Оператора в процессе управления системой снижало нагрузку на машину. А в настоящий момент, визуальный "программист" просто не способен написать логический модуль, действие которого не может наблюдать "вживую". Не перечесть предложений, не просто визуального, но даже просто "рисовательного" программирования (и не только в играх и обучении).

02.02. МАЛЕВИЧ, ГОВОРИТЕ? C8c010

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


Последний раз редактировалось: Gudleifr (Вт Фев 20, 2018 1:47 pm), всего редактировалось 1 раз(а)
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Сб Дек 09, 2017 11:12 am

ЗАДАЧА 1 ("ПРАВИЛА"). ЭТАП 1 ("СКРИПТЫ")

Главная проблема скриптописания - выбор момента перехода к другим инструментам. В какой момент мне надоест комбинировать слабые команды перетасовки файлов [огрызков правил STARGRUNT II] и я создам "честную Базу Данных"?

Для начала попробую выжать все из одиночных файлов. Очевидным аналогом ГЛЮКВЫ для них будет распихивание ссылок на файлы по поддиректориям (надеюсь, вы уже создали "где-то рядом" директорию UNIVERSAL с полным набором ссылок на файлы). Попробуем распихать.

У меня есть файл с содержимым книги:

CONTENTS
.. CHAPTER 1. INTRODUCTION
DESIGNERS' NOTES .. 2
RELATIONSHIP BETWEEN STARGRUNT II AND DIRTSIDE II .. 3
USING THIS RULEBOOK .. 3
THE SPIRIT OF THE GAME .. 3
THE ROLE OF THE UMPIRE .. 4
YOUR FIRST GAMES OF STARGRUNT II .. 4
TACTICAL NOTES AND SUGGESTIONS .. 4
.. CHAPTER 2. GAME SCALES AND DEFINITIONS
FIGURE SCALE .. 5
...
.. CHAPTER 3. ORGANISING YOUR FORCES
...

Выберу из него названия глав и добавлю обвес

mkdir "CHAPTER 01. INTRODUCTION"
mkdir "CHAPTER 02. GAME SCALES AND DEFINITIONS"
mkdir "CHAPTER 03. ORGANISING YOUR FORCES"
mkdir "CHAPTER 04. BASIC PRINCIPLES OF PLAY"
mkdir "CHAPTER 05. SETTING UP THE GAME"
mkdir "CHAPTER 06. GAME SEQUENCE"
mkdir "CHAPTER 07. ACTIONS"
mkdir "CHAPTER 08. CONFIDENCE AND REACTION"
mkdir "CHAPTER 09. MOVEMENT"
mkdir "CHAPTER 10. OBSERVATION AND HIDDEN UNITS"
mkdir "CHAPTER 11. SNIPERS AND CHARACTERS"
mkdir "CHAPTER 12. WEAPONS AND EQUIPMENT"
...

Получится командный файл для создания в корневой директории "узлов первого уровня".

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

Теперь надо бы выбрать из того же файла оглавления названия разделов и скопировать соответствующие им ссылки (из UNIVERSE) в соответствующую директорию. Где золотая середина между копированием двух сотен файлов руками и написанием длинного скрипта, учитывающего все возможные случаи? Можно решить эту задачу как предыдущую, заменив все названия главы в оглавлении на определение целевой директории, а остальных - на операции копирования. Но при этом потеряются все ссылки, не упомянутые в оглавлении (а таковые точно есть). Может, есть другой способ? Для его нахождения надо удачно выбрать единицу копирования - которую можно легко выделить и в оглавлении, и в директории. В данном случае удобно выбрать единицей страницу правил, т.к. каждая глава начинается с новой страницы, а все имена файлов начинаются с номера страницы. "Вилка" теперь между записью на бумажке номеров страниц глав с последующим переносом соответствующих кучек файлов в нужные директории и превращением оглавления в страшноваты скрипт (это не так уж и трудно в умном текстовом редакторе)

@echo off
set D=..\..\SKLAD\SGII\UNIVERSE
set S="CHAPTER 01. INTRODUCTION"
copy "%D%\000*.lnk" %S%
copy "%D%\001*.lnk" %S%
copy "%D%\002*.lnk" %S%
copy "%D%\003*.lnk" %S%
copy "%D%\004*.lnk" %S%
set S="CHAPTER 02. GAME SCALES AND DEFINITIONS"
copy "%D%\005*.lnk" %S%
copy "%D%\006*.lnk" %S%
copy "%D%\007*.lnk" %S%
...

(Отметим обязательный прыжок с бубном: строчку "@ECHO OFF" в начале скрипта - чтобы убрать лишнее эхо. Хорошо бы добавить и еще пару строк - "CHCP 1251" и "SETLOCAL ENABLEDELAYEDEXPANSION" - для запрета использования DOS-кодировок русских букв и разрешения использования в циклах !переменных!, соответственно).

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

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

Первое реализуется очень просто:

dir /s /b <шаблон нужного имени>*.lnk

(Обвес для включения этой команды в скрипт не показан. Ключ /s нужен для поиска в поддиректориях, а /b - для того, чтобы выдавались только пути/имена файлов).

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

@echo off
chcp 1251 >nul
dir /b ..\..\SKLAD\SGII\UNIVERSE | sort >universe.txt
del work.txt 2>nul
for /f "tokens=*" %%i in ('dir /s /b *.lnk') do echo %%~nxi>>work.txt
sort work.txt /o work.txt
fc universe.txt work.txt
del universe.txt work.txt
pause

(Видна потребность в тщательной доработке скрипта напильником. Один лишний пробел - и все рухнет).

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

Можно представить даже текстовый ВЗГЛЯД на Базу Данных из предыдущей главы. Для этого надо где-то хранить "текущую точку зрения" от которой и проводить все пути к файлам огрызкам.

Но, все-таки, рано или поздно нам эти упражнения в "директоризации" надоедят...
***

Когда я начал осваивать IBM PC, мне очень понравился NORTON COMMANDER - одна из первых, и, наименее требовательная к умственным способностям пользователя, программа визуального управления DOS-файлами. Быстро найти на диске игру, быстро ее запустить, быстро перенести на другой компьютер, даже, немножко подправить файлы конфигурации... Что еще надо?

Однако, чем больше я программировал персоналки, те больше меня NORTON раздражал. Слишком он был плохо заточен, чтобы быть полезным инструментом.
Тогда я вспомнил о виденной ранее очень удачной системе Pascal-программирования - UCSD (02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #116, АБЗАЦ #193402.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10):

02.02. МАЛЕВИЧ, ГОВОРИТЕ? C8c110
Когда система загружена впервые, ею выдается строка-подсказка вида
Команды: E(dit, R(un, F(ile, C(omp, L(ink, X(ecute, A(ssem, D(ebug.
По команде Е пользователь переводится на один уровень ниже и попадает в Редактор (Editor), где выдается новая строка-подсказка. Она может иметь вид
Редактор: A(djst, C(py, D(lete, F(ind, I(nsrt, J(mp, R(eplace, Q(uit, X(chng, Z(ap.
По команде I система запрашивает у пользователя вводимый текст. По команде Q пользователь выходит из Редактора и возвращается к корню дерева (начальной строке-подсказке).

Нажимаешь клавишу - вызываешь нужный редактор/компилятор. Выбранная программа отработала, возвращаешься к исходному выбору.
И все это элементарно реализовалось на убогом языке скриптов MS DOS.
Вот, например, "рабочее место", в котором я несколько лет правил DOS-версию своего FOBOS:

@ ECHO OFF
SGR
C:
CD \CRAZY\FORTH
:LOOP
ECHO ***** FOBOS ***** Softfeet 1992-2000 *****
ECHO A)ssembler E)xit D)ebug G)ame L)ist M)ake N)ote P)roject R)un T)ime
ASK AaEeDdLlMmNnRrTtGgPp
IF ERRORLEVEL 19 GOTO PROJECT
IF ERRORLEVEL 17 GOTO GAME
IF ERRORLEVEL 15 GOTO TIME
IF ERRORLEVEL 13 GOTO RUN
IF ERRORLEVEL 11 GOTO NOTE
IF ERRORLEVEL 9 GOTO MAKE
IF ERRORLEVEL 7 GOTO LIST
IF ERRORLEVEL 5 GOTO DEBUG
IF ERRORLEVEL 3 QUIT
NE G1.ASM
GOTO LOOP
:PROJECT
NE FORTH.ALG
GOTO LOOP
:GAME
NE \GAMES\TXT\NEXT.ALG
GOTO LOOP
:DEBUG
DEBUG G1.COM
GOTO LOOP
:LIST
NE G1.LST
GOTO LOOP
:MAKE
MAKE G1
GOTO LOOP
:NOTE
NE \TXT\NOTE.TXT
GOTO LOOP
:RUN
G1
GOTO LOOP
:TIME
TIME <\BAT\YES.DAT
GOTO LOOP

Недостающие программы - SGR (установка цвета) и ASK (запрос литеры) - были написаны в DEBUG за минуты. Невзирая на простоту, в этом скрипте можно найти основные черты программ-интерпретаторов (в т.ч. FORTH).

Конечно, в наш визуальный век надо вместо "создайте цикл, включающий нужные команды" писать "создайте окно-папочку, в которой разместите иконки-ссылки"... Но, честно говоря, "цикл" проще и удобнее. По двум причинам: можно оптимизировать процесс работы и можно прописать все эти локализации и настройки путей, которые жутко мешают Windows-автоматизации. Более того, "цикл" позволяет легче переключаться с одной работы на другую, не надо открывать и закрывать кучу окон.
 
Еще одна проблема состоит в организации обмена данными между командами.
К сожалению, даже расширенное (юниксовское) понимание файла, не просто как именованной области диска, а как канала связи/синхронизации процессов, нам мало чем поможет (ну, там, направить выход одной команды на вход другой, следующей за ней в ОС-скрипте...).

Есть три решения, использующее дисковые файлы:
1. "Регистровая модель" (см. выше первую степень обобщенности). Для каждого данного придумать особое имя файла, которое и будут использовать все заинтересованные команды. Минус - невозможность команды использовать данные из других файлов. Зато, можно каждому имени приписать определенный смысл, т.е., в философском смысле, считать обращение к данным отдельным видом процедуры.
2. "Переменные". Использование косвенных ссылок на имена файлов. Можно, конечно. Но не слишком ли сложно? Если команды могут конфликтовать из-за одного имени файла, то кто им запретит конфликтовать из-за одинаковых имен переменных?
3. "Стек". Как ни странно, организовать стек файлов не просто, а очень просто. Берем исходное имя базы и добавляем к его имени номер или другой довесок. В система не сильно ограничивающих имена файлов вполне удобно иметь стек: файл.txt, файл.txt.txt, файл.txt.txt.txt и т.д. Т.о. "вырезатель" вполне естественно берет с вершины стека один файл и разбивает его на два.

К сожалению, GW-BASIC имеет наикривейшую реализацию доступа к файловой системе, поэтому проще всего перебирать файлы стека или списка "снаружи" - в командном файле, передавая BASIC-у текущее имя в переменной окружения. Например, так:

@ ECHO OFF
REM В ЭТОМ ФАЙЛЕ БУДЕМ НАКАПЛИВАТЬ РЕЗУЛЬТАТЫ
IF EXIST COMP.TXT DEL COMP.TXT
SET NUM1=0
SET NUM2=0
:LOOP
REM ПЕРЕМЕННАЯ С ТЕКУЩИМ ИМЕНЕМ
SET FOP=COMP%NUM1%%NUM2%.TXT
IF NOT EXIST %FOP% GOTO DONE
REM ЗАПУСКАЕМ, НАПРИМЕР ВЫРЕЗАТЕЛЬ, ЗАПИСЫВАЮЩИЙ СОДЕРЖИМОЕ %FOP%
REM ЧАСТИЧНО В TEMP.TXT, ЧАСТИЧНО - В КОНЕЦ COMP.TXT  
GWBASIC PROG.BAS
REM СОХРАНЯЕМ ОСТАТОК ПОСЛЕ ВЫРЕЗАНИЯ
REN TEMP.TXT %FOP%
IF %NUM2%==9 GOTO ADD1
SET /A NUM2=%NUM2%+1
GOTO LOOP
:ADD1
SET NUM2=0
SET /A NUM1=%NUM1%+1
GOTO LOOP
:DONE
REM СОХРАНЯЕМ ВЫРЕЗАННОЕ В ФАЙЛЕ СО СЛЕДУЮЩИМ НОМЕРОМ
REN COMP.TXT %FOP%

Страшно? На самом деле, не очень. Во-первых, если вы хоть как-то хотите автоматизировать свою работу на компьютере выучить несложные команды DOS/Windows, придется. Во-вторых, все эти модные WEB-разработки базируются на языках, которые выросли из этих простых командных. И, если эти убогие дизайнеры справляются, то уж инженеру - сам бог велел.
***

Ну, хорошо, мы научились соединять "вырезатели-добавляторы" в цепочки, а дальше? Весь этот эквилибр нас так и не приблизил к переходу количества наших огрызков в игровое качество.

Так, для этого я и сделал их такими простыми. Чтобы каждый мог создавать их в нужном количестве.

Здесь буду выкладывать кубики и сборки из их, понадобившиеся при редактировании базы STARGRUNT II до тех пор, пока не буду способен сделать конструктор по-мощнее.
***

Сразу могу сказать, что, приходящие на ум в первую очередь, команды копирования/перемещения узлов "дерева" оказались на редкость бесполезными.
***

Изначально у нас только одна (ОБЩАЯ) команда - текстовый редактор нашей ОС, в которой мы можем править файлы данных (и скриптов). Длина файла с базой данных (если все огрызки объединить) - около 11200 строк (две сотни "листьев" - они же огрызки).

Для "нормального" программиста использование редактора очевидно: он использует его только в "безопасном месте" своего программно-аппаратного комплекса. Его любимый "обезьянник" позволяет править программу (и ее данные) и, по мере готовности, запускать-отлаживать ее, время от времени сохраняя результат на диске.

В моем примере DOS-овского УППК-скрипта тоже все очевидно и без проблем. Видно, что редактор (древний NE) не конфликтует с остальными программами по еще более простой, чем наличие умного "обезьянника", причине - чтобы УППК продолжила работу, NE должен закончить свою. Единственная возможная провокация - испортить в редакторе сам скрипт.
В Windows-окошках (или в моем первоначальном HTML) все гораздо неудобнее. Окно редактора постоянно болтается "где-то рядом" и нет никакой гарантии, что то, что мы в нем видим, соответствует данным или скриптам, которые будут прочитаны нашими программами, тем более, с дисков сервера.
***

ЛИРИЧЕСКОЕ ОТСТУПЛЕНИЕ. В чем отличие текстового редактора от текстовой игры?

Если посмотреть на последние, то можно видеть два вида операций: над синтаксически значимыми единицами - буквами, словами, абзацами, блоками..; другие - над смысловыми - попадающими под шаблоны поиска...

Можно даже заметить, что автоматизация первых идет по "пути интерпретаторов" (тот же vim), а вторых - по "пути компиляторов" (ср. awk). Т.е. в первые представляют из себя ОБЩИЕ программы со все более усложняющимся набором команд, а вторые - все усложняющиеся ПОСЛЕДОВАТЕЛЬНЫЕ программы-фильтры.
А игры? А в них между синтаксисом и семантикой существует баланс, избавляющий игрока от поиска "по всему документу" и ограничивающий его поля зрения законченным семантически-значимым объектом.
КОНЕЦ ЛИРИЧЕСКОГО ОТСТУПЛЕНИЯ.


Последний раз редактировалось: Gudleifr (Пт Окт 13, 2023 12:39 am), всего редактировалось 6 раз(а)
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Вс Апр 15, 2018 9:29 am

Как сделать подобный цикл играющим?

Вспомним игру X-Com 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #11702.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10. Внешний цикл игры - простой экономический симулятор, какой мы во второй главе первой части в пару десятков строк писали. Только с двумя нетривиальными дополнениями: то и дело приходилось отвлекаться на проведение тактических боев, а, возвращаясь с войны, мы видели, что что-то поменялось - перед нашей "экономикой" ставились новые задачи, появлялись новые возможности.

Необходим ли для такой организации игры компьютер? Да, вроде, на первый взгляд, нет. Взять ту же "Пандору" 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #28, АБЗАЦ #19302.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10. Такой же внешний цикл - перебор посещаемых планет, прерываемый высадками. Кое-какие происшествия. Хозяйственные проблемы.

В главе "про Чемодан" мы определили возможности порождения этого цикла главным свойством ролевого скелета игры, на который можно навешивать самые разные, возможно, изобретаемые по ходу дела приключения и квесты. Т.е. одно из главных свойств внешнего игрового цикла - его гомеостатичность: с одной стороны, устойчивость к различным игровым происшествиям и, с другой, возможность изменить состояние - перейти на новый уровень игры.
Это даже не гомеостат, а три закона Марксистско-Ленинской философии в действии: единство и борьба противоположностей (игра, же), переход количества в качество (ролевое развитие персонажей) и отрицание отрицания (спиральное развитие сюжета)...

Может ли этими качествами обладать цикл разработки, записанный в виде дурацкого командного файла? А почему нет?
***

Или еще проще: папка, заполненная файлами-командами и файлами-данными. Например, папка "ЛУНОЛЕТ-1" с такими именами файлов:

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Lnltdi10

Состояние модели видно из имен файлов. Управлять можно вводя другие цифры в имена. Осталось написать программу ПРОГОН, которая будет эти файлы перетасовывать...
Попробовать, что ли?


Последний раз редактировалось: Gudleifr (Вс Июл 14, 2019 11:22 am), всего редактировалось 3 раз(а)
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Сб Апр 21, 2018 9:16 am

Какого же рода должны быть позвонки этого скелета?

Жуков описывает блоки, как порции процесса обработки информации (относятся к решению задачи).
Кнут - как единицы соответствия кода документации (относятся к программированию решения).
В командных файлах блоки определяются требованиями Операционной Системы (запуск запрограммированного решения).

Можно ли совместить все три подхода? К сожалению, нет, взаимного соответствия одних блоков другим не просматривается. Скорее, наоборот, они описывают практически не пересекающиеся фрагменты кода. А случись взаимопроникновение, оно означает лишь потерю управления. Как, например, в предыдущей главе объекты JavaScript (детали запуска) мешали нам структурировать (программировать) решение.

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

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

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

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Пн Май 21, 2018 7:59 pm

СКРИПТЫ ПО ВИНДОСОВСКИ

Т.к. я окровенно слаб в JavaScript, то, пытаясь перейти с DOS-скриптов на мастдайные, я попытался найти какую-нибудь умную книжку. Облом за обломом. В большинстве рассматривался лишь простейший оживляж HTML-файлов, а в очень редких оставшихся - рассказывалось, как пересчитать системные директории и достучаться до сетевых принтеров... Наконец, в одной из книжек А.В.Попова я нашел способ организации простого интерфейса с пользователем и файловой системой на примере поэтапного создания записной книжки. Немного покопипастил и причесал...
(Сами книги - 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10PDF, 18.6Мб02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10 и 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10PDF, 6.98Мб02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10 - объясняющие как писать для Windows начала XXI века на самом Windows - т.н. WSH - Windows Script Host).

Ни в коем случае нельзя путать Javascript, на котором мы писали в прошлой главе визуализатор базы данных, с этим. Тот читался-исполнялся браузером, этот - самим Мастдаем. Тот обращался за файлами через http (Интернет), этот - читает файлы с диска. За отрисовку на экране того отвечал html, этот - должен использовать Win-консоль или пытаться создавать свое окно. Когда дальше мы будем пытаться прицепить к MD-скриптам HTML-окно, то два JavaScript будут путаться, а с точки зрения большинства антивирусов - злобно пытаться хакать систему. Пытайтесь отслеживать, кто где.

Сначала Автор представлял эту учебную записную книжку в виде текстового файла book.txt:

Потапов|Сергей|55-55-55|Моховая|3|10|Без примечаний
Попов|Андрей|56-56-56|Ленина|3|5|Без примечаний
Иванов|Иван|17-17-17|Садовая|4|6|Очень хороший человек
Казаков|Сергей|24-19-68|Полежаева|101|22|Тоже очень хороший человек

Скрипт SortName.js, выдающий ее в отсортированном виде, приведен ниже. Обратите внимание на кучу "системных объектов" и на то, что в JavaScript (в отличие от VBScript) приходится запоминать числовые значения констант системных вызовов.
Файлы .js (как и .vbs - для VBScript - или .wsf - для нескольких скриптов зараз) запускаются как обычные командные - набиванием имени в командной строке (если хочется, с явным указанием запускателя - cscript или wscript) или нажатием на иконку. CMD- и WIN-запускатели немного отличаются: первый умеет работать с DOS-потоками, а второй - выводит исключительно в окошки. Нам - без разницы.
И, конечно, никакой компиляции или установки специальных утилит не требуется. Мастдай уже давно это умеет.

function PrintPerson(Person) {
FOut.WriteLine("Фамилия: "+Person[0]);
FOut.WriteLine("Имя: "+Person[1]);
FOut.WriteLine("Телефон: "+Person[2]);
FOut.WriteLine("Улица: "+Person[3]);
FOut.WriteLine("Дом: "+Person[4]);
FOut.WriteLine("Кв.: "+Person[5]);
FOut.WriteLine("Заметки: "+Person[6]);
FOut.WriteLine("*****")
}
function SortLastName(Pers1, Pers2) {
if (Pers1[0]<Pers2[0]) return -1;
else if (Pers1[0]==Pers2[0]) return 0;
else return 1
}
var WshShell = WScript.CreateObject("WScript.Shell");
var BasePath = WshShell.CurrentDirectory+"\\";
var FSO = WScript.CreateObject("Scripting.FileSystemObject");
var FBook = FSO.OpenTextFile(BasePath+"book.txt", 1, true);
var PersonArr = [];
while (!FBook.AtEndOfStream)
PersonArr[PersonArr.length] = FBook.ReadLine().split("|");
FBook.Close();
var PathOut = BasePath+"out.txt";
var FOut = FSO.OpenTextFile(PathOut, 2, true);
FOut.WriteLine("Сортировка по фамилии");
FOut.WriteLine("--------------------");
FOut.WriteLine("");
PersonArr.sort(SortLastName);
for (var i=0; i<PersonArr.length; i++) PrintPerson(PersonArr[i]);
FOut.WriteLine("");
FOut.WriteLine("Всего записей: "+PersonArr.length);
FOut.Close();
WshShell.Run("notepad "+PathOut, 1);

Затем Автор переносит свою записную книжку в XML-формат (жуткая жуть), чего нам совсем не надо. Мы продолжим работать с текстовым форматом.
Немного усложним. FindAndDelRecord.wsf - скрипт для удаления строки из записной книжки. Он .wsf потому, что ф-ии InputBox в JavaScript нет, приходится прицепить кусочек VBScript.

<job id="FindAndDel">
<script language="VBScript">
Function InputName
InputName = InputBox("Введите фамилию для удаления:", "Записная книжка")
End Function
</script>
<script language="JScript">
var WshShell = WScript.CreateObject("WScript.Shell");
var BasePath = WshShell.CurrentDirectory+"\\";
var FSO = WScript.CreateObject("Scripting.FileSystemObject");
var PathBook = BasePath+"book.txt";
var LastName = InputName();
var Res, FBook, PersonArr, Person, FOut;
if (LastName && LastName.length) {
Res = WshShell.Popup("Удалить фамилию "+LastName+" из \n"+
PathBook+"?", 0, "Записная книжка", 32+4);
if (Res==6) {
FBook = FSO.OpenTextFile(PathBook, 1, true);
PersonArr = [];
Res = 0;
while (!FBook.AtEndOfStream) {
Person = FBook.ReadLine();
if (Res || (LastName!=Person.split("|")[0]))
PersonArr[PersonArr.length] = Person
else Res = 1 }
FBook.Close();
FOut = FSO.OpenTextFile(PathBook, 2, true);
for (var i=0; i<PersonArr.length; i++) FOut.WriteLine(PersonArr[i]);
FOut.Close();
if (Res) WshShell.Popup("Запись удалена!", 0, "Записная книжка", 64);
else WshShell.Popup("Фамилия "+LastName+
" не найдена в записной книжке!", 0, "Записная книжка", 64) } }
</script>
</job>

После этого Автор объединил эти кусочки общей оболочкой, что нас, собственно и интересует. В отличие от предыдущих скриптов, работающих самостоятельно, тут, прежде чем запускать, нужно сначала набить все файлы-библиотеки. Во-первых, "общая библиотека" - Usage.js.

var WshShell, BasePath, FSO, FBook, PathBook, FOut, PersonArr, Person, LastName, Res;
function PrintPerson(Person) {
FOut.WriteLine("Фамилия: "+Person[0]);
FOut.WriteLine("Имя: "+Person[1]);
FOut.WriteLine("Телефон: "+Person[2]);
FOut.WriteLine("Улица: "+Person[3]);
FOut.WriteLine("Дом: "+Person[4]);
FOut.WriteLine("Кв.: "+Person[5]);
FOut.WriteLine("Заметки: "+Person[6]);
FOut.WriteLine("*****")
}
function SortLastName(Pers1, Pers2) {
if (Pers1[0]<Pers2[0]) return -1;
else if (Pers1[0]==Pers2[0]) return 0;
else return 1
}
function InitPath() {
WshShell = WScript.CreateObject("WScript.Shell");
BasePath = WshShell.CurrentDirectory+"\\";
FSO = WScript.CreateObject("Scripting.FileSystemObject")
}
function MakeOut(Top, Bottom) {
var PathOut = BasePath+"out.txt";
FOut = FSO.OpenTextFile(PathOut, 2, true);
FOut.WriteLine(Top);
FOut.WriteLine("--------------------");
FOut.WriteLine("");
PersonArr.sort(SortLastName);
for (var i=0; i<PersonArr.length; i++) PrintPerson(PersonArr[i]);
FOut.WriteLine("");
FOut.WriteLine(Bottom+": "+PersonArr.length);
FOut.Close();
WshShell.Run("notepad "+PathOut, 1);
}

Далее - библиотека второго уровня - PhoneBook.wsf, объединяющая (поэтому и .wsf) в себе уже введенные операции (и, дополнительно, еще пару). Т.к. я не стал отказываться от эффективности в пользу единообразия, то не запутайтесь, где записи (Person) хранятся в виде массивов, а где - в виде строк. Обратите внимание на получение ф-иями параметров из командной строки - WScript.Arguments.Named.

<package>
<job id="SortName">
<script language="JScript" src="usage.js"/>
<script language="JScript">
InitPath();
FBook = FSO.OpenTextFile(BasePath+"book.txt", 1, true);
PersonArr = [];
while (!FBook.AtEndOfStream)
PersonArr[PersonArr.length] = FBook.ReadLine().split("|");
FBook.Close();
MakeOut("Список всех записей, сортировка по фамилии","Всего записей");
</script>
</job>
<job id="FindName">
<script language="JScript" src="usage.js"/>
<script language="JScript">
LastName = WScript.Arguments.Named("X");
InitPath();
FBook = FSO.OpenTextFile(BasePath+"book.txt", 1, true);
PersonArr = [];
while (!FBook.AtEndOfStream) {
Person = FBook.ReadLine().split("|");
if (LastName==Person[0]) PersonArr[PersonArr.length] = Person }
FBook.Close();
if (PersonArr.length) MakeOut("Поиск записей", "Всего найдено")
else WshShell.Popup("Фамилия "+ LastName+ " не найдена!", 0,
"Записная книжка", 64)
</script>
</job>
<job id="DelRec">
<script language="JScript" src="usage.js"/>
<script language="JScript">
LastName = WScript.Arguments.Named("X");
if (LastName && LastName.length) {
InitPath();
PathBook = BasePath+"book.txt";
Res = WshShell.Popup("Удалить фамилию "+LastName+" из \n"+
PathBook+"?", 0, "Записная книжка", 32+4);
if (Res==6) {
FBook = FSO.OpenTextFile(PathBook, 1, true);
PersonArr = [];
Res = 0;
while (!FBook.AtEndOfStream) {
Person = FBook.ReadLine();
if (Res || (LastName!=Person.split("|")[0]))
PersonArr[PersonArr.length] = Person
else Res = 1 }
FBook.Close();
FOut = FSO.OpenTextFile(PathBook, 2, true);
for (var i=0; i<PersonArr.length; i++) FOut.WriteLine(PersonArr[i]);
FOut.Close();
if (Res) WshShell.Popup("Запись удалена!", 0, "Записная книжка", 64);
else WshShell.Popup("Фамилия "+LastName+
" не найдена в записной книжке!", 0, "Записная книжка", 64) } }
</script>
</job>
<job id="AddRec">
<script language="JScript" src="Usage.js"/>
<script language="JScript">
Person = WScript.Arguments.Named("X");
InitPath();
PathBook = BasePath+"book.txt";
FBook = FSO.OpenTextFile(PathBook, 8, true);
FBook.WriteLine(Person);
FBook.Close()
WshShell.Popup("Новая запись\n\n"+Person+"\n\nдобавлена в файл "+
PathBook, 0, "Записная книжка", 64)
</script>
</job>
<job id="Test">
<script language="JScript">
WScript.Echo("Параметр2: "+WScript.Arguments.Named("X"))
</script>
</job>
</package>

Отдельно - VBScript-кусочек WSHInputBox.vbs для InputBox().

Function WSHInputBox(Message,Title)
'Выводим диалоговое окно со строкой ввода
WSHInputBox = InputBox(Message,Title)
End Function

Первый вариант оболочки - ArgMenu.wsf - для работы из консоли. Т.е. либо открываем консоль, переходим в директорию, где сохраняем эти примеры, и запускаем этот файл; либо, перетягиваем файл в окошко Пуск-Run (путь при этом сам копируется). Команды вводятся ключами вызова.

<job id="ArgMenu">
<runtime>
<description>
Сценарий для работы с телефонной книжкой
</description>
<named name="L" helpstring="Просмотр содержимого книжки" type="simple" required="false"/>
<named name="F" helpstring="Поиск по фамилии" type="simple" required="false"/>
<named name="A" helpstring="Добавление записи" type="simple" required="false"/>
<named name="D" helpstring="Удаление записи" type="simple" required="false"/>
</runtime>
<script language="VBScript" src="WSHInputBox.vbs"/>
<script language="JScript">
var Res, Person;
var WshShell = WScript.CreateObject("WScript.Shell");
if ((WScript.Arguments.Named.Exists("L")) ||
(WScript.Arguments.Named.Exists("l")))
WshShell.Run("wscript PhoneBook.wsf //Job:SortName");
else if ((WScript.Arguments.Named.Exists("F")) ||
(WScript.Arguments.Named.Exists("f"))) {
Person = WSHInputBox("Введите фамилию для поиска:","Записная книжка");
if (Person && Person.length)
WshShell.Run("wscript PhoneBook.wsf //Job:FindName /X:\""+Person+"\"") }
else if ((WScript.Arguments.Named.Exists("A")) ||
(WScript.Arguments.Named.Exists("a"))) {
Res = WshShell.Popup("Добавить запись?", 0,
"Записная книжка", 32+4);
if (Res==6) {
Person = [];
Person[0] = WSHInputBox("Введите фамилию","Добавление записи");
Person[1] = WSHInputBox("Введите имя","Добавление записи");
Person[2] = WSHInputBox("Введите телефон","Добавление записи");
Person[3] = WSHInputBox("Введите улицу","Добавление записи");
Person[4] = WSHInputBox("Введите дом","Добавление записи");
Person[5] = WSHInputBox("Введите квартиру","Добавление записи");
Person[6] = WSHInputBox("Введите примечание","Добавление записи");
WshShell.Run("wscript PhoneBook.wsf //Job:AddRec /X:\""+
Person.join("|")+"\"") } }
else if ((WScript.Arguments.Named.Exists("D")) ||
(WScript.Arguments.Named.Exists("d"))) {
Person = WSHInputBox("Введите фамилию для поиска:","Записная книжка");
if (Person && Person.length)
WshShell.Run("wscript PhoneBook.wsf //Job:DelRec /X:\""+Person+"\"") }
else WScript.Arguments.ShowUsage()
</script>
</job>

Конечно, команды можно вводить так же, как мы вводили фамилии, но это совсем не интересно. Поэтому сразу перейдем к HTML. Здесь начинается та самая путаница MD/HTML. Браузер вызывает JavaScript при нажатии кнопочки в HTML-форме, но не свой браузерный JavaScript, как на обычной интернет-страничке, а мастдайный... Точнее MD-скрипт перехватывает событие браузера и не дает его скриптам шанса. И да, я не знаю, возможно ли это с другими браузерами, а не с одним - Internet Explorer. За графическое представление нашей программы будет отвечать файл Phone.htm:

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Форма для записной книжки</title>
</head><body bgcolor="silver" scroll="no">
<form name="MainForm">
<table><tr><td>Фамилия</td>
<td><input type="text" name="txtLastName" size="50"></td></tr>
<tr><td>Имя</td>
<td><input type="text" name="txtName" size="50"></td></tr>
<tr><td>Телефон</td>
<td><input type="text" name="txtPhone" size="15"></td></tr>
<tr><td>Улица</td>
<td><input type="text" name="txtStreet" size="50"></td></tr>
<tr><td>Дом</td>
<td><input type="text" name="txtHouse" size="10"></td></tr>
<tr><td>Кв.</td>
<td><input type="text" name="txtApp" size="5"></td></tr><tr>
<td>Примечание</td>
<td><input type="text" name="txtNote" size="80"></td>
</tr></table><br>
<input type="button" value="&lt;&lt;" name="btnFirst">
<input type="button" value="&lt;" name="btnPrevious">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" value="Новая запись" name="btnNew">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" value="Записать" name="btnSave">
<input type="button" value="Отменить" name="btnCancel">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" value="Удалить" name="btnDelete">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" value="&gt;" name="btnNext">
<input type="button" value="&gt;&gt;" name="btnFinal">
</form></body></html>

Теперь напишем программу, которая согласиться считать эту экранную форму своим интерфейсом - IEPhoneBook.wsf.

<job id="IEPhone">
<script language="JScript" src="usage.js"/>
<script language="JScript">
var IsQuit, IsNotOk, Doc, Num;
function SetData () {
if (Num==PersonArr.length) Num--;
Doc.all.txtLastName.value = PersonArr[Num][0];
Doc.all.txtName.value = PersonArr[Num][1];
Doc.all.txtPhone.value = PersonArr[Num][2];
Doc.all.txtStreet.value = PersonArr[Num][3];
Doc.all.txtHouse.value = PersonArr[Num][4];
Doc.all.txtApp.value = PersonArr[Num][5];
Doc.all.txtNote.value = PersonArr[Num][6];
IsNotOK = false;
Doc.title = "Запись #"+(Num+1)
}
function RefreshData() {
FBook = FSO.OpenTextFile(PathBook, 1, true);
PersonArr = [];
while (!FBook.AtEndOfStream)
PersonArr[PersonArr.length] = FBook.ReadLine().split("|");
FBook.Close();
if (!PersonArr.length) {
PersonArr[0] = ["", "", "", "", "", "", ""];
Num = 0; }
SetData()
}
function SaveData(N) {
if (IsNotOk) {
PersonArr[Num][0] = Doc.all.txtLastName.value;
PersonArr[Num][1] = Doc.all.txtName.value;
PersonArr[Num][2] = Doc.all.txtPhone.value;
PersonArr[Num][3] = Doc.all.txtStreet.value;
PersonArr[Num][4] = Doc.all.txtHouse.value;
PersonArr[Num][5] = Doc.all.txtApp.value;
PersonArr[Num][6] = Doc.all.txtNote.value;
FOut = FSO.OpenTextFile(PathBook, 2, true);
for (var i=0; i<PersonArr.length; i++) FOut.WriteLine(PersonArr[i].join("|"));
FOut.Close() }
Num = N;
SetData()
}
function ChangeData() {
IsNotOk = true;
Doc.title = "Редактируется запись #"+(Num+1)
}
function ie_DocumentComplete() {
Doc = ie.Document;
Doc.all.btnSave.onclick = function() { SaveData(Num) };
Doc.all.btnCancel.onclick = function() { IsNotOk = false; SaveData(Num) };
Doc.all.btnFirst.onclick = function() { SaveData(0) };
Doc.all.btnPrevious.onclick = function() { SaveData(Num?Num-1:0) };
Doc.all.btnNew.onclick = function() {
PersonArr[PersonArr.length] = ["", "", "", "", "", "", ""];
SaveData(PersonArr.length) };
Doc.all.btnDelete.onclick = function() {
ie.Visible = false;
WshShell.Run("wscript PhoneBook.wsf //Job:DelRec /X:\""+
PersonArr[Num][0]+"\"", 0, true);
ie.Visible = true;
RefreshData() }
Doc.all.btnNext.onclick = function() { SaveData(Num+1) };
Doc.all.btnFinal.onclick = function() { SaveData(PersonArr.length) };
Doc.all.txtLastName.onchange = ChangeData;
Doc.all.txtName.onchange = ChangeData;
Doc.all.txtPhone.onchange = ChangeData;
Doc.all.txtStreet.onchange = ChangeData;
Doc.all.txtHouse.onchange = ChangeData;
Doc.all.txtApp.onchange = ChangeData;
Doc.all.txtNote.onchange = ChangeData;
Num = 0;
RefreshData();
ie.Visible = true;
}
function ie_OnQuit() {
IsQuit = true
}
InitPath();
PathBook = BasePath+"book.txt";
PathHTML = BasePath+"Phone.htm";
ie = WScript.CreateObject("InternetExplorer.Application", "ie_");
ie.AddressBar = false;
ie.FullScreen = false;
ie.MenuBar = false;
ie.Resizable = false;
ie.StatusBar = false;
ie.ToolBar = false;
ie.Height = 350;
ie.Width = 780;
IsQuit = false;
ie.Navigate(PathHTML);
while (!IsQuit) WScript.Sleep(100)
</script></job>

Нужна ли эта цепочка: библиотеки_операций - библиотека_команд - оболочка? Конечно, нет. Автор, например, свою HTML-оболочку полностью написал заново (.js). Я же, как дурак, старался сохранить хоть какую-то преемственность примеров, плюс, подчеркнуть связь WSH-скриптов с Операционной Системой.

Что дальше? Читать книжки по правильному ООП в JavaScript, изучать библиотеки системных объектов... Главное, у нас теперь есть способ прицепить к нашим учебным программам хоть какой-то интерфейс и худо-бедно сохранять результаты работы в виде файлов. Как говорят строители, нулевой цикл пройден.
***

Попробую как-то систематизировать.

Во-первых, Мастдай дает нам интерпретатор WSH (даже два - оконный и консольный). Этот интерпретатор понимает JavaScript (файлы с расширениями .js), VBasicScript (.vbs) и их комбинацию (.wsf). В последнем случае возможно добавление некоторых оформительных элементов. Все файлы - текстовые, их можно изготовить в любом редакторе. И тут я заявляю, что, по МОЕЙ классификации, это не интерпретатор, а ЗАГРУЗЧИК - т.к. во время запуска программы нет никакого диалога, а вся прелесть интерпетаторов состоит именно во вводе команд по ходу дела. Итак, ЗАГРУЗЧИК-WSH неявно присутствует во всех описанных здесь четырех программах.

Во-вторых, во всех четырех программах присутствует ТАБЛИЦА book.txt - "пример телефонной книги", над которой издеваются программы. Попов в своей книге приводит дополнительные примеры для хранения данных в формате XML, но это - для убогих (как и формат JSON). Итак, все четыре программы работают с ТАБЛИЦЕЙ-BOOK, и я не стал отдельно выделять блоки чтения/записи текстовых файлов, поскольку в WSH (в отличие от HTML) они не представляют никакой трудности.

В-третьих, я, пардон, пропущу описания очевидных ФАЙЛОВ и СООБЩЕНИЙ, которые сиюминутно организовываются программами для организации временных интерфыейсов.

Первая программа:
- ТАБЛИЦА-BOOK
- СООБЩЕНИЕ-OUT. Единственная сложная передача СООБЩЕНИЯ в примере. Формируется специальный текстовый файл - out.txt - который затем передается тектовому РЕДАКТОРУ. Этот трюк возник во времена внедрения Мастдая - этакая псевдо-консоль, позволяющая "просто вывести текст без этих ваших окошек".
- РЕДАКТОР-NOTEPAD. Одна из двух явно вызываемых в примерах мастайных приблуд "чтобы не писать самому".
- ПРОЦЕСС-SORTNAME. Сама программа-скрипт в файле .js. Читает ТАБЛИЦУ-BOOK, сортирует ее и ответ выдает в виде СООБЩЕНИЯ-OUT. Вызывает РЕДАКТОР-NOTEPAD и передает ему это СООБЩЕНИЕ.

Вторая программа:
- ТАБЛИЦА-BOOK
- ПОЛЬЗОВАТЕЛЬ-INPUT. В этой программе ПОЛЬЗОВАТЕЛЮ дается шанс поучаствовать в процессе, а не просто ждать, пока он получит какой-то там файл. Ввод "фамилии телефонного абонента для удаления" организуется средствами WSH - где можно - js, где чуть-сложнее - vbs. Этот пример показывает, что авторы WSH считают: для убогих пользователей хватит и таких диалогов.
- ПРОЦЕСС-FINDANDDELRECORD. Скрипт .wsf - упаковка .js и .vbs понадобилась для диалога. Читает-пишет ТАБЛИЦУ-BOOK.

В последних двух примерах огрызки кода первых двух используются в виде некоторой обобщенной библиотеки - ТАБЛИЦЫ-PHONEBOOK (.wsf), в которой сконцентрирована вся функциональность работы с ТАБЛИЦЕЙ-BOOK (включая ПОЛЬЗОВАТЕЛЯ-INPUT и СООБЩЕНИЕ-OUT).

Третья программа:
- ИНТЕРПРЕТАТОР-ARGMENU. Этот ArgMenu.wsf - просто выбиратор функции из ТАБЛИЦЫ-PHONEBOOK. И пример оформительской ф-ии .wsf - генерации HELP-окошка.
- ПОЛЬЗОВАТЕЛЬ-CON. Тот, кто вызывает ИНТЕРПРЕТАТОР-ARGMENU. Единственное место примеров, чувствительное к способу запуска скрипта. Вызов должен происходить в DOS-режиме, т.к. имя нужной функции нужно ввести в качестве "ключа командной строки". Нужна консоль. Заметьте, что этот ПОЛЬЗОВАТЕЛЬ не имеет никакого отношения к ПОЛЬЗОВАТЕЛЮ-INPUT.

Четвертая программа:
- ИНТЕРПРЕТАТОР-PHONE (Phone.htm). Это замена консоли из предыдущего примера окном Internet Explorer (здесь - вторая мастдайная приблуда "чтобы не писать самому"). Вместо консольных ключей - кнопочки. Чуть удобнее.
- ЗАГРУЗЧИК-IEPHONEBOOK (IEPhoneBook.wsf). Код, подменяющий код HTML-форм ИНТЕРПРЕТАТОРА-PHONE вызовами функций ТАБЛИЦЫ-PHONEBOOK или их аналогами. Главный плюс - остается доступ к файловой системе, который сильно затрудняется при честном вызове HTML-скриптов. Главный минус - можно использовать только Internet Explorer, но не другие программы-браузеры.
- ПОЛЬЗОВАТЕЛЬ-HTML. Тот, кто правит ТАБЛИЦУ-BOOK в Internet Explorer.

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Incuba13


Последний раз редактировалось: Gudleifr (Пн Авг 07, 2023 1:16 am), всего редактировалось 9 раз(а)
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Пт Июл 20, 2018 11:52 am

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

Для начала - совершенно тупая программа (test.js), проверяющая, не возникло ли в результате правки очередной вырезанной порции листьев конфликта с другим листьями. Вдруг лист с таким путем уже существует? Стек файлов (как описано выше) организован путем добавления нужного числа расширений ".TXT" к основному имени файла "COMP.TXT".
Использую ту же машину для построения дерева (см. прошлую главу), что и ранее, только сами листья нам уже не нужны, достаточно только флага, указывающего, что лист в узле есть. Названия переменных остались те же.

var G, P, R, V, W, Y;
var A1 = function () {
P = 0;
W = R.split("\\");
for (V=1; V<W.length; V++) {
if (Y[P][1][W[V]]) P = Y[P][1][W[V]]
else {
Y.push([0, {}]);
Y[P][1][W[V]] = Y.length-1;
P = Y.length-1 } }
if (Y[P][0]) WScript.echo(R);
Y[P][0]=1
}
A = [[[/^\\/, function () { }, 1, 0],
[/^\s*$/, function () { }, 0, 1],
[0, function () { }, 0, 1]],
[[/^\s*$/, function () { }, 4, 1],
[/^[A-Za-z] /, function () { }, 4, 0],
[/^\\/, A1(), 1, 1],
[/^ТЕКСТ/, function () { }, 3, 1],
[/^ТАБЛИЦА/, function () { }, 2, 1],
[/^ЗАПИСИ/, function () { }, 2, 1],
[0, function () { }, 0, 0]],
[[/^\s*$/, function () { }, 3, 1],
[0, function () { }, 2, 1]],
[[/^\s*$/, function () { }, 4, 1],
[0, function () { }, 3, 1]],
[[/^[A-Za-z] /, function () { }, 4, 1],
[/^\\/, function () { }, 1, 0],
[/^\s*$/, function () { }, 0, 1],
[0, function () { }, 0, 0]]];
var RE, LF, TF, FE;
LF = new Enumerator(
WScript.CreateObject("Scripting.FileSystemObject")
.GetFolder(WScript.CreateObject("WScript.Shell")
.CurrentDirectory)
.Files);
RE = /^COMP.TXT(.TXT)*$/i;
Y = [[0, {}]];
while (!LF.atEnd()) {
FE = LF.item();
if (RE.test(FE.Name)) {
TF = FE.OpenAsTextStream(1, 0);
R = "";
G = 0;
while (R || !TF.AtEndOfStream) {
if (!R) R = TF.ReadLine();
for (var U=0; U<A[G].length; U++) {
if (!A[G][U][0]||A[G][U][0].exec(R)) {
A[G][U][1]();
if (A[G][U][3]) R = "";
G = A[G][U][2];
break }}}
TF.Close()
}
LF.moveNext()
}

Можно ли описать эту штуку как-то более понятно? Попробуем.
Во-первых, что происходит со стеком?

I...I -- I...I

т.е. все файлы на стеке воспринимаются как исходные, но не изменяются.
Файлы скармливаются машине считывания дерева:

M1(I):
P\PI (ДОБАВИТЬ К ДЕРЕВУ ПУТЬ; СООБЩИТЬ, ЕСЛИ ПУТЬ УЖЕ ЕСТЬ)

Т.е. единственная обрабатываемая ситуация - чтение пути листа (P\P - чтение строки, начинающейся с "обратной косой" в состоянии чтения пути).
***

Экспериментируя с Windows-консолью надо быть готовым к тому, что русские буквы будут постоянно пытаться превратиться в галиматью. Для борьбы с этим надо изначально поставить шрифт Lucida Console в свойствах консоли. И постоянно быть готовым к переключению кодовой страницы командой chcp (с параметром 1251 или 866). Кстати, в ф-ии OpenAsTextStream выше нолик указывает на то, что файл набит буквами в кодировке 1251.

Да, и искать учебник по командам, понимаемых консолью (т.е. командным интерпретатором DOS/Windows) не особо нужно. Все сугубо необходимое указано в справке (команда help и/или ключ /? в самой команде). А все самое интересное передается от хакера к хакеру при личном общении.  
***

Вырезатель будет намного сложнее.
Во-первых, надо решить, как передавать программе критерии поиска. Можно их как-то передать программе через параметры вызова (например, в специальном диалоговом окошке, как в примере с телефонной книгой), можно в тексте листьев специального вида, можно в файле специального вида. Я выбрал последнее, т.к. оба других к нему легко сводятся.
Во-вторых, допустим несколько листьев уже выбрано. Как нам использовать вырезатель? Добавить новые листья к уже выбранным, наоборот, выбрать только из уже выбранных или игнорировать текущую выборку и создать новую?
Соответствующие стековые комментарии, соответственно:

I...IAS -- O...ОR
N...NIS -- N...NR
I...IS -- O...OR

S - файл с критериями выбора
I - входные
A - пополняемый (уже выбранные ранее)
N - нейтральные
O - выходной (I, из которого вырезаны найденные узлы).
R - все выбранные
***

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

/* Транспозиция стека COMP3.TXT...TXT и списка аргументов */
var F0, FL, FN;
F0 = new Enumerator(
WScript.CreateObject("Scripting.FileSystemObject")
.GetFolder(WScript.CreateObject("WScript.Shell")
.CurrentDirectory)
.Files);
FL = [];
while (!F0.atEnd()) {
if (/^COMP3.TXT(.TXT)*$/i.test(F0.item().Name)) FL.push([F0.item()]);
F0.moveNext()
}
for (FN=0; FN<FL.length-1; FN++)
FL[FL.length-2-FN].push(FN<WScript.Arguments.length
? WScript.Arguments(FN)
: WScript.Arguments(WScript.Arguments.length-1));
FL[FL.length-1].push("S");
for (FN=0; FN<FL.length; FN++)
WScript.Echo(FL[FN][0]+" *** "+FL[FN][1]);

Т.е. расширяющая выборка запишется (в консоли Windows) как

cscript <вырезатель>.js A I

S упоминать не надо, как, очевидно, и выходные файлы, а I будет расширено на весь остаток стека. Т.е. <вырезатель> будет ждать стек I...IAS.
***

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

Вспомним картинку в заглавной теме "про FORTH". Всякие LISP лежат о области голой теории и ближе всего к ним "из работающего" тот самый FORTH - т.е. самые простые интерпретаторы. Зачем нам брать список "в целом", если мы можем просто брать элементы "по очереди".

Вместо:

1) Формируем список файлов
2) Нормализуем список аргументов (дописываем в начало S, удлиняем/обрезаем хвост)
3) Выполняем транспозицию
4) Обрабатываем результирующий список пар

получаем

1) Формируем стек файлов
2) Выполняем для вершины стека операцию S
3) Пока не кончился список аргументов выполняем его элементы, как операции над стеком
4) Повторяем для каждого файла остатка стека последнюю операцию из (3)
***

На первый взгляд кажется, что сменили шило на мыло: вместо организации списков нужен цикл интерпретации. И что из них будет страшнее выглядеть на Javascript, еще тот вопрос.
Но тут-то мы и выигрываем! Ведь интерпретаторов-то у нас много. И перебирать файлы в каждой программе не надо. Пусть это делает консоль.

Кстати, если мы применим вырезатель с несколькими командами A, то в стеке появятся дыры. Например, после COMP.TXT.TXT сразу пойдет COMP.TXT.TXT.TXT.TXT. Поэтому к нашей утилите text.js добавим еще одну - norm.cmd. Для нормирования стека нам будет достаточно простых консольных команд.

@ ECHO OFF
SET CUR=COMP.TXT
FOR /F "usebackq" %%I IN (`DIR /ON /B COMP.TXT*`) DO CALL :TEST %%I
EXIT /B
:TEST
IF NOT %CUR%==%1 REN %1 %CUR%
SET CUR=%CUR%.TXT
EXIT /B

(Сложную конструкцию перебора файлов вместо очевидного FOR %%I IN (COMP.TXT*) ... вставил на всякий случай: никто не берется гарантировать, что файлы будут перебираться FOR в порядке, отличным от алфавитного, хотя я не помню, чтобы такое встречал).  
Добавив аналогично обычные команды для работы со стеком PUSH, POP, DUP, DROP, SWAP мы сможем вообще не волноваться о том, сколько файлов и каким способом нужно перебрать, оставив для Javascript только простейший вырезатель (IS -- OR). Т.е. на Javascript мы получили то же, что и для BASIC - все перетасовки файлов - только в командных скриптах. Где там наш BASIS-вырезатель из прошлой главы?
***

Перед тем, как приступить всерьез, добавим машину для считывания критериев поиска:

S --

M2(S):
GXGI, TXTI (ДОБАВИТЬ ТЕКСТОВЫЙ КРИТЕРИЙ)
P\PI (ДОБАВИТЬ ПУТЕВОЙ КРИТЕРИЙ)
PTTI, P#HI, PRHI (ДОБАВИТЬ КРИТЕРИЙ ТИПА)
HXHI (ДОБАВИТЬ ЗАГОЛОВОЧНЫЙ КРИТЕРИЙ)
LLLI (ДОБАВИТЬ ПАРАМЕТРИЧЕСКИЙ КРИТЕРИЙ)
PXG, LXG, L0GI (КОНЕЦ РАБОТЫ)

За основу взял таблицу из прошлой главы. Критерий для текста и мусора один.

А как проверять соответствие строки критерию?

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

Далее проверяются все критерии списка. Проверка зависит от типа блока.
Строка мусора считается соответствующей, если содержит один из критериев списка текстовых.
Строка пути считается соответствующей, если содержит один из критериев списка путевых (первый символ критерия - очевидно, обратная косая - отбрасывается). Критерий, который всегда успешен - две обратных косых: первая отбрасывается, вторая завсегда присутствует в строке пути.
Строка типа считается соответствующей, если, наоборот, содержится в критерии (т.о. можно задавать несколько типов, ведь список критериев типа не может содержать более одной штуки).
Строка заголовка считается соответствующей, если содержит один из критериев списка заголовочных.
Строка текста считается соответствующей, если содержит один из критериев списка текстовых. Если тип искомых листов не имеет значения или путь может быть любым, проще задать текстовые критерии в поле мусора.
Строка параметров считается соответствующей, если один из критериев списка параметрических относится к тому же параметру, а его значение содержится в значении параметра строки.
***

Причем, надо обратить внимание, что если я работаю в том же BASIC, я могу схитрить. Записать и критерии поиска, и ф-ии проверки строк в в одном файле, в виде куска кода (с определенными номерами строк). И подключать получившиеся машины поиска к типовому вырезателю.


Последний раз редактировалось: Gudleifr (Пн Авг 07, 2023 12:56 am), всего редактировалось 11 раз(а)
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Вс Авг 05, 2018 12:59 pm

JAVASCRIPT-ВЫРЕЗАТЕЛЬ

JavaScript-скрипт, содержащий две машины разбора (для разбора критерия и для разбора входного файла) слишком тяжеловесен. Но мы же говорим о скриптах... Напишем скрипт-оболочку (IS_OR.CMD):

@ ECHO OFF
SET CUR1=
FOR %%I IN (COMP3.TXT*) DO CALL :SETS %%I
SET OP=CSCRIPT //U //Nologo
%OP% S_.JS %CUR1% | %OP% I_.JS %CUR2% | %OP% _OR.JS %CUR2%
COPY /Y %CUR2%.2 %CUR2% >NUL
COPY /Y %CUR2%.1 %CUR1% >NUL
DEL %CUR2%.1
DEL %CUR2%.2
EXIT /B
:SETS
SET CUR2=%CUR1%
SET CUR1=%1
EXIT /B

Опять танцы с бубном: все эти "//U", ">NUL" "//Nologo" и т.п. нужны для того, чтобы программы могли общаться без проблем. Чаще читайте HELP-ы к командам (ключ /?)! Кроме того, обратите внимание, где лежит "стек файлов" (COMP3.TXT...TXT), и на то, что мы портим два верхних элемента (исходный и критерии) заменяя их (на оставленные и выбранные).
Центральная часть нашего скрипта-оболочки вызов трех частных скриптов:

Первый скрипт - S_.JS - разбирает критерии. Он берет верхний файл стека (S), разбирает его - выкидывает критерии в простом формате в общий канал.

var X = [[], [], [], [], []];
var E, R;
var M = [[[/^\\/, function() { }, 1, 0],
[/^\s*$/, function() { }, 0, 1],
[0, function() { X[3].push(R) }, 0, 1]],
[[/^\s*$/, function() { }, 4, 1],
[/^[A-Za-z] /, function() { }, 4, 0],
[/^\\/, function() { X[0].push(R) }, 1, 1],
[/^ТЕКСТ/, function() { X[1].push(R) }, 3, 1],
[/^ТАБЛИЦА/, function() { X[1].push(R) }, 2, 1],
[/^ЗАПИСИ/, function() { X[1].push(R) }, 2, 1],
[0, function () { E = 0 }, 0, 0]],
[[/^\s*$/, function() { }, 3, 1],
[0, function() { X[2].push(R) }, 2, 1]],
[[/^\s*$/, function () { }, 4, 1],
[0, function() { X[3].push(R) }, 3, 1]],
[[/^[A-Za-z] /, function() { X[4].push(R) }, 4, 1],
[/^\\/, function() { E = 0 }, 1, 0],
[/^\s*$/, function() { E = 0 }, 0, 1],
[0, function() { E = 0 }, 0, 0]]];
var G, U;
R = "";
G = 0;
E = 1;
var F=WScript.CreateObject("Scripting.FileSystemObject")
.OpenTextFile(WScript.Arguments(0), 1, true);
while (E && (R || !F.AtEndOfStream)) {
if (!R) R = F.ReadLine();
for (U=0; U<M[G].length; U++) {
if (!M[G][U][0]||M[G][U][0].exec(R)) {
M[G][U][1]();
if (M[G][U][3]) R = "";
G = M[G][U][2];
break }}}
F.Close()
var N1, N2;
for (N1=0; N1<X.length; N1++) {
WScript.Echo(X[N1].length);
for (N2=0; N2<X[N1].length; N2++) {
WScript.Echo(X[N1][N2])
} }

Второй скрипт - I_.JS - разбирает исходный файл. Он берет со стека второй файл (I) и разбирает его согласно критериям, считанным из общего канала. Разобранные строки и команды их обрабатывающие в простом формате отправляются в общий канал. Разбор происходит подобно тому, как мы делали в прошлой главе на BASISC - строим таблицу (она тут посложнее) и "компилируем" ее в шкалы.

var LQ = [[], [], [], [], []];
var Q1, Q2, RQ;
for (Q1 = 0; Q1<LQ.length; Q1++) {
RQ = Number(WScript.StdIn.ReadLine());
for (Q2 = 0; Q2<RQ; Q2++)
LQ[Q1].push(WScript.StdIn.ReadLine()) }
var RD;
function QT(Y) { return RD.indexOf(Y)+1 }
function QP(Y) { return RD.indexOf(Y.slice(1))+1 }
function QY(Y) { return Y.indexOf(RD)+1 }
function QL(Y) { return RD.charAt(0)!=Y.charAt(0)?0:
RD.slice(2).indexOf(Y.slice(2))+1 }
function Q0(Z) { return !Z.length }
function QQ(Z, Q) {
if (!Z.length) return 1;
var I, T = 0;
for (I = 0; I<Z.length && !T; I++)
T = Q(Z[I]);
return T }
function QG(Z, Q) {
if (!Z.length) return 0;
var I, T = 0;
for (I = 0; I<Z.length && !T; I++)
T = Q(Z[I]);
return T }
var _F = 1, _U = 2, _A = 4, _S = 8, _UAS = 14;
var _GQ = 16, _PQ = 32, _YQ = 64, _HQ = 128, _TQ = 256, _LQ = 512;
var _Y0 = 1024, _H0 = 2048, _T0 = 4096, _L0 = 8192;
var _MU = 16, _MA = 32, _MS = 64, _MC = 128, _MB = 256, _ME = 512, _MX = 1024, _MT = 2048;
var FUAS = _A;
var SP = /^\\/;
var SE = /^\\s*$/;
var SL = /^[A-Za-z] /;
var M = [[[SP, [0, 0, _ME+_A, _MB+_MT+_A, 0], 1, 0],
[SE, [0, 0, _ME+_A, _MB+_MT+_A, 0], 0, 1],
[0, [_A+_GQ, _MC+_MU+_U, _MU+_U, _MA+_A, 0], 0, 1]],
[[SE, [_U+_Y0+_H0+_T0, _MX+_A, _MB+_MT+_S, _MB+_MT+_S, 0], 4, 1],
[SL, [_U+_Y0+_H0+_T0, _MX+_A, _MB+_MT+_S, _MB+_MT+_S, 0], 4, 0],
[SP, [_A+_PQ, _MA+_U, _MA+_U, _MA+_A, 0], 1, 1],
[/^ТЕКСТ/, [_U+_YQ+_H0, _MA+_A, _MB+_MS+_S, _MB+_MS+_S, 0], 3, 1],
[/^ТАБЛИЦА/, [_U+_YQ, _MA+_A, _MB+_MS+_S, _MB+_MS+_S, 0], 2, 1],
[/^ЗАПИСИ/, [_U+_YQ, _MA+_A, _MB+_MS+_S, _MB+_MS+_S, 0], 2, 1],
[0, [_U+_Y0+_H0+_T0+_L0, _MC+_ME+_A, _MB+_MT+_A, _MB+_MT+_A, 0], 0, 0]],
[[SE, [_A+_H0, _MX+_A, _MX+_A, _MB+_MT+_S, _MT+_S], 3, 1],
[0, [_A+_HQ, _MA+_U, _MA+_U, _MA+_A, _MS+_S], 2, 1]],
[[SE, [_A+_T0, _MX+_A, _MX+_A, _MB+_MT+_S, _MT+_S], 4, 1],
[0, [_A+_TQ, _MA+_U, _MA+_U, _MA+_A, _MS+_S], 3, 1]],
[[SL, [_A+_LQ, _MC+_MU+_U, _MU+_U, _MA+_A, _MS+_S], 4, 1],
[SP, [_A+_L0, _MC+_ME+_A, _ME+_A, _MB+_MT+_A, _MT+_A], 1, 0],
[SE, [_A+_L0, _MC+_ME+_A, _ME+_A, _MB+_MT+_A, _MT+_A], 0, 1],
[0, [_A+_L0, _MC+_ME+_A, _ME+_A, _MB+_MT+_A, _MT+_A], 0, 0]]];
var FR = WScript.CreateObject("Scripting.FileSystemObject")
.OpenTextFile(WScript.Arguments(0), 1, true);
var MG, MU;
RD = "";
MG = 0;
function RX () {
var X, Q;
for (MU=0; MU<M[MG].length; MU++) {
if (!M[MG][MU][0]||M[MG][MU][0].exec(RD)) {
X = M[MG][MU][1][0];
if (X & FUAS) {
Q = true;
if (Q && X & _Y0) Q = Q0(LQ[1]);
if (Q && X & _H0) Q = Q0(LQ[2]);
if (Q && X & _T0) Q = Q0(LQ[3]);
if (Q && X & _L0) Q = Q0(LQ[4]);
if (Q && X & _GQ) Q = QG(LQ[3], QT)
else if (Q && X & _PQ) Q = QQ(LQ[0], QP)
else if (Q && X & _YQ) Q = QQ(LQ[1], QY)
else if (Q && X & _HQ) Q = QQ(LQ[2], QT)
else if (Q && X & _TQ) Q = QQ(LQ[3], QT)
else if (Q && X & _LQ) Q = QQ(LQ[4], QL);
if (Q) FUAS = _F }
var R;
if (FUAS == _F) R = 1;
else if (FUAS == _U) R = 2;
else if (FUAS == _A) R = 3;
else R = 4;
WScript.StdOut.WriteLine(M[MG][MU][1][R]);
if (!SE.exec(RD) && M[MG][MU][3]) WScript.StdOut.WriteLine(RD);
FUAS = M[MG][MU][1][R] & _UAS;
if (M[MG][MU][3]) RD = "";
MG = M[MG][MU][2];
break }}}
while (RD || !FR.AtEndOfStream) {
if (!RD) RD = FR.ReadLine();
RX() }
FR.Close();
RD = ""; RX(); RX(); RX();
WScript.StdOut.WriteLine("0");

Третий скрипт - _OR.JS - распихивает строки по файлам. Строки и указания по распихиванию считывает из общего канала.

var RS;
var FS, F1, F2;
var E1 = false, T1 = false, A1 = false;
var BA = "";
function MU() { F1.WriteLine(RS); E1 = true }
function MS() { F2.WriteLine(RS); T1 = true }
function MA() { if (BA) BA += "\n"; BA += RS; A1 = true }
function MC() { if (BA) { F1.WriteLine(BA); BA = ""; E1 = A1; A1 = false } }
function MB() { if (BA) { F2.WriteLine(BA); BA = ""; T1 = A1; A1 = false } }
function ME() { if (E1) { F1.WriteLine(""); E1 = false } }
function MX() { if (A1) { BA += "\n"; A1 = false } }
function MT() { if (T1) { F2.WriteLine(""); T1 = false } }
var _MU = 16, _MA = 32, _MS = 64, _MC = 128, _MB = 256, _ME = 512, _MX = 1024, _MT = 2048;
var _RD = _MU+_MA+_MS;
var FS = WScript.CreateObject("Scripting.FileSystemObject");
var F1 = FS.OpenTextFile(WScript.Arguments(0)+".1", 2, true);
var F2 = FS.OpenTextFile(WScript.Arguments(0)+".2", 2, true);
var RD;
do {
RD = Number(WScript.StdIn.ReadLine());
if (RD & _RD)
RS = WScript.StdIn.ReadLine();
if (RD & _MC) MC();
if (RD & _MB) MB();
if (RD & _MU) MU();
if (RD & _MA) MA();
if (RD & _MS) MS();
if (RD & _ME) ME();
if (RD & _MX) MX();
if (RD & _MT) MT();
} while (RD);
F1.Close();
F2.Close();

Теперь надо написать красивый охватывающий скрипт, не дающий нашему вырезателю разрушить всю нашу базу данных и делающий что-то полезное.
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Пт Сен 21, 2018 11:29 am

Вот на что это похоже (по сути, это примерно то же самое, что я показывал в предыдущей главе):

02.02. МАЛЕВИЧ, ГОВОРИТЕ? 2p10

С этого момента мы начинаем раскрашивать наши скрипты и пытаться добавлять в них игровой смысл.

На рисунке можно видеть два окна. Левое - статистика по нашему стеку. Ее выдает немного доработанный скрипт, описанный выше - test.js. Кнопки под ним - это "обычные стековые операции", позволяющие манипулировать парой "верхних" элементов. Их скрипты устроены, как уже описывалось выше - пересчитывались все имена файлов данных, и с парой последних производилась какая-либо обычная файловая операция.
Правое окно - верхний файл стека. Не правда ли, удобно, что нам не нужно писать никаких редакторов - наш интерфейс (Internet Explorer) все умеет сам. Кроме обычных двух кнопок "сохранить" и "отменить" я всобачил сюда же кнопку вырезателя из предыдущего примера.
Из хитростей только использование промежуточного текстового файла для передачи информации от CMD-скриптов в WSF-скрипт, рисующий HTML-форму. Кривенько, зато просто. Проще, чем канал между командами в вырезателе.

И работает!

Две попутные неприятности:
1. Офонарев от такого количества скриптов, антивирусы начинают бить тревогу. Нужно останавливаться и успокаивать их (помечать файлы и папки как обличенные всеми правами).
2. Для старых (понимай, вчерашних) версий Internet Explorer (и других офисных приложений) текстовые файлы размером 2Мб представляют почти непосильную ношу. Хоть на DOS возвращайся.
***

3. На добавление JavaScript в HTML файл, вызываемый из WSH-скрипта, Internet Explorer реагирует крайне болезненно. Мол, "опасное активное содержимое". Поэтому в HTML должны быть только оформительские детали, а функционал должен весь остаться в WSH. Это не страшно, т.к. HTML можно переписывать "на лету":

ie.Document.getElementById("x1").innerHTML = "...<span id=mark0>...";
ie.Document.getElementById("mark0").onclick = click;

Т.е. некий элемент, по нажатию которого мы вызываем некоторую функцию, мы создаем в предыдущей строчке. Кстати, "innerHTML" - это самое удобное место, куда мы можем вставлять наш код (обычно внутрь заранее заготовленных в HTML <div id=...>).


Последний раз редактировалось: Gudleifr (Сб Май 13, 2023 2:05 am), всего редактировалось 2 раз(а)
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Сб Мар 23, 2019 8:20 pm

А вот, как это должно было выглядеть по мнению журнала В МИРЕ НАУКИ 11/1984 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #15, АБЗАЦ #38602.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10. Берем универсальную суперпрограмму и отрезаем от нее все лишнее:

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Wmn-8410

Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Сб Мар 23, 2019 8:32 pm

А можно ли в это играть?
Я тут как-то пытался обозначить, в чем состоит придумывание игры.

Во-первых, ПРИЧИНА: графомания, обязательства, потребность в результате или интерес самого процесса? (02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #15, АБЗАЦ #4102.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10)
Здесь, явно второе. Раз я взялся писать, эти записки, то написание этих глав - вопрос долга. А, раз все застопорилось, явно, никакой более сильной причины не нашлось. Чего это мне будет стоить - видимо придется выбросить избыточные (слишком личные?) цитаты и измышлизмы. По крайней мере, добавить общей связности... Чем я тут, без особого успеха, последнее время и занимался.

Но, этот-то фрагмент явно "коммерческий" - он символизирует, что работа движется и, хотя, мне нечего сказать, я могу об этом поговорить...

Во-вторых, к какой КАТЕГОРИИ относится Ваша игра? (02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #2, АБЗАЦ #202.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10)
Я уже неоднократно писал, что все игры в наведение порядка относятся ко второй категории - "Уголки". Опять этот проклятый "тетрис", да еще многоуровневый.

Выбор категории приводит к обобщенной МАТРИЦЕ игры (какие стратегии доступны игроку, какова их успешность в зависимости от игры автора/природы).
Для "Уголков" - на одном конце стратегии неухудшения позиции, на другой ее улучшения. Для игры в построение офиса - это выбор между созданием сиюмино- и универсально-полезных инструментов. Для игры в работу с документами - выбор между правильной организацией и размером готового документа. Вот она многоуровневость! От редактирования одной большой текстовой простыни, до изготовления полноценного офиса, позволяющего за раз исполнить над текстом за раз любую полезную операцию.
Что может противопоставить этим стратегиям "природа"? Конечно, сложность текста (размер, структуризация, трудности перевода). И еще - интересность текста. Окупит ли она эту возню?

А как с ТАКТИКОЙ? Первые ходы этой игры не были особенно результативными. Ни программа манипулирования структурой дерева, ни пара использованных комбинаций "вырезатель-добавлятор". Первая оказалась слишком мощной - процедуры полного перелопачивания дерева требовались не часто, вторые потребовали более развитых интерфейсов, позволяющих точнее выразить, что именно надо сделать с выбранными узлами.

Подробнее о ляпах:
1. Слишком много редакторов; причем стандартные часто оказываются удобнее специализированных; но их труднее синхронизировать (в смысле запомнить, что куда положил и где что поправил).
2. Много кусков, которые надо переводить; это опять требует стандартных редакторов.
3. Перевод жутко раздражает низким КПД; хочется сразу переводить не на русский, а на язык алгоритмов.
4. В специализированных редакторах хочется иметь тексты меньшего размера с большим количеством гиперссылок-кнопочек.
5. Как ни крути, присутствует чувство того, что я, редактируя очередной фрагмент, "ухудшаю позицию" - неточно перевожу термины, теряю ссылки...

Добавить еще тетрисообразности? "Совмещения фигур в пространстве"? Для этого надо, чтобы редакторы умели отслеживать словарь терминов. И переводить порожденные ими связи их в ГЛЮКВУ.

Или добавить саперообразности? (02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #68, АБЗАЦ #74502.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10)
Направления "движения фишки":
- совершенствование ГЛЮКВА-структуры - "ход вниз";
- улучшение программ - "влево";
- перевод фрагмента - "вверх";
- привязывание фрагмента - "вправо".

Что означает проигрыш в Тетрисе? Фигуры неплотно заполнили весь стакан. А в Сапере? Игрок наступил на мину.
А как выглядело игровое поле за шаг до катастрофы? В Тетрисе - стакан столь забит, что надо усиленно крутить и двигать очередную фигурку. В Сапере - ситуация, которую сложно просчитать (большая концентрация мин).

В нашей текстовой игре Тетрис-проигрыш является естественным. Рост неразрешенных ссылок или их неточное соответствие очевидно свидетельствует о близости конца. А Сапер-проигрыш, видимо, придется эмулировать искусственно, добавляя "мин" по мере ухудшения ситуации.

Что в данный момент больше мешает? Неготовность ГЛЮКВЫ или недостаток текста для анализа?
Неготовность программы или избыток необработанных блоков текста.
Требуется оценить это в количественной форме. В принципе, древообразная структура документа это вполне позволяет.
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Вс Май 19, 2019 2:57 pm

ЕЩЕ О ПРОБЛЕМЕ КОДИРОВКИ РУССКИХ БУКВ

Я не могу поручиться, что нет возможности настроить свою пользовательскую программную среду на работу исключительно в одной-правильной кодировке. Но у меня почти всегда было не меньше трех одновременно. И мне обычно было лень искать все триггера, настроечные файлы и команды, которые позволили бы иметь "правильно-одноязычную ОС". И всегда была пара-другая очень нужных программ, которые напрочь отказывались соблюдать "единые правила кодирования"...

Так что, мне проще считать кодировку окружения враждебной к моей программе. Это было бы не страшно, если бы программа представляла из себя один процесс. Всего-то:
- придумать главную систему кодирования, в которой и производятся все внутренние символьные вычисления;
- запомнить, где лежат блоки перекодирования (их придется переписывать при переносе программы в другое окружение) и
- научиться работать с файлами в выбранной кодировке (для экономии времени).

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

Кстати, очевидный способ "заранее перекодировать все в латиницу" (например, в %-коды, применяемые при кодировке адресов в Сети) применим не всегда. Иногда поймать момент, когда система вдруг решает, что лучше вас знает кириллицу, достаточно сложно.  
***

Ниже буду вести список случаев, встречающихся в этих заметках.

ЛАТИНСКИЕ БУКВЫ одинаково кодируются почти везде. Так что, с английскими текстами не должно было бы быть никаких проблем. Но они могут быть. Из-за спец.символов - маркеров конца строк/файлов. Реже - псевдографических символов, вылезающих за безопасный диапазон номеров символов 32-127. (А как славно рисовались этими символами рамочки - см. 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #70, АБЗАЦ #76002.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10...)

В DOS-скрипте 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #70, АБЗАЦ #76302.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10, например, уже в строчке

FOR /F "usebackq delims=: tokens=1,*" %%i IN (`FINDSTR /N .* COMP.TXT`) DO CALL :%%status%% %%i "%%j"

мы надеемся, что обрабатываемый текст не содержит "двойных кавычек", иначе текущая строчка ("%%j") не сможет быть нормально обработана. В современных скриптовых языках такое тоже случается. В HTML зарезервированы "угловые скобки" и "&", в форумных текстах - "квадратные скобки" и "смайлики" (меня просто бесит превращение "восьмерки со скобкой" в Cool).
***

DOS-866 КОДИРОВКА КИРИЛЛИЦЫ, казалось бы, должна давным-давно отмереть. (Если, конечно, вы не захотите честно запустить BASIC-примеры. Но для этого вам, скорее всего, понадобится настроить и русифицировать DOS-box "машину", т.к. DOS-программы в наше отстойное время МастДай нормально выполнить не способен).

Но, не тут-то было. Некоторые консольные команды до сих пор ей пользуются. Обычно, для вывода справки. И приходится в консоли вызывать команду chcp с параметром 866...

В случае наличия старых документов/исходников с этой кодировкой, можно использовать текстовый редактор, способный к переводу (например, MS Word, в параметрах которого поставить галочку "Подтверждать преобразование файла при открытии" и, заодно, отключить всякие "автозамены"). Или, если удастся запустить DOS-программу в консоли, пометить-скопировать текст из нее при помощи системного меню консоли (работает и в обратную сторону).      
***

WIN-1251 КОДИРОВКА КИРИЛЛИЦЫ - наиболее удобная в настоящая время кодировка. Ее проще всего назначить главной.

Для нормальной работы консоли требуется, как я писал выше, поставить шрифт Lucida Console в ее свойствах. И выполнить команду chcp с параметром 1251...

Некоторые старые WIN-программы при копировании из них текста пытаются заменить кириллицу всякими азиопскими умляутами, если в них регистр ввода не переключен на ввод русских букв. Щелкайте им, пока не получится как надо.

Сложности возникают при передаче кириллических сетевых адресов. Настолько большие, что лучше не использовать ее в параметрах html-ссылок. Перекодировать в код Волапюк.

Как уже писал выше, в WSH ф-ии OpenAsTextStream нужен параметр-нолик.
***

UTF-8 - это непотребство придумано с целью обеспечить видимость совместимости всех возможных кодировок. Что свелось к обычному: "Угадайте, что это было до того, как перекодировалось?" К сожалению, большинство современных Операционных Систем работает именно в ней.

Вот пример обычных сложностей. В 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #70, АБЗАЦ #86102.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10 показано, как перекодировать в UTF-8 из WIN-1251:

R += ("*********\t**********************"+
" !\"#$%&'()*+,-./0123456789:;<=>?"+
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "+
"****************************************************************"+
"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя")[K];

Но хитрость-то в том, что сама эта строчка должна быть в UTF-8. Это не честный массив! Разные его элементы имеют разный размер. Эта программа должна быть набита в редакторе, сохраняющим текст в UTF-8! А как это определить "на глаз"?!

В условия, когда весь обмен идет в UTF-8 ориентированной системе "просто получить массив байт" уже является проблемой. В том же коде:

D = [X.response]; // Поток ввода
D[0] = new DataView(D[0]);
...
K = D[0].getUint8(...);

Т.е. JavaScript для этого понадобился специальный объект-"контейнер".

Выше  - в 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10АБЗАЦ #105402.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10 - промежуточный UTF-8 (ключ //U) используется для того, чтобы объединенные в цепочку скрипты не путались с кодировками.

SET OP=CSCRIPT //U //Nologo
%OP% S_.JS %CUR1% | %OP% I_.JS %CUR2% | %OP% _OR.JS %CUR2%

Т.о. UTF-8, ввиду его "естественности" для Операционной Системы удобно применять для общения процессов. Тем более, что для символов диапазона 0-127 UTF-8 не отличим ни от DOS-, ни от WIN-кодировок.  
***

ЭКЗОТИЧЕСКИЕ КОДИРОВКИ. Например, поминавшийся выше Волапюк для пропихивания спецсимволов в честно-символьный канал. В том же 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #70, АБЗАЦ #86102.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10 - base64 для создания HTML-ных картинок "на лету".
***

Тут, очевидно, будет продолжение...


Последний раз редактировалось: Gudleifr (Чт Июн 29, 2023 3:32 pm), всего редактировалось 3 раз(а)
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Ср Июл 10, 2019 5:43 pm

ПОПУТНЫЕ ОГРЫЗКИ

Если научить программу работать с текстом кажется сложным (и, тем более, страшно потерять информацию, правя текст "по живому"), можно вынести текст "за скобки". Просто перенумеровать текстовые блоки и оперировать в программе только их номерами.

Этот прием часто использовался в старых настольных и компьютерных играх, вся "литературная составляющая" выносилась в отдельные книги. А в игре "обсчитывались" только номера параграфов.

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Wl8410

Игра Wasteland (1988) просит игрока прочесть параграф #84.

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Wl84t10

Более того, этот прием очень удобен для работы в стиле старых СУБД (систем управления базами данных).

И, наконец, он используется даже в настоящей литературе (как иначе организовать Указатель имен?).

Т.о. на первых порах описанный в прошлой главе "вырезатель" может просто возвращать список номеров подходящих параграфов.
Всяко, по мере структуризации текста информационный "центр тяжести" будет постепенно перемещаться с художественного повествования на индексные таблицы.

Работа с индексами сократит потребность в копировании и дублирования текста.

О том, насколько подобные решения оправданы, я уже пытался размышлять 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10ТЕМА #20, АБЗАЦ #10702.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10.
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Ср Июл 10, 2019 10:10 pm

...

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

Ведь каких только форм тех же списков не бывает. И вложенные, и сквозные, и помеченные... А кроме списков есть еще таблицы, заголовки, сноски... Не даром в старых пособиях по текстовым редакторам рекомендовалось перед началом набора любого текста сначала тщательно продумать необходимые для его представления "стили".

А картинки? Как ни придумывай наиболее универсальный стиль, все будет зависеть от конкретного единичного экземпляра физического представления. (Куда теперь эти Gif-ы 320*200, которых хватало в те времена, когда я создавал свою страничку?)

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

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

Однако, повсеместно предпринимаются меры по поиску универсального решения "строго посредине шкалы". Форматтеры и верстальные машины, редакторы офисных документов, конструкторы книг-игр... Даже, например, тот же HTML... Или упомянутый выше CWEB... И результат всегда один - появление сверхсложных стандартов и языков, которые "позволяют все". Но, если мы и так начинаем с необходимости решить "откуда начинать копать", как нам поможет сверхистема позволяющая "копать" с любого места? Зачем мне помощник в форматировании, спрашивающий у меня, как форматировать?

Я предлагаю делать проще: раз цель нашей игры - постепенное "превращение текста в программу", удобство описания конкретного функционала первично. А на единообразие - плюнуть. Проще иметь отдельные красивые и логичные огрызки, чем прокрустово ложе для приведения их в единообразный вид. Плата за это - требование наличия семантических описаний в узловых местах документа (позволяющих понять, о чем идет речь и где что лежит).
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

02.02. МАЛЕВИЧ, ГОВОРИТЕ? Empty Re: 02.02. МАЛЕВИЧ, ГОВОРИТЕ?

Сообщение автор Gudleifr Вс Сен 15, 2019 11:58 am

Нашел книжку: Альберт Сысоев, Программное обеспечение для писателей и творческих людей, 2018 02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10PDF, 10.2Мб02.02. МАЛЕВИЧ, ГОВОРИТЕ? Leaf10

02.02. МАЛЕВИЧ, ГОВОРИТЕ? 2018wr10

Там описана тройка программ, позволяющих структурированно разрабатывать книги. В отличие от моих избыточно универсальных структур там все заранее разложено по полочкам: сюжеты - сюда, персонажи - туда...
Gudleifr
Gudleifr
Admin

Сообщения : 3220
Дата регистрации : 2017-03-29

Вернуться к началу Перейти вниз

Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения