Даже для маленьких по объему программ возникают некоторые из перечисленных здесь проблем:
· плохое понимание исходного текста программы, особенно по прошествии некоторого времени после ее написания;
· ограниченность набора команд;
· повторяемость некоторых идентичных или незначительно отличающихся участков программы;
· необходимость включения в каждую программу участков кода, которые уже были использованы в других программах.
Если бы мы писали программу на машинном языке, то данные проблемы были бы принципиально не решаемыми. Но язык ассемблера, являясь символическим аналогом машинного языка, предоставляет для их решения ряд средств.Основной целью, которая при этом преследуется, является повышение удобства написания программ. В общем случае эта цель достигается по нескольким направлениям за счет следующего:
· расширения набора директив;
· введения некоторых дополнительных команд, не имеющих аналогов в системе команд микропроцессора. За примером далеко ходить не нужно — команды setfield и getfield, которые скрывают от программиста рутинные действия и генерируют наиболее эффективный код;
· введения сложных типов данных.
Но это все глобальные направления, по которым развивается сам транслятор от версии к версии. Что же делать программисту для решения его локальной задачи, для облегчения работы в определенной проблемной области? Для этого разработчики компиляторов ассемблера включают в язык и постоянно совершенствуют аппарат макросредств. Этот аппарат является очень мощным и важным. В общем случае есть смысл говорить о том, что транслятор ассемблера состоит из двух частей — непосредственно транслятора, формирующего объектный модуль, и макроассемблера.
Если вы знакомы с языком С или С++, то конечно помните широко применяемый в них механизм препроцессорной обработки. Он является некоторым аналогом механизма, заложенного в работу макроассемблера. Для тех, кто ничего раньше не слышал об этих механизмах, поясню их суть. Основная идея — использование подстановок, которые замещают определенным образом организованную символьную последовательность другой символьной последовательностью. Создаваемая таким образом последовательность может быть как последовательностью, описывающей данные, так и последовательностью программных кодов. Главное здесь то, что на входе макроассемблера может быть текст программы весьма далекий по виду от программы на языке ассемблера, а на выходе обязательно будет текст на чистом ассемблере, содержащем символические аналоги команд системы машинных команд микропроцессора.
Таким образом, обработка программы на ассемблере с использованием макросредств неявно осуществляется транслятором в две фазы. На первой фазе работает часть компилятора, называемая макроассемблером, функции которого на идейном уровне мы описали выше.На второй фазе трансляции работает непосредственно ассемблер, задачей которого является формирование объектного кода, содержащего текст исходной программы в машинном виде.
Далее мы обсудим основной набор макросредств, доступных при использовании компилятора TASM. Отметим, что большинство этих средств доступно и в компиляторе с языка ассемблера MASM фирмы Microsoft. Обсуждение начнем с простейших средств и закончим более сложными.