Введение
Правило подстановки заданного ввода заданным выводом
В компьютерном программировании макрос (сокращение от "макро-инструкция") — это правило или шаблон, определяющий, как определенный ввод должен быть преобразован в замену-вывод. Применение макроса к вводу называется развертыванием макроса. Ввод и вывод могут представлять собой последовательность лексических токенов или символов, либо синтаксическое дерево. Символьные макросы поддерживаются в программных приложениях для упрощения вызова общих последовательностей команд. Макросы токенов и деревьев поддерживаются в некоторых языках программирования для повторного использования кода или расширения языка, в том числе для предметно-ориентированных языков. Макросы позволяют представить программисту последовательность вычислительных инструкций в виде одной программной конструкции, что делает процесс программирования менее трудоемким и менее подверженным ошибкам. Таким образом, они называются "макросами", поскольку "большой" блок кода может быть развернут из "маленькой" последовательности символов. Макросы часто допускают позиционные или именованные параметры, определяющие, что генерирует условный ассемблер, и используются для создания целых программ или пакетов программ в зависимости от таких переменных, как операционная система, платформа или другие факторы. Термин происходит от "макро-инструкции", и изначально такие развертывания использовались для генерации кода на языке ассемблера.
Макро клавиатуры и мыши
Макросы клавиатуры и макросы мыши позволяют коротким последовательностям нажатий клавиш и действий мыши преобразовываться в другие, как правило, более длительные последовательности нажатий клавиш и действий мыши. Таким образом, часто используемые или повторяющиеся последовательности нажатий клавиш и движений мыши можно автоматизировать. Отдельные программы для создания этих макросов называются программами записи макросов. В 1980-х годах макропрограммы – изначально SmartKey, затем SuperKey, KeyWorks, Prokey – были очень популярны, сначала как средство автоматического форматирования сценариев, а затем для различных задач ввода данных. Эти программы работали в режиме "завершения и оставания в памяти" и применялись ко всем нажатиям клавиш, независимо от контекста. В некоторой степени они устарели с появлением пользовательских интерфейсов, управляемых мышью, и встроенных макросов клавиатуры и мыши в приложениях, таких как текстовые процессоры и электронные таблицы, что позволило создавать макросы клавиатуры, зависящие от конкретного приложения. Макросы клавиатуры могут использоваться в массовых многопользовательских онлайн-ролевых играх (MMORPG) для выполнения повторяющихся, но прибыльных задач, что позволяет накапливать ресурсы. Поскольку это делается без участия человека, это может исказить экономику игры. Поэтому использование макросов является нарушением пользовательского соглашения (TOS) или лицензионного соглашения (EULA) большинства MMORPG, и их администраторы прилагают значительные усилия для борьбы с ними.
Макросы приложений и сценарии
Макросы клавиатуры и мыши, созданные с использованием встроенных в приложение функций макросов, иногда называются макросами приложений. Они создаются путем однократного выполнения последовательности действий и записи этих действий приложением. Также может существовать базовый язык макропрограммирования, как правило, скриптовый язык, обеспечивающий прямой доступ к функциям приложения. Текстовый редактор для программистов Emacs (сокращение от "editing macros" – макросы редактирования) доводит эту идею до логического завершения. По сути, большая часть редактора состоит из макросов. Emacs изначально был разработан как набор макросов на языке редактирования TECO, а затем был портирован на диалекты Lisp. Другой текстовый редактор для программистов, Vim (потомок vi), также имеет реализацию клавиатурных макросов. Он может записывать в регистр (макрос) нажатия клавиш и воспроизводить или редактировать их, подобно VBA-макросам для Microsoft Office. Vim также имеет скриптовый язык Vimscript для создания макросов. Visual Basic for Applications (VBA) – это язык программирования, включенный в Microsoft Office с Office 97 по Office 2019 (хотя он был доступен в некоторых компонентах Office и до Office 97). Однако его функциональность эволюционировала и заменила макроязыки, которые изначально входили в состав некоторых из этих приложений. XEDIT, работающий в составе компонента Conversational Monitor System (CMS) VM, поддерживает макросы, написанные на EXEC, EXEC2 и REXX, а некоторые команды CMS фактически являлись оболочками для макросов XEDIT. Hessling Editor (THE), частичный клон XEDIT, поддерживает макросы Rexx с использованием Regina и Open Object REXX (oorexx). Многие распространенные приложения, и некоторые на ПК, используют Rexx в качестве скриптового языка.
Макровирус
VBA имеет доступ к большинству системных вызовов Microsoft Windows и выполняется при открытии документов. Это облегчает создание компьютерных вирусов на VBA, обычно называемых макровирусами. В середине и конце 1990-х годов они стали одним из самых распространенных типов компьютерных вирусов. Однако, начиная с конца 1990-х годов и по настоящее время, Microsoft выпускает исправления и обновления для своих программ. Кроме того, современные антивирусные программы эффективно нейтрализуют подобные атаки.
Встраиваемые языки
Некоторые языки программирования, такие как PHP, могут быть встроены непосредственно в текст в свободном формате или в исходный код других языков. Механизм, посредством которого распознаются фрагменты кода (например, обрамленные тегами <?php и ?>), аналогичен текстовому макроязыку, однако это полноценные, гораздо более мощные языки программирования.
Процедуральные макросы
Макросы в языке PL/I написаны на подмножестве самого PL/I: компилятор выполняет "предпроцессорные операторы" во время компиляции, и результат этого выполнения становится частью компилируемого кода. Возможность использования знакомого процедурного языка в качестве макроязыка обеспечивает значительно большую мощность, чем у макросов подстановки текста, но требует более крупного и медленного компилятора. Макросы в PL/I, как и во многих ассемблерах, могут иметь побочные эффекты, например, устанавливать переменные, к которым могут обращаться другие макросы. Фрейм-макросы технологии фреймов имеют собственный синтаксис команд, но могут также содержать текст на любом языке. Каждый фрейм является одновременно универсальным компонентом в иерархии вложенных подкомпонентов и процедурой для интеграции с фреймами своих подкомпонентов (рекурсивный процесс, разрешающий конфликты интеграции в пользу подкомпонентов более высокого уровня). Результатом являются пользовательские документы, как правило, компилируемые исходные модули. Технология фреймов позволяет избежать размножения схожих, но незначительно различающихся компонентов – проблемы, преследующей разработку программного обеспечения с момента изобретения макросов и подпрограмм. Большинство языков ассемблера имеют менее мощные средства процедурных макросов, например, позволяющие повторять блок кода N раз для развертывания цикла, но они имеют совершенно иной синтаксис, чем сам язык ассемблера.
Синтаксические макросы
Макросистемы, такие как C-препроцессор, описанный ранее, работающие на уровне лексических токенов, не могут надежно сохранять лексическую структуру. Синтаксические макросистемы работают вместо этого на уровне абстрактных синтаксических деревьев и сохраняют лексическую структуру исходной программы. Наиболее широко используемые реализации синтаксических макросистем встречаются в языках, подобных Lisp. Эти языки особенно хорошо подходят для такого стиля макросов благодаря их единообразному синтаксису с использованием скобок (известному как S-выражения). В частности, единообразный синтаксис облегчает определение вызовов макросов. Макросы Lisp преобразуют саму структуру программы, при этом весь язык доступен для выражения этих преобразований. Хотя синтаксические макросы часто встречаются в языках, подобных Lisp, они также доступны в других языках, таких как Prolog, Erlang, Dylan, Scala, Nemerle, Rust, Elixir, Nim, Haxe и Julia. Они также доступны в виде сторонних расширений для JavaScript и C#.
Ранние макросы Lisp
До того, как в Lisp появились макросы, существовали так называемые FEXPRs – операторы, подобные функциям, которые принимали на вход не значения, вычисленные аргументами, а их синтаксические формы, и выдавали значения для использования в вычислениях. Иными словами, FEXPRs были реализованы на том же уровне, что и EVAL, и предоставляли доступ к уровню метаоценки. Эта модель, как правило, оказалась сложной для эффективного понимания и анализа. В 1963 году Тимоти Харт предложил добавить макросы в Lisp 1.5 в AI Memo 57: MACRO Definitions for LISP.
Анафорические макрос
Анафорический макрос — это тип программистского макроса, который намеренно захватывает некоторую переданную ему форму, на которую может ссылаться анафора (выражение, отсылающее к другому выражению). Анафорические макросы впервые появились в книге Пола Грэма «On Lisp», а их название является отсылкой к лингвистической анафоре — использованию слов для замены ранее упомянутых слов.
Гигиенические макрос
В середине 1980-х годов ряд работ представил понятие гигиенического макрорасширения (правила синтаксиса) – систему, основанную на шаблонах, в которой синтаксические окружения определения и использования макроса различны, что позволяет авторам и пользователям макросов не беспокоиться о случайном захвате переменных (ср. референтная прозрачность). Гигиенические макросы были стандартизированы для Scheme в стандартах R5RS, R6RS и R7RS. Существует несколько конкурирующих реализаций гигиенических макросов, таких как правила синтаксиса, синтаксические случаи, явное переименование и синтаксические замыкания. И правила синтаксиса, и синтаксические случаи были стандартизированы в стандартах Scheme. Недавно Racket объединил концепции гигиенических макросов с "многоуровневой системой вычислений", так что время синтаксического расширения одной макросистемы является обычным временем выполнения другого блока кода, и показал, как применять чередующееся расширение и разбор в языке без скобок. Ряд языков, отличных от Scheme, либо реализуют гигиенические макросы, либо реализуют частично гигиенические системы. Примеры включают Scala, Rust, Elixir, Julia, Dylan, Nim и Nemerle.
Макросы для машинно-независимого программного обеспечения
Макросы обычно используются для сопоставления короткой строки (вызова макроса) с более длинной последовательностью инструкций. Другое, менее распространенное применение макросов – обратное преобразование: сопоставление последовательности инструкций со строкой макросов. Такой подход был реализован в мобильной программирующей системе STAGE2, которая использовала примитивный компилятор макросов (называемый SIMCMP) для преобразования специфического набора инструкций конкретного компьютера в машино-независимые макросы. Приложения (особенно компиляторы), написанные на этих машино-независимых макросах, затем могут выполняться без изменений на любом компьютере, оснащенном этим примитивным компилятором макросов. Первым приложением, запускаемым в такой среде, является более сложный и мощный компилятор макросов, написанный на машино-независимом языке макросов. Этот компилятор макросов применяется к самому себе, в процессе начальной загрузки, для создания скомпилированной и значительно более эффективной версии. Преимущество этого подхода заключается в том, что сложные приложения можно переносить с одного компьютера на совершенно другой с минимальными усилиями (для каждой целевой архитектуры требуется только разработка примитивного компилятора макросов). Однако, с появлением современных языков программирования, в частности C, для которых компиляторы доступны практически на всех компьютерах, такой подход стал ненужным. Тем не менее, это был один из первых (если не первый) случаев начальной загрузки компилятора.
История
В середине 1950-х годов, когда программирование на языке ассемблера широко использовалось для написания программ для цифровых компьютеров, макроинструкции стали применяться для двух основных целей: сократить объем кода программы, который необходимо было писать, генерируя несколько инструкций языка ассемблера из одной макроинструкции, и обеспечить соблюдение стандартов программирования, например, унифицировать команды ввода-вывода. Макроинструкции представляли собой эффективный промежуточный этап между программированием на языке ассемблера и языками программирования высокого уровня, такими как FORTRAN и COBOL. Две из первых вычислительных установок, разработавших "макроязыки" для компьютера IBM 705, находились в Dow Chemical Corp. в штате Делавэр и в Командовании авиационных материалов, Офисе логистики баллистических ракет в Калифорнии. Макроинструкция, написанная в формате целевого ассемблера, обрабатывалась макрокомпилятором – препроцессором ассемблера, который генерировал одну или несколько инструкций ассемблера для последующей обработки программой ассемблера, преобразующей инструкции ассемблера в инструкции машинного кода. К концу 1950-х годов макроязыкам последовали макроассемблеры, объединявшие в себе функции макропрепроцессора и ассемблера в одном пакете, что привело к появлению так называемых Macro SAP. Работа Макроя 1960 года стала основополагающей в области расширения возможностей любых (включая языки высокого уровня) языков программирования посредством макропроцессоров. Макроассемблеры позволяли программистам на языке ассемблера создавать собственные макроязыки и обеспечивали ограниченную переносимость кода между машинами с одним и тем же процессором, но работающими под разными операционными системами, например, ранними версиями MS DOS и CP/M 86. Библиотеку макросов необходимо было разрабатывать для каждой целевой машины, но не для всей программы на языке ассемблера. Следует отметить, что более мощные макроассемблеры поддерживали использование условных конструкций сборки в макроинструкциях, что позволяло генерировать различный код для разных машин или операционных систем, снижая потребность в нескольких библиотеках. В 1980-х и начале 1990-х годов настольные ПК работали на частоте всего несколько МГц, и подпрограммы на языке ассемблера часто использовались для ускорения программ, написанных на C, Fortran, Pascal и других языках. В то время эти языки использовали различные соглашения о вызовах. Макросы можно было использовать для взаимодействия подпрограмм, написанных на языке ассемблера, с фронтендом приложений, написанных практически на любом языке. При этом базовый код на языке ассемблера оставался неизменным, требовалось лишь создание макробиблиотек для каждого целевого языка. В современных операционных системах, таких как Unix и ее производные, доступ к операционной системе осуществляется через подпрограммы, обычно предоставляемые динамическими библиотеками. Языки высокого уровня, такие как C, обеспечивают всесторонний доступ к функциям операционной системы, устраняя необходимость в программах на языке ассемблера для выполнения этих функций.