<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=416359&amp;view=findpost&amp;p=3852600</guid>
        <pubDate>Sat, 02 Oct 2021 04:38:00 +0000</pubDate>
        <title>Некоторые возможности макроязыка TASM</title>
        <link>https://forum.sources.ru/index.php?showtopic=416359&amp;view=findpost&amp;p=3852600</link>
        <description><![CDATA[Kopa: Дополню тему такой статьёй в применении ассемблера. (Fasm)<br>
<a class='tag-url' href='https://habr.com/ru/users/forthuse/posts/' target='_blank'>Разместить FORTH в 512 байтах</a><br>
<br>
P.S. <a class='tag-url' href='https://github.com/NieDzejkob/miniforth' target='_blank'>Проект MiniForth на Github </a>]]></description>
        <author>Kopa</author>
        <category>Assembler FAQ</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=416359&amp;view=findpost&amp;p=3815519</guid>
        <pubDate>Sat, 23 Nov 2019 14:15:02 +0000</pubDate>
        <title>Некоторые возможности макроязыка TASM</title>
        <link>https://forum.sources.ru/index.php?showtopic=416359&amp;view=findpost&amp;p=3815519</link>
        <description><![CDATA[Eretic: <div class='tag-align-center'><span class='tag-size' data-value='13' style='font-size:13pt;'><span class="tag-color tag-color-named" data-value="blue" style="color: blue"><strong class='tag-b'>Некоторые возможности макроязыка TASM.</strong></span></span></div><br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Введение. </strong></span></span></div><br>
	Данная статья не является учебником по макроязыку Turbo Assembler, скорее это забавный пример его практического использования, предполагающий знания основ макроязыка. <br>
	Когда-то мне понадобилось защитить часть кода загрузчика CD-ROM. Вариант шифрования кода и данных отбросил сразу, поскольку аналогичная защита на диске «Reanimator 2K» была снята мной менее чем за день. И тогда вспомнил про старый добрый Форт, с его прямым шитым кодом, который и без шифрования создает трудный для понимания код. Вот его мы и создадим, используя макроязык Turbo Assembler. <br>
Нам понадобится TASM последней версии, то есть 5.3. Есть еще версия 5.4, но она отличается от предыдущей только копирайтом.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Имена. </strong></span></span></div><br>
	Основная проблема, которую нужно решить, заключается в том, что в Форте для имён допустимы любые символы, включая те, что TASM запрещает использовать в именах меток и идентификаторов. Вдобавок, имена в Форте могут начинаться с цифры. Поэтому, строку вида:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&#62;R R@ R&#62; ;</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script> ассемблер не воспримет. Единственным выходом является создание макроса, которому будет передаваться строка с командами Форта, а он разберет её на составляющие и скомпилирует в код, примерно так:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">_ &nbsp;&#62;R R@ R&#62; EXIT</div></ol></div></div></div></div><br>
Первым делом необходимо изъять из строки некоторые спецсимволы, которые, которые макроязык ассемблера интерпретирует особым образом. Это символы ‘&gt;’, ‘&lt;’ и ‘&#33;’. Для начала определим макрос подмены одного символа в строке:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $SWAP new, old: rest</div><div class="code_line">&nbsp;&nbsp; &nbsp;??ch equ &amp;old&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;??pos instr ??NAME, ??ch</div><div class="code_line">&nbsp;&nbsp; &nbsp;:while</div><div class="code_line">&nbsp;&nbsp; &nbsp;if ??pos</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;??prev substr ??NAME, 1, ??pos-1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;??next substr ??NAME, ??pos+1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;??NAME catstr ??prev, &#60;new&#62;, ??next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;??pos &nbsp;instr &nbsp;??NAME, ??ch</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;goto while</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">endm</div></ol></div></div></div></div>Поиск производится в строке ??NAME, штатной функцией INSTR, а строка, в случае успешного поиска символа old, разбивается функцией SUBSTR на две части – до символа (??prev) и после (??next). Затем строки склеиваются функцией CATSTR, а между ними, вместо символа old, вставляется строка new. <br>
Теперь можно написать макрос предварительной обработки строки:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $PRENAME name: rest</div><div class="code_line">&nbsp;&nbsp; &nbsp;??NAME &nbsp; equ &amp;name&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;less, &#60;&#60;</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;more, &#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;save, !</div><div class="code_line">endm</div></ol></div></div></div></div>Макрос подменяет символы ‘&gt;’, ‘&lt;’ и ‘&#33;’ на строки ‘more’, ‘less’ и ‘save’ соответственно. Это поможет корректно разбить строку на отдельные слова, но не избавит от проблем с именами подпрограмм, поскольку остаются другие недопустимые символы. Поэтому нам понадобится еще один макрос, завершающий подмену остальных символов:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $POSTNAME name</div><div class="code_line">&nbsp;&nbsp; &nbsp;??NAME &nbsp; equ &amp;name&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;plus, +</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;minus, -</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;mul, *</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;eq, =</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;div, /</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;dot, .</div><div class="code_line">&nbsp;&nbsp; &nbsp;$SWAP &nbsp; &nbsp;tld, ~</div><div class="code_line">endm</div></ol></div></div></div></div>Он будет использоваться на завершающем этапе формирования имен, когда уже будут отсеяны числа и символы. Почему не сразу? Проще это понять на примере. Допустим, имеется строка:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">54 -2 * ‘*’ !</div></ol></div></div></div></div>Если бы мы подменяли все символы сразу, то получили бы строку:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">54 minus2 mul ‘mul’ save</div></ol></div></div></div></div>То есть, вместо числа (-2) идентификатор (minus2), а вместо символа (‘*’) целую строку (‘mul’), что очевидно неправильно. Если же использовать сначала &#036;PRENAME, то получим для разбора строку:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">54 -2 * ‘*’ save</div></ol></div></div></div></div> В этой строке мы легко выберем числа и символы, а оставшиеся слова пропустим через &#036;POSTNAME и получим допустимые идентификаторы:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">mul save</div></ol></div></div></div></div><br>
Поскольку числа-константы, символы и подпрограммы компилируются разными способами, нужен макрос для их распознавания. В макроязыке нет предусмотренных средств для определения типа идентификатора, а что есть – не работает. Придется сделать макрос идентификации чисел и символов самостоятельно: <br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $ISNUM n</div><div class="code_line">&nbsp;&nbsp; &nbsp;??ISNUM = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;??NUM equ &amp;n&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;@len sizestr ??NUM</div><div class="code_line">&nbsp;&nbsp; &nbsp;;; проверяем первый символ</div><div class="code_line">&nbsp;&nbsp; &nbsp;@cfirst SubStr ??NUM, 1, 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;@IsFirst InStr &#60;&#39;&#39;&#62;, @cfirst</div><div class="code_line">&nbsp;&nbsp; &nbsp;if (@IsFirst ne 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;;; это символ, обрабатывается как число</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;??ISNUM = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;exitm</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp; &nbsp;;; проверяем первый символ на наличие знака числа</div><div class="code_line">&nbsp;&nbsp; &nbsp;@IsFirst InStr &#60;-+&#62;, @cfirst</div><div class="code_line">&nbsp;&nbsp; &nbsp;if (@IsFirst ne 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;;; первым идет знак числа, убираем его</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;??NUM SubStr ??NUM, 2, @len-1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@cfirst SubStr ??NUM, 1, 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@len sizestr ??NUM</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp; &nbsp;if (@len eq 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;;; это не число</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;exitm</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp; &nbsp;;; проверяем основание числа по последнему символу</div><div class="code_line">&nbsp;&nbsp; &nbsp;@numstr CatStr &#60;0123456789&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;@clast SubStr ??NUM, @len, 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;@IsLast InStr &#60;bBhH&#62;, @clast</div><div class="code_line">&nbsp;&nbsp; &nbsp;if (@IsLast ne 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;;; это основание числа, убираем его</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (@IsLast gt 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;;; это шестнадцатеричное число</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@numstr CatStr @numstr,&#60;ABCDEFabcdef&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;;; это двоичное число, допустимы только 0 и 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@numstr CatStr &#60;01&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;??NUM SubStr ??NUM, 1, @len-1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@len sizestr ??NUM</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp; &nbsp;;; первым символом, после знака, должна быть цифра</div><div class="code_line">&nbsp;&nbsp; &nbsp;@IsFirst InStr &#60;0123456789&#62;, @cfirst</div><div class="code_line">&nbsp;&nbsp; &nbsp;if (@len eq 0) or (@IsFirst eq 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;exitm</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp; &nbsp;;; сканируем число, без учета символов знака и основания</div><div class="code_line">&nbsp;&nbsp; &nbsp;rept @len</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@nchr SubStr ??NUM, 1, 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;??NUM SubStr ??NUM, 2, @len</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@isDigit InStr @numstr, @nchr</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (@isDigit eq 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;exitm</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp; &nbsp;endm</div><div class="code_line">&nbsp;&nbsp; &nbsp;if (@isDigit ne 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;??ISNUM = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">endm</div></ol></div></div></div></div>Вначале пропускаем возможные символы знака числа. Затем, убираем символ основания числа в конце строки и задаем набор допустимых цифр для данного числа в идентификатор @numstr. И в заключение, проверяем оставшуюся строку на предмет соответствия цифрам из строки @numstr. Результат возвращаем в глобальном идентификаторе ??ISNUM. Все просто. <br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Компиляция кода</strong></span></span></div><br>
Теперь можно приступать к макросу компиляции Форт-строки. Цель макроса – разбить строку на отдельные слова, идентифицировать их и скомпилировать в шитый код. Сам макрос выглядит проще некуда:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro _ listcmd: rest</div><div class="code_line">&nbsp;&nbsp; &nbsp;$PRENAME listcmd</div><div class="code_line">% &nbsp; &nbsp;$parsewords ??NAME</div><div class="code_line">endm</div></ol></div></div></div></div>То есть, подменяем в строке недопустимые символы и результат передаем в макрос &#036;parsewords, который и произведет разбивку строки на слова. Обращаем внимание, что параметр макроса определен как REST, чтобы строка передавалась в него в неизменном виде, без предварительной обработки транслятором ассемблера. Однако есть нюанс. Если первым символом идет ‘&lt;’, то его нужно продублировать ‘&lt;&lt;’, иначе ассемблер воспримет его, как начало текстовой строки и естественно отбросит. В других местах стоки прокатит и одиночный символ ‘&lt;’.<br>
Макрос разбивки строки на слова вполне стандартен:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $parsewords name: vararg</div><div class="code_line">&nbsp;&nbsp; &nbsp;irp @i, &#60;name&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$COMPILE @i</div><div class="code_line">&nbsp;&nbsp; &nbsp;endm</div><div class="code_line">endm</div></ol></div></div></div></div>Параметр задан через VARARG, поэтому строку на слова разобьет уже сам транслятор ассемблера и макрос получит готовый массив слов, который он поочередно, с помощью IRP, скормит макросу &#036;COMPILE:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;macro $COMPILE name</div><div class="code_line">&nbsp;&nbsp; &nbsp;$ISNUM &#60;&amp;name&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;if ??ISNUM</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dw &nbsp; &nbsp; &nbsp;_LIT</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dw &nbsp; &nbsp; &nbsp;&amp;name</div><div class="code_line">&nbsp;&nbsp; &nbsp;else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;$POSTNAME name</div><div class="code_line">% &nbsp; &nbsp; $COMPILENAME ??NAME</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">endm</div></ol></div></div></div></div>А вот это и есть компилятор слов Форта. Если слово распознано как число или символ, то оно компилируется в связке с подпрограммой LIT, которая, во время выполнения, извлекает его из кода и помещает на арифметический стек. В противном случае считаем слово идентификатором и, завершив подмену спецсимволов макросом &#036;POSTNAME,  компилируем его в код:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $COMPILENAME name</div><div class="code_line">&nbsp;&nbsp; &nbsp;ifdef _&amp;name&amp;_F</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_&amp;name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;;; немедленно выполняем слово</div><div class="code_line">&nbsp;&nbsp; &nbsp;else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;dw &nbsp; &nbsp; &nbsp;_&amp;name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;;; просто компилируем слово в код</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">endm</div></ol></div></div></div></div>Тут две тонкости. Во первых, к имени добавляется префикс ‘_’, для решения проблем с именами, начинающимися с цифры. Во вторых, есть два типа подпрограмм – немедленного исполнения (immediate) и простые. С простыми все ясно, их адрес просто добавляется в код, т.е. компилируется. А вот с immediate сложнее. Они не компилируются, а сразу же выполняются, то есть это некий аналог макросов. Такие подпрограммы используются, в основном, в командах ветвления, или циклах, где необходимо сразу же расставить метки для переходов. Поэтому, реализуем их в виде макросов, а для отличия от простых слов, параллельно им будем определять идентификатор, с тем же именем, но с постпрефиксом ‘_F’.  Подробнее о подпрограммах немедленного исполнения будет ниже.<br>
<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Подпрограммы</strong></span></span></div><br>
Настало время определиться со стеками и регистрами. Стеков будет два, арифметический и возвратов. На верхушку первого будет указывать регистр SP, а второй реализуем через регистр BP. Регистр SI задействуем в качестве некоего аналога IP, он будет указывать на адрес следующей исполняемой подпрограммы. Регистры CS, DS и SS должны быть настроены на один сегмент. Остальные регистры свободны.<br>
Подпрограммы бывают двух видов – высокого и низкого уровня. Начнем с простейших. Низкоуровневые подпрограммы – это почти обычные ассемблерные вставки. Для их объявления достаточно преобразовать имя в допустимый вид и объявить метку:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $CODE cname: rest</div><div class="code_line">&nbsp;&nbsp; &nbsp;$PRENAME cname</div><div class="code_line">% &nbsp; $POSTNAME ??NAME</div><div class="code_line">&nbsp;&nbsp; &nbsp;$LABEL &#60;%??NAME&#62;</div><div class="code_line">endm</div><div class="code_line">&nbsp;</div><div class="code_line">macro $LABEL name</div><div class="code_line">&nbsp;&nbsp; &nbsp;_&amp;name&amp;:</div><div class="code_line">endm</div></ol></div></div></div></div>Для завершения ассемблерных вставок нельзя использовать команду RET, вместо этого нужно передать управление на следующую подпрограмму. Адрес следующей подпрограммы хранится в слове, на которое указывает регистр SI. Для удобства оформим макрос:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $NEXT</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; lodsw</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; jmp &nbsp; &nbsp; ax </div><div class="code_line">endm</div></ol></div></div></div></div>Таким образом, низкоуровневая подпрограмма будет выглядеть следующим образом:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">$CODE &#62;R &nbsp; &nbsp; &nbsp;; ( x -- )(R: -- x ) &nbsp; &nbsp;переносит x с ариф. стека на стек возвратов</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; ax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;xchg &nbsp; &nbsp;bp, sp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;ax</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;xchg &nbsp; &nbsp;bp, sp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$NEXT</div></ol></div></div></div></div><br>
Подпрограммы высокого уровня реализуются прямым шитым кодом. Это значит, что для их выполнения нужна специальная функция. Назовем её DOLST. В качестве аргумента ей передается адрес подпрограммы высокого уровня, которую она и запустит на выполнение:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">$CODE DOLST &nbsp; ; ( addr -- )</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;xchg &nbsp; &nbsp;bp, sp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;si</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;xchg &nbsp; &nbsp;bp, sp</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;pop &nbsp; &nbsp; si</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$NEXT</div></ol></div></div></div></div>Функция сохраняет в стек возвратов текущее значение регистра SI и загружает в регистр новое, с арифметического стека. Этим значением будет указатель на массив адресов подпрограмм, что составляют тело исполняемой подпрограммы. С помощью макроса &#036;NEXT запускаем выполнение первой подпрограммы из массива, а она передаст управление следующей и т.д., пока не будет достигнут конец массива, то есть особая функция завершения подпрограммы. В Форте имя этой подпрограммы – точка с запятой. Ассемблер не даст нам использовать такое имя, поэтому выберем другое:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">$CODE EXIT</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;mov &nbsp; &nbsp; si, [bp]</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;add &nbsp; &nbsp; bp, 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$NEXT</div></ol></div></div></div></div>Подпрограмма восстанавливает значение регистра SI из стека возвратов и таким образом возвращает управление туда, откуда и была вызвана подпрограмма, точнее на следующий адрес.<br>
Теперь можно написать макрос для объявления подпрограмм высокого уровня:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $COLN cname: rest</div><div class="code_line">&nbsp;&nbsp; &nbsp;$CODE cname</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;call &nbsp; &nbsp;_DOLST</div><div class="code_line">endm</div></ol></div></div></div></div>Для примера:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">$COLN NEG &nbsp; &nbsp; ; ( n -- -n ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; n = -n</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; NOT 1+ EXIT</div></ol></div></div></div></div>сгенерирует код:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">03C5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_NEG:</div><div class="code_line">03C5 &nbsp;E8 FD93 &nbsp; &nbsp; &nbsp; &nbsp; call &nbsp; &nbsp;_DOLST</div><div class="code_line">03C8 &nbsp;0539r &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dw &nbsp; &nbsp; &nbsp;_NOT</div><div class="code_line">03CA &nbsp;03F2r &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dw &nbsp; &nbsp; &nbsp;_1plus</div><div class="code_line">03CC &nbsp;011Dr &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dw &nbsp; &nbsp; &nbsp;_EXIT</div></ol></div></div></div></div>Инструкция CALL кладет на арифметический стек адрес первого элемента массива подпрограмм, что составляют тело текущей подпрограммы (dw _NOT, _1plus и т.д.), а DOLST запускает выполнение.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Подпрограммы немедленного исполнения</strong></span></span></div><br>
Как уже упоминалось ранее, для реализации ветвления кода и циклов необходимы подпрограммы немедленного исполнения, так называемые immediate. Все дело в том, что еще на этапе генерации кода необходимо расставить команды переходов на код, который еще даже не объявлен. Возьмем для примера простейшую конструкцию: IF – ELSE - THEN (так в Форте называется ENDIF).<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">IF</div><div class="code_line">&nbsp;&nbsp;if (param == FALSE) then GOTO (ELSE or THEN)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;&#60;code&#62;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;jmp THEN</div><div class="code_line">[ELSE]</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;&#60;code&#62;</div><div class="code_line">&nbsp;</div><div class="code_line">THEN</div></ol></div></div></div></div>При выполнении макроса IF придется сгенерировать код проверки условия и возможный переход либо на конец условия (THEN), либо на возможную ветку ELSE, на данном этапе просто невозможно определить, куда именно будет переход. Поэтому, мы сгенерируем переход на некую метку и занесем ее имя в список. Последующий макрос, THEN или ELSE,  извлечет это имя из списка, и сгенерируют метку в коде. <br>
Список меток организуем по принципу стека, последним пришел – первым ушел. Всего нам понадобится три макроса, &#036;PUSH – для генерации новой метки и помещению ее в список, &#036;POP – соответственно для извлечения метки из списка, и &#036;TOP – для получения метки со списка, без ее извлечения из этого списка. Примерно так:<br>
 <div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro $PUSH variable</div><div class="code_line">&nbsp;&nbsp;local @@lab</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;??STACK CatStr &#60;@@lab&#62;, &#60;,&#62;, ??STACK</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ifnb &#60;variable&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;variable CatStr &#60;@@lab&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;endif</div><div class="code_line">endm</div><div class="code_line">&nbsp;</div><div class="code_line">macro $POP variable: req</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;variable equ &#60;&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@pos InStr ??STACK, &#60;,&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if @pos</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@pos &nbsp; &nbsp; = @pos-1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;variable SubStr ??STACK, 1, @pos</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@pos &nbsp; &nbsp; = @pos+2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;??STACK &nbsp;SubStr ??STACK, @pos</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;endif</div><div class="code_line">endm</div><div class="code_line">&nbsp;</div><div class="code_line">macro $TOP variable: req</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;variable equ &#60;&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;@pos InStr ??STACK, &#60;,&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if @pos</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@pos &nbsp; &nbsp; = @pos-1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;variable SubStr ??STACK, 1, @pos</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;endif</div><div class="code_line">endm</div></ol></div></div></div></div>В параметре макросам передается имя идентификатора, в который будет сохранено имя метки. Имена меток нам генерирует сам ассемблер, посредством своего макроса LOCAL. Это гарантирует уникальность имени. В остальном, думаю все понятно, новое значение добавляется в начало строки, чтобы при извлечении снова быть первым.<br>
Теперь непосредственно сами макрокоманды условия. Первым делом объявляем их IMMEDIATE:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">IMMEDIATE &nbsp; &nbsp; &nbsp; = 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; флаг слов немедленного исполнения</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;_IF_F &nbsp; &nbsp; &nbsp; &nbsp; = IMMEDIATE</div><div class="code_line">&nbsp;&nbsp;_THEN_F &nbsp; &nbsp; &nbsp; = IMMEDIATE</div><div class="code_line">&nbsp;&nbsp;_ELSE_F &nbsp; &nbsp; &nbsp; = IMMEDIATE</div></ol></div></div></div></div>Сам макрос условия:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro _IF &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; ( bool -- )</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$PUSH &nbsp; &#60;??LABEL&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dw &nbsp; &nbsp; &nbsp;_?BRANCH</div><div class="code_line">% &nbsp; &nbsp; &nbsp; dw &nbsp; &nbsp; &nbsp;??LABEL</div><div class="code_line">endm</div></ol></div></div></div></div>Генерирует метку и условный переход на нее, если на верхушке арифметического стека находится значение FALSE (подпрограмма ?BRANCH). <br>
Макрос завершения тела условия:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro _THEN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$POP &nbsp; &nbsp;&#60;??LABEL&#62;</div><div class="code_line">% &nbsp;??LABEL:</div><div class="code_line">endm</div></ol></div></div></div></div>Просто извлекает из списка метку, что сгенерировал макрос IF или ELSE, и ставит в конец условия. <br>
 Макрос альтернативного выбора:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro _ELSE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$POP &nbsp; &nbsp;&#60;??LABEL&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$PUSH &nbsp; &#60;??NEWLAB&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dw &nbsp; &nbsp; &nbsp;_BRANCH</div><div class="code_line">% &nbsp; &nbsp; &nbsp; dw &nbsp; &nbsp; &nbsp;??NEWLAB</div><div class="code_line">% &nbsp;??LABEL:</div><div class="code_line">endm</div></ol></div></div></div></div>Вначале генерирует код безусловного перехода на конец условия (BRANCH), то есть на метку, что сгенерирует THEN. Этим самым завершается выполнение ветки IF. После этого объявляем метку, что сгенерировал макрос IF. Теперь именно сюда и перейдет управление, в случае если не сработает условие оператора IF.<br>
Похожим образом строятся конструкции CASE – OF – ENDCASE, а также конструкции циклов BEGIN – UNTIL, BEGIN – WHILE – REPEAT, DO – LOOP. Приводить их реализацию не буду, все есть во вложении.<br>
<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Данные</strong></span></span></div><br>
В Форте нет переменных и констант, в том виде, что есть в других языках программирования. Любая переменная или константа - это подпрограмма. При вызове переменной, она оставляет на стеке адрес связанной с ней ячейки памяти, куда можно что-то записать, или считать из нее. В отличие от переменной, константа оставляет на стеке не адрес ячейки, а её значение. При желании, значение константы можно менять по ходу выполнения программы, хотя вряд ли в этом есть смысл. В большинстве реализаций Форта для создания переменных и констант предусмотрены слова VARIABLE и CONSTANT. Не будем и мы отбиваться от большинства. Начнем с констант:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro CONSTANT name, imm:req</div><div class="code_line">&nbsp;&nbsp; &nbsp;$CODE &#60;&amp;name&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;push &nbsp; &nbsp;&amp;imm</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$NEXT</div><div class="code_line">endm</div></ol></div></div></div></div>Макрос создает подпрограмму, которая кладет на арифметический стек значение константы. <br>
При объявлении переменной нужно учесть возможность зарезервировать место под массив, а так же возможность объявления инициированных данных:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro VARIABLE name: req, len, imm</div><div class="code_line">&nbsp;&nbsp; &nbsp;$CODE &#60;&amp;name&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;@name CatStr &#60;$$_&#62;,??NAME</div><div class="code_line">% &nbsp; &nbsp; &nbsp; &nbsp;push offset @name</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; $NEXT</div><div class="code_line">&nbsp;&nbsp;ifnb &#60;imm&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;align 2</div><div class="code_line">&nbsp;&nbsp; &nbsp;ifnb &#60;len&#62;</div><div class="code_line">% &nbsp; &nbsp; &nbsp; &nbsp;@name dw len dup(imm)</div><div class="code_line">&nbsp;&nbsp; &nbsp;else</div><div class="code_line">% &nbsp; &nbsp; &nbsp; &nbsp;@name dw imm</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp;else</div><div class="code_line">&nbsp;&nbsp; &nbsp;udataseg</div><div class="code_line">&nbsp;&nbsp; &nbsp;align 2</div><div class="code_line">&nbsp;&nbsp; &nbsp;ifnb &#60;len&#62;</div><div class="code_line">% &nbsp; &nbsp; &nbsp; &nbsp;@name dw len dup(?)</div><div class="code_line">&nbsp;&nbsp; &nbsp;else</div><div class="code_line">% &nbsp; &nbsp; &nbsp; &nbsp;@name dw ?</div><div class="code_line">&nbsp;&nbsp; &nbsp;endif</div><div class="code_line">&nbsp;&nbsp; &nbsp;codeseg</div><div class="code_line">&nbsp;&nbsp;endif</div><div class="code_line">endm</div></ol></div></div></div></div>Макрос создает подпрограмму, которая кладет на арифметический стек адрес зарезервированной памяти, из LEN ячеек. Если LEN не задана, то резервируется одна ячейка. Если задано значение параметра IMM, то создаются инициализированные данные.<br>
Что касается строк, то в Форте предусмотрены средства для работы с паскаль-строками, но я не стал реализовывать определяющие строки слова. Вместо этого создал отдельный макрос для объявления строк:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro STRING name, imm:rest</div><div class="code_line">&nbsp;&nbsp;local @endstr</div><div class="code_line">&nbsp;&nbsp; &nbsp;$CODE &#60;&amp;name&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;@name CatStr &#60;$$_&#62;,??NAME</div><div class="code_line">% &nbsp; &nbsp; &nbsp; &nbsp;push offset @name</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;$NEXT</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;align 2</div><div class="code_line">% &nbsp; &nbsp;label @name byte</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;db @endstr - @name - 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;;; байт длины строки</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;db &amp;imm&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; label @endstr byte</div><div class="code_line">endm</div></ol></div></div></div></div>Это удобнее чем в Форте, так можно задавать строки с любым набором символов. Например:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">STRING sAnyKey, &quot;Press any key&quot;,13,10,&quot;to continue&quot;,&#39;$&#39;</div></ol></div></div></div></div>В стандартном Форте пришлось бы выводить это сообщение в три приема.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Практика</strong></span></span></div><br>
	 Макросы готовы, ядро написано и заняло всего 2 Кб. Осталось проверить. Я не сторонник искусственных тестов, поэтому поискал нечто более комплексное. Не помню, откуда, но завалялись у меня старые исходники тетриса на Форте. Добавил цвет и получил годный тетрис под DosBox. Полностью приводить код не буду, он есть в аттаче, разве что небольшой кусочек для наглядности:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">$COLN PLAY-GAME ; ( -- )</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; BEGIN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NEW-BRICK</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -1 3 INSERT-BRICK</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NEXT-DRAW</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; WHILE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BEGIN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4 0 DO</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HELP.X HELP.Y GOTO-XY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; KEY?</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IF</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BEGIN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; KEY KEY?</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WHILE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DROP</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; REPEAT</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ON-KEY 0= &nbsp; &nbsp; &nbsp; &nbsp; ; обрабатываем нажатия клавиш</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IF</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNLOOP EXIT &nbsp; ; прерываем игру</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; THEN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; THEN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GAME.SPEED @ DELAY</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LOOP</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; перемещаем фигуру вниз</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1 0 MOVE-BRICK &nbsp;0=</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNTIL</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; фигура достигла &quot;дна&quot;, проверяем и удаляем зап. линии</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PIT-CHECKFULL</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SHOW-SCORES</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CALCK-SPEED</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; REPEAT</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; запрашиваем новую игру, или выходим</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; sNew GET-INPUT NOT GAME.CONTINUE !</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; EXIT</div></ol></div></div></div></div>Если бы не символ подчеркивания, ничем бы не отличалось от кода на «натуральном» Форте. Что собственно и требовалось.<br>
<br>
<div class='tag-align-center'><span class='tag-size' data-value='11' style='font-size:11pt;'><span class="tag-color tag-color-named" data-value="green" style="color: green"><strong class='tag-b'>Заключение</strong></span></span></div><br>
	Понятно, что я далеко не первый и не последний, кто занимался «исследованиями» на тему возможностей макроязыка. Уже на заре увлечения ассемблером имел удовольствие ознакомиться с макробиблиотекой “Macro Language Version 2.0”. Просто из примера:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;Include &quot;system.h&quot;</div><div class="code_line">&nbsp;</div><div class="code_line">Program ArrayDemo;</div><div class="code_line">&nbsp;</div><div class="code_line">Var</div><div class="code_line">&nbsp;&nbsp;array ARR1[10*20] of shortint;</div><div class="code_line">&nbsp;&nbsp;array ARR2 of integer = &#60;10,9,8,7,6,5,4,3,2,1&#62;;</div><div class="code_line">&nbsp;&nbsp;words i, j;</div><div class="code_line">&nbsp;</div><div class="code_line">Begin</div><div class="code_line">&nbsp;&nbsp;lea si,[ARR2];</div><div class="code_line">&nbsp;&nbsp;for i = 1 to 10 do</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;asm lodsw &nbsp;\ &nbsp;j = ax;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;WriteLn&#60;&#39;ARR2[&#39;&#62;,i,&#60;&#39;] = &#39;&#62;,j;</div><div class="code_line">&nbsp;&nbsp;next i;</div><div class="code_line">End_</div></ol></div></div></div></div>Если кто-нибудь вам скажет, что это не ассемблер, плюньте ему в глаза © «Эл Стоу».<br>
Пожалуй, всё. К статье, помимо «Форта», прикладываю вышеупомянутую макробиблиотеку «Macro Language Version 2.0». Заодно выложу инклюды к Turbo Assembler. Начинал их еще AndNot, а я доработал и опробовал в нескольких небольших проектах, пока окончательно не перешел на Си. В них тоже есть немножко макросов, облегчающих жизнь при работе со строками – text, invoke и move. В качестве примера их использования приложу вывод фрактала папоротника, написанный по мотивам книги Никулина «Компьютерная геометрия и алгоритмы машинной графики». Пример в папке EXAMPLE, для компиляции нужно в батнике настроить пути к TASM’у. В папке TOOLS конвертеры инклюдов, детали в файле ‘READ.ME’.<br>
<br>
<span class="b-attach" data-size="20532" data-hits="333" data-attach-id="61143" data-attach-post-id="3815519">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3815519&amp;attach_id=61143' title='Скачать файл' target='_blank'>FORTH.ZIP</a> (, : 333)
		</span><br>
<span class="b-attach" data-size="196835" data-hits="330" data-attach-id="61144" data-attach-post-id="3815519">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3815519&amp;attach_id=61144' title='Скачать файл' target='_blank'>INCLUDE.rar</a> (, : 330)
		</span><br>
<span class="b-attach" data-size="59156" data-hits="331" data-attach-id="61145" data-attach-post-id="3815519">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3815519&amp;attach_id=61145' title='Скачать файл' target='_blank'>LIB.rar</a> (, : 331)
		</span><br>
<span class="b-attach" data-size="200000" data-hits="339" data-attach-id="61146" data-attach-post-id="3815519">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3815519&amp;attach_id=61146' title='Скачать файл' target='_blank'>TASM_Macro_Language.part1.rar</a> (, : 339)
		</span><br>
<span class="b-attach" data-size="200000" data-hits="336" data-attach-id="61147" data-attach-post-id="3815519">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3815519&amp;attach_id=61147' title='Скачать файл' target='_blank'>TASM_Macro_Language.part2.rar</a> (, : 336)
		</span><br>
<span class="b-attach" data-size="156440" data-hits="327" data-attach-id="61148" data-attach-post-id="3815519">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3815519&amp;attach_id=61148' title='Скачать файл' target='_blank'>TASM_Macro_Language.part3.rar</a> (, : 327)
		</span>]]></description>
        <author>Eretic</author>
        <category>Assembler FAQ</category>
      </item>
	
      </channel>
      </rss>
	