Старый Жук

                и л и


           П Р О Г Р А М М И Р О В А Н И Е

          Д О С Т У П Н О Е    К А Ж Д О М У




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





                Посвящается Фреду

                и

                Светлой памяти Юрика Горбунова






                *  *  *
                Профессионалам –
                зарплаты навалом,
                Хотя они с башен
                На граждан -
                плюют.
                А наши ребяты
                Воще без зарплаты
                Под «Маде ин рашен» -
                Такое (!) куют.

                По мотивам В.Высоцкого




                0.

Почему я решил написать данную статью? Я обнаружил, что рядовые современные пользователи лишены простых прелестей программирования. Они считают, что это занятие для заморочек. Почему? – У них нет под рукой доступного средства, чтобы хотя бы попробовать программирование «на вкус». Тогда бы они сразу убедились, какое это увлекательное занятие. Лучше, чем любые компьютерные игры, карты, нарды, шахматы и т.д., которые придуманы и реализованы не ими. А стоит дать им такое средство, и многие бы погрузились в него с головой. Ведь программирование – это чистое творчество.

Сначала я думал, что мобильные телефоны, которые умеют выполнять апплеты на языке Ява, будут включать в себя какой-нибудь язык программирования типа Бейсика. Но оказалось, что даже путёвого калькулятора на мобильниках не сыскать. У них нет сопроцессора. А значит, все вычисления надо проводить через целочисленную арифметику. А это увеличивает затраты на написание и размер кодов, которые в итоге  сожрут память и увеличат цену. И тогда (о ужас!) телефонная книжка будет не на 1000 номеров, а всего на 10… ;-) А стоить он будет дороже… И такой мобильник в магазине ни кто не купит. Потому что продавец магазина не в состоянии объяснить покупателю, что «такого» находится в этой коробочке. Он скажет вам заученную фразу, которой его научили: тут встроенный язык программирования. И что? Вы купите такой? Ведь вы же считаете, что это занятие для избранных! Вот то-то и оно…

Из стандартного комплекта Microsoft тоже исчез язык программирования (с пятой версии MS-DOS он был –  «QBasic», а теперь исчез).

Можно приобрести специальное устройство российского производства – последователя линейки программируемых калькуляторов, серия которых именовалась с момента создания «Микро Калькуляторами». НПП «Семико» живёт и процветает в Новосибирске, есть свой сайт ( http://www.semico.ru ). Они делали сначала настольный вариант такой универсальной машинки (МК-152), а теперь уже выпускают и карманный вариант (МК-161). В апреле 2009 года, когда я смотрел их цены, МК-152 стоил 3800 руб., а МК-161 – 4700 руб. И документация вся на родном, и никаких ссылок на посторонние источники. Бери и программируй! Уже ж/к дисплейчик с подсветкой вместо цифрового индикатора. Разработчики даже уверяют, что можно на нём писать и гонять свои собственные простенькие игры. Есть внешние сменные электронные диски (диск электронный  «УЗВМК-1» 280 руб.) для сохранения программок. Внутри работает своя операционка. Есть файловая система. Но чтобы захотеть – надо же попробовать… А иначе как?

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

Приведу выдержку из окна «О программе», чтобы вы её смогли отыскать в Интернете.
<<
Название Калькуляторы 3000
Описание Симулятор калькуляторов
Версия   5.1
Дата     13.05.2004

Автор    Евгений Троицкий
Веб сайт http://www.emulator3000.it/
>>

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


Можно откапать в Интернете простой Бейсик для ДОС (Turbo Basic v 1.0 , который умеет создавать EXE-файлы, или тот же QBasic , работающий только с исходными текстами программ) и, при сильном желании, документацию к ним. Но как показывает практика тот, кто способен на такие геройские поступки, тот не случайно приобщается к программированию. А таких людей в общей массе – единицы. Не многие захотят тратить время на изучение устаревших оболочек или экзотической техники.

Нет. Рядовому человеку нужно знать, что на его компьютере уже всё необходимое для программирования есть. И ничего качать, искать, подгонять не нужно. А изучать, он согласен лишь то, что имеет для него конкретную ценность.

И тут я вспомнил про «Старого Жука» – отладчика, который входит во все комплекты виденных мною ДОС и Виндоус. И, пожалуй, он единственный, кто остался среди претендентов на универсальный программируемый «калькулятор» для любого пользователя, кто сидит под любым Виндом или просто загрузил старую MS-DOS c внешнего загрузочного диска.

В данном случае DEBUG.EXE выгодно отличается от любого другого средства, ведь изучать придётся ни что-нибудь, а свой личный Центральный Процессор – практически, «мотор» собственного компьютера! И изучать не ради изучения, а чтобы приспособить его к своим нуждам. Представьте, если бы вы двигатель от личного автомобиля смогли «запрячь» в свои домашние дела? При этом, ни коим образом не меняя конструкцию авто, и не влияя на ходовые качества своего автомобиля! Он как работал, так и работает, но при этом ещё и «пашет» в домашнем хозяйстве. Как вам такая перспектива? А?

Вот тогда любого можно подвигнуть в часы досуга на эксперименты с собственными маленькими программулями, чтобы прочувствовал, какая это прелесть – написание собственных кодов, решение своих личных задачек самостоятельно. И не думал более, что программы пишут одни гиганты типа «Microsoft», «IBM» да «Intel».

Учитывая всеобщее распространение DEBUG.EXE и то, что результат программирования в нём легко можно представить: и в виде текста программы, и в виде кодов, и переслать любому как для изучения, так и для исполнения – можно смело утверждать, что он – тот «ключик», который позволит открыть «дверцу» в страну программирования для любого.

Не хватает только инструктора, подробного описания, которое помогло бы ввести неподготовленного человека в курс дела и помочь начать ваять своё самостоятельно.

Например, известная всем «Википедия» даёт очень скудное описание DEBUG ( http://ru.wikipedia.org/wiki/Debug ). Но в других источниках нет и этого! Она хотя бы понимает значимость этой небольшой, но очень полезной программы.

Позволю себе процитировать первый абзац оттуда:

<<
Назначение

Данная программа является консольным приложением и предназначена для создания или изменения кода файлов. С помощью неё можно создавать простые приложение под MS-DOS и отслеживать их работу. Данный отладчик находится на самом низком уровне компиляторов assembler. Но обладает неплохими возможностями, такими как просмотр, изменение памяти и получение состояния регистров.
>>

Но о том, что DEBUG может быть употреблён для повседневного домашнего программирования, чтобы что-то написать своё – предметно речи не идёт. Видимо, такого опыта у писавших эти слова людей нет.

Вот поэтому я и взялся за эту статью.



                I.

Я посвящаю эти строки Фреду Александровичу.

Фред – это его не настоящее имя. Так его звали в FIDO, и как-то само собой получилось, что все окружающие тоже стали так его звать – «Фред». Я к его «позывному» добавлял отчество, поскольку он был много старше меня. В те годы я был молод, и хотя дружбы между нами не случилось, но я навсегда сохранил поразительное впечатление от его «мастеровитости» – другого слова подобрать трудно.

В то время я «отчалил» из института, где научился программировать на ассемблере для машины PDP-11, знал Фортран, Бейсик и на новом месте взялся за изучение Си и новой серии процессоров линейки i-х86, которые стояли в только что пришедших в СССР компьютерах «IBM-совместимых». Их в народе звали «писюками». Начиналась эра персональных компьютеров.

Фред программировал практически голыми руками. Все программы писал сам. А начинал их писать в машинных кодах на пустом месте. Ещё не было файловых менеджеров, ещё не был написан QBasic, ещё ранние версии дебагера не умели писать и читать в файл, а работали только с секторами дискеты (сторона, дорожка, номер сектора), не было винчестеров, не было ещё дисководов для трёхдюймовых дискет… У него была самая примитивная операционка (одна из первых версий ДОС) и собственноручно сделанная документация о командах процессора, его регистрах, способах адресации. Сделав дубль с загрузочной дискеты и дизассемблировав загрузочную запись, он получил доступ к запуску своих программ. Писал их в нулевую дорожку и всё. Они запускались вместо ДОС. И от этой точки стал отталкиваться. Он не знал ни COM, ни EXE форматов. Ему было интересно программировать, а тратить время на поиски (тогда очень дефицитной информации по всем внутренним функциям ДОС) – он считал пустой тратой времени.

У него не было даже сборщика модулей – линковщика, он собирал свою программу вручную. Проектировал на бумажке.

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

С тех пор я трепетно отношусь к проникновению в суть вещей.



                II.

Каждый может программировать – это мой тезис. Я бы даже рискнул заменить в нём слово «может» на слово «должен», но боюсь принять позу статуи (кто я такой, чтобы навязывать вам свои представления?)

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

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

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

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



Здесь я позволю себе сделать допущение, что вы работаете под каким-нибудь Windows или MS-DOS. Даже если это не так, то не забывайте, что MS-DOS вы можете получить либо, создав загрузочную дискету с любого компьютера, либо отыскав один из многочисленных мультизагрузочных лазерных дисков, умеющих стартовать в различных режимах.

Я, например, сконфигурировал свой вариант MS-DOS уже несколько лет назад (сначала на системную дискету). «Притёр» все драйвера, нужные программы, проверил, отладил, а потом создал свой лазерный загрузочный диск, который умеет работать вообще без жестких дисков (просто не нуждается в них). Создаёт в памяти четыре «электронных диска» по 32Мб каждый, и даже переносит систему на один из них, освобождая лоток привода – чтобы можно было свободно читать любые другие диски.

Правда, я держу небольшой раздел FAT32 на винчестере, остальную (большую) часть которого занимает NTFS и XP Windows, но в любой момент я могу загрузить свой вариант MS-DOS и покопаться от души в кодах, не прикасаясь к содержимому современных мастодонтов. Но ни что не мешает Вам работать в командной строке и под их неусыпным бдением. Тем более что у вас появляется возможность одновременно держать открытыми и рабочее окошко командной строки, и текстовый редактор, и справку, и калькулятор – всё под рукой.

Если же вы работаете под Linux, и не хотите ничего менять, то я отсылаю вас к Дональду Кнуту, к его добротной статье: «Ассемблер в Linux для программистов Си». Автор Donald Knuth (Дональд Кнут). Он рассказывает о написании программ на языке вашего «мотора» – Центрального Процессора серии i-x86. В конце статьи описан ваш отладчик GDB (аналог DEBUG).

Но опять же, Автор даже не предполагает, что вы будете писать свои программки изнутри отладчика! Он сосредотачивается на «серьёзном трансляторе» с языка assembler. А весь материал статьи «заточен» якобы под программиста «Си», хотя в начале Дональд Кнут и говорит, что единственные умения, необходимые пользователю для применения, написанного им: уметь создать текстовый файл и запустить программу из консоли (то есть – суметь вызвать командную строку).

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

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

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

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

А так ли много этих «специфических понятий» в архитектуре Центрального Процессора? Не большее ли количество «особенностей» наплодили уважаемые разработчики разных языков?

Позволю себе процитировать первые абзацы статьи Дональда Кнута, и призываю всех задуматься над моими предыдущими словами:


«
Эта книга ориентирована на программистов, которые уже знают Си на достаточном уровне. Почему так? Вряд ли, зная только несколько интерпретируемых языков вроде Perl или Python, кто-то захочет сразу изучать ассемблер. Используя Си и ассемблер вместе, применяя каждый язык для определённых целей, можно добиться очень хороших результатов. К тому же программисты Си уже имеют некоторые знания об архитектуре процессора, особенностях машинных вычислений, способе организации памяти и других вещах, которые новичку в программировании понять не так просто. Поэтому изучать ассемблер после Си несомненно легче, чем после других языков высокого уровня. В Си есть понятие «указатель», программист должен сам управлять выделением памяти в куче, и так далее — все эти знания пригодятся при изучении ассемблера, они помогут получить более целостную картину об архитектуре, а также иметь более полное представление о том, как выполняются их программы на Си. Но эти знания требуют углубления и структурирования.

Хочу подчеркнуть, что для чтения этой книги никаких знаний о Linux не требуется (кроме, разумеется, знаний о том, «как создать текстовый файл» и «как запустить программу в консоли»). Да и вообще, единственное, в чём выражается ориентированность на Linux, — это используемые синтаксис ассемблера и w:ABI.

Программисты на ассемблере в DOS и Windows используют синтаксис Intel, но в системах *nix принято использовать синтаксис AT&T. Именно синтаксисом AT&T написаны ассемблерные части ядра Linux, в синтаксисе AT&T компилятор GCC выводит ассемблерные листинги и так далее.

Большую часть информации из этой книги можно использовать для программирования не только в *nix, но и в Windows, нужно только уточнить некоторые системно-зависимые особенности (например, ABI).
»

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

Я считаю иначе. Дайте пользователю исчерпывающую информацию. Покажите на простых и наглядных примерах, как можно программировать. Расскажите о программе, которая УЖЕ ИЗНАЧАЛЬНО СТОИТ под его «капотом». – И без сомнения, даже если он никогда ранее не занимался программированием и умеет только, как вы сами только что сказали «создать текстовый файл» и «запустить командную строку», вы подвигните очень многих начинающих на постижение основ программирования на ассемблере (машинном языке вашего Центрального Процессора).

Попробуем? Проверим?

Давайте! Смелость – города берёт.



Теперь, прежде чем перейти непосредственно к DEBUG, несколько слов о том окошке, в котором мы будем работать. О командной строке.


Идём:
Пуск – Выполнить – cmd – OK.

(Если вы работаете под стареньким Виндоусом, то вместо cmd вам нужно запускать command, а если вы в ДОС-е, то командная строка она всегда с вами, т.е. вы уже работаете под управлением командного интерпретатора).

Открывается чёрное, как уголь окошко, с «серебряными» буквами; в заголовке окна мы видим C:\WINDOWS\System32\cmd.exe – это имя запущенной программы, а в окошке появляется надпись (у меня такая):

Microsoft Windows XP [Версия 5.1.2600]
(C) Корпорация Майкрософт, 1985-2001.

C:\Documents and Settings\Work1>_


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

Перед вами командный интерпретатор строк CMD.EXE . Прошу любить и жаловать!

(Для тех, кто не желает пояснений о нём, а хочет сразу перейти к «Старому Жуку», тому надо смотреть часть третью. Хотя, желательно читать последовательно, чтобы вы понимали: где вы находитесь, в какой папке создаются файлы и с какими именами. Как содержимое этой папки проконтролировать и удалить ненужное, которое вы насоздавали в качестве экспериментов.)
 
Вы думаете, что чёрное окошко – признак устаревшего и отжившего своё? Как бы ни так! Настоящему профи смешно смотреть на обилие красивых прямоугольничков (форм) с одной единственной кнопкой, выпадающих то и дело перед неопытным юзером, пытающихся привлечь его внимание и вечно требующих от него участия для единственного нажатия мышью на кнопке с мистическим «OK». Если бы этот юзер знал, сколько накладных расходов связано с этим! И потом, вы разве не чувствуете, что это не вы командуете компьютером, а он вами? Это же он своим навязчивым участием делает коротенькими ваши мысли, давит их своим броским интерфейсом. Это он требует вашего постоянного присутствия и нажатия мышью всех этих «OK». У него своих ручек-ножек нет, вот он и пользуется вашими! А думать пытается за вас, тупо изображая из себя продвинутого и компетентного…

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

Если бы у вас были программы, которым вы как Командир выдавали задание, а они уже сами за вас сидели за компьютером и работали, то вы сберегли бы уйму своего времени! Не согласны?


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

На чём построена вся Кибернетика? – На понятии «Чёрный ящик». (Это не то, о чём вы подумали.) В простейшим изложении программиста «чёрный ящик» – это программа. Вы посылаете ей входной сигнал, она выдаёт ответный.

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

Если же вы встречаете незнакомый «чёрный ящик», то он должен сам рассказать о своём назначении и тех параметрах командной строки, которые ему требуется подать на вход, чтобы он выполнил свою задачу.

Поэтому, когда дорастёте до создания своих «чёрных ящиков», которые будете писать не только для себя, а станете ими делиться с окружающими, запомните, что правилом хорошего тона предусмотрено: на вход даёшь HELP, и программа сама о себе всё необходимое сообщает. Вместо HELP возможны варианты: «/?», «?», и вообще «ничего», т.е. программа по умолчанию выдаёт справочное сообщение.


Демонстрирую.

Набираем в чёрном окошке HELP и давим клавишу <Enter>. Получаем вот такое сообщение от нашего «чёрного ящика» CMD.EXE – интерпретатора командных строк:

<<

Для получения сведений об определенной команде наберите HELP <имя команды>

ASSOC – Вывод либо изменение сопоставлений по расширениям имен файлов.
AT – Выполнение команд и запуск программ по расписанию.
ATTRIB – Отображение и изменение атрибутов файлов.
BREAK – Включение/выключение режима обработки комбинации клавиш CTRL+C.
CACLS – Отображение/редактирование списков управления доступом (ACL) к файлам.
CALL – Вызов одного пакетного файла из другого.
CD – Вывод имени либо смена текущей папки.
CHCP – Вывод либо установка активной кодовой страницы.
CHDIR – Вывод имени либо смена текущей папки.
CHKDSK – Проверка диска и вывод статистики.
CHKNTFS – Отображение или изменение выполнения проверки диска во время загрузки.
CLS – Очистка экрана.
CMD – Запуск еще одного интерпретатора командных строк Windows.
COLOR – Установка цвета текста и фона, используемых по умолчанию.
COMP – Сравнение содержимого двух файлов или двух наборов файлов.
COMPACT – Отображение/изменение сжатия файлов в разделах NTFS.
CONVERT – Преобразование дисковых томов FAT в NTFS. Нельзя выполнить преобразование текущего активного диска.
COPY – Копирование одного или нескольких файлов в другое место.
DATE – Вывод либо установка текущей даты.
DEL – Удаление одного или нескольких файлов.
DIR – Вывод списка файлов и подпапок из указанной папки.
DISKCOMP – Сравнение содержимого двух гибких дисков.
DISKCOPY – Копирование содержимого одного гибкого диска на другой.
DOSKEY – Редактирование и повторный вызов командных строк; создание макросов.
ECHO – Вывод сообщений и переключение режима отображения команд на экране.
ENDLOCAL – Конец локальных изменений среды для пакетного файла.
ERASE – Удаление одного или нескольких файлов.
EXIT – Завершение работы программы CMD.EXE (интерпретатора командных строк).
FC – Сравнение двух файлов или двух наборов файлов и вывод различий между ними.
FIND – Поиск текстовой строки в одном или нескольких файлах.
FINDSTR – Поиск строк в файлах.
FOR – Запуск указанной команды для каждого из файлов в наборе.
FORMAT – Форматирование диска для работы с Windows.
FTYPE – Вывод либо изменение типов файлов, используемых при сопоставлении по расширениям имен файлов.
GOTO – Передача управления в отмеченную строку пакетного файла.
GRAFTABL – Позволяет Windows отображать расширенный набор символов в графическом режиме.
HELP – Выводит справочную информацию о командах Windows.
IF – Оператор условного выполнения команд в пакетном файле.
LABEL – Создание, изменение и удаление меток тома для дисков.
MD – Создание папки.
MKDIR – Создание папки.
MODE – Конфигурирование системных устройств.
MORE – Последовательный вывод данных по частям размером в один экран.
MOVE – Перемещение одного или нескольких файлов из одной папки в другую.
PATH – Вывод либо установка пути поиска исполняемых файлов.
PAUSE – Приостановка выполнения пакетного файла и вывод сообщения.
POPD – Восстановление предыдущего значения текущей активной папки, сохраненного с помощью команды PUSHD.
PRINT – Вывод на печать содержимого текстовых файлов.
PROMPT – Изменение приглашения в командной строке Windows.
PUSHD – Сохранение значения текущей активной папки и переход к другой папке.
RD – Удаление папки.
RECOVER – Восстановление читаемой информации с плохого или поврежденного диска.
REM – Помещение комментариев в пакетные файлы и файл CONFIG.SYS.
REN – Переименование файлов и папок.
RENAME – Переименование файлов и папок.
REPLACE – Замещение файлов.
RMDIR – Удаление папки.
SET – Вывод, установка и удаление переменных среды Windows.
SETLOCAL – Начало локальных изменений среды для пакетного файла.
SHIFT – Изменение содержимого (сдвиг) подставляемых параметров для пакетного файла.
SORT – Сортировка ввода.
START – Запуск программы или команды в отдельном окне.
SUBST – Сопоставляет заданному пути имя диска.
TIME – Вывод и установка системного времени.
TITLE – Назначение заголовка окна для текущего сеанса интерпретатора командных строк CMD.EXE.
TREE – Графическое отображение структуры папок заданного диска или заданной папки.
TYPE – Вывод на экран содержимого текстовых файлов.
VER – Вывод сведений о версии Windows.
VERIFY – Установка режима проверки правильности записи файлов на диск.
VOL – Вывод метки и серийного номера тома для диска.
XCOPY – Копирование файлов и дерева папок.

>>

Видите, сколько команд вы можете использовать! Ну, например, чтобы очистить экран внутри чёрного окошка, воспользуйтесь командой CLS.

Вводим CLS и жмём <Enter>.

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

Аналогично предыдущему:

DIR и жмём <Enter>.


У меня выходит следующая информация:



Том в устройстве C имеет метку 1
 Серийный номер тома: F456-7852

 Содержимое папки C:\Documents and Settings\Work1

30.04.2011  19:30    <DIR>          .
30.04.2011  19:30    <DIR>          ..
17.01.2011  16:33             1 793 1.txt
04.02.2011  23:48               457 2.txt
05.02.2011  07:00               193 3.txt
05.02.2011  07:06               352 4.txt
23.02.2011  15:41             1 816 5.txt
01.03.2011  00:28             1 816 6.txt
04.03.2011  15:11             5 633 7.txt
04.03.2011  16:48             9 083 8.txt
18.11.2010  05:09                88 default.xml
08.02.2006  17:49               256 DOS-WIN.KEY
04.02.2011  23:49                96 PR1.TXT
21.02.2011  18:32             5 987 PR2.TXT
24.02.2011  09:57             5 600 Proverk1.txt
24.02.2011  10:00            14 836 proverk2.txt
24.02.2011  09:56             5 600 Proverka.txt
31.01.2011  23:55               256 SHIFR01.BIN
09.07.2008  20:19            55 420 STORM5.EXE
21.02.2011  18:33             1 824 TEXT0000.TXT
08.01.2008  21:35    <DIR>          Главное меню
28.05.2009  11:53    <DIR>          Избранное
05.05.2011  15:16    <DIR>          Мои документы
13.03.2011  07:46               573 Работай.txt
02.05.2011  09:38    <DIR>          Рабочий стол
13.03.2011  05:22             1 575 цср.txt
              20 файлов        113 254 байт
               6 папок  11 118 329 856 байт свободно

C:\Documents and Settings\Work1_



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


Только не поймите меня превратно – я не призываю вас отказаться от графического интерфейса и вернуться к командной строке. Нет. Но командные строки могут быть записаны в так называемый «пакетный файл», ещё именуемый «командный» файл. И тогда вы уже не будете набирать каждую команду вручную на клавиатуре, а можете запускать на выполнение сразу «пакет»! Более того, внутри этого пакета могут быть МЕТКИ, ПЕРЕХОДЫ, логические ВЕТВЛЕНИЯ, проверки существования или отсутствия необходимых для работы ФАЙЛОВ. К тому же пакет сам может принимать на вход входные параметры из командной строки от вас, и может совершать вызовы, как других программ Виндоуса, написанных для оконного интерфейса, и «чёрных ящиков», созданных по принципу командной строки, так и вызовы других командных файлов!

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

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


Приведу ссылку на полезный ресурс в Интернете, где вы можете почитать подробности о языке командных файлов. Захотите – закажите себе книжку. Нет – просто будете листать странички на сайте.

<<
3. Лекция: Язык интерпретатора Cmd.exe. Командные файлы
http://www.intuit.ru/department/os/compromtwin/3/

Описываются возможности языка командных файлов: работа с переменными и параметрами командной строки, реализация циклов, условных операторов и операторов перехода. Даются примеры обработки текстовых файлов с помощью командных файлов.
>>

Пока же полезно запомнить, что делают такие команды:

CLS – очистка экрана
MORE – Последовательный вывод данных по частям размером в один экран



Для тех, кто желает научиться переходить в командной строке по дереву папок и дисков, советую посмотреть команды:

DIR – показать содержимое папки
CD – сменить папку
MD – создать папку
RD – удалить папку



Для операций с файлами:

COPY – копировать файлы
FC – сравнить файлы
FIND – поиск текстовой строки в одном или нескольких файлах
FINDSTR – поиск строк в файлах
REN – переименование файлов и папок
MOVE – перемещение и переименование папок и файлов
ATTRIB – Отображение и изменение атрибутов файлов
TYPE – вывод на экран содержимого текстовых файлов
SORT – сортировка ввода
DEL – удаление одного или нескольких файлов
XCOPY – копирование файлов и структур каталогов



Для операций с системными датой и временем:

DATE – вывод либо установка текущей даты
TIME – вывод и установка системного времени



Для операций с дисками:

VOL – вывод метки и серийного номера тома для диска
LABEL – создание, изменение и удаление меток тома для дисков
DISKCOMP – сравнение содержимого двух гибких дисков
DISKCOPY – копирование содержимого одного гибкого диска на другой
VERIFY – установка режима проверки правильности записи файлов на диск
FORMAT – форматирование диска для работы с Windows
SUBST – сопоставляет заданному пути имя диска


По любой из этих команд вы можете получить справку от CMD при помощи команды HELP.



И, наконец, чтобы завершить работу командного интерпретатора:

EXIT – Завершение работы программы CMD.EXE (интерпретатора командных строк)

Впрочем, крестик в верхнем правом углу работает аналогично команде EXIT. Но она может вам понадобиться при выходе из вложенных друг в друга копий CMD.EXE внутри пакетных файлов.


Советую посмотреть описание и других команд, тем более что вы можете копировать содержимое их вывода с экрана, как вручную:

(
Для этого нажмите <Alt>+<пробел> или ткните мышью значок в верхнем левом углу окошка. Появится системное меню окна. В нём идите так:

Изменить – Пометить

После этого в окне появится мигающий курсор. Вы можете перемещать его при помощи мыши (тыкая ей в нужное место) или стрелок на клавиатуре. А, удерживая клавишу <Shift> нажатой, выделять нужный прямоугольный фрагмент текста в окне. По нажатию <Enter> – выделенный фрагмент попадает во внутренний буфер, который потом легко вставить, например, в Блокнот или обратно в командную строку.
)

– так и автоматически:

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

HELP FOR>FOR.TXT
)


Кстати, допускается употребление двойного знака угловой скобки >> . Разница лишь в одном: одиночный знак > каждый раз создаёт выходной файл заново, а двойной знак >> дописывает содержимое потока в конец указанного файла. И таким образом можно составить всю инструкцию по всем командам CMD.EXE, если последовательно выполнять команды:


HELP ASSOC > HELP-CMD.TXT
HELP AT >> HELP-CMD.TXT
HELP ATTRIB >> HELP-CMD.TXT
HELP BREAK >> HELP-CMD.TXT
. . .
HELP TYPE >> HELP-CMD.TXT
HELP VER >> HELP-CMD.TXT
HELP VERIFY >> HELP-CMD.TXT
HELP VOL >> HELP-CMD.TXT
HELP XCOPY >> HELP-CMD.TXT


Конечно, проще сначала написать текст всех выполняемых команд (хоть в Блокноте), а потом выдать в качестве задания на исполнение своему командному интерпретатору.

Кстати, ни что не мешает копировать строки прямо из текста и выдавать их через системное меню окошка внутрь, как команду. Хотя лучше сохранить в TXT-формате, только поменять тип файла на выходе на *.BAT или *.CMD . (Операционная система по умолчанию считает все текстовые файлы с расширениями BAT и CMD – пакетными файлами).


Но вернёмся к справке по команде FOR. Теперь, прямо здесь можете проверить, появился ли такой файл в папке?

DIR FOR.TXT

А затем и вывести его содержимое на экран:

TYPE FOR.TXT

Так как файл справки по команде FOR целиком на экране не умещается, то вы либо станете прокручивать бегунок справа в окошке, либо дополните предыдущую команду командой поэкранного вывода MORE.

TYPE FOR.TXT | MORE

Не забывайте, однако, что созданный файл FOR.TXT – обычный текстовый файл, и вы можете его открыть, например, в Блокноте. Прямо тут, не выходя из чёрного окошка!

NOTEPAD FOR.TXT


Абра-кадабра? Это потому, что кодировка ДОС-овская. А попробуйте при помощи Интернет-проводника!

START IEXPLORE "C:\Documents and Settings\Work1\FOR.TXT"

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

После выполнения команды START… , описанной выше, откроется окно Интернет Проводника, а в нём будет справка по команде FOR. Это одна из сильнейших команд. Она позволяет организовывать внутри пакетных файлов групповую обработку по шаблону всех файлов, которые подходят под него.

Что такое шаблон? (Внимание: «шаблон» в документации может именоваться теперь «подстановочными знаками»). Это символы «*» (звёздочка) и «?» (знак вопроса). Звёздочка означает «любое количество любых символов», а знак вопроса «любой знак или даже его отсутствие».

(Мне бы очень хотелось, чтобы «?» означал «любой знак», но, к сожалению, вынужден говорить правду: «?» означает – «любой знак или даже его отсутствие»… Увы! Но об этом «увы» ниже.)


Например, чтобы посмотреть в текущей папке только текстовые файлы, нужно дать команду:

DIR *.TXT

А чтобы только те, которые начинаются на букву «A»:

DIR A*.TXT

А вот такая команда:

DIR ??1*.*

Выдаст список файлов, у которых в имени третий символ единица, при этом типы файлов любые.

DIR *1*.*

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


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


Но для вас будет проблемой следующая задача: «выдать список всех файлов, кроме тех, кто имеет одну букву в имени».

Я бы предпочёл, чтобы эту задачу можно было решить одним «движением плеча»:

DIR ??*.*

Предполагая, что раз в начале имени указаны два знака «?», то имя не может быть меньше «двух знаков»! Но! (Блин…) Майкрософт считает иначе…

И команда DIR ??*.* – эквивалентна команде DIR *.* (ещё раз блин!), означая любые имена и любые типы файлов, то есть – все вообще файлы в данной папке. Эх…


В справке по команде FOR описаны и расширенные возможности, которые позволяют брать не только полное имя файла: Диск – Путь – Имя – Расширение, но и часть имени, выделяя из него нужную составляющую, (чего так не хватало в прошлом!) – теперь это есть.

Расширение – это так называются три буквы, или теперь уже даже четыре или пять, которые стоят после имени и отделяются от него точкой. Они кстати, определяют для системы тип файла – как только вы переименуете файл (например, командой REN) с FOR.TXT на FOR.HTM, так система поменяет и значок у этого файла. Конечно, само содержимое файла от этого не изменится, но при щелчке мышью по нему будет стартовать уже другая программа, берущая его для открытия.



Я бы рекомендовал создать на диске папку первого уровня с коротким именем и переходить перед работой с командным интерпретатором туда (не очень приятно вечно таскать за собой эту лапшу «C:\Documents and Settings\»).

Причём, мы можем это сделать с вами прямо здесь и прямо сейчас в качестве первого простого упражнения. Создадим на диске папку первого уровня, ну, например, с именем «DEBUG». А в текущей папке напишем командный файл с очень коротким именем, например, «D.CMD», который будет нас перемещать автоматически в эту папку. Тогда после любого запуска командной строки, нам будет достаточно набрать D и нажать <Enter>, и мы автоматически будем переходить в нужное нам место.

Итак, приступим.

Дадим команду:
MD      C:\DEBUG        и жмём <Enter>

Эта команда (просмотрите выше список, если забыли) создаёт папку в корне диска C:\ с нужным нам именем. Если вы хотите другое имя, или другой диск – пожалуйста. Только бы у вас этот диск был.


Теперь посмотрим прямо здесь, появилась ли такая папка?

Дадим команду:
DIR     C:\D*.*        и жмём <Enter>

На экран будет выдан список всех папок и файлов с именами, начинающимися на букву «D». Если у вас много таких, то вы можете сделать список поменьше, повторив команду DIR, но уже указав перед звёздочкой не одну букву, а две «DE» (или больше).


Убедились, что папка уже есть.


Что внутри неё? Наверняка чисто, ведь мы её только-только создали. Посмотрим.

Даём команду:
DIR C:\DEBUG

Показывает содержимое и сообщает, что файлов 0 (ноль). Так и должно быть.


Теперь нам надо создать обычный текстовый файл с расширением, которое определяет пакетные файлы. Файл будет лежать не в новой папке C:\DEBUG , а в текущей. Ведь когда мы запускаем CMD.EXE – он стартует в той папке, в которой мы сейчас находимся. Поэтому и пакетный файл D.CMD нужно положить прямо здесь.

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

Для этого воспользуемся старым, как мир способом ввода с консоли, то есть я не буду прибегать к услугам никакого текстового редактора – сделаю всё «голыми руками».

Даём команду:
COPY    CON    D.CMD      и жмём <Enter>
_

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

Набираем первую строку:
@ECHO OFF        и жмём в конце <Enter>

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

Теперь набираем саму нашу команду перехода:
CD   C:\DEBUG          и снова жмём <Enter>

А теперь надо завершить ввод в файл и закрыть его, записав в папку. Это делается одновременным нажатием клавиш <Ctrl>+Z . <Ctrl> удерживаем, Z жмём. На экране появляется « ^Z », ещё раз жмём <Enter> и появляется сообщение, что «Скопировано файлов:  1.»

Теперь выполняем нашу новую команду:
D

И оказываемся в новой папке. Попробуйте закрыть CMD при помощи EXIT или крестика, а потом запустите его снова и воспользоваться услугами новой команды перехода в папку DEBUG.


Примечание:

Не забывайте закрывать ввод команд нажатием <Enter>. Именно после нажатия <Enter> команда берётся на исполнение. А пока вы её не закрыли, её ещё можно исправить: работают клавиши «стрелка вправо», «стрелка влево», «Delete», «Backspace», «Home», «End». То есть командную строку при наборе можно редактировать, как в простом текстовом редакторе из одной строки. Работают даже переходы от слова к слову при нажатии комбинаций «Ctrl+стрелка вправо», «Ctrl+стрелка влево». А в системном меню окна у вас есть возможности для выделения фрагмента, копирования и вставки.

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

Например, найдите в перечне выполненных команд ту, при помощи которой вы создавали в текущей папке файл справку по команде FOR. Выполните её снова. Теперь текстовый файл FOR.TXT лежит и в папке C:\DEBUG .



Для запуска стандартных файлов Виндоуса из командной строки в отдельном окне используйте команду START, а для запуска пакетных, внутренних или внешних команд (в том числе DEBUG) можно просто набрать нужное имя и нажать <Enter>.

Ещё несколько слов о команде START.

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

Например, если мы переименуем файл FOR.TXT в файл FOR.HTM при помощи команды «Rename» вот так:

REN  FOR.TXT   FOR.HTM


То тип файла (по расширению) изменится, а содержимое всё равно останется текстовым.

И теперь команда

START       FOR.HTM


Приведёт к запуску Интернет Проводника, а содержимое внутри него будет из файла FOR.HTM , но выглядеть оно будет безобразно – сплошная каша из неформатированных строк. Это и понятно, ведь содержимое файла FOR.HTM после его переименования осталось ТЕКСТОВЫМ. Смена имени не приводит к смене формата, а меняет лишь приписку к данному приложению. Закройте это безобразие.


Переименуем назад файл FOR.HTM вот так:

REN   FOR.HTM    FOR.TXT



А теперь снова откроем при помощи Интернет Проводника:

START IEXPLORE C:\DEBUG\FOR.TXT

И вы увидите прежний, хороший текст. Справка по команде FOR .


Подумайте, как можно по каждой команде CMD сделать справку в виде текстового файла и организовать выдачу этих справок не на чёрном экране, а через окно Интернет Проводника (благо, он автоматически распознаёт кодировку DOS).

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

Назвать новый пакетный файл можно HELP1.CMD .

Давайте напишем такой пакет справки. Пока для двух команд, например, «DIR» и «FOR». А потом вы сами расширите его по необходимости.

Сначала подготовим второй файл справки по команде «DIR».

Выполним команду:
HELP DIR > DIR.TXT

Проверим, что файл появился:
DIR /B

Обратите внимание, что в этот раз я предложил вам выполнить команду «DIR» вообще без указания имени файла, но зато добавил ключик «/B» . Что он означает? Он выдаёт короткий список файлов, без размера и указания числа файлов, метки диска и свободного пространства на нём. Такой укороченный формат вывода. А имя файла я опустил (это допускается), потому что в нашей папке их ещё мало, а по умолчанию (если имя не указано) выводятся все файлы, то есть работает шаблон ( *.* ). За подробными объяснениями всех возможностей команды DIR я отсылаю вас к её HELP-нику (вот этому самому DIR.TXT).

Итак, вы видите, что оба файла справки уже есть.

Теперь нам нужно создать файл с именем HELP1.CMD и записать в него такие команды:

@ECHO OFF
IF -% 1==-DIR START IEXPLORE C:\DEBUG\DIR.TXT
IF -% 1==-FOR START IEXPLORE C:\DEBUG\FOR.TXT


Обратите внимание, тут впервые появляется знак « % 1 ». Это первый параметр, который будет получать на вход наш командный файл. Всего таких параметров внутри пакета можно именовать десять штук (от % 0 – до % 9 ), но « % 0 » содержит имя самого выполняемого пакета (так командный файл всегда может узнать, как его зовут). И хотя в командной строке может уместиться больше 10 шт. параметров, но обратиться к следующим (например, 13 параметру) можно лишь при помощи команды SHIFT . Она сдвинет все параметры на один в сторону нулевого. При этом в параметре с именем % 9 уже окажется 10-тый. Таким образом, если вы уже не нуждаетесь в первых параметрах (например, вы их уже обработали или сохранили в переменных), то, повторив SHIFT три раза, вы получите доступ к 13-му параметру командной строки. В расширенных версиях языка командных файлов есть возможность указать номер после SHIFT, чтобы сдвиг произошёл в нужном месте. Подробности опять же смотрите через HELP.

Итак, как записать приведённые строки в новый файл HELP1.CMD ?

Если вы захотите менять содержимое текста, например, чтобы писать новый пакетный файл, то для этого пригодится и стандартный Блокнот Виндоуса, и встроенный редактор MS-DOS, который входит в комплект с давних времён, его зовут просто EDIT.COM .

Например, открыть тот же самый FOR.TXT можно из текстового редактора EDIT.COM вот так:

EDIT FOR.TXT


А можете вызывать EDIT без параметров, в качестве текстового редактора и писать в нём свои «заготовки». Меню на русском, справка тоже. Захотите распахнуть окошко на весь экран – жмите <Alt>+<Enter>. Ещё одно нажатие вернёт вас в оконный режим.

Обратите внимание, что EDIT – редактор многооконный! То есть в одном редакторе вы можете держать открытыми сразу несколько текстовых файлов. И при этом через меню «Правка» или при помощи «горячих клавиш» приведённых в подсказке переносить фрагменты текста из одного окна в другое.

Попробуйте поработать в этом редакторе. Оцените его. Возможно, он вам пригодится не однажды.

Я же воспользуюсь «дедовским способом» – сделаю всё снова «голыми руками». Набираю команду:

ECHO @ECHO OFF>HELP1.CMD

В результате команда « @ECHO OFF » записывается в файл HELP1.CMD в качестве первой строки.

Теперь дописываю следующие строки в конец фала HELP1.CMD , вот так:

ECHO IF -% 1==-DIR START IEXPLORE C:\DEBUG\DIR.TXT>>HELP1.CMD

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

ECHO >>HELP1.CMD

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

Вторую строку я получу, вызвав из стека предыдущую команду клавишей «стрелка вверх», и в ней отредактирую содержимое команды, подправив в двух местах (заменив везде DIR на FOR) и выполню её.

Вот так. Готово.


А теперь давайте посмотрим содержимое получившегося файла пакета.

TYPE HELP1.CMD

А потом попробуем HELP1 , как новый пакет работает?

HELP1 DIR

и

HELP1 FOR


На экране появляются два окна Интернет Проводника с раскрытыми в них справками по командам DIR и FOR .


Примечание:

Заметьте, что «DIR» и «FOR» при выполнении пакета нужно набирать большими буквами! Иначе команды не сработают. Почему? Потому что в строке команды IF сравнение происходит с символами набранными большими буквами. Если вы хотите, чтобы пакет обрабатывал и маленькие буквы, то надо повторить последние две строки, подправив в них «DIR» на «dir» и «FOR» на «for» . Строк будет в пакете уже пять штук.

Сделайте это сами. Воспользуйтесь стеком команд!


Теперь можете дополнить вашу справочную систему, например, справкой по команде «IF» !

Сделайте это. Вы это можете.


Но и это ещё не всё.


Вспомните, что я говорил вам о «Чёрных ящиках» вначале? Они должны рассказывать о своём назначении сами! Потому что пройдёт неделя, и вы уже не вспомните, зачем был создан ваш HELP1.CMD .

Давайте же допишем необходимые строки в пакет, чтобы он говорил, чего он хочет, и что он делает. И вообще сделаем его более защищённым от неожиданностей. Например, если файлы справки будут утеряны (случайно удалены из папки C:\DEBUG).

Нам нужно переписать пакет HELP1.CMD так:

@ECHO OFF
REM Проверка на отсутствие параметров
IF -% 1==- GOTO METKA1

REM Проверка на запрос помощи
IF -% 1==-HELP GOTO METKA1
IF -% 1==-help GOTO METKA1

REM Проверка на запрос справки по команде DIR
IF -% 1==-DIR GOTO METKA3
IF -% 1==-dir GOTO METKA3

REM Проверка на запрос справки по команде FOR
IF -% 1==-FOR GOTO METKA4
IF -% 1==-for GOTO METKA4

REM Проверка на запрос справки по команде IF
IF -% 1==-IF GOTO METKA5
IF -% 1==-if GOTO METKA5
EXIT /B

REM Блок вывода сообщения при запросе помощи по HELP
REM или при отсутствии входных параметров
:METKA1
IF NOT EXIST C:\DEBUG\HELP.TXT GOTO METKA2
IF EXIST C:\DEBUG\HELP.TXT START IEXPLORE C:\DEBUG\HELP.TXT
EXIT /B

:METKA2
ECHO "Для получения сведений об определенной команде наберите HELP1 <имя команды>"
ECHO.
ECHO DIR – Вывод списка файлов и подпапок из указанной папки.
ECHO FOR – Запуск указанной команды для каждого из файлов в наборе.
ECHO IF – Оператор условного выполнения команд в пакетном файле.
EXIT /B

REM Блок вывода справки по команде DIR
:METKA3
IF NOT EXIST C:\DEBUG\DIR.TXT HELP DIR
IF EXIST C:\DEBUG\DIR.TXT START IEXPLORE C:\DEBUG\DIR.TXT
EXIT /B

REM Блок вывода справки по команде FOR
:METKA4
IF NOT EXIST C:\DEBUG\FOR.TXT HELP FOR
IF EXIST C:\DEBUG\FOR.TXT START IEXPLORE C:\DEBUG\FOR.TXT
EXIT /B

REM Блок вывода справки по команде IF
:METKA5
IF NOT EXIST C:\DEBUG\IF.TXT HELP IF
IF EXIST C:\DEBUG\IF.TXT START IEXPLORE C:\DEBUG\IF.TXT
EXIT /B


Обратите внимание, что я заканчиваю блоки командой « EXIT /B », то есть завершаю пакет, но оставляю в работе окно командной строки. Если бы я написал просто EXIT без ключика /B , то и само окошко командной строки тоже закрылось. Только не путайте ключик « /B » команды EXIT с ключиком команды DIR – они ни как не связаны между собой.

Ещё в пакете появились метки. Метки всегда стоят отдельной строкой и начинаются с символа двоеточие «:» .

Обратите внимание на блок, начинающийся с метки « METKA1 ». Предполагается, что файл заготовленного сообщения на запрос HELP будет имёть имя HELP.TXT и располагаться в этой же папке вместе со всеми. Везде предусмотрена проверка на существование текстовых файлов справки. Если они существуют, то открываются при помощи Интернет Проводника в отдельном окне. А если они по какой-либо причине утрачены, то аналогичная справка выдаётся за счёт справочной службы CMD.EXE (т.е. по-прежнему в окне командной строки).

А при отсутствии файла справки HELP.TXT выдаётся последовательность строк, включённых внутрь самого пакетного файла. Чтобы снабдить наш пакет собственным окошком справки, надо создать файл HELP.TXT вот такого содержания:

<<
Для получения сведений об определенной команде наберите HELP1 <имя команды>

DIR – Вывод списка файлов и подпапок из указанной папки.
FOR – Запуск указанной команды для каждого из файлов в наборе.
IF – Оператор условного выполнения команд в пакетном файле.
>>

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


А вот в этом случае ситуация другая.

Ещё одна тонкость: в строке, следующей за меткой « METKA2 » текст сообщения, следующий за командой ECHO (эхо), заключён в парные кавычки. Если этого не сделать, то угловые скобки в строке будут восприняты командой ECHO как перенаправление потока, и пакет выдаст в этом месте ошибку.

Команда ECHO. (эхо с точкой) – выдает пустую строку. Точка прижата непосредственно к самой команде.



Теперь давайте подумаем, как написать такой пакет, который бы сам, при отсутствии нужного файла справки, создавал его в папке в виде текстового файла и открывал в Интернет Проводнике? И как только мы задумаемся над такой возможностью, так поймём, что хранить незачем все справки в виде файлов!  Все они могут генерироваться тут же в какой-нибудь промежуточный текстовый файл и отображаться Интернет Проводником. Имя файла будет одно, например, TEMP.TXT .

И тогда весь пакет (для всех справок вообще! , а не только для трёх, как сейчас) будет весьма и весьма прост и короток:


@ECHO OFF
HELP % 1>C:\DEBUG\TEMP.TXT
START IEXPLORE C:\DEBUG\TEMP.TXT


Вот так!

Проверяйте. Вы можете теперь читать все справки по командам CMD из Интернет Проводника. При этом вызывать их как в произвольном порядке, так и одну и ту же справку несколько раз.



И хотя всё отлично работает, но куда же вставить собственный HELP, который бы сообщал, для чего этот командный файл служит?

Можно сделать его в виде строк комментариев, которые будут первыми (до подавления эха на экране). И тогда при каждом запуске эти строки будут видны.

То есть можно добавить вначале строки:


REM Выдаёт справку по командам CMD.EXE через Интернет Проводник
REM Для получения справки о допустимых командах наберите HELP


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


А можно добавить проверку на специальный ключ (только уже не HELP, ведь HELP отсылается к CMD и работает там – и очень сильно и полезно работает!).


Ну, например, нарисуем так:

REM Свой HELP = help
@ECHO OFF
REM -----------------------------------------------------------
REM Выдаёт справку по командам CMD.EXE через Интернет Проводник
REM Для получения справки о допустимых командах наберите HELP
REM Для получения собственной справки нужно дать    help
REM -----------------------------------------------------------
IF -% 1==-help GOTO METKA
HELP % 1>C:\DEBUG\TEMP.TXT
START IEXPLORE C:\DEBUG\TEMP.TXT
EXIT /B

:METKA
ECHO.
ECHO -----------------------------------------------------------
ECHO Выдаёт справку по командам CMD.EXE через Интернет Проводник
ECHO Для получения справки о допустимых командах наберите HELP
ECHO -----------------------------------------------------------
ECHO.
EXIT /B


Строки комментариев вначале пакета поставлены для информации программисту, то есть когда вы задаётесь вопросом: а что это за пакет я тут «наваял»? Вы начинаете просматривать его и читаете эти первые строки REM. А для вас, как пользователя пакета, справка по нему выполнена отдельным блоком в командах ECHO. Не стоит пренебрегать этим кажущимся ненужным дублированием. Только нужно подумать, что стоит писать в одном случае (для себя, как программиста) и что в другом (для себя, как пользователя).

Последний « EXIT /B » можно было и не ставить, как только CMD упрётся в конец файла пакета, так его и завершит. Но я обычно ставлю по той причине, что при последующем редактировании таких командных файлов (а они могут быть весьма не малых размеров) отдельный блок может быть просто скопирован вниз, не нарушая всей логики. Ведь если в конец командника потом допишутся ещё какие-нибудь команды, то отсутствие выхода в предыдущем блоке может привести к ошибке – продолжению работы вниз, когда надо было завершиться. А поди через неделю, месяц – вспомни! что внизу стоял « EXIT /B » ?!


Итак, мы получили универсальный пакет.


Однако нам просто повезло (!), что Интернет Проводник: во-первых, не блокирует файл TEMP.TXT при его чтении (такое поведение для него единственно правильное, иначе при чтении файла коллективного доступа с какого-нибудь сервера этот ресурс окажется недоступен другим); а во-вторых, позволяет создавать копии своих окон в большом количестве (без чего тоже обойтись для него немыслимо).

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

Если мы изменим команду отображения файла справки, например, будем открывать её в редакторе EDIT, то такие «фокусы» ещё пройдут. Хотя EDIT – это уже редактор. Он берёт файл не только для чтения, а предполагает его менять и потом сохранять. Поэтому он должен заблокировать его, чтобы другие программы в этот момент его не трогали. Так? – Логично. Но он этого не делает. И число копий себя самого позволяет запускать много. Однако что будет, когда вы (случайно или нет) начнёте менять содержимое одного и того же файла, открытого в двух копиях редактора, и сразу в двух? Ну, для простого редактора EDIT и коротких файлов справки будет только одно – есть опасность запутаться и потерять или исказить содержимое открытого файла до неузнаваемости. А вот с большими файлами и другими программами нужно быть осторожнее.

Однако конкретно для EDIT есть выход. Например, у EDIT есть режим работы с открытием файла только для чтения! (Кстати, справка по командной строке редактора EDIT вызывается не командой HELP, а вот так « /? ». Это понятно, если бы вы написали EDIT HELP, то открыли редактор с новым файлом по имени HELP.)

Вызвав справку EDIT, вы как раз и прочтёте о ключике « /R », который позволяет открывать файлы «только чтобы почитать».

EDIT /R C:\DEBUG\TEMP.TXT


В связи с выше сказанным, приведу текст ещё одной версии командного файла, который написан из предположения, что открытый однажды файл блокируется программой. И его уже нельзя ни удалить, ни открыть заново, пока программа его не «отпустит», т.е. не завершит своё выполнение. Мало того, если система работает медленно (например, файл справки создаётся на файл-сервере), то может сложиться ситуация, когда само создание будет занимать определённое время. И то, что команда «HELP % 1>C:\DEBUG\TEMP.TXT» уже выдана, ещё не будет означать, что файл «C:\DEBUG\TEMP.TXT» уже существует для открытия! В таких «трудных» случаях приходится писать командники иначе, с дополнительными проверками, сообщениями и паузами.


Примечание:

Внимание, этот командник работать не будет, поскольку в блоке с меткой 4 в команде старт не прописано нормальное имя запускаемой программы. Он служит лишь как демонстрация. Но при этом ни что не мешает вам самим найти такую «трудную» программу и прописать её имя в указанное место. Тогда всё начнёт работать.

Ну, например, если у вас установлен Word, попробуйте поставить его имя WINWORD на место «трудная» под меткой 4. Я ставил. Сразу стало трудно. ;-) Зато система начинает демонстрировать «характер», а командник свои способности по её «укрощению».


@ECHO OFF
REM Проверяем наличие временного файла
IF EXIST C:\DEBUG\TEMP.TXT GOTO METKA1
GOTO METKA2

REM Пытаемся удалить его

:METKA1
DEL C:\DEBUG\TEMP.TXT
IF NOT EXIST C:\DEBUG\TEMP.TXT GOTO METKA2
ECHO.
ECHO C:\DEBUG\TEMP.TXT заблокирован и не может быть очищен,
ECHO возможно файл справки уже отображается в окне программы?
ECHO Пожалуйста, закройте это окно с текущей справкой
ECHO и нажмите для продолжения любую клавишу.
ECHO.
PAUSE>NUL
GOTO METKA1

REM Теперь создаём временный файл заново
:METKA2
HELP % 1>C:\DEBUG\TEMP.TXT
:METKA3
IF EXIST C:\DEBUG\TEMP.TXT GOTO METKA4
ECHO.
ECHO Системе не удалось создать справку C:\DEBUG\TEMP.TXT ,
ECHO возможно файл справки ещё находится в процессе записи.
ECHO Пожалуйста, попробуйте ещё раз через некоторое время,
ECHO для этого нажмите для продолжения любую клавишу.
ECHO.
PAUSE>NUL
GOTO METKA3

:METKA4
REM А теперь открываем его через «трудную» Программу
START «трудная» C:\DEBUG\TEMP.TXT

REM И завершаем пакет
EXIT /B



Обратите внимание, что между строками с меткой и возвратом на неё

:METKA1
. . . . .
GOTO METKA1

образован БЕСКОНЕЧНЫЙ цикл! Выход из этого цикла будет, когда старый файл будет удалён. Это послужит сигналом, что «путь свободен». А что будет, если он НИКОГДА не будет удалён? (ну, нет такой возможности по каким-то системным трудностям). Тогда вы можете оборвать выполнение командного файла специальной комбинацией клавиш <Ctrl>+C (она появилась задолго до ставшей привычной комбинации копирования), но по-прежнему успешно работает в пакетах.

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

При этом должен появиться запрос от CMD.EXE (он интересуется, может вы случайно нажали не ту кнопку?) :

Завершить выполнение пакетного файла [Y(да)/N(нет)]? _

И будет ждать вашего ответа. После выбора не забудьте нажать <Enter>. До его нажатия у вас ещё есть время передумать.



Ещё обратите внимание на строку

PAUSE>NUL

PAUSE – это команда, которая выдаёт на экран стандартное сообщение «Press any key to continue...» (Для продолжения нажмите любую клавишу...) и ждёт нажатия этой «любой» от оператора.

Сообщение этой команды можно «загасить» перенаправив потоком «в никуда», то есть в системе есть такое специальное имя « NUL », которое означает « НИКТО ». И этот господин «никто» может принимать потоки от любых программ!
 ;-)

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



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



Возможен ещё один вариант для «трудного режима работы», вообще простой-простой. А не будем удалять временный файл автоматически никогда! Только «ручками» по желанию. Каждая справка будет дописываться в конец файла. И таким образом после нескольких запросов нескольких справок они накопятся. И зададим нашему команднику специальную НОВУЮ команду, например, View, по которой этот результирующий файл отображался бы через «трудную программу». А чтобы избежать конфликтов между повторными вызовами, нужно создавать некоторый вспомогательный файл FLAG.TXT , наличие которого будет сообщать, что в данный момент справка занята, и никаких операций с ней производить не следует.

Вот такая реализация:

@ECHO OFF
REM Проверка на запрос собственного help
IF -% 1==-help GOTO METKA0

REM Проверка на команду View
IF -% 1==-View GOTO METKA1

REM Проверка на блокировку
IF EXIST C:\DEBUG\FLAG.TXT GOTO METKA0

REM Иначе можно копить
HELP % 1>>C:\DEBUG\TEMP.TXT
REM Добавим в конец файла справки пустые строки,
REM чтобы отделять один раздел от другого
ECHO.>>C:\DEBUG\TEMP.TXT
ECHO.>>C:\DEBUG\TEMP.TXT
ECHO ECHO.>>C:\DEBUG\TEMP.TXT
REM Выведем сообщение на экран, чтобы сообщить о том, что справка выдана
ECHO Запрошена справка по команде     % 1    .
ECHO Чтобы посмотреть справку, наберите  : HELP1  View
ECHO И ищите её в самом низу файла справки .
EXIT /B

REM Блок выдачи справки по пакету
:METKA0

ECHO.
ECHO ----------------------------------------------
ECHO Этот пакет копит справку в C:\DEBUG\TEMP.TXT
ECHO.
ECHO Для просмотра справки наберите : HELP1  View
ECHO.
ECHO Для очистки закройте окно справки и удалите
ECHO файл   C:\DEBUG\FLAG.TXT   командой     DEL
ECHO.
ECHO ----------------------------------------------
EXIT /B

REM Блок просмотра справки
:METKA1

REM Создаём файл-флаг для блокирования
ECHO FLAG.TXT>C:\DEBUG\FLAG.TXT

REM Открываем справку через Ворд
START WINWORD C:\DEBUG\TEMP.TXT

REM И завершаем пакет
EXIT /B


Заметьте, что пакет специально не имеет возможности сам удалять и сигнальный «файл флага». Эта функция отдана человеку. Зато добавлена справка, которая рассказывает, какой файл нужно удалить, чтобы снять блокировку.

А если человек «тупой»? И возьмёт, и удалит «файл флаг», т.е. «отопрёт» командник для накопления других справок? А сам справку текущую не закроет. Что тогда? Да ещё и запустит снова командник – обрадовалася чукча! Дорвалася до бесплатного.

Ну, тогда он получит «по мордасам» пять «ругачек» от системы. Вот таких:

<<
Процесс не может получить доступ к файлу, так как этот файл занят другим процессом.
Процесс не может получить доступ к файлу, так как этот файл занят другим процессом.
Процесс не может получить доступ к файлу, так как этот файл занят другим процессом.
Процесс не может получить доступ к файлу, так как этот файл занят другим процессом.
Процесс не может получить доступ к файлу, так как этот файл занят другим процессом.
Запрошена справка по команде     FOR    .
Чтобы посмотреть справку, наберите  : HELP1  View
И ищите её в самом низу файла справки .
>>

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


Справку по этому пакету получаем, если на вход дана команда help, но непременно маленькими буквами. Если выдать команду большими « HELP », то она будет передана на вход интерпретатора и в справку добавится HELP по команде HELP CMD, а не этого командника. А если вообще не задать никакого параметра, то выйдет справка по всем командам CMD.EXE .


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

Удаляйте все ненужности, кроме, пожалуй, хорошего пакета, для чтения справки через Интернет Проводник. Я его у себя тоже сохранил и буду им пользоваться. А имя ему дал однобуквенное H.CMD .

REN HELP1.CMD H.CMD

Надеюсь, что вы поняли, что я вам продиктовал…


А теперь вопрос на «засыпку»: как удалить в этой папке все файлы, имена которых длиннее одного знака?

Ну!

А-а… Не знаете…

А вот так:

MD TEMP
COPY ?.* TEMP\
DEL /Q *.*
COPY TEMP\*.*
DEL /Q TEMP\*.*
RD TEMP

Круто? То-то же! Знай наших.


Хотя в старых версиях MS-DOS, под управлением примитивной Command.com я бы это сделал одной командой (не вздумайте её попробовать, сотрёте всё в нашей папке к одной американской матери и без всякого запроса со стороны системы):

DEL ??*.*

Дело в том, что раньше шаблон «?» означал ровно один знак. Теперь же он означает «хотя бы один»! Чувствуете разницу? Это значит, что под шаблон «??» подходят и имена с двумя знаками, и имена с одним знаком…

Получается, что эта команда удаляет все файлы в папке, и делает это «молча», как партизан, будто она означает не то же самое, что и « DEL *.* » !!!

Но при выполнении « DEL *.* » требует запрос на подтверждение, а « DEL ??*.* » – нет! Эта логика меня озадачивает.

«Вот тебе бабушка Клара Цеткин и освобождённый Труд!» – сказала Машенька, снимаясь с Медведя…


   *    *    *
. . .
«Как всё изменилось!
Уже развалилось
Подножие Лысой горы…
И молодцы вродя
Давно не заходят –
Остались одни упыри…»
. . .
            В.Высоцкий


   *    *    *
. . .
«Всё это так… Архитектура!
Вы мне доверьтесь как врачу, –
Вас от недуга излечу,
Поможет вам моя миксту-у-ура…»
. . .

            Лопе де Вега


Займёмся решением вычислительных задачек при помощи языка командных файлов. Рассмотрим, как это можно сделать.



Попробуем простой пример.

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

Для примера возьмём итерационную формулу расчёта кубического корня из числа Zo.

Zo = 100 ;для примера
Xo = 1   ;приближённое значение на первом шаге
Yo = ( Zo / Xo / Xo + Xo ) / 2 ;наша формула
Дальше идёт проверка: если Yo равен Xo, то нужно выводить результат, Yo – есть кубический корень из Zo. Иначе Xo = Yo , и вернуться к вычислению по формуле.


Если бы у вас и у меня на столе стоял самый первый IBM PC выпуска начала 80-х годов прошлого столетия, на котором не было ни жесткого диска, ни цветного монитора. Естественно не было мыши, многозадачности, а Виндоусами ещё и не пахло в проекте. То я бы воспользовался примитивным языком Бейсик, который был прошит прямо в микросхему на материнской плате и написал бы крохотную программку за пять минут:

REM N'1
100 B = 100
200 YI = 4
300 YII = (B / YI / YI + YI) / 2
400 IF ABS(YII - YI) < 0.0001 THEN GOTO 700
500 YI = YII
600 GOTO 300
700 PRINT YII
800 STOP

А теперь давайте кувыркаться с нашей задачей в стандартной комплектации Виндоус начала XXI – века. В нём есть много памяти, огромные жёсткие диски, сумасшедшие тактовые частоты процессора. Есть многооконная и многозадачная операционная система, которая (прошу это учесть) защищена авторским правом, поставляется отдельно от компьютера за крутые бабки. Но! В ней нет никакого стандартного языка, чтобы решить простенькую вычислительную задачку!!! Для этого вам надо докупить комплект дополнительных программ. А к ним ещё поискать документацию на родном языке. И ещё разобраться в ней, что тоже не малый труд!

Есть стандартный Калькулятор? Да… А вы способны выполнить вручную 50 – 100 итераций, ни где не ошибившись при наборе числа? Нет? Тогда не прячьте денежки по банкам и углам. Несите ваши денежки, иначе быть беде. Идите на поклон к фирменному программисту. А о собственных программах можете забыть.

Спасибо тебе Билл! за построенный рай земной для производителя железа и софта. За коммунизм, который ты построил для себя. И как же не повезло всем остальным бедным простым смертным родиться обычными пользователями этого крутого компьютера за 1000 баксов.



Сказал пару ласковых разработчикам … и ладно. Пусть живут. Дадим им шанс реабилитироваться – блеснуть новьём. А мы посмотрим.



Итак. Для тех, кто лишён прелестей CMD.EXE – нового командного интерпретатора, могу рекомендовать простенькую программку ACALC.EXE из комплекта PC-DOS v 7.0 Русская версия. Она конечно по прикиду и в подмётки не годится современному калькулятору от Майкрософт. Зато умеет работать из командной строки.

В комплекте установочных файлов найдите файл «DOS1.4» и «UNPACK2.EXE». ACALC.EXE лежит внутри DOS1.4 . А вынуть его оттуда можно при помощи UNPACK2.EXE . Нужно скопировать, например, в нашу папку эти файлы и дать такую команду:

          UNPACK2 DOS1.4 C:\DEBUG /N:ACALC.EXE

В результате получите калькулятор, которому можно задать целое выражение из командной строки. Умеет вычислять логарифмы, степени, факториал, тригонометрические функции, переводить числа из одной системы счисления в другую, выполняет все необходимые арифметические действия, логические операции, умеет делать сдвиги операндов (прямо как микропроцессор!), круто разбирается в скобках внутри выражения и занимает всего-то 22 954 байта.

Установка не требуется (следите за руками) :

C:\DEBUG>UNPACK2  DOS1.4  C:\DEBUG  /N:ACALC.EXE
DOS1.4
- C:\DEBUG\ACALC.EXE
     1 файлов распаковано.

C:\DEBUG>_



Справка по программе ACALC.EXE выходит на экран при его запуске без параметров:

<<
Вычисляет значение математического выражения.
 
ACALC [/T[:]формат] выражение
 
  /T           Описывает тип выходного формата
  формат         D=10-ный (по умолчанию)   B=2-ный   O=8-ный  X=16-ный
                A=Все (10-, 2-, 8- и 16-ный)
  выражение    Описывает числовое выражение, имеющее значение.
 
Числа с префиксом 'b', 'o', или 'x' воспринимаются как 2-ные, 8-ные
и 16-ные соответственно. Для 10-ных чисел нет префикса.
 
Арифметические операторы:          Поразрядные операторы:
  ()  Разделители                &   Поразрядное И
  *   Умножение                :   Поразрядное ИЛИ
  /   Деление                ^   Поразрядное исключающее ИЛИ
  %    По модулю (остаток от x/y)     {   Сдвиг влево
  +   Сложение                }   Сдвиг вправо
  -   Вычитание
 
Основные математические функции:
  ABS(x)     Абсолютное значение от x
  EXP(x)     Экспонента от x
  FACT(x)    Факториал от x (от положительного числа меньше 21 )
  LOG(x)     Натуральный логарифм от x (положительного числа)
  LOG10(x)   Логарифм от x (положительного числа) по основанию 10
  MAX(x;y)   Наибольшее из двух значений: x или y
  MIN(x;y)   Наименьшее из двух значений: x или y
  PI()       Значение числа Pi (3,14159265359)
  POW(x;y)   Возведение x в степень y
  SQRT(x)    Квадратный корень от x (положительного числа)
 
Тригонометрические арифметические функции:
  COS(x)     Косинус угла x в радианах
  SIN(x)     Синус угла x в радианах
  TAN(x)     Тангенс угла x в радианах
 
Пример: ACALC FACT(((8+1)/2)*2-SQRT(MAX(6;3)))
>>



Кстати, выполнив приведённый пример, у меня получилось:

C:\DEBUG>ACALC FACT(((8+1)/2)*2-SQRT(MAX(6;3)))
FACT(((8+1)/2)*2-SQRT(MAX(6;3))) = 720

C:\DEBUG>_


Для тех, кто не знает, где откопать комплект PC-DOS v 7.0 Русская версия, даю временную ссылку (срок хранения 3 месяца с момента последней закачки) на эту микроскопическую (по современным меркам) программку:

http://narod.ru/disk/13262074001/ACALC.ZIP.html

Размер архива ACALC.ZIP - 23 087 байт.

Внутри два файла:

ACALC.EXE - 22 954 байта, это сама программа калькулятор; для контроля приведу контрольную сумму WinRar 3.41 (CRC 66B48900), и

ACALC.TXT - 1 588 байт, текстовый файл в кодировке ДОС – инструкция (то, что выдаёт сам калькулятор, и то, что вы уже видите выше).



Тут же становится интересно вычислить косинус «пи пополам» и тангенс «пи пополам», дабы взглянуть, что эта программа подразумевает под НУЛЁМ и БЕСКОНЕЧНОСТЬЮ?

C:\debug>acalc cos(pi()/2)
COS(PI()/2) = -1.03411555577373e-013

C:\debug>acalc tan(pi()/2)
TAN(PI()/2) = -9670101726304.88

C:\debug>_


Ну, что же… Теперь понятно.


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

Вот я определяю один процент от «пи пополам»:
C:\debug>acalc (pi()/2)/100
(PI()/2)/100 = 0.01570796326795

А потом смотрю значение функции справа и слева:
C:\debug>acalc tan((pi()/2)-0.01570796326795)
TAN((PI()/2)-0.01570796326795) = 63.6567411632865

C:\debug>acalc tan((pi()/2)+0.01570796326795)
TAN((PI()/2)+0.01570796326795) = -63.6567411624482

Они отличаются ненамного:
C:\debug>acalc 63.6567411632865-63.6567411624482
63.6567411632865-63.6567411624482 = 8.38299998862091e-010



Можно пошарить с минимальным шагом вокруг «бесконечности»:

C:\debug>acalc tan(pi()/2-0.0000000000003)
TAN(PI()/2-0.0000000000003) = 5086767182853.59

C:\debug>acalc tan(pi()/2-0.0000000000002)
TAN(PI()/2-0.0000000000002) = 10353207183593.1

C:\debug>acalc tan(pi()/2-0.0000000000001)
TAN(PI()/2-0.0000000000001) = -293121846973075

C:\debug>acalc tan(pi()/2-0.0000000000000)
TAN(PI()/2-0.0000000000000) = -9670101726304.88

C:\debug>acalc tan(pi()/2+0.0000000000001)
TAN(PI()/2+0.0000000000001) = -4916142738204.39

C:\debug>acalc tan(pi()/2+0.0000000000002)
TAN(PI()/2+0.0000000000002) = -3295854150973.82

C:\debug>acalc tan(pi()/2+0.0000000000003)
TAN(PI()/2+0.0000000000003) = -2478858002038.47


Очевидно, что точка разрыва функции (при вычислении на ACALC) лежит не как положено (на «пи пополам»), а сдвинута – функция меняет знак за шаг до точного значения. Но это всё тонкости, укладывающиеся в погрешность вычисления 1.0e-013 . Хотя машинная БЕСКОНЕЧНОСТЬ для калькулятора оказывается равна -293121846973075 .


Не будем придираться. В целом неплохо всё написано. Но… Вопрос на «засыпку», а как пристегнуть эту программу к вычислению в пакетах?

Понятно, что можно вызывать её в пакете с заданными выражениями. Параметры (исходные числовые данные) передавать из командной строки.

Много за раз не получится, и дело тут не только в ограниченности числа доступных параметров внутри пакета (% 1 – 9% ). Можно ведь воспользоваться командой SHIFT и получить доступ к следующим параметрам. Тут дело в другом. Вспомните про ограничение на длину самой командной строки. Она не должна превышать 255 байт.

Но, это ладно. Для массовой обработки данных нужно пользоваться иными средствами. Всё понятно. Но как вычислять в пакете при помощи ACALC хотя бы простые выражения? Чтобы выходные данные одних выражений служили входными данными для других!

Понятно, что вывод можно перенаправить потоком куда-нибудь в файл, а потом сам файл дать на вход как входной параметр. Но вот незадача! Если бы выдавался на экран только результат – оно было бы логичнее. Результат мог бы служить новым операндом в другой команде, и так бы они цеплялись друг за друга и работали совместно. Или хотя бы результат в строке стоял первым. Нет же, вначале стоит само выражение. И получается, что предварительно нужно суметь найти в строке результата знак равенства, а потом выделить итоговое число…

Впрочем… А почему нет?

Посмотрите. Результат всегда состоит из трёх частей, словно нарочно разделённых пробелами. Значит, если на вход другого пакета подать строку результата от верхнего уровня, словно мы её набрали на клавиатуре вручную, то внутри вложенного пакета под именем « % 1 » будет находиться исходное выражение, а под именем « % 2 » можно «пощупать» итого. А куда денется знак равенства? А знак равенства (просто удивительно!) командный интерпретатор – поедает. Видимо, он ими питается…

 ;-)

То есть, одиночный символ « = » задать в качестве параметра в командной строке – НЕЛЬЗЯ. Запоминайте.

Остаётся только суметь вернуть «итого» в пакет верхнего уровня в качестве очередного входного параметра – и дело в шляпе! Цепочка замкнётся и можно продолжать считать. А выход осуществлять по условию.


Если абстрагироваться от деталей, то пакетный файл в первом приближении должен был бы называться, например, KORENKUB.CMD , на вход ему нужно было бы подать входные параметры: % 1 = 100, % 2 = 1 .

Вызов KORENKUB.CMD будет таким:

KORENKUB 100 1

А сам он выглядел бы так:

@ECHO OFF
:METKA
SET Zo=% 1
SET Xo=% 2
ACALC (% 1/% 2/% 2+% 2)/2>FIL1.TXT
«неизвестная команда» FIL1.TXT
IF NOT -% 2=-% YI%  GOTO METKA
ECHO Кубический корень из % 1 = % 2
EXIT /B

Логика простая. Сохраняем % 2 в переменную YI. Запускаем ACALC с выводом в файл FIL1.TXT , а потом «неизвестная команда» выделяет из FIL1.TXT результат и возвращает в параметр % 2 . После чего следует проверка: если % 2 и значение переменной отличаются, то возвращаемся по метке. Иначе выводим значение % 2 и всё.




А теперь рассмотрим работоспособный вариант, состоящий из трех пакетов и одной заготовки. KORENKUB.CMD – стартовый пакет. (Смотри комментарии в нём самом.) VYZOV.CMD – необычный пакет для вызова второй части. Состоит из одной строки, которая составляется первой частью из файла заготовки ZAG1.TXT и результата работы программы ACALC.EXE . Эта часть попадает в файл FIL1.TXT в результате перенаправления потока. А короткий VYZOV.CMD вызывает третью часть – пакет с именем PROVER.CMD . Он осуществляет проверку и при необходимости, либо снова вызывает первую часть (замыкает итерацию по кольцу), либо выводит результат на экран и завершает выполнение.

Вот что получилось.


@ECHO OFF
REM MY NANE IS KORENKUB.CMD
REM Вызов пакета осуществляется так:
REM KORENKUB   100    1
REM -----------------------
REM Первый параметр - это число, из которого
REM извлекается корень кубический
SET Zo=% 1
REM
REM Второй параметр – это первое приближение
REM если оно неизвестно, то можно брать 1
SET Xo=% 2
REM
REM Служебный вывод очередного приближения
REM на случай отсутствия сходимости
ECHO % 2
REM ECHO % 2>>PROTOCOL.TXT
REM
REM Вызов ACALC.EXE для вычисления.
REM Вывод результирующего сообщения в файл FIL1.TXT
ACALC (% 1/% 2/% 2+% 2)/2>FIL1.TXT
REM
REM Подготовка вызова слиянием ZAG1.TXT и FIL1.TXT
REM Сообщение о копировании подавляется (отправляется
REM на нулевое устройство - NUL)
COPY /B ZAG1.TXT + FIL1.TXT VYZOV.CMD>NUL
REM
REM Передача управления вызову, подготовленному
REM на предыдущем шаге. На этом текущий запуск
REM этого пакета завершён. Переменные сохранились
REM в переменных окружения   Zo   и   Xo
VYZOV


Мне кажется, что тут всё понятно. Отмечу лишь два нюанса: вывод в файл протокола PROTOCOL.TXT закомментарен, дабы не плодить лишние записи в папке. Его можно посмотреть разок-другой, но оставлять включённым не след. И вообще возможны особенности, как у всякого итерационного численного алгоритма, но о них ниже… И вторая особенность. Пакет прерывается не по привычному выходу «EXIT /B», а странным вызовом, который сам себе предварительно «клеит» ?! Как так? А вот так.

Если пакет обратился к другому пакету, просто указав его имя (в любом месте), то первый пакет завершается, а второй начинает выполнение. И всё. Никаких возвратов в следующую строку, из которой был вызов, не будет. Таким образом можно разбивать пакеты на составные части (хоть по строчкам) и обращаться друг к другу совместно. При этом все переменные, которые они наопределяют по команде SET и будут присваивать им значения, доступны каждому из пакетов. Это очень удобно для организации обмена между разными частями.


Теперь о файле «заготовке».

ZAG1.TXT
"PROVER "

Что из себя представляет файл ZAG1.TXT ? Это начало строки вызова, в которой прописано имя командного файла, который будет вызван. А после имени стоит один ПРОБЕЛ. Но в строке должны отсутствовать конечные символы 0D, 0A – те самые, которые добавляются после нажатия клавиши <Enter>. При работе с простым текстовым редактором добиться этого невозможно. Даже если вы забыли нажать <Enter> в последней строчке, редактор сам добавит эти символы.

Я изобразил под именем файла строку, закрытую справа и слева парными апострофами. Надеюсь вам видно, что между правым конечным символом и концом имени пустое пространство – это пробел. А отсутствие <Enter> в конце я изобразил тем, что не указал коды этих символов. Вы должны понимать условность моей записи. На самом деле апострофы ставить не надо. А как избавиться от <Enter>? Читайте дальше.

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

Редактор программиста вообще не должен проявлять инициативу. Он должен беречь текст программы ровно с точностью до знака. Всякие самовольные преобразования слов, замена символов, потеря пробелов и т.д. – должно расцениваться, как вредительство со стороны редактора и безжалостно искореняться вместе с самим объектом таких своеволий!

Как же быть?

У вас есть EDIT.COM . Он не зря прожил столько лет на белом свете. И кое-чему научился. В отличие от «моднячей молодёжи», которая гордиться красотой своих окон, но не может сделать простейших вещей. Вот он вас и спасёт.

Открываете EDIT. Вводите в нём строку с пробелом в конце:
PROVER

и сохраняете с именем ZAG1.TXT в нашей папке. Затем закрываете этот текст из меню (пункт «Закрыть»), а потом снова открываете его, НО! Это важно! Внимание! При открытии устанавливаете флажок «[х] Двоичный файл», длину строки можете не трогать.

Вот тогда вы УВИДИТЕ в конце только что набранной вами строки файла ZAG1.TXT эти два символа, которые добавляются в конец каждой строчки любого текста при нажатии <Enter>. Теперь осторожненько их удалите. А пробел после имени НЕ ТРОГАЙТЕ! И сохраните снова. Всё. Теперь у вас есть «заготовка» - оборванная наполовину строка вызова.


Вот так будет выглядеть наш файл из примера для сохранения итогового результата, после выполнения первого вычисления программой ACALC. Это вторая часть, которая будет «приклеена» к заготовке и получится вызов.

FIL1.TXT
"(100/1/1+1)/2 = 50.5", 0D, 0A

Опять же, апострофов вы не увидите – я их поставил только для того, чтобы показать, где начинается, а где кончается строка символов. Запятых тоже не будет. Запятыми я разделил чтобы показать, что подряд идут: символьная строка и два кода в шестнадцатеричных – 0D и 0A .


После выполнения команды «COPY /B ZAG1.TXT + FIL1.TXT VYZOV.CMD>NUL», которая означает: работать в бинарном режиме, взять ZAG1.TXT, дописать ему в конец FIL1.TXT, а результат поместить в новый файл VYZOV.CMD, старый такой же уничтожить, а сообщение на экран об успешном копировании отправить на нулевое устройство NUL.

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

VYZOV.CMD
"PROVER (100/1/1+1)/2 = 50.5", 0D, 0A

Всё сказанное ранее об условности представлении содержимого справедливо и тут. Апострофов не будет. Конечные коды не видны. Запятых нет.



Теперь следующий пакет из комплекта «КОРЕНЬ КУБИЧЕСКИЙ». Этот файл называется PROVER.CMD, который получает управление от вызова VYZOV.CMD , а командная строка, принимаемая им на вход, разлагается на два параметра. Первый параметр % 1 он игнорирует. Зато второй бережно записывает в переменную Yo, которую сам и создает первый раз, а потом каждый раз обновляет новым значением. После чего производит проверку: если переменная Xo (первое приближение) совпадает посимвольно с переменной Yo (результатом вычислений), то совершается переход по метке «METKA» вниз. Там выводится сообщение, мол, так и так, корень ваш кубический (будь он неладен) найден, хотя это было не просто… И напоминает из какого числа он был получен, и чему получился равен. А после этого делает «кердык», т.е. тормозит по EXIT /B.

Ну, а если переменные не совпали, тогда - хошь ни хошь, а иди и считай по новой. Но перед этим надо перенести результат Yo в начальное приближение Xo, что он и делает. А потом вызывает заново первичный модуль командой «KORENKUB % Zo%  % Xo% », т.е. передавая ему начальные значения, которые по первому разу мы задавали ему вручную. % 1 = Zo (исходное число), а % 2 = Xo (следующее вычисленное приближение).

Вот так. Смотри народ. И дивися!

@ECHO OFF
REM MY NANE IS PROVER.CMD
SET Yo=% 2
IF % Yo% ==% Xo%  GOTO METKA
SET Xo=% Yo%
KORENKUB % Zo%  % Xo%
:METKA
ECHO Корень кубический из % Zo%  = % Yo%
EXIT /B


И вся эта халабуда запускается и шустрит так, что только ветер в лицо дует!

Вот пример исполнения заветного вызова с числами 100 и 1 .

C:\debug>KORENKUB 100 1
Режим вывода команд на экран (ECHO) отключен.
50.5
25.2696059209881
12.7131049985389
6.66591433531072
4.45821112247527
4.74474701320058
4.59334959152907
4.66647102580706
4.62934639611793
4.64775865837751
4.63851620130865
4.6431282034851
4.64081991412966
4.64197348446383
4.64139655599629
4.64168498436932
4.64154076122208
4.64161287055496
4.6415768153284
4.64159484280165
4.64158582903001
4.64159033590708
4.64158808246636

4.64158920918617
4.64158864582613
4.64158892750611
4.64158878666612
4.64158885708611
4.64158882187611
4.64158883948111
4.64158883067861
4.64158883507986
4.64158883287924
4.64158883397955
4.64158883342939
4.64158883370447
4.64158883356693
4.6415888336357
4.64158883360132
4.64158883361851
4.64158883360991
4.64158883361421
4.64158883361206
4.64158883361314
4.6415888336126
4.64158883361287
4.64158883361273
4.6415888336128
4.64158883361277
4.64158883361278
Корень кубический из 100 = 4.64158883361278

C:\debug>

Вы можете сохранить протокол в файле PROTOCOL.TXT, если раскомментарите одну строку из файла KORENKUB.CMD, вот так:

REM Служебный вывод очередного приближения
REM на случай отсутствия сходимости
ECHO % 2
ECHO % 2>>PROTOCOL.TXT


Сравним значение, вычисленное «хитрыми ребятами» - нашими пакетами, при помощи дедовского ACALC.EXE, и полученное стандартным калькулятором из набора Виндоус:


KORENKUB = 4.64158883361278
Виндоус  = 4,6415888336127788924100763509194


Совпало.


Теперь поговорим за алгоритм. Это стоит сделать обязательно. Потому что он несовершенен. И мы сейчас его будем менять. Почему?

Иногда наступает состояние, когда расчёт никогда не будет окончен. Вот пример:

(
Только прежде, чем запускать его – убедитесь, что вы выключили протокол, т.е. закомментарили строчку, относящуюся к выводу протокола, командой REM. Иначе на диск полезет масса повторяющихся до бесконечности данных. А на экран не жалко – пусть идёт.
)

C:\debug>KORENKUB 17 1
. . .
2.57128159065823
2.57128159065824
2.57128159065823
2.57128159065824
2.57128159065823
2.57128159065824
2.57128159065823
2.57128159065824
2.57128159065823
2.57128159065824
2.57128159065823
^C2.57128159065824
Завершить выполнение пакетного файла [Y(да)/N(нет)]? y

C:\debug>_

Мне пришлось обрывать зациклившейся счёт нажатием <Ctrl>+C , при чём сработало не первое нажатие. Почему алгоритм зациклился? Проверка несовершенна. Она просто проверяет совпадение двух символьных строк побайтно. А ситуация вычислительная сложилась так, что на одном шаге получается значение 2.57128159065824 а на другом 2.57128159065823 . И так и будет продолжается…

Что? Разрядности вычислителя не хватило? Нет, конечно. Это совсем не значит, что вычислитель несовершенен! Для любого вычислителя с любой разрядностью всегда найдутся такие числа Zo, из которых вычисление по данному алгоритму будет приводить к бесконечной итерации между двух близких значений.


Попробуем выйти из данной трудности простым способом. Добавим ещё одну переменную Xs, в которую будем сохранять значение Xo, перед тем как переопределить его новым значением Yo. И на каждом шаге будем проверять не только совпадение Yo=Xo (с предыдущим шагом), но и Yo=Xs (т.е. с пред- предыдущим).


Перепишем вторую часть, отвечающую за проверку, так:

@ECHO OFF
REM MY NANE IS PROVER.CMD
SET Yo=% 2
IF % Yo% ==% Xo%  GOTO METKA
IF % Yo% ==% Xs%  GOTO METKAERROR
SET Xs=% Xo%
SET Xo=% Yo%
KORENKUB % Zo%  % Xo%
:METKA
ECHO Расчёт окончен! Получено значение:
ECHO Корень кубический из % Zo%  = % Yo%
ECHO.
ECHO Функции POW() даёт значение:
ACALC POW(% Zo% ;(1/3))
EXIT /B

:METKAERROR
ECHO Внимание! Алгоритм попал в бесконечную последовательность.
ECHO На выбор предлагаются два значения:
ECHO Корень кубический из % Zo%  = % Xo%  либо % Yo%
ECHO.
ECHO Среднее значение будет таким:
ACALC (% Xo% +% Yo% )/2
ECHO а разница между значениями такая:
ACALC ABS(% Xo% -% Yo% )
ECHO.
ECHO Функции POW() даёт значение:
ACALC POW(% Zo% ;(1/3))
EXIT /B


Обратите внимание, что пакет претерпел значительные изменения: основное (о чём мы с вами говорили) - это добавлена проверка % Yo% ==% Xs%  с переходом на метку METKAERROR. Естественно перед переопределением Xo новым значением Yo, вставлена строка SET Xs=% Xo% , в Xs это значение сохраняется (а раньше терялось).

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

Теперь он стал более информативным. А кроме этого, я выдаю значение ACALC POW(% Zo% ;(1/3)), т.е. вычисляю корень кубический из нашего Zo средствами встроенной в ACAL функции POW(), и таким образом получаю возможность анализировать своё значение, сравнивая его с «фирменным». Я не говорю «истинным», а именно «фирменным», поскольку даже в «фирменных» программах бывают ошибки.

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


А теперь я предлагаю вам модифицировать наш алгоритм не в части проверки – это всё косметические приёмы. А изменить саму формулу приближённого вычисления! Как? А вот так:


REM N'2
100 B = 100
200 YI = 4
300 YII = (SQR(B) / SQR(YI) + YI) / 2
400 IF YII - YI < 0,0001 THEN GOTO 700
500 YI = YII
600 GOTO 300
700 PRINT YII
800 STOP

Это второй вариант на Бейсике алгоритма вычисления корня кубического моего собственного сочинения. Я воспользовался тем, что есть стандартная функция SQR() для вычисления квадратного корня.

SQR() - работает по схожему алгоритму последовательного приближения, который изобрёл гениальный инженер, живший около двух тысяч лет назад! Мудрейшего и достойнейшего мужа звали Герон Александрийский. Жил он в городе на берегу Средиземного моря. И занимался тем же самым, чем занимаемся сейчас мы с вами. Но к тому же он был ещё великолепный механик, непревзойдённый инженер, изобретатель и мастер!

Мы с вами даже не подозреваем, что нажимая каждый раз на кнопку калькулятора с изображения квадратного корешка на ней, мы незримо вызываем дух Герона Александрийского – пользуемся плодами его размышлений, бессонных ночей, стремления к победе! Победе разума над мраком незнания.

А мы? Его потомки? Чем мы можем похвастать? На нашем столе стоит устройство, за которое Герон заложил бы душу дьяволу! А мы используем его, как примитивную пишущую машинку…


Итак. Что нужно сделать, чтобы модифицировать наш алгоритм? Всего лишь заменить строку вызова ACALC в пакете KORENKUB.CMD !

Заменить вот эту строку:
ACALC (% 1/% 2/% 2+% 2)/2>FIL1.TXT

На эту:
ACALC (SQRT(% 1)/SQRT(% 2)+% 2)/2>FIL1.TXT

И всё!


Старый вызов ACALC не надо уничтожать, просто пометим строку впереди REM, сделав из неё комментарий.

Меняем. И пробуем.


C:\debug>KORENKUB 100 1
Режим вывода команд на экран (ECHO) отключен.
5.5
4.8820071635561
4.70393190494002
4.657329868629
4.64553407340521
4.64257577187081
4.64183560751758
4.64165052954886
4.64160425775056
4.64159268965683
4.64158979762439
4.64158907461572
4.64158889386352
4.64158884867546
4.64158883737845
4.6415888345542
4.64158883384813
4.64158883367162
4.64158883362749
4.64158883361646
4.6415888336137
4.64158883361301
4.64158883361284
4.64158883361279
4.64158883361278
Расчёт окончен! Получено значение:
Корень кубический из 100 = 4.64158883361278

Функции POW() даёт значение:
POW(100;(1/3)) = 4.64158883361278

C:\debug>_


Давайте не поленимся и сравним с приведённым мною ранее выводом для расчёта того же значения по предыдущей формуле. И вы увидите, что число итераций стало вдвое меньше!

N’    Старый алгоритм      Новый алгоритм
-------------------------------------------
01.   50.5                5.5
02.   25.2696059209881     4.8820071635561
03.   12.7131049985389     4.70393190494002
04.   6.66591433531072     4.657329868629
05.   4.45821112247527     4.64553407340521
06.   4.74474701320058     4.64257577187081
07.   4.59334959152907     4.64183560751758
08.   4.66647102580706     4.64165052954886
09.   4.62934639611793     4.64160425775056
10.   4.64775865837751     4.64159268965683
11.   4.63851620130865     4.64158979762439
12.   4.6431282034851      4.64158907461572
13.   4.64081991412966     4.64158889386352
14.   4.64197348446383     4.64158884867546
15.   4.64139655599629     4.64158883737845
16.   4.64168498436932     4.6415888345542
17.   4.64154076122208     4.64158883384813
18.   4.64161287055496     4.64158883367162
19.   4.6415768153284      4.64158883362749
20.   4.64159484280165     4.64158883361646
21.   4.64158582903001     4.6415888336137
22.   4.64159033590708     4.64158883361301
23.   4.64158808246636     4.64158883361284
24.   4.64158920918617     4.64158883361279
25.   4.64158864582613     4.64158883361278
26.   4.64158892750611
27.   4.64158878666612
28.   4.64158885708611
29.   4.64158882187611
30.   4.64158883948111
31.   4.64158883067861
32.   4.64158883507986
33.   4.64158883287924
34.   4.64158883397955
35.   4.64158883342939
36.   4.64158883370447
37.   4.64158883356693
38.   4.6415888336357
39.   4.64158883360132
40.   4.64158883361851
41.   4.64158883360991
42.   4.64158883361421
43.   4.64158883361206
44.   4.64158883361314
45.   4.6415888336126
46.   4.64158883361287
47.   4.64158883361273
48.   4.6415888336128
49.   4.64158883361277
50.   4.64158883361278



Но и это ещё не всё! Обратите внимание на одну очень тонкую деталь. Значения в первом ряду постоянно «болтаются» возле истинного значения. На одном шаге превышают его, а на другом не достигают. Эта «пилообразность» постепенно становится всё меньше, меньше; пока не сходит на нет.

А значения в правом ряду никогда не превышают истинное значение! Ряд сходится плавно, гладко. И если вы проведёте дополнительные запуски, дабы поискать: когда же сработает наш блок, написанный для вывода алгоритма из бесконечного цикла? - то ваши поиски окажутся безуспешны.

Таким образом, мы не только сократили вдвое число итераций, но и избавились от проблемы с бесконечным циклом.

Вот так.


Теперь можно закомментарить строчку вывода промежуточного результата на экран, что даст нам существенную экономию по времени расчёта (ведь вывод на экран съедает значительную долю процессорного времени!)


Как ещё повысить скорость? Один из способов – создать электронный диск (диск, который будет эмулирован в оперативной памяти компьютера). Наши пакеты ведь постоянно обращаются к жёсткому диску. Пишут туда вспомогательные файлы, считывают их, «клеят» вызов, вызывают ACALC снова и снова, то загружая его в память, то выгружая… А жёсткий диск очень сильно уступает по скорости оперативной памяти. Если же все части пакета будут расположены на электронном диске, то это существенно улучшит скорость вычислений.
 
Помните? , вначале я упоминал вам о своём загрузочном лазерном диске, который может работать вообще без винчестера? А на жёстком диске можно держать маленький раздел FAT32 – (до 2 Гб ;-), который будет виден под MS-DOS, только чтобы сохранять свои наработки и результаты вычислений. В этом есть свой резон.



Но есть и кардинальный способ, как улучшить сразу всё: и точность, и скорость, и компактность. - Это перейти от программирования на языке командных файлов, к программированию в машинных кодах, т.е. к Старому Жуку. Поверьте, выжать из Центрального Процессора больше, чем он – не способен ни кто. Никакие Бейсики, Паскали, Си – они ему в подмётки не годятся.


Только не забывайте, что плохой алгоритм – он и в Африке плохой. И разработка эффективного алгоритма – первейшая задача программиста. Но об этом мы ещё поговорим предметно, когда закончим с языком командных файлов. Обещаю. Не пожалеете.


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

Может быть, вы сумеете написать такой «движок» из Старого Жука? А?

А почему нет? Не боги горшки обжигают!




Ценное замечание о тех, которые обжигают:

при проведённом тестировании пакетов по вычислению кубического корня под MS-DOS и Windows-98SE пришлось столкнуться с неприятной вещью. Региональные (русские) установки предписывают использовать в числах вместо десятичной точки – запятую. А калькулятор ACALC оказался таким дотошным, что педантично следует этим надуманным правилам. Однако в переменные окружения такие параметры попасть НЕ МОГУТ! По причине того, что «запятая» с незапамятных времён служит разделителем параметров (как и пробел) в командной строке. Значит запись 4,5 будет воспринята (в отличии от 4.5) как два отдельных параметра.

Справиться с этим казусом удалось двумя способами: сначала я отключил в CONFIG.SYS команду с указанием регионов и в AUTOEXEC.BAT загрузку кодовой страницы в команде MODE. И всё заработало.

А потом решил использовать этот казус, как пример для демонстрации программирования под дебагером. И привожу его в главке IV , которую назвал «Точка, точка, запятая…» . Очень рекомендую почитать.


Ещё незначительная особенность – в Command.com продвинутая команда «EXIT /B» не работает, ключ надо убрать – тогда всё приходит в норму.

И наконец, строки комментариев с пометкой их вначале «REM» при наличии в строке перенаправления потока (знаков «>>» и «>») всё равно дают генерацию файлов с такими именами, хотя и нулевой длинны. Поэтому, будьте бдительны! Если у вас в пакете стоят два вызова:

REM ACALC (% 1/% 2/% 2+% 2)/2>FIL1.TXT
ACALC (SQRT(% 1)/SQRT(% 2)+% 2)/2>FIL1.TXT

и вы пометили REM верхний из них, то всё будет работать, как вы хотите. Но если вы пометите REM нижний вызов, а у верхнего его уберёте, вот так:

ACALC (% 1/% 2/% 2+% 2)/2>FIL1.TXT
REM ACALC (SQRT(% 1)/SQRT(% 2)+% 2)/2>FIL1.TXT

То вторая строка хотя и не будет выполнена, но файл FIL1.TXT нулевого размера родит, и конечно убьёт этим ваш нормальный FIL1.TXT !!! Последствия будут тоже нулевыми.

Рекомендую, когда приписываете REM вначале строки, то убирайте знаки потока, а чтобы не забыть, что имя файла указано, как приёмник перенаправления вывода, пишите для себя в конце строки – «поток», ил что-то ещё…



Теперь. Вызывайте справку по команде SET, будем читать вместе и пробовать, пробовать, и ещё раз пробовать… (как велел дедушка Ленин). Будем вычислять на языке командных файлов по-новому.

Поглядим же, что новенького предлагает Майкрософт со времён старых Command.com ?



Я привожу выдержку из справки по команде SET, то чего нет в старых версиях. Не кажется ли вам, что ключик «/A» для вычисления выражений кого-то очень сильно напоминает?


Смотрите:

<<

SET /A выражение

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

    ()                - группировка
    ! ~ -               - унарные операторы
    * / %                - арифметические операторы
    + -                - арифметические операторы
    << >>               - двоичный сдвиг
    &                - двоичное И
    ^                - двоичное исключающее ИЛИ
    |                - двоичное ИЛИ
    = *= /= % = += -=    - присвоение
      &= ^= |= <<= >>=
    ,                - разделитель операторов

При использовании любых логических или двоичных операторов необходимо заключить строку выражения в кавычки.  Любые нечисловые строки в выражении рассматриваются как имена переменных среды, значения которых преобразуются в числовой вид перед использованием.  Если переменная с указанным именем не определена в системе, вместо нее подставляется нулевое значение.  Это позволяет выполнять арифметические операции со значениями переменных среды, причем не нужно вводить знаки %  для получения значений.  Если команда SET /A вызывается из командной строки, а не из пакетного файла, она выводит окончательное значение выражения.  Слева от любого оператора присваивания должно стоять имя переменной среды.  Числовые значения рассматриваются как десятичные, если перед ними не стоит префикс 0x для шестнадцатеричных чисел, и 0 для восьмеричных чисел.

Например, числа 0x12, и 022 обозначают десятичное число 18.  Обратите внимание на запись восьмеричных числе: 08 и 09 не являются допустимыми числами, так как в восьмеричной системе исчисления цифры 8 и 9 не используются.

>>

Однако никаких продвинутых функций из набора ACALC мы не видим: ни тригонометрии, ни логарифмов, ни степеней, ни факториала, ни выбора минимума или максимума из двух аргументов… Вот тебе и новьё… Проигрывает оно … старью.


А все вычисления, которые я вам продемонстрировал при участии ACALC, они будут работать не только под новыми Окнами (NT, W2K, XP, Vista), не только под старыми (95, 98, ME), но и под MS-DOS (от 6.2 до, я думаю, вплоть до 3 версии).

. . .

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



                III.

Теперь настала пора вести речь за дебагер.

Почему мы так долго подбирались к «Старому Жуку»? Потому что его запуск будет выполняться из CMD, а выходные файлы, которые мы будем подавать ему на вход, и получать в результате наших упражнений – будут накапливаться в текущей папке. И мне очень бы хотелось, чтобы вы понимали: где и что появляется от ваших действий. И в любой момент могли посмотреть содержимое папки прямо из CMD или из Проводника, чтобы убрать за собой ненужное; или наоборот сохранить полезное на резервный накопитель: лазерный диск, флешку, дискету… (если у кого остались такие приводы…)

Не могу упустить случая, чтобы не пнуть всех любителей хоронить старые форматы и устройства (в том числе дискеты): часто эти любители не знают ни новых, ни старых. А каждая такая «революция», принимаемая ими на Ура! – лишь глупая надежда, что теперь всех «стариков» мы кинем, и начнём всё заново. Но через некоторое время оказывается, что «старики» (имея общие представления и академическую базу) без труда разобрались в новье, а эти «попугаи», как скакали по верхам, так и продолжают…


Запускаем «Старого Жука». Даём команду:

DEBUG и жмём <Enter>


Что такое? На экране ничего не поменялось! Поменялось. Старый Жук – он такой скромняга, что из всех своих возможностей не выпячивает ни одной. Партизан. А единственным признаком его загрузки является смена приглашения. Вы видите, что теперь подсказка с именем текущей папки уже не появляется, а в начале следующей строчки стоит скромный минус. Вот это он и есть – DEBUG.

Чтобы расколоть этого партизана, даже стандартная команда HELP не подойдёт, на неё он ругнётся ошибкой и укажет птичкой «^», с какого символа (по его мнению) ошибка начинается.

Дайте ему знак вопроса «?», и он начнёт говорить. Вот так:

-?
assemble     A [адрес]
compare      C диапазон адрес
dump         D [диапазон]
enter        E адрес [список]
fill         F диапазон список
go           G [=адрес] [адреса]
hex          H значение1 значение2
input        I порт
load         L [адрес] [диск] [превый_сектор] [число]
move         M диапазон адрес
name         N [путь] [список_аргументов]
output       O порт байт
proceed      P [=адрес] [число]
quit         Q
register     R [регистр]
search       S диапазон список
trace        T [=адрес] [значение]
unassemble   U [диапазон]
write        W [адрес] [диск] [первый_сектор] [число]
выделение памяти EMS            XA [#число_страниц]
освобождение памяти EMS         XD [дескриптор]
сопоставление страниц EMS       XM [Lстраница] [Pстраница] [дескриптор]
вывод состояния памяти EMS      XS



Теперь вы видите, что у жука есть команда «hex», поэтому команду «HELP» заменили знаком вопроса. Учтите, что все команды у дебагера однобуквенные, а маленькими буковками слева расписано короткое пояснение смысла каждой команды. Раз уж мы заговорили о «hex», то давайте её и рассмотрим. Она элементарна, Ватсон, – как сказал бы Шерлок Холмс.


Выполните команду:
-H   2   2

и получите в качестве её результата сумму и разность двух заданных чисел:

0004   0000

По сути ничего особенного, но при помощи этой команды мы с вами познакомимся с числами, которыми оперирует дебагер (и не только он – всё программирование насквозь пронизано термином HEX, что означает 16-ричную систему счисления).

Если вы дадите команду:
-H   9   1

то результатом будет не 10 и 8, как можно ожидать, а

000A   0008

То есть чисел в наборе не десять штук, как мы привыкли (0-9), а шестнадцать:

0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F

Не спешите возмущаться, что программисты такой народ, который стремится всё запутать. Это не так. Совсем не случайно 16-ричная система применяется в программировании. Сейчас вы в этом убедитесь.

Выполним команду «register» без параметров:

-R
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0100   NV UP EI PL NZ NA PO NC
0B1C:0100 AA            STOSB

Вот он – внутренний мир того кристалла, на котором построена вся внутренняя жизнь вашего компьютера! Что мы видим?

AX, BX, CX, DX, SP, BP, SI, DI, DS, ES, SS, CS, IP – названия внутренних регистров Центрального Процессора. А через знак равенства показано их содержимое.

О назначении и названии регистров буду повествовать по ходу дела, пока лишь скажу, что они не равноправны. Некоторые настолько специфичны, что употребляются с единственной целью (например, IP «Instruction Pointer register» – указывает адрес ячейки памяти, из которой будет выбрана следующая команда на исполнение центральным процессором). Заметьте, что в последней строке, выданной на экран по команде R, стоит адрес как раз этой самой ячейки и показано её содержимое. То есть, 0B1C соответствует значению в регистре CS («Code Segment register» – сегментный регистр кода), а следующее за ним значение через двоеточие 0100 – значению в регистре IP. Таким образом, пара значений в регистрах CS:IP образуют ссылку (адрес ячейки), из которой ЦП возьмёт себе следующую команду на выполнение.

В моём случае в ячейке лежит команда размером в один байт, код её «AA», а STOSB – это мнемоническое имя, чтобы человек мог лучше ориентироваться в командах процессора. Это её условное обозначение, которое компьютеру ни о чём не говорит. Чтобы он принял команду STOSB ему нужно именно AA, и ни что иное.

Как эта команда сюда попала? Да никак. Она вообще не наша. В памяти остались данные от работы предыдущих программ. Мы пришли, а нас не ждали.

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

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

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

Всё же элементарно! Изнутри логика ЦП выглядит не сложнее продвинутого калькулятора. Давайте же попробуем в ней разобраться, научимся управлять этим супер калькулятором, сохранять свои коды на диск и загружать нужные нам на выполнение.


( Примечание: для эстетствующих программёров, которые знакомы с отличием x86 от его последующих модификаций – не спешите хоронить усечённую проекцию ЦП для рядового пользователя. Если он разберётся в логике x86, то овладение старшими модификациями – это уже дело техники. А совместимость «снизу вверх» для x86 – максимальная. И в ней тоже можно написать много чего. )


Давайте теперь посмотрим на содержимое памяти, что там у нас с вами лежит, за нашим стартовым адресом 100 .

Даём команду «dump» дамп:
-D
0B1C:0100  AA 43 E2 F1 32 C0 AA C3-F6 46 04 02 75 43 8B D5   .C..2....F..uC..
0B1C:0110  83 C2 05 57 B8 00 6C BB-40 00 33 C9 34 00 0B 0B   ...W..l.@.3.4...
0B1C:0120  01 CD 21 5F 73 15 E8 C4-DB 3D 02 00 74 23 3D 03   ..!_s....=..t#=.
0B1C:0130  00 74 1E 3D 05 00 74 19-E9 E3 D8 8B D8 B8 00 44   .t.=..t........D
0B1C:0140  CD 21 B4 3E CD 21 F6 C2-80 75 53 F6 46 04 04 74   .!.>.!...uS.F..t
0B1C:0150  4D 8B 56 05 80 FA 00 74-05 80 FE 3A 74 02 B2 40   M.V....t...:t..@
0B1C:0160  80 CA 20 80 EA 60 E8 74-E4 73 06 E8 7F DB E9 AD   .. ..`.t.s......
0B1C:0170  D8 8B D5 83 C2 05 8A 7E-04 80 E7 06 80 FF 06 75   .......~.......u

Вот в принципе ответ, почему в программировании используется 16-тиричная система. Потому что минимальной адресуемой единицей в памяти является байт. Один байт – это восемь разрядов, каждый из которых может быть установлен в 0 или 1. В HEX два знака занимают ровно один байт. Один знак – половину байта. Таким образом определить размер данных становится легко даже на глаз. Например, становится понятно, что все регистры, отображаемые по команде «register» имеют размер в два байта, то есть 16 разрядов – шестнадцать последовательно выстроенных битиков, каждый из которых может принимать значение либо ноль, либо единица.

Хотя есть и дополнительные возможности для регистров AX, BX, CX и DX . Для них возможно использование «по частям» старшего и младшего байта, как самостоятельных регистров. Нужно лишь указать какую часть вы подразумеваете: старшую «High» или младшую «Low» .

Таким образом, имя AX – это 16 разрядов (два байта), а AH и AL – это восемь разрядов (по одному байту) того же самого регистра AX.

Например, если в регистре AX содержится вот такой набор 1 и 0 :
          AX = 0011 1100 1100 0011

То имя    AH = 0011 1100 , а имя AL = 1100 0011

Это я расписал подробно в двоичном представлении.

То же самое в 16-тиричном будет выглядеть так:

AX = 3CC3
AH = 3C , AL = C3


Обратите внимание, что в нашем дампе в байте по адресу 0B1C:0100 лежит «AA». А так как стартовый адрес для программы CS:IP тоже сюда ссылается, вот и получается STOSB.

Давайте запишем сюда другое значение, например, 90.

Сделаем это по-простому, воспользуемся командой «enter»:
-E 100
0B1C:0100   AA._

Дебагер показывает содержимое запрошенного байта и ждёт от нас действий. Если мы просто нажмём <Enter>, то команда завершится, ничего не изменив в памяти. Но мы введём число 90 и только после этого нажмём <Enter>.

Теперь дайте команду «register» и увидите, что первая команда на старте уже другая.

-R
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0100   NV UP EI PL NZ NA PO NC
0B1C:0100 90            NOP

Код «90» в HEX означает команду NOP – нет операции. То есть эта команда велит процессору «ничего не делать»! (А ещё говорят, что только русские такие ленивые. Пусть не врут! ;-) ) По этой команде процессор посмотрит на NOP, и пойдёт дальше. «Нопики» придуманы для того, чтобы при отладке всегда можно было вручную заполнить часть ошибочного или сомнительного кода этой однобайтовой командой и таким образом не перемещать все фрагменты в памяти к образовавшейся прорехе.

Слово «вручную» не означает, что всю кучу нопиков придётся набирать один за одним. Есть команда «fill», которая может прошить в память сразу кучу. Но об этой команде поговорим позже.

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

Можно так хитро писать программу в кодах, чтобы они были перемещаемыми. И тогда такие законченные фрагменты можно свободно класть в любое место памяти – они всё равно будут работать правильно. Кстати, есть у DEBUG команда «move», которая тем и занимается, что перемещает указанный диапазон байтов на указанный адрес памяти. Поэтому, перемещаемость кодов иногда очень важна. Обычно так пишут подпрограммы, которым все внешние параметры передают через стек.


Что такое стек? – Это очень просто. Очередь, которая работает по принципу «первый пришёл – последний ушёл». Вы думаете, что такая очередь лишена смысла? Вспомните, мы с вами в предыдущем разделе выполняли команды CMD, и они образовывали очередь в точности похожую на стек (эта очередь так и называется «стек команд»); вспомните старые монетники – специальное устройство, в котором отверстия закрывались подпружиненными накладками, по размеру соответствующими различным монетам. И когда требовалась монетка определённого достоинства, то снимали её сверху. А чтобы достать самую первую монетку, которая попала в очередь, нужно было вытащить все предыдущие. То же самое случается, когда ящики ставят один на один; книги кладут в стопку; листы бумаги сложены поверх друг друга в ящике письменного стола.

Вот и у Центрального Процессора тоже есть свои команды работы со стеком: PUSH – запихнуть слово в стек (слово – это два байта, как раз размер регистра), и POP – вытолкнуть из стека. А пара регистров SS:SP точно так же ссылается на вершину стека, как CS:IP на адрес следующей инструкции. SS так и называется «Stack Segment register» (Регистр сегмента стека), а SP «Stack Point register» (указатель стека) является плавающим указателем, который как раз меняет своё значение при выполнении команд PUSH и POP. При этом стек нарастает не в сторону увеличения адресов, а наоборот – в сторону уменьшения. Поэтому, глядя на значения сегментных регистров в дебагере, вы тут же понимаете, что стек не может расти неконтролируемо. У него есть предел! Он ссылается на тот же сегмент, что и коды нашей программы. А указатель стека SP указывает на конец этого сегмента. И если в цикле начнётся неконтролируемый рост стека, то он начнёт постепенно пожирать всё больше и больше пространства в сегменте, и под конец сотрёт и саму нашу программу и все её данные попортит.

Какова величина сегмента? От 0 до FFFF байт, то есть 65536 шт., например, нопиков. А если учесть, что стартовый адрес в IP стоит на 100 (256 байт), то сегмент становится чуть меньше. Можно разнести сегменты кодов и стека, установив их разными. Но это нужно делать лишь в том случае, если вам это действительно необходимо.

Только не думайте, что все команды процессора такие короткие (однобайтовые). Давайте для примера рассмотрим команду сложения. Тут нам уже не обойтись без аргументов. Складывать будем содержимое регистров AX и BX. Заодно поглядим, как менять значение регистров. Где окажется результат. И изучим команду «assemble», которая сама будет переводить названия команд процессора в коды автоматически, (ей-то мы и будем пользоваться постоянно).

Даём:
-A 100
0B1C:0100 ADD AX,BX
0B1C:0102 _

Обратите внимание, что адрес следующей команды, которую готова переводить в коды «assemble», начинается с адреса 102 . Значит, введённая нами команда ADD AX,BX уложилась в два байта: первый с адресом 100 и второй с адресом 101 .

Давайте введём с адреса 102 уже знакомый нам нопик (только уже не в виде кода 90, а в виде его названия NOP) и закроем команду «assemble» ещё одним <Enter>.

У нас получится так:

-A 100
0B1C:0100 ADD AX,BX
0B1C:0102 NOP
0B1C:0103
-

Посмотрим «register»:
-R
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0100   NV UP EI PL NZ NA PO NC
0B1C:0100 01D8          ADD     AX,BX

Теперь первой командой на старте стоит наша команда сложения. И видно, что она занимает два байта и закодирована в машинный код 01D8 .

Чтобы увидеть содержимое в кодах, выполним «dump», но теперь уже с параметром, иначе он покажет не с адреса 100, а выдаст следующую порцию из 128 байт (шестнадцать штук в строке, по восемь строк за раз = 128 шт.)

Кстати, обратите внимание, что вести расчёты в привычной, десятичной системе (DEC) уже неудобно. Легче считать в шестнадцатеричной (HEX). В строке 10 шт. Восемь строк по 10 шт. получается 80 шт. 80 (HEX) = 128 (DEC). Если захотите проверить, то запустите стандартный Виндовский калькулятор; через «Вид» переключитесь в Инженерный, и вводите нужные числа, предварительно тыкнув мышкой в нужный переключатель Hex, Dec, Oct или Bin . Hex – он и в Африке Hex. Dec – понятно и так. А Oct и Bin означают Восьмеричную и Двоичную системы счисления. Октава – восемь. Бинар – два. Так что у вас под рукой есть помощник, который переведёт для первого случая непонятный HEX в DEC. Но, честное слово, после нескольких упражнений вы уже наблошнитесь.

-D 100
0B1C:0100  01 D8 90 F1 32 C0 AA C3-F6 46 04 02 75 43 8B D5   ....2....F..uC..
0B1C:0110  83 C2 05 57 B8 00 6C BB-40 00 33 C9 34 00 0B 0B   ...W..l.@.3.4...
0B1C:0120  01 CD 21 5F 73 15 E8 C4-DB 3D 02 00 74 23 3D 03   ..!_s....=..t#=.
0B1C:0130  00 74 1E 3D 05 00 74 19-E9 E3 D8 8B D8 B8 00 44   .t.=..t........D
0B1C:0140  CD 21 B4 3E CD 21 F6 C2-80 75 53 F6 46 04 04 74   .!.>.!...uS.F..t
0B1C:0150  4D 8B 56 05 80 FA 00 74-05 80 FE 3A 74 02 B2 40   M.V....t...:t..@
0B1C:0160  80 CA 20 80 EA 60 E8 74-E4 73 06 E8 7F DB E9 AD   .. ..`.t.s......
0B1C:0170  D8 8B D5 83 C2 05 8A 7E-04 80 E7 06 80 FF 06 75   .......~.......u


Видите, первые два байта – это команда сложения, а третий байт – нопик. А дальше идут обрывки старых значений.

А если мы захотим посмотреть не одну первую команду? А сразу несколько! Нет проблем. Воспользуемся командой «unassemble», которая производит обратное действие – переводит машинные коды в мнемонические имена инструкций Центрального Процессора.

Даём:
-U 100
0B1C:0100 01D8          ADD     AX,BX
0B1C:0102 90            NOP
0B1C:0103 F1            DB      F1
0B1C:0104 32C0          XOR     AL,AL
0B1C:0106 AA            STOSB
0B1C:0107 C3            RET
0B1C:0108 F6460402      TEST    BYTE PTR [BP+04],02
0B1C:010C 7543          JNZ     0151
0B1C:010E 8BD5          MOV     DX,BP
0B1C:0110 83C205        ADD     DX,+05
0B1C:0113 57            PUSH    DI
0B1C:0114 B8006C        MOV     AX,6C00
0B1C:0117 BB4000        MOV     BX,0040
0B1C:011A 33C9          XOR     CX,CX
0B1C:011C 3400          XOR     AL,00
0B1C:011E 0B0B          OR      CX,[BP+DI]


По умолчанию DEBUG переводит в мнемонику порцию в 20 (32) байт. Поэтому мы видим первые две команды наши, а остальные как Бог на душу положил. Впрочем, жёсткое соответствие между адресами и кодами слева и символами справа – факт неоспоримый. С этим не поспоришь. В этом моща и ценность DEBUG.

А ещё вы должны усечь тут одну очень важную вещь – компьютер не различает где у него данные, а где у него команды Процессора! И хотя сейчас повально говорят об объектах в программировании, но Центральный Процессор об этих разговорах ничего не знает. Они ему «до лампочки».

Это ни сколько не отрицает сказанного ранее про специальные сегментные регистры. Иначе с чего бы при старте жука все сегменты были установлены на один и тот же адрес: и сегмент кодов CS, и сегмент данных DS, и сегмент стека SS . Не знает процессор, как интерпретировать содержимое байта: то ли это код для выполнения, то ли это данные?

Не удивляйтесь. Оказывается всё обилие этих разговоров нескольких поколений программистов, разработчиков, учёных, написание научных статей, книг, создание новых технологий программирования, дорогостоящие проекты с миллиардными бюджетами типа «Манхетн», различные среды 3D-моделирования и т.д., и т.п. … –

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

Ну, так это и позволяет нам с вами пользоваться «Старым Жуком»! Смотреть содержимое регистров нашего «мотора» и запускать на исполнение свои короткие программки.


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

Простейший способ выполнить одну команду процессора в дебагере – это дать команду «trace» трассировка без параметров.

Выведем информацию о регистрах (для наглядности):
-R
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0100   NV UP EI PL NZ NA PO NC
0B1C:0100 01D8          ADD     AX,BX

Даём:
-T
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL ZR NA PE NC
0B1C:0102 90            NOP

Теперь смотрим, что произошло? Регистры не изменились. (Это и понятно, ведь они были пустыми. Мы же не задали им значения!) Но команда выполнилась. Поменялся счётчик адресов (IP). И следующей, готовой к выполнению инструкцией процессора, стала уже не сложение (ADD), а нопик (NOP) по адресу 102. Но, кроме этого, обращаю ваше внимание! – изменились значения пар букв, которые всегда по команде «register» появляются справа от IP . Изменились не все, а лишь пятая и предпоследняя: было до выполнения «NZ» и «PO», а стало «ZR» и «PE».

Тут я вам расскажу, что означают эти пары букв и почему они так важны. Эти буквы – условное обозначение отдельных частей (битов) ещё одного регистра, именуемого «Flag Register» (регистром флагов). Если остальные регистры отображаются в дебагере целиком, как числа в формате HEX, то регистр флагов отображается отдельными разрядами (битами), каждый из которых может оказаться установленным в 1 или сброшенным в 0 . И каждая пара букв – это сигнал, в каком состоянии находится разряд (0 или 1) после выполнения команды центральным процессором.

Пока главное, что вы должны понять, что регистр флагов меняет флаги при выполнении инструкций Центрального Процессора. Именно по этим флагам сам ЦП анализирует своё собственное состояние и производит все логические ветвления в программах. Вы же понимаете, что единственным «живым» органом является именно ЦП, и только он в состоянии следить за исполнением программы. А то, что дебагер держит перед вами текстовое представление регистров, адресов и флагов – есть лишь удачная и очень хитрая эмуляция работы Центрального Процессора, который в этот момент занят какими-то своими неотложными системными делами, и уделяет дебагеру лишь часть своего процессорного времени. Причём, не только потому, что вы работаете в многозадачной Виндоус. Даже в DOS, где выполняется лишь одна задача пользователя, всё равно Центральный Процессор всегда занят хотя бы регенерацией памяти, чтобы её значение «не вытекло».

Мы выполнили арифметическую команду сложения «ADD AX,BX» вот и изменились значения двух флагов: флага нуля «Zero Flag» (значение «NZ» – «No Zero» – «Не ноль» = 0, сменилось на значение «ZR» – «ZeRo» – «Ноль» = 1), и флага чётности (или флага паритета) «Parity Flag» (значение «PO» – «Паритет не чётный» = 0, сменилось на «PE» – «Паритет чётный» = 1).

Почему флаг нуля устанавливается в 1, когда результат 0? И наоборот, равен 0, когда результат ему не равен? Эти вопросы не ко мне. Адресуйте их разработчикам вашего «мотора». Хотя, если вы подумаете, то поймёте: флаг установленный означает «Да» (условие выполняется), флаг сброшенный означает «Нет» (условие не выполняется).

У нас в регистрах AX и BX вначале были нули, поэтому после сложения условие нуля выполнилось, флаг установился в 1. А единичек в результате вообще нет – при этом случае паритет тоже считается чётным, то есть флаг установлен в 1.


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


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

Это точно так же, как изучение алфавита в первом классе.

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



Как задать значение в регистры и снова повторить нашу команду, ведь не нули же мы вечно будем складывать!


А вот так:
-R AX
AX 0000
:_

дебагер ждёт ввода нового значения.

Вводим, например, 2 и жмём <Enter>

Теперь посмотрим:
-R
AX=0002  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL ZR NA PE NC
0B1C:0102 90            NOP

Теперь таким же образом вернём счётчик команд на адрес 100.

-R IP
IP 0102
:100 и жмём <Enter>

-R
AX=0002  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0100   NV UP EI PL ZR NA PE NC
0B1C:0100 01D8          ADD     AX,BX

-T
AX=0002  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP


Почему же содержимое регистров не изменилось? Ни AX, ни BX? Или инструкция сложения ADD не сработала?

Ну-ка, повторим ещё и ещё раз!

Сделаем это теперь при помощи команды «go», которая запускает программу с указанного адреса, а «тормозит» в заданном адресе:

-G=100 102
AX=0002  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000

DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP

Чтобы повторить туже самую команду, просто «утопите» клавишу <Стрелка вправо>, и команда вернётся сама, словно вы её набрали с клавиатуры снова. И снова пускайте её на исполнение нажатием <Enter>.

-G=100 102

AX=0002  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP


-G=100 102

AX=0002  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP
-

Ничего не меняется! В чём причина? Сломался Центральный Процессор? Ну, что вы! Всё очень и очень просто. Результат сложения помещается в регистр AX. А к содержимому AX каждый раз добавляется содержимое BX. А мы его оставили нулевым! Вот и не меняется. Сколько к двойке ноль не прибавляй – результат будет два.

Давайте поменяем содержимое регистров наоборот – в AX зададим ноль, а в BX положим два:

-R AX
AX 0002
:0

-R BX
BX 0000
:2

И снова начнём давать команду G=100 102 несколько раз:

-R
AX=0000  BX=0002  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP

-G=100 102
AX=0002  BX=0002  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP

-G=100 102
AX=0004  BX=0002  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP

-G=100 102
AX=0006  BX=0002  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PE NC
0B1C:0102 90            NOP


Теперь дело наладилось! AX копит содержимое BX.

Кстати, AX называется регистром «аккумулятором». Он предназначен изначально (при проектировании) для накопления. Однако это совсем не значит, что обратная запись команды сложения ADD будет работать по-другому. Проверим?

Меняем в команде сложения регистры:
-A 100
0B1C:0100 ADD BX,AX
0B1C:0102

Задаём в AX двойку:
-R AX
AX 0006
:2

В регистр BX кладём ноль:
-R BX
BX 0002
:0

И снова пошли по кругу:

-R
AX=0002  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PE NC
0B1C:0102 90            NOP

-G=100 102
AX=0002  BX=0002  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP

-G=100 102
AX=0002  BX=0004  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PO NC
0B1C:0102 90            NOP

-G=100 102
AX=0002  BX=0006  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B1C  ES=0B1C  SS=0B1C  CS=0B1C  IP=0102   NV UP EI PL NZ NA PE NC
0B1C:0102 90            NOP


Работает.

Правда, мы не видим нашу модифицированную команду:
         ADD BX,AX

Каждый раз перед глазами следующая за ней команда NOP, но по содержимому регистров понятно, что сложение работает, причём теперь – в обратном порядке. Результат накапливается уже в BX, а значение AX остаётся неизменным.

Вот тут вы должны усечь, что запись
         ADD AX,BX
и
         ADD BX,AX
существенно различаются.

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


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

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

 0 ( 0) = 0000000000000000 «PE» = 1
 1 ( 1) = 0000000000000001 «PO» = 0
 2 ( 2) = 0000000000000010 «PO» = 0
 3 ( 3) = 0000000000000011 «PE» = 1
 4 ( 4) = 0000000000000100 «PO» = 0
 5 ( 5) = 0000000000000101 «PE» = 1
 6 ( 6) = 0000000000000110 «PE» = 1
 7 ( 7) = 0000000000000111 «PO» = 0
 8 ( 8) = 0000000000001000 «PO» = 0
 9 ( 9) = 0000000000001001 «PE» = 1
 A (10) = 0000000000001010 «PE» = 1
 B (11) = 0000000000001011 «PO» = 0
 C (12) = 0000000000001100 «PE» = 1
 D (13) = 0000000000001101 «PO» = 0
 E (14) = 0000000000001110 «PO» = 0
 F (15) = 0000000000001111 «PE» = 1
10 (16) = 0000000000010000 «PO» = 0
. . .
и т.д.


Понятно, что на следующем шаге 6 + 2 = 8 и флаг опять поменяется – число единичек станет снова нечётным. А ещё через шаг 8 + 2 = A , снова будет сигналить о чётности числа единичек. Так что не путайте этот сигнал с признаком арифметической «чётности» числа (делимости на два). Все чётные числа (нацело делящиеся на два) имеют младший разряд равный нулю. А флаг паритета генерирует сигналы о другом – «о количестве единичек».

Зачем я вас мучаю этими блошиными шажками вокруг и около? С единственной целью, чтобы вы научились самостоятельно СТАВИТЬ ЭКСПЕРИМЕНТЫ на своём вычислителе. Чтобы не принимали на веру все слова из различных источников. В текстах могут быть ошибки, и будут – никуда от этого не деться. А вам нужно понять, как работает именно Ваш «мотор» – ваш Центральный Процессор, что именно Он делает в результате выполнения каждой своей инструкции! И тут вычислительный эксперимент – вещь незаменимая.

Если бы у вас в руках оказался программируемый калькулятор, то вы, наверное, тоже не один раз попробовали каждую его команду, да ещё и в разных вариантах. И только бы уже потом, стали писать программку (мысленно представляя себе последствия выполнения каждой из них). А как иначе?


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



                IV.


                Точка, точка, запятая…



Пишем программу для замены в файле FIL1.TXT кода "запятой" 2C на код "точки" 2E.

;Сначала сохраняем в стеке регистры,
;которые изменятся в работе
       PUSH AX    ;затолкнуть AX в стек
       PUSH BX    ;           BX в стек
       PUSH CX    ;           CX в стек

;Проверим с самого начала размер загруженной строки
;в регистре CX.
       JCXZ STOP   ;если регистр пуст, то уйдём на метку
                ;STOP и закончим на этом программу

;Теперь в регистр BX берём адрес строки данных
       MOV BX,MET3

MET1:  MOV AH,[BX] ;берём в AH байт из строки по адресу в BX
       CMP AH,2C   ;проверяем значение на код "запятой"
       JNE MET2    ;если не равно 2C, то идём на MET2
       MOV AH,2E   ;иначе код "точки" в AH
       MOV [BX],AH ;и возвращаем AH в строку
MET2:  INC BX      ;увеличиваем адрес байта на 1
       LOOP MET1   ;цикл по регистру CX с возвратом на MET1

;Теперь восстанавливаем регистры из стека в обратном порядке
       POP CX ;вытолкнуть из стека в регистр CX
       POP BX ;   в  BX
       POP AX ;   в  AX
STOP:  NOP    ; нет операции
MET3:  NOP    ; нет операции

Теперь переходим к набору

С:\DEBUG>debug
-a 100
166C:0100 push ax
166C:0101 push bx
166C:0102 push cx
166C:0103 jcxz 100
166C:0105 mov bx,100
166C:0108 mov ah,[bx]
166C:010A cmp ah,2c
166C:010D jne 100

166C:010F mov ah,2e
166C:0111 mov [bx],ah
166C:0113 inc bx
166C:0114 loop 108
166C:0116 pop cx
166C:0117 pop bx
166C:0118 pop ax
166C:0119 nop
166C:011A nop
166C:011B
-

Вот так будет выглядеть первый (предварительный) набор этой программы. Посмотрите, в строках 103, 105, 10D - стоят неверные адреса. В момент набора я их ещё не знаю. И ставлю вместо них стартовый адрес. И только метка для цикла в строке 114 стоит правильно, потому что его переход находится выше этой команды. В момент набора он мне уже известен = 108.

Когда я введу все команды, то я узнаю значения для всех меток:
MET1: = 108
MET2: = 113
STOP: = 119
MET3: = 11A

Теперь их надо правильно записать в команды.

Вносим коррекцию:

-a 103
166C:0103 jcxz 119
166C:0105
-a 105
166C:0105 mov bx,11A
166C:0108
-a 10d
166C:010D jne 113
166C:010F
-

Теперь вывожу на экран программу для контроля
-u 100 11A
166C:0100 50            PUSH    AX
166C:0101 53            PUSH    BX
166C:0102 51            PUSH    CX
166C:0103 E314          JCXZ    0119
166C:0105 BB1A01        MOV     BX,011A
166C:0108 8A27          MOV     AH,[BX]
166C:010A 80FC2C        CMP     AH,2C
166C:010D 7504          JNZ     0113
166C:010F B42E          MOV     AH,2E
166C:0111 8827          MOV     [BX],AH
166C:0113 43            INC     BX
166C:0114 E2F2          LOOP    0108
166C:0116 59            POP     CX
166C:0117 5B            POP     BX
166C:0118 58            POP     AX
166C:0119 90            NOP
166C:011A 90            NOP
-


Вот это уже наш "рабочий" вариант.

В отличии от набора по команде "assemble", команда "unasseble" уже переводит буквы в большие, иногда меняет мнемонику инструкции на собственную нотацию (сохраняя её смысл), а главное - выдаёт машинные коды рядом с адресами. И уже видно какая команда как кодируется и сколько байт занимает в памяти компьютера. А значит, даже на интуитивном уровне, вы будете стараться использовать команды меньших размеров, и ваши программы со временем станут более компактными!

А так как процесс ввода очень "кропотлив", то опять же "волей не волей" вам придётся стараться писать маленькие программки. И это ограничение снова повышает ваше мастерство!

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


Теперь загрузим строку и проверим программу в работе.

-nfil1.txt   ;задаю имя файла FIL1.TXT для загрузки в DEBUG

-r ;для наглядности предварительно смотрю значение регистров
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=166C  ES=166C  SS=166C  CS=166C  IP=0100   NV UP EI PL NZ NA PO NC
166C:0100 50            PUSH    AX

-l 11A ;даю команду: загрузить файл с объявленным именем с адреса 11A

-r ;смотрю сколько байт загрузилось (их значение в регистре CX)
AX=0000  BX=0000  CX=0017  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=166C  ES=166C  SS=166C  CS=166C  IP=0100   NV UP EI PL NZ NA PO NC
166C:0100 50            PUSH    AX

-d 11A l 17 ;смотрю с адреса 11A длиной 17 байт загруженную строку
166C:0110                28 31 30 30 2F 35             (100/5
166C:0120  2F 35 2B 35 29 2F 32 20-3D 20 34 2C 35 20 20 0D   /5+5)/2 = 4,5  .
166C:0130  0A                .

-g=100 119 ;делаю пробный запуск программки c адреса 100 , а "торможу" на нопике в адресе 119

AX=0000  BX=0000  CX=0017  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=166C  ES=166C  SS=166C  CS=166C  IP=0119   NV UP EI PL NZ NA PO CY
166C:0119 90            NOP
-

Обратите внимание, что значение регистров AX, BX, CX осталось таким же как и перед запуском. И указатель вершины стека (регистр SP) тоже вернулся в первоначальное состояние. Это очень важно! Без предварительного сохранения в стеке, и последующего восстановления его значения из стека (в конце программки), CX был бы пуст (исчерпался бы в цикле), а в регистре AX (его старшей части AH) находился бы последний обработанный в строке символ, а в BX находился бы адрес, ссылающийся уже за пределы строки. И было бы уже невозможно правильно выполнить команду дебагера

-w 11A

Которая записывает из памяти с адреса 11A число байт, которое в свою очередь составляет из содержимого трёх регистров: AX:BX:CX, при чём младшая часть - это CX, средняя - BX, а старшая - AX. И записывает обратно в файл, с именем, объявленным ранее по команде n.


Ну, вот мы и смастерили нашу "заплатку" против досадного расхождения точки с запятой.


Теперь сохраним нашу программу в виде машинных кодов на диск в файле PROG#001.BIN . Как это сделать? Да точно так же, как мы только что читали из файла FIL1.TXT и писали в него. Только регистр CX мы на этот раз должны установить сами, а сопутствующие ему (BX и AX) проверить - не прицепили ли мы килобайты и мегабайты попутно из памяти?

Мы знаем, что наша программа начинается с адреса 100, а заканчивается адресом 119. Естественно, что разница 119 - 100 = 19 . Вот это значение заносим в CX. (Если есть сомнения, то вспомните про команду "H" дебагера - она сосчитает вам и сумму, и разницу.)


-r cx
CX 0017
:19
-

Теперь определяем новое имя файла PROG#001.BIN для нашей программы:
-nPROG#001.BIN

-

Проверяем значение регистров перед записью:
-r
AX=0000  BX=0000  CX=0019  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=166C  ES=166C  SS=166C  CS=166C  IP=0119   NV UP EI PL NZ NA PO CY
166C:0119 90            NOP
-

AX и BX чистенькие, а CX = 19 - то, что нужно.

И записываем на диск:
-w 100
Запись: 00019 байт
-

А теперь выходим по команде q из дебагера
-q

С:\DEBUG>_


 
Теперь всё это надо организовать в автоматическом режиме и запускать в качестве предварительной обработки файла FIL1.TXT из нашего пакета, в модуле KORENKUB перед склейкой вызова.

У нас есть два способа сделать это.

Первый - это вызывать PROG#001.BIN, загружая в дебагер вот такой командой:

DEBUG PROG#001.BIN<UPR#001.TXT

По этой команде наша программа PROG#001.BIN в машинных кодах загрузится в дебагер с адреса 100, а потом, вместо наших нажатий клавиш с клавиатуры (вся наша ручная работа), на вход дебагеру будет направлен поток из обычного текстового файла UPR#001.TXT, который должен содержать такие (уже понятные нам) команды для DEBUG.

nfil1.txt
l 11A
g=100 119
w 11A
q

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

Пояснения к содержимому UPR#001.TXT:
nfil1.txt ;задать имя FIL1.TXT
l 11A     ;загрузить этот файл с адреса 11A
g=100 119 ;выполнить программу от начала до нопика
w 11A     ;записать результат обратно в файл FIL1.TXT
q         ;и выйти из дебагера

Обращаю ваше внимание, что все эти команды не имеют никакого отношения к командному интерпретатору Command.com или CMD.EXE . Хотя принцип обработки один в один напоминает работу с пакетом. Получается, что дебагер сам играет роль командного интерпретатора. Нужно только знать его команды и язык, и умело ими пользоваться.

Теперь о втором способе, который на первый взгляд может показаться "странным", но в нём есть свой плюс: можно ведь хранить нашу программу в виде мнемоники самого дебагера, как текстовый файл, как исходный текст программы!

И тогда вызов нашей программы на исполнение будет слит в тот же текстовый файл управления UPR#001.TXT . Вот так:

-------------------------------
a 100
PUSH    AX
PUSH    BX
PUSH    CX
JCXZ    0119
MOV     BX,011A
MOV     AH,[BX]
CMP     AH,2C
JNZ     0113
MOV     AH,2E
MOV     [BX],AH
INC     BX
LOOP    0108
POP     CX
POP     BX
POP     AX
NOP

nfil1.txt
l 11A
g=100 119
w 11A
q
-------------------------------

Обратите внимание на пустую строку между завершающим нопиком и командой определения имени загружаемого в память файла. Она просто НЕОБХОДИМА, чтобы дебагер вышел из режима своей команды "assemble", и перешёл в режим выполнения команд работы с файлом данных и выполнения программы.

Чем привлекает такой вариант? В любой момент вы можете исправить однотипные коды на другие. Например, поменять код "запятой" и код "точки" местами, и заставить программу работать в обратную сторону!

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

Я думаю, что можно использовать оба варианта.

Там, где программа используется в однократном запуске - очень просто и наглядно взять её в мнемонике. Даже рекомендую вам иметь свой общий текстовый файл, в котором все ваши программы будут составлять вашу собственную библиотеку. Ведь работая в многооконном режиме Виндоус, вам так просто даже через системное меню окошка командной строки вставить в дебагер уже однажды набранные вами команды через его режим "assemble".

В этом случае, дебагер действительно очень сильно напоминает "Программируемый калькулятор". Если вы ещё отыщите хороший, надёжный и легкий текстовый редактор, который умеет оперировать с прямоугольными блоками выделения и вставки (каким был в своё время для всех программистов "Лексикон" Веселова для MS-DOS, - я им до сих пор пользуюсь с огромным успехом!), то ваша библиотека (текстовый файл с исходниками) может быть существенно рационализирована.

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

166C:0100 50            PUSH    AX          ;Просто этот фрагмент будет
166C:0101 53            PUSH    BX          ;разделён на три колонки.
166C:0102 51            PUSH    CX          ;
166C:0103 E314          JCXZ    0119        ;И вы будете, когда вам нужно,
166C:0105 BB1A01        MOV     BX,011A     ;выделять средний фрагмент
166C:0108 8A27          MOV     AH,[BX]     ;прямоугольным блоком, копировать
166C:010A 80FC2C        CMP     AH,2C       ;
166C:010D 7504          JNZ     0113        ;и вставлять внутрь окна
166C:010F B42E          MOV     AH,2E       ;дебагера
166C:0111 8827          MOV     [BX],AH     ;
166C:0113 43            INC     BX          ;
166C:0114 E2F2          LOOP    0108        ;а комментарии и адреса
166C:0116 59            POP     CX          ;останутся на месте
166C:0117 5B            POP     BX          ;внутри текстового
166C:0118 58            POP     AX          ;файла библиотеки
166C:0119 90            NOP                ;ваших программ
166C:011A 90            NOP                ;


Если бы Word был "полегче", то я бы мог вам сказать - пользуйтесь им. Он умеет работать с прямоугольными блоками: сочетание клавиш <Ctrl>+<Shift>+F8 начинает выделение такого блока. Но делает это так топорно, что просто - мучение. Надо использовать для него пропорциональный шрифт (например, Courier New) - это раз. А во-вторых, его строки обрываются сами собой по концу ввода. И с этой "гребёнкой" можно умом рехнуться! Как просто всё в "Лексиконе". Гуляешь по экрану в тексте, как у себя дома. Курсор никуда не скачет по концам строк. Ловить его не нужно. Прямоугольные блоки строятся не взирая на концы строк. Если надо добавить пробелы, редактор Евгения Веселова сам это делает.

А уж о навязчивости "сэрвиса" Word-а я уже не говорю. Каких только преобразований с текстом он не начинает без всякого вашего запроса!

EDIT.COM - не плох. Легкий, многооконный. Но с прямоугольными блоками не работает.

А если я скажу вам, что Веселовский "Лексикон" для MS-DOS занимает 70 Кб и при этом имеет встроенный (хотя и примитивный) язык макросов! Вы тогда слюнкой захлебнётесь. И даже умеет выполнять предопределённый макрос при своём старте. И если вы напишите в этом макросе команду в конце, означающую "завершить редактирование, сохранить файл и выйти", то он всё это сделает без ваших ручек. И тогда вообще, он может рассматриваться, как ещё один командный интерпретатор, только уже для обработки текста программ. Не даром его Веселов назвал "Текстовый процессор", ох, не даром.

(Речь везде веду о "Лексиконе" самых первых версий - все последующие "утяжеления" его привели к деградации, а клинической смертью стало переписывание под стиль Windows и переориентация на работу исключительно с документами. - Стали соревноваться с Майкрософт. А сделали только себе хуже. Угробили великолепную идею в погоне за прибылЯми.)



И всё же.

Для задач (подобно нашей) с многочисленными запусками, оба описанных мною варианта (и в машинных кодах - в виде файла *.BIN; и в мнемонике дебагера, как довесок к управляющему текстовому файлу) - "не фонтан". Хотя компьютеры сейчас настолько быстро работают, что можно вытерпеть любой из них. И всё же, просматривается хороший вариант программки на ассемблере по замене в файле одного символа на другой. Желательно и коды символов, и имя файла - задавать в командной строке. И тогда такой "кирпичик" можно будет с успехом применять в своих пакетах, наравне с фирменными программками.

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

Но если вы дорастёте до такого уровня, то вам уже прямая дорога к транслятору MASM.EXE (макроассемблеру Микрософт), языку, который работает с исходными текстами программ, генерирует листинги, объектные модули. В комплекте будет линковщик (Link.exe), который будет собирать эти модули в единый EXE-файл, используя библиотеки. Будет и свой библиотекарь LIB.EXE, который будет объединять объектные модули в один файл. Понадобится программа EXE2BIN, которая будет переводить из EXE-формата в COM-формат. И конечно, центральное место будет занимать пухлая документация по всем этим программам, по инструкциям "вашего мотора", и по системным вызовам встроенных функций.




                *          *          *

Что такое мир программирования? Он очень притягателен. Он очень странен. Он занимает промежуточное положение между реальным Миром нашей Вселенной и тем Миром Теней, где обитают умершие души - ушедшие от нас, и растворившиеся в мире Идей.

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

Вы будете путешествовать по нему на своём "космическом корабле" - Центральном Процессоре - от одного алгоритма к другому. Вы будете совершать удивительные открытия! Вот эта "планета"-алгоритм, найденная вами в "звёздном" скоплении простых чисел, оказывается открыта много веков назад и носит загадочное имя - "Решето Эсфера". А вот эта "планета", всегда считавшаяся неприступной, вдруг откроет перед вами свои покровы, и одарит вас своими, поверженными вашим интеллектом, Тайнами. И вы будете всю жизнь гордиться, что сумели взять "на абордаж" Проблему Коня. А та маленькая и такая красивая "планетка", будет именоваться, так как вы пожелаете - ибо, вы первый, кто открыл её для Человечества! И возможно её вы назовёте Алгоритмом Волны...



Надеюсь, вы запомните того безымянного старого духа, висящего в пустоте более бесконечной чем вся Вселенная; того "сталкера", который привёл вас к этой волшебной "зоне" и показал дорогу.

Стоит лишь углубиться по ней в безмерную глубину, и вы уйдёте в этот мир навсегда.


Счастливого пути!




НЕ ХЛЕБОМ ЕДИНЫМ...



4:42:01 21.05.2011





Список литературы:


Учебники и справочники по программированию на ассемблере
http://skachivaem.ru/books/16-books.html

Вот список, доступный для закачек:

 1.  язык ассемблера уроки программирования 
http://skachivaem.ru/books/16-books/137-books.html

Книга является простым и доступным для широкого круга пользователей пособием по программированию на языке ассемблера для персональных компьютеров IBM PC. Рассматриваются основы разработки программ, аппаратная организация компьютера, использование системных средств DOS и BIOS, программирование сопроцессора и защищенного режима. Отдельный раздел посвящен разработке прикладных драйверов Windows для управления нестандартной аппаратурой. Для читателей, не являющихся профессионалами-программистами, но имеющих дело с персональными компьютерами, а также студентов вузов, аспирантов и преподавателей.
весит 8,75 МБ



 2.  ассемблер на примерах базовый курс 
http://skachivaem.ru/books/16-books/136-books.html

 3.  assembler второе издание 
http://skachivaem.ru/books/16-books/135-books.html

 4.  assembler учебный курс 
http://skachivaem.ru/books/16-books/134-books.html

 5.  искусство программирования на ассемблере 
http://skachivaem.ru/books/16-books/133-books.html

 6.  Ассемблер и дизассемблирование 
http://skachivaem.ru/books/16-books/132-books.html

 7.  Ассемблер для процессоров Intel Pentium 
http://skachivaem.ru/books/16-books/131-books.html

 8.  ассемблера разработок и оптимизация windows-приложений 
http://skachivaem.ru/books/16-books/130--windows-.html

 9.  язык ассемблера для процессоров intel 
http://skachivaem.ru/books/16-books/129--intel.html

10.  Ассемблер в задачах защиты информации 

11.  Ассемблер для Windows 
http://skachivaem.ru/books/16-books/127--windows.html

12.  Assembler. Практикум 
http://skachivaem.ru/books/16-books/126-assembler-.html

13.  kmdtut программирование драйверов 
http://skachivaem.ru/books/16-books/125-kmdtut.html

14.  Assembler: учебный курс 2 
http://skachivaem.ru/books/16-books/124-assembler.html

15.  Иллюстрированный самоучитель по Ассемблеру 

16.  работа над файлами 

17.  ассемблер это просто 
весит 78,1 Кб

18.  zubkov 
http://skachivaem.ru/books/16-books/120-zubkovchm.html

19.  справочник по командам ассемблера
весит 20,7 Кб




Основы программирования на ассемблере

Учебное пособие подготовлено по материалам книги:
П. Нортон, Д. Соухе. Язык ассемблера для IBM PC:
Пер. с англ., - М.: Компьютер, 1993. - 352 с., ил.


Одна из страниц из этой книги называется
"Арифметика микропроцессора Intel x86"




Система команд i-x86
http://www.hardline.ru/3/26/3641/



                ПРИЛОЖЕНИЕ

Выдержка из файла ASMDOS1.DOC --> X:\98\DOC\ASM&DOS1\ASMDOS1.ZIP
X: --> Лазерный диск "Программирование от А до Я" Том 2. обнов.

     Сегменты

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

     Существуют три основных типа сегментов:

- сегмент кода - содержит машинные команды, адресуется регистром CS;

- сегмент данных - содержит данные, то есть константы и рабочие области, необходимые программе. Адресуется регистром DS;

- сегмент стека - содержит адреса возврата в точку вызова подпрограмм. Адресуется регистром SS.

     Каждый из упомянутых регистров содержит адрес начала сегмента (базовый адрес). В программе все адреса записаны относительно начала сегмента, и они определяются как смещение (offset) от начала сегмента. Двухбайтовое смещение (одно слово) может принимать значение от 0000 до 0FFFFh. Для того, чтобы выполнить обращение по любому адресу процессор выполняет суммирование адреса, записанного в регистре сегмента, со смещением. При этом, содержимое регистра сдвигается на четыре двоичных разряда влево. Результирующий адрес занимает 20 позиций, что и позволяет адресовать 1 Мбайт памяти.

Пример.

Содержимое DS 045F
+
Смещение 0032
---------------------
Исполнительный 04622
адрес (EA)


Примечание: Адреса шестнадцатеричные.



     РЕЖИМЫ АДРЕСАЦИИ

Режим адресации                Формат адреса       Стандартный сегментный регистр
Регистровая                регистр                Нет

Непосредственная               данные                Нет

Косвенная регистровая
                [BX]                DS
                [BP]                SS
                [DI]                DS
                [SI]                DS
По базе со смещением
                метка [BX]                DS
                метка [BP]                SS
Прямая
                метка [DI]                DS

с индексированием
                метка [SI]                DS

По базе
                метка [BX + SI]                DS
с индексированием
                метка [BX + DI]                DS
                метка [BP + SI]                SS
                метка [BP + DI]                SS

Строковые команды

исходный адрес                DS:SI
место назначения                ES:DI


*  Метка [...] может быть заменена  на [смещение + ...].
Следовательно, запись [24 + BX] будет означать адрес 24+ВХ.


Примечание: Многие строковые команды используют ES:DI как место назначения, а DS:SI как адрес источника.


Рецензии
Ссылки на Старого Жука

Так как отображение текста в браузере «хромает» и из текста пакетных файлов выпадают параметры со знаком «процент», то вот ссылки на оригинальный текст:

http://narod.ru/disk/13563535001/Debugtxt.zip.html
Debugtxt.zip = 62 648 байт
«Старый Жук».txt = 163 200 байт (CRC 32 = 12DC9660 под WinRAR 3.41)

http://narod.ru/disk/13563673001/Debugdoc.zip.html
Debugdoc.zip = 146 573 байт
«Старый Жук».doc = 704 512 байт (CRC 32 = 0CCEF96F под WinRAR 3.41)

Тексты идентичны. Различен лишь формат и размер.

Ссылки будут актуальны 3 месяца с момента размещения.

Мудman   21.05.2011 15:05     Заявить о нарушении
Примечание: Уф! Похоже выкрутился… Заменил везде «прОцент» на «прОцент» с пробелом. Зато теперь проценты отражает. Вы уж соображайте там. Шевелите мозгою. Ладно?

Автор

Мудman   21.05.2011 22:17   Заявить о нарушении
Очень трудно отыскать "продвинутость" в вычислительных способностях современной версии командного интерпретатора CMD.EXE , когда имеешь под рукой для сравнения старенький ACALC.EXE . Посудите сами, - вот я даю две одинаковые команды на вход этим программам, а получаю диаметрально противоположный результат.

C:\debug>acalc 65536*65536
65536*65536 = 4294967296

C:\debug>set /a Xo=65536*65536
0
C:\debug>_

Причём, я понимаю, что и второй результат по-своему верен (просто числа, которые способен вычислять CMD все ограничены 32-мя разрядами), но ... Где же хотя бы сообщение об ошибке? Значение потеряли, и как будто так и надо! Где сообщение о переходе через знак? Ведь числа CMD считает со знаком, значит 32-й разряд служит не для счёта, а для знака. Это что? Мода сейчас такая - игнорировать ошибки при вычислении?

Увеличим нагрузку:

C:\debug>acalc 65536*65536*65536
65536*65536*65536 = 281474976710656

C:\debug>set /a Xo=65536*65536*65536
0
C:\debug>_

И снова, ACALC.EXE справился, а CMD.EXE , как твердил упрямо "ноль", так и твердит.

Увеличим нагрузку ещё раз:

C:\debug>acalc 65536*65536*65536*65536
Ошибка при вычислениях с плавающей точкой

C:\debug>set /a Xo=65536*65536*65536*65536
0
C:\debug>_

И снова - ACALC.EXE сообщает об ошибке, а CMD.EXE - игнорирует.

Давайте посмотрим, может быть CMD.EXE хотя бы код ошибки даёт?

Напишем простой пакет:

@ECHO OFF
REM Установка начальных значений
SET Xo=2
SET Yo=1

REM Выполняем цикл в поисках ошибки
:METKA0
SET /A Yo=Yo+1
SET /A Xo=Xo*2
ECHO 2 в степени % Yo % = % Xo % Код ошибки = % ERRORLEVEL %
REM Повторять, пока результат не равен 0
IF % Xo % NEQ 0 GOTO METKA0

REM Естественно дальше мы будем получать нулевой результат
:METKA1
SET /A Yo=Yo+1
SET /A Xo=Xo*2
ECHO 2 в степени % Yo % = % Xo % Код ошибки = % ERRORLEVEL %
REM Повторять, пока степень меньше 32
IF % Yo % LSS 32 GOTO METKA1

Вот протокол его работы:
2 в степени 2 = 4 Код ошибки = 0
2 в степени 3 = 8 Код ошибки = 0
2 в степени 4 = 16 Код ошибки = 0
2 в степени 5 = 32 Код ошибки = 0
2 в степени 6 = 64 Код ошибки = 0
2 в степени 7 = 128 Код ошибки = 0
2 в степени 8 = 256 Код ошибки = 0
2 в степени 9 = 512 Код ошибки = 0
2 в степени 10 = 1024 Код ошибки = 0
2 в степени 11 = 2048 Код ошибки = 0
2 в степени 12 = 4096 Код ошибки = 0
2 в степени 13 = 8192 Код ошибки = 0
2 в степени 14 = 16384 Код ошибки = 0
2 в степени 15 = 32768 Код ошибки = 0
2 в степени 16 = 65536 Код ошибки = 0
2 в степени 17 = 131072 Код ошибки = 0
2 в степени 18 = 262144 Код ошибки = 0
2 в степени 19 = 524288 Код ошибки = 0
2 в степени 20 = 1048576 Код ошибки = 0
2 в степени 21 = 2097152 Код ошибки = 0
2 в степени 22 = 4194304 Код ошибки = 0
2 в степени 23 = 8388608 Код ошибки = 0
2 в степени 24 = 16777216 Код ошибки = 0
2 в степени 25 = 33554432 Код ошибки = 0
2 в степени 26 = 67108864 Код ошибки = 0
2 в степени 27 = 134217728 Код ошибки = 0
2 в степени 28 = 268435456 Код ошибки = 0
2 в степени 29 = 536870912 Код ошибки = 0
2 в степени 30 = 1073741824 Код ошибки = 0
2 в степени 31 = -2147483648 Код ошибки = 0
2 в степени 32 = 0 Код ошибки = 0
2 в степени 33 = 0 Код ошибки = 0

Модет быть, код ошибки у меня в пакете не верно выводится?

Проверим:
@ECHO OFF
SET Xo=100
SET Yo=4
:METKA
SET /A Zo=Xo/Yo
ECHO % Xo % / % Yo % = % Zo % Код ошибки = % ERRORLEVEL %
SET /A Yo=Yo-2
REM Повторять, пока Yo не равно -2
IF % Yo % NEQ -2 GOTO METKA

Теперь посмотрим, как это работает:
100/4 = 25 Код ошибки = 0
100/2 = 50 Код ошибки = 0
Ошибка деления на ноль.
100/0 = 50 Код ошибки = 9169

То есть, пакет ошибку ловит верно. А в предыдущем примере она просто не генерируется! Обратите внимание, что результат Zo после ошибочного деления на ноль сохранил прежнее значение.

.

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

Мудman   22.05.2011 20:55   Заявить о нарушении
Довесочек для ищущих.

http://narod.ru/disk/13947089001/MASM.zip.html

MASM.ZIP - 226 410 байт

Внутри архива в папке MASM лежат:

Макро Ассемблер
MASM.EXE - 110 704 байт (CRC32=7E383507)

Линковщик
LINK.EXE - 39 076 байт (CRC32=312FA461)

Папка DOC (документация на русском)
30 файлов TXT - 542 200 байт

Даже если вы не собираетесь программировать в MASM, всё равно настоятельно рекомендую скачать ради документации и читать четвёртую часть - "Справочное руководство по командам микропроцессора". Это как раз то, что вам нужно. И тогда Дебагер будет для вас, как раскрытая книга.

.

http://narod.ru/disk/13947098001/LEXICON.zip.html

LEXICON.ZIP - 86 962 байт

Внутри архива в папке LEXICON лежат:

Текстовый процессор "Лексикон" Евгения Веселова
LEXICON.EXE - 70 896 байт (CRC32=905FE8C1)
KEYMACRO.LEX - 530 байт - файл макросов
PARAM.LEX - 277 байт - файл конфигурации

А также русификатор (для тех, у кого не набираются в окне командной строки русские буквы). Раскладку клавиатуры я сделал под Windows, экранные шрифты подправил (появилась буква Ё и №). Переключатель РУС/ЛАТ - правый <Ctrl>.
KEYRUS.COM - 22 351 байт (CRC32=994B3851)

Рекомендую запускать KEYRUS только для запуска редактора текстов LEXICON или EDIT в отдельном окне. А основную работу с командной строкой проводить в своём окне.

И в качестве бонуса я положил свою маленькую программку, написанную на Visual Basic v6.0 . Она умеет выдавать ASCII и Scan коды любой нажатой клавиши, фиксировать положение модификаторов (Ctrl, Alt, Shift), отмечать нажатие и отпускание клавиши.
Keyboard.EXE - 24 576 байт (CRC32=9EDFB033)

Будет полезна тем, кто займётся написанием своих кодов на реакцию пользователя на клавиатуре. Она ответит на все ваши вопросы: какая клавиша какой код генерирует.

7:11:22 25.05.2011

Мудman   25.05.2011 06:17   Заявить о нарушении
Про Лексикон

Первые версии Лексикона Евгений Веселов создавал на общественных началах, когда в СССР ещё не завозили фирменные IBM PC. В нашем распоряжении были клоны различных сборок. Клавиатура таких подобий была русифицирована вплоть до замены надписей на регистровых клавишах. Например, вместо F1 - было написано Ф1; вместо Ctrl – Упр; вместо Alt – Доп; вместо Shift – Заг. Ни кто ведь не думал, что до развала Империи СССР и краха «железного занавеса» оставались считанные годы. И все принимали «правила игры», навязанные КПСС, и приспосабливались под реалии дня. Вот поэтому Лексикон, который я выложил, обладает архаичным сленгом.

Но при всём при этом, его функциональность (с точки зрения программиста, нуждающегося в хорошем многооконном редакторе, умеющим работать с прямоугольными блоками) остаётся на высоком уровне. Современные Майкрософтовские Блокнот, WordPad и Word не выдерживают конкуренции со старым Лексиконом. Блокнот слишком прост и неуклюж. А другие наследуют идеологию от издательских систем. Они не предназначены для написания программ.

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

Не всегда задачу приходится решать кропотливо, выдумывая сложный алгоритм. Если задача одноразовая, то легче решить её «в лоб», иногда путём повторения в командном файле однотипных строк, в которых будут меняться только, например, имена входных файлов для обработки. (Тем более что вы лучше меня знаете, - задачи порой возникают непредвиденно, по инициативе начальства. А им всегда, всё надо «срочно». Времени «на подумать» - у вас просто нет.)

Список входных файлов мы получим без труда, при помощи команды:

DIR *.* /B>LIST.TXT

перенаправив его в файл LIST.TXT .

Далее программист грузит этот список в текстовый редактор, и ему надо поставить колонку имён в колонку строк команд (которые он уже размножил в другом файле и подогнал по количеству, чтобы их было столько же).

И тут выясняется, что «пришить» прямоугольный блок – нечем! И нужно либо переносить вручную каждое имя из списка, либо начинать мудрить с командой FOR, либо писать макрос под Word. (О том, что Word умеет работать с прямоугольными блоками, ни где в документации не упоминается! – это, видимо, недокументированная функция – <Ctrl>+<Shift>+<F8>.) Но работает он с блоками отвратительно.

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

EDIT.COM – редактор MS-DOS с прямоугольными блоками не работает, но в системном меню его окошка есть возможность выделить любую видимую часть на экране – и именно прямоугольным блоком. Но только то, что попадает в поле зрения экрана в текущем окне. А если вам надо 300 строк взять в прямоугольный блок? Что тогда? - Делать это порциями «поэкранно»? … Замучаетесь.

«Прямоугольный блок» для программиста очень важен. Он позволяет генерировать текст одноразовой программы за очень короткое время (которая вам больше никогда не понадобится, и которую вы сотрёте после использования без сожаления), давая существенную экономию труда. Ведь командному интерпретатору совершенно без разницы – 2 строки выполнить в пакете, 102 или 1002. Иногда такое нарочитое упрощение задачи, позволяет выполнять большой объём работы, на которую обычный оператор убил бы день, и два, и три…

Поэтому не пренебрегайте Лексиконом. Эта старая программа написана Евгением Веселовым не для того, чтобы «бабла срубить» и «впарить мозги» клиенту. Он её писал для себя. Первые версии проходили отладку «на пиве». Он обещал каждому, кто отыщет ошибку в редакторе – бутылку пива. И так постепенно сообщество любителей пива переловило все ошибки…
;-)

Жаль, у меня нет документации на Лексикон в электронном виде. Я им пользуюсь уже более 20 лет, и руки сами привыкли к сочетаниям клавиш. Я вам указал вначале, как перевести старые названия управляющих клавиш. А в меню все они прописаны в качестве подсказок.

Например, прямоугольный блок начинает выделяться при нажатии <Shift>+<F3>, потом расширяете его до нужных размеров и забираете внутрь буфера <Ctrl>+<F3>. Подгоняете курсор к нужному месту и вставляете <Shift>+<F4>. Потом сбрасываете выделение <F4> или <Esc>. Все эти сочетания есть в меню (вход туда по <F10>).

Аналогично строковый блок: <F3> - <Ctrl>+<F3> - … - <Ctrl>+<F4> - <F4>.

Чего вам ни кто не подскажет изнутри – выключите «Num Lock» при работе с Лексиконом!

.

Некоторые полезные сочетания для Лексикона:

<Shift>+«стрелка» - переход на границу в выбранном направлении. Если стрелка вверх, то на начало файла (позиция в строке при этом не меняется – это очень правильно!); стрелка вниз – на конец файла; стрелка влево – на первую позицию; стрелка вправо – в крайнюю правую позицию (определяется настройкой абзаца). Каждая строка Лексикона не продолжается до бесконечности – максимальный размер строки 251 символ.

Последнюю строку в файле можно использовать, как аналог клавиш <Ctrl>+A, <Ctrl>+X в Майкрософтовских редакторах. Вот как это делается: <Shift>+«стрелка вниз» - перешли в последнюю строку; <F3> - выделили строчным блоком эту строку; <Ctrl>+<F3> - забрали в «карман». В любом другом месте в «карман» (так называется внутренний буфер) попадает только выделенная строка. А если вы заберёте последнюю строку, то заберёте весь текст в окне.

Переход от одного окна к другому по <Alt>+«цифра» - это номер окна. Окон всего 10 шт. от 1 до 0. Можно менять цвет фона окна, цвет букв, цвет рамки. Можно менять размер окна на экране, располагая их самым причудливым образом.

А ещё есть встроенное средство для записи макросов – ничего казалось бы особенного: просто нажимаете <F2>, а потом любую клавишу, какую вам надо. Но вместо отработки нажатой клавиши появляется управляющая запись для неё. Собрав все такие управляющие названия нужных вам нажатий вместе, вы можете затем объявить букву макроса и вставить внутрь все эти записи. Не смотрите, что отражается только одна строка макроса из меню. Её можно прокручивать. Или прописать свой макрос в специальный файл Макросов - KEYMACRO.LEX . В нём уже есть управляющие комбинации, и, просмотрев их, вы увидите, что они должны отступать от первой позиции, а заголовок макроса с его латинской буквой должен стоять первым. Вызов на исполнение макроса из Лексикона выполняется сочетанием <Alt>+ той латинской буквы.

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

Если я сумел заинтересовать вас этой программой, то поищите документацию на Лексикон. Интернет велик и могуч. Возможно, вы откопаете в нём что-то.

Со своей стороны могу порекомендовать вам книгу:

А.И.Катаев «Текстовый процессор Лексикон», вот её выходные данные.
Катаев А.И.
К 29 Текстовый процессор ЛЕКСИКОН (от «н» до «с»). – М.: Радио и связь, 1992. – 160 с.: ил.
ISBN 5-256-01060-3.

.

Мудman   25.05.2011 16:06   Заявить о нарушении
Через всё своё обилие слов я хочу донести до вас очень простую и, казалось бы, очевидную мысль – попытка собрать в одной программе все функции, которые только можно себе представить – обречена на провал, как говорят по-русски «на всех не угодишь». Такие программы получаются безликие, сложные, лишённые концептуального единства. В них масса не состыковок, а по обилию своих разнородных возможностей они напоминают сельпо: тут мешок с картошкой стоит, тут телевизор, тут отрез сатина, тут хлебная полка, тут коробка с конфетами, тут кошка сидит, лижется…

Лучше создавать строго функциональные приложения, которые имеют узкую направленность, но и возможность работать в автономном режиме (без участия человека). Тогда управляя такими «кирпичиками» из пакета, можно освободить человека от вечного прозябания за компьютером. Пусть программы работают сами. Почему мы должны сопровождать каждый их шаг своим присутствием? Пора уже их научить ходить своими ножками…

Мудman   25.05.2011 16:44   Заявить о нарушении
Я окрылён наивной надеждой, что операторы персональных компьютеров воспримут мои слова и научатся сами для себя писать, если не «кирпичики» и модули под «Старого Жука», то хотя бы пакетные файлы! Но, к сожалению, скептицизм бывалого программиста и сисадмина шепчет мне иное.

Как правило, в организации на группу операторов из нескольких человек приходится один программист или системный администратор (это в лучшем случае!). Программистом работает мужик. А операторами - смазливые девочки, страдающие «косожопием» - это болезнь такая, когда задница «гуляет» то вправо, то влево, то вправо, то влево… Особенно это заметно сзади, при их ходьбе по коридору. Такое впечатление, что вместе с «танцем ягодиц» у них и мозговые полушария «танцуют», и в результате этого в голове не удерживаются никакие мысли.

Я в своей жизни был знаком только с одной женщиной, которая предпочитала высоким каблукам кроссовки, мотивируя это просто – мне в них удобно. Но потом и она встала на каблуки, и на этом наше с ней взаимопонимание закончилось…

Мудman   25.05.2011 17:34   Заявить о нарушении