Разработка общего программного обеспечения |
Оператор, работающий в какой-либо системе, часто встречается с необходимостью повторять некоторые последовательности действий много раз? Такая последовательность может, например, состоять из ввода некоторой текстовой последовательности, нажатии определенной последовательности клавиш, выполнении однотипного ряда каких-либо арифметических операций. В подобных случаях часто можно воспользоваться аппаратом макрокоманд. Макрокоманды (часто называемые макро или макрос) являются однострочными сокращениями для группы команд. Используя макрокоманду, программист по существу определяет одну “команду” для представления некоторой последовательности команд. Определяя соответствующие макрокоманды, оператор может удобным для себя образом вводить свои собственные средства более высокого уровня, не заботясь о структуре системы. Он может достигнуть краткости и простоты управления системой, не теряя при этом основных преимуществ использования исходной системы, такой, как например язык ассемблера. Крупные макрооперации упрощают пользование, отладку и модификацию программ, и облегчают стандартизацию. Многие разработчик вычислительных машин используют макрокоманды для автоматизации составления “подходящих” операционных систем в процессе, называемом генерацией системы В своей простейшей форме макрокоманда представляет собой сокращение для обозначения последовательности операций Рассмотрим следующий набор команд, взятый из макроязыка IDE для Borland C++ версии 3.1 (TEMC). Рассмотрим следующую программу, написанную с помощью этих операций Аппарат макрокоманд позволяет присвоить этой последовательности имя и использовать это имя вместо нее. Можно также определить некоторый макроязык, позволяющий рассматривать данную конструкцию, как определение и в дальнейшем использовать это определение. Фактически, макропроцессор представляет собой отдельный языковой процессор со своим собственным языком. Форматы макроопределений в различных системах может отличаться друг от друга. В данном случае последовательность команд, определяющая макрокоманду имеет следующий формат Псевдокоманда MACRO – первая строка определения – определяет следующий за ней идентификатор, как имя макрокоманды. Вслед за этой строкой располагается последовательность команд, называемых “телом макроопределения”. Определение заканчивается строкой с псевдокомандой END. Аппарат макрокоманд в том виде, как он был описан до сих пор, позволяет подставлять последовательности команд вместо макровызовов, причем все обращения к макроопределению будут заменены идентичными последовательностями команд. Такой аппарат недостаточно гибок: в макровызове нет средств модифицировать коды, которые его заменяют. Существенное расширение возможностей макросредств достигается добавлением операндов (параметров) макрокоманд. В данном случае последовательности команд очень похожи, но не абсолютно идентичны. В первой последовательности используется операнд “1”, а во втором – операнд “2”. Можно считать, что они выполняют одну и ту же операцию с переменным параметром, или операндом. Такой параметр называют “операндом макрокоманды” или “формальным параметром”, и он обычно объявляется в той же строке, где и имя макроса. В случае работы с языком макроассемблера, он обычно помечается символом &, что отличает его как символ макроязыка от символов ассемблера. В нашем случае, фирма Борланд не предусмотрела в своем макроязыке работы с макрооперандами, однако можно предположить, что если бы макроопределения в языке TEMC могли бы обрабатывать подобную ситуацию, то формат макроопределения мог бы выглядеть следующим образом: Комбинация IF…THEN…ELSE является макрометками или символами следования и не появляются в выходном тексте макропроцессора. В макроязыке также могут быть предусмотрены псевдокоманды условного и безусловного перехода на псевдо-метку, с которой макропроцессор продолжит обработку текста программы. Точно так же, как и в случае выполнения программы, операторы переходов служат для указания выполнения операторов программы, операторы макро-переходов служат для указания порядка компиляции текста программы. Это дает возможность в процессе расширения получать конкретные варианты последовательностей команд, соответствующие данному случаю применения макрокоманды. Выполнение переходов и проверок внутри выполняемого кода увеличивает его размер и время выполнения, в то время, как проверка и переходы в макросах происходят на стадии компиляции и поэтому не требуют затрат времени при выполнении кода. Эта возможность избирательной выборки нужных частей текста является одним из самых мощных средств в системном программировании. Любой процессор макрокоманд должен решать следующие четыре основные задачи: 1. Распознавать макроопределения. Процессор макрокоманд должен распознавать макроопределения, выделяемые соответствующими псевдокомандами. В языке макроассемблера этими псевдооператорами являются псевдокоманды MACRO и MEND. Эта задача может быть усложнена тем, что внутри макроопределений могут встречаться также другие макроопределения. Когда макроопределения вложены, как было продемонстрировано выше, макропроцессор должен правильно распознавать вложения и сопоставить начало и конец макроса. Весь вложенный текст, включая и другие макроопределения определяет отдельную макрокоманду. 2. Запоминать макроопределения. Процессор должен запомнить определения макрокоманд, которые будут впоследствии использоваться для расширения макровызовов 3. Распознавать вызовы. Необходимо также и распознавать макровызовы, представленные в виде мнемонического кода операции. Это предполагает, что имена макрокоманд обрабатываются на тех же самых основаниях, как и один из кодов операции. 4. Выполнять расширение макрокоманд и подстановку фактических параметров. Вместо формальных параметров макроопределения макропроцессор должен подставить соответствующие операнды макрокоманды. Этот текст, в свою очередь может содержать как макрокоманды так и макроопределения. Таким образом, макропроцессор должен распознавать и обрабатывать макроопределения и макрокоманды. Что же касается формальных параметров, то тут нужно принять несколько решений. Необходимо определить – могут ли они встречаться в качестве кода операции, каков синтаксис допустимых параметров. В разных реализациях макроязыков могут встречаться разные варианты методы реализации подобных ситуаций, поэтому можно только дать некоторые разумные варианты, покрывающие большую часть возможных реализаций. Формальные параметры могут встречаться в макроопределении где угодно, в том числе и в команде и в коде операции. Мы хотим, чтобы была обеспечена возможность конкатенации формальных параметров макроопределения с фиксированными символьными строками. В таком случае встает вопрос о некоем разделительном символе, обеспечивающем конкатенацию формальных параметров и заданных пользователем символьных последовательностей. Например, если из один из параметров должен быть соединен с другим (macro[x, y] = xy), то возможен синтаксис x&y, что означает конкатенацию формального параметра x с формальным параметром y. Этот случай не вызывает больших трудностей. Гораздо сложней обрабатывается случай, когда речь идет о подстановке параметра внутри символьной строки. В таком случае возможным выходом будет конкатенация по умолчанию двух последовательно друг за другом идущих символьных строк, а также преобразование формального параметра, заключенного в скобки к символьной строке. Таким образом, если мы хотим, чтобы в макросе фигурировала строка вида “blablabla[x]xxxxx”, где [x] должно заменяться формальным параметром вполне возможно заменить строку такого вида строкой типа “blablabla”(x)”xxxxx”. Надо заметить, что множество замечательных идей по реализации подобных макроязыков реализовано в языке REXX, поддерживаемом на системном уровне операционной системой OS/2 компании IBM. Также для выполнения функций условных переходов должны вычисляться некоторые арифметические выражения (возьмем в пример хотя бы обыкновенных счетчик). Таким образом часто оказывается полезной возможность использования псевдо-переменных времени компиляции внутри макросов.
|