Макроси - Програмиране на макроси и контрол на асемблирането
Съществуват обаче и символни променливи, чиито стойности се определят на етапа на сглобяване, т.е. на етапа на изпълнение на асемблерната програма. Символните променливи са два вида. Първият включва така наречените символни (формални) параметри, чиито стойности се определят по време на обработката от асемблера на изречение, в чието поле за работа е името на някакъв макрос. На променливите SET се присвояват стойности с помощта на специални псевдокоманди SET. SET променливите се използват главно за организиране на условно сглобяване и за контролиране на цикли на асемблер. Ще видим примери за това как да използвате SET променливи малко по-късно.
Всички символни променливи започват с & (амперсанд). Това е последвано от име, състоящо се от не повече от седем елементарни знака, първият от които трябва да е буква. Например &A, &A1, &ALLIGTR са налични символни променливи, но &1A и &TOOOLONG не са. Ако желаете, самият амперсанд (&) може да се използва като символ, но за това трябва да напишете низ от формата && вместо един амперсанд на съответното място. Например по команда
ВАЛИ ДЪЖД DC C'CATS && КУЧЕТА
създава се символична константа, която изглежда като CATS&DOGS в EBCDIC кодове.
Сега нека да преминем към въпроса за използването на символни параметри при дефиниране и използване на макроси.
Дефиницията на макрос е последователност от оператори за управление на асемблер и машинни инструкции, с помощта на които асемблерът получава името на макроса, метода за уточняване на действителните параметри и определя реда, в който се генерира разширението на макроса, т.е. последователността от команди на асемблерния език и машинни инструкции, която се изпълнява при използване намакрос в програмата. Инструкция за използване на макрос в програма се нарича макрос. И така, като имаме предвид това ново, по-тясно определение на макрос, можем да кажем, че вече се запознахме с три основни концепции, свързани с програмирането на макроси. Това е, първо, макродефиниция, т.е. набор от изречения, които образуват макрос, второ, макро команда, т.е. индикация за използването на макрос на някое място в програмата и, накрая, разширяване на макрос, т.е. поредица от команди, извлечени от дефиниция на макрос при използване на макрос в програма.
Всички макроси, които трябва да се използват в програмата, трябва да бъдат дефинирани в самото начало на програмата. За да направите това, можете да посочите макрос заедно с програмата като част от входа към асемблера. Можете също така предварително да поставите дефиниции на макроси в библиотека с макроси. Дефинициите на всички системни макроси, както и макросите, които използвахме по-рано, бяха въведени в системата по втория начин.
Всяка макро дефиниция се състои от четири основни части:
1. MACRO клауза, която казва на асемблера, че следва макро дефиниция.
2. Предложение-прототип, с помощта на което се посочва името на макроса и начина за настройка на параметрите му.
3. Моделни изречения или тялото на макродефиниция, т.е. поредица от изречения за управление на асемблер и машинни инструкции, които определят реда, в който трябва да се извърши генерирането на макроси.
4. Клаузата MEND (Macro END), указваща края на дефиницията на макроса.
Клаузата за прототип е схемата на самия макрос, която определя как макросът трябва да бъде написан в програмата. Като цяло прототипът изглежда така:
Полето за операция в този случай се превръща в поле за име, което може да съдържа произволновалидно име на асемблерния език, като GET, RWD или MYMAC1. Това име по-късно се използва за дефиниране на макроса в програмата. Полето за етикет може да е празно или може да съдържа някакъв етикет, обикновено символичен параметър, който се превръща в име на някое изречение, когато се получи разширението на макроса. Полето операнд изброява параметрите, които след това ще бъдат използвани в макроса. Параметрите се разделят със запетаи. Символните имена и константи могат да действат като параметри, но най-често те са символни параметри.
В макро дефинициите и макро разширенията символните параметри заемат централно място. Посочвайки символни параметри в клаузата за прототип, ние всъщност казваме на асемблера, че присвояването на определени стойности към него трябва да бъде отложено, докато макросът не бъде използван. Стойностите ще бъдат дадени от операндите на макроса. Моделните клаузи определят реда, в който се използват тези стойности. Например, ако символният параметър &VAR е третият в списъка с параметри на клаузата за прототип, а името XQW е третото в списъка с операнди на съответния макрос, тогава асемблерът замества низа &VAR, където и да се среща в тялото на макроса с XQW. Това означава, че определянето на действителната стойност на символен параметър се отлага, докато макросът, съдържащ този параметър като етикет или операнд, се използва в програмата.
Ето няколко примера, свързани с използването на символни параметри. Спомнете си, че по време на изпълнението на макроса RWD се извиква подпрограмата $$IO, която въвежда изображението на перфорираната карта в паметта, преобразува го в двоично представяне и поставя получената стойност в регистър 1. След това RWD произвеждапрехвърляне на съдържанието на регистър 1 към друг регистър или място в паметта в съответствие със стойността на макрооперанда.
Ориз. 18.1. Дефиниция на макро RWD с регистров операнд.
Да предположим, че операндът е регистър. Когато съставяме макро дефиниция, ние не знаем кой регистър програмистът иска да използва, за да въведе информация от картата. Така в прототипното изречение вместо конкретен номер на определен регистър се записва символен параметър. По-късно, когато програмистът избере конкретен номер на регистъра, той ще го посочи в полето операнд на макроса RWD. На фиг. 18.1 показва макро дефиницията на RWD.
Операндът на прототипната клауза е параметърът &LOC. Можете например да пишете
На разположение на монтажника е предложението-прототип
Стойността на &LOC се присвоява при използване на макроса. В този случай &LOC ще има стойност 5. Докато асемблерът изгражда макроразширението, асемблерът замества &LOC навсякъде с неговата стойност, т.е. 5. Следователно макроразширяването на RWD изглежда така:
Тези три команди ще бъдат вмъкнати в програмата на мястото на макроса RWD.
Обърнете внимание, че самата клауза за прототип не е включена в разширението на макроса по никакъв начин. Това е общото правило; прототипното изречение всъщност играе само ролята на схема за бъдещ макрос.
Този факт става пряко важен, ако някоя клауза за разширяване на макроси трябва да бъде маркирана. Показано на фиг. 18.1 дефиницията на макрос не позволява използването на макроса RWD, например в следния цикъл:

Ориз. 18.2. Макрос RWD, който позволява да се използва етикет при писане на макрос.
Макро разширение, получено чрез използване на стариямакродефиниции
не съдържа етикета NEXTCARD.
Макродефиницията на RWD, модифицирана в съответствие с възникналата необходимост, е показана на фиг. 18.2. На пръв поглед етикетът &LAB може да изглежда като дефиниран два пъти тук. Но това не е така, защото прототипът не е включен в макроразширението. Ако сега се съгласим да използваме определението, показано на фиг. 18.2, след това при разширяване на макроса
NEXTCARD L 15, = V($$I0)
което е желаният резултат. Асемблерът просто замени символните параметри &LAB и &LOC с техните действителни стойности, съответно NEXTCARD и 7.
Асемблерът позволява конкатенация, т.е. прикрепване на стойността на символен параметър към началото или края на някакъв символен низ от моделно изречение. За да добавите стойност към края на низ, просто поставете името на този символен параметър непосредствено след низа. Ако &LET е BAGE, тогава низът

Ориз. 18.3. Дефиниция на макроса BEGIN.
в моделното изречение ще бъде заменено в разширението на макроса с
Можете да добавите стойност към началото на низ по почти същия начин, само че сега трябва да поставите точка преди началото на оригиналния низ. Ако е лесно да се пише
тогава асемблерът ще реши, че сме използвали нова символна променлива
В този случай знаците &TYPE и C се свързват, за да се получи мнемониката на желаната команда за сравнение. Ако искаме да сравним две полудуми, тогава H трябва да бъде посочено като тип на операндите.
LOOP COMPARE 3, HW, H, EQUAL, NOTEQUAL
Но какво ще стане, ако на операндът не е необходимо да се присвоява никаква стойност, както например в случай на сравняване на две пълнидуми? За да направите това, просто не посочвате никаква стойност, съответстваща на този параметър в списъка с операнди на макроса. Но в същото време трябва да поставите всички запетаи в списъка - в края на краищата параметърът действително съществува.
Ориз. 18.4. Макросът COMPARE.
СЛЕДВАЩ СРАВНЕНИЕ 6,FULWD,,EQ,NEQ
Досега се занимавахме изключително с позиционни параметри, на които се присвояват стойности според тяхната позиция в списъка с операнди на клаузата за прототип. Има и така наречените ключови параметри. Ключовите параметри вече могат да бъдат дефинирани в произволен ред, но те трябва да следват всички позиционни параметри в списъка. В предложението за прототип основните параметри имат формата
където "име" е името на параметъра, а "стойност" е стойността, която ще бъде присвоена на този параметър по подразбиране, т.е. ако не посочим стойност за този параметър в макроса.
На фиг. Фигура 18.5 показва друга версия на макроса COMPARE, в която параметърът &TYPE е ключов. По подразбиране параметърът &TYPE е зададен на интервал, така че ако стойността &TYPE не е посочена в макроса, тогава ще се генерира команда с C мнемоника, т.е. команда за сравняване на цели думи. За да определите стойността на ключов параметър, трябва да запишете следната комбинация в списъка с операнди на макроса: име на параметър без знака & отпред, знак за равенство и желаната стойност. По този начин, ако искаме, използвайки последната дефиниция на макроса COMPARE, да организираме сравнение на числа с плаваща запетая (тип E), имаме нужда

Ориз. 18.5. Дефиниция на макрос COMPARE с ключов параметър &TYPE.
FP СРАВНЕНИЕ 2,FPNO,FPEQ,FPNEQ,TYPE = E
Полученото разширение на макроса ще съдържа командата с мнемоника CE, т.есравнения с плаваща запетая.