В компьютерном программировании макрос ( сокращение от « макроинструкция »; от греческого μακρο — «длинный, большой» [1] ) — это правило или шаблон , который определяет, как определенный входной сигнал должен быть сопоставлен с замещающим выходным сигналом. Применение макроса к входным данным называется расширением макроса . Входными и выходными данными могут быть последовательность лексических токенов или символов или синтаксическое дерево . Символьные макросы поддерживаются в программных приложениях , что упрощает вызов общих последовательностей команд . Макросы токенов и деревьев поддерживаются в некоторых языках программирования , что позволяет повторно использовать код или расширять язык, иногда для языков, специфичных для предметной области .
Макросы используются для того, чтобы сделать последовательность вычислительных инструкций доступной программисту в виде одного оператора программы , что делает задачу программирования менее утомительной и менее подверженной ошибкам. [2] [3] (Поэтому их называют «макросами», потому что «большой» блок кода может быть расширен из «маленькой» последовательности символов.) Макросы часто допускают позиционные или ключевые параметры, которые определяют, что будет делать программа на условном ассемблере . генерируется и используется для создания целых программ или комплектов программ в соответствии с такими переменными, как операционная система , платформа или другие факторы. Этот термин происходит от «макроинструкции», и такие расширения первоначально использовались при создании кода на языке ассемблера .
Макросы клавиатуры и макросы мыши позволяют коротким последовательностям нажатий клавиш и действий мыши трансформироваться в другие, обычно более трудоемкие последовательности нажатий клавиш и действий мыши. Таким образом можно автоматизировать часто используемые или повторяющиеся последовательности нажатий клавиш и движений мыши . Отдельные программы для создания этих макросов называются макрорекордерами .
В 1980-е годы макропрограммы — первоначально SmartKey , затем SuperKey, KeyWorks, Prokey — были очень популярны, сначала как средство автоматического форматирования сценариев , а затем для выполнения различных задач пользовательского ввода. Эти программы были основаны на резидентном режиме работы и применялись ко всему вводу с клавиатуры, независимо от того, в каком контексте он происходил. Они в некоторой степени устарели после появления пользовательских интерфейсов, управляемых мышью, и доступности макросов клавиатуры и мыши в таких приложениях, как текстовые процессоры и электронные таблицы , что позволило создавать макросы клавиатуры, чувствительные к приложению.
Макросы клавиатуры можно использовать в многопользовательских ролевых онлайн-играх (MMORPG) для выполнения повторяющихся, но прибыльных задач, накапливая таким образом ресурсы. Поскольку это делается без участия человека, это может исказить экономику игры. По этой причине использование макросов является нарушением TOS или EULA большинства MMORPG, и их администраторы тратят значительные усилия на их подавление. [4]
Макросы клавиатуры и мыши, созданные с использованием встроенных функций макросов приложения, иногда называются макросами приложения . Они создаются путем однократного выполнения последовательности и разрешения приложению записывать действия. Также может существовать базовый язык макропрограммирования, чаще всего язык сценариев , с прямым доступом к функциям приложения.
Текстовый редактор программистов Emacs (сокращение от «редактирование макросов») доводит эту идею до конца. По сути, большая часть редактора состоит из макросов. Emacs изначально был разработан как набор макросов на языке редактирования TECO ; позже он был портирован на диалекты Лиспа .
Другой текстовый редактор программистов, Vim (потомок vi ), также имеет реализацию клавиатурных макросов. Он может записывать в регистр (макрос) то, что человек набирает на клавиатуре, и его можно воспроизводить или редактировать так же, как макросы VBA для Microsoft Office. В Vim также есть язык сценариев Vimscript [5] для создания макросов.
Visual Basic для приложений (VBA) — это язык программирования, включенный в Microsoft Office начиная с Office 97 до Office 2019 (хотя он был доступен в некоторых компонентах Office до Office 97). Однако его функция развилась и заменила макроязыки, которые изначально были включены в некоторые из этих приложений.
XEDIT , работающий на компоненте Conversational Monitor System (CMS) VM , поддерживает макросы, написанные на EXEC , EXEC2 и REXX , а некоторые команды CMS фактически были обертками вокруг макросов XEDIT. Редактор Hessling (THE), частичный клон XEDIT, поддерживает макросы Rexx с использованием Retina и Open Object REXX (oorexx). Многие распространенные приложения, в том числе и на ПК, используют Rexx в качестве языка сценариев.
VBA имеет доступ к большинству системных вызовов Microsoft Windows и выполняется при открытии документов. Это позволяет относительно легко писать компьютерные вирусы на VBA, широко известные как макровирусы . В середине-конце 1990-х годов этот тип компьютерных вирусов стал одним из наиболее распространенных. Однако с конца 1990-х годов и по настоящее время Microsoft исправляет и обновляет свои программы. [ нужна цитата ] Кроме того, современные антивирусные программы немедленно противодействуют таким атакам.
Параметризованный макрос — это макрос, который может вставлять заданные объекты в свое расширение. Это дает макросу некоторую мощь функции .
В качестве простого примера на языке программирования C это типичный макрос, который не является параметризованным макросом, т. е. макросом без параметров :
#define PI 3.14159
Это приводит к PI
тому, что всегда заменяется на то 3.14159
, где бы оно ни возникало. С другой стороны, пример параметризованного макроса:
#define pred(x) ((x)-1)
До чего расширяется этот макрос, зависит от того, какой аргумент x ему передается. Вот некоторые возможные расширения:
пред(2) → ((2) -1) пред(y+2) → ((y+2) -1) пред(f(5)) → ((f(5))-1)
Параметризованные макросы — полезный механизм на уровне исходного кода для выполнения встроенного расширения , но в таких языках, как C , где они используют простую текстовую замену, они имеют ряд серьезных недостатков по сравнению с другими механизмами выполнения встроенного расширения, такими как встроенные функции. .
С другой стороны, параметризованные макросы, используемые в таких языках, как Lisp , PL/I и Scheme , гораздо более мощные и способны принимать решения о том, какой код создавать на основе своих аргументов; таким образом, их можно эффективно использовать для генерации кода во время выполнения .
Такие языки, как C и некоторые ассемблерные языки , имеют рудиментарные макросистемы, реализованные как препроцессоры для компилятора или ассемблера. Макросы препроцессора C работают путем простой текстовой замены на уровне токена , а не на уровне символов. Однако макросы более сложных ассемблеров, например, IBM High Level Assembler (HLASM), не могут быть реализованы с помощью препроцессора; код сборки инструкций и данных перемежается кодом сборки вызовов макросов.
Классическим примером использования макросов является компьютерная система набора текста TeX и ее производные, где большая часть функций основана на макросах.
MacroML — это экспериментальная система, которая стремится согласовать статическую типизацию и макросистемы. В Nemerle есть типизированные синтаксические макросы, и один из продуктивных способов представить эти синтаксические макросы — это многоэтапные вычисления .
Другие примеры:
Некоторые основные приложения написаны в виде текстовых макросов, вызываемых другими приложениями, например XEDIT в CMS.
Некоторые языки, такие как PHP , могут быть встроены в текст свободного формата или исходный код других языков. Механизм распознавания фрагментов кода (например, заключение в скобки <?php
и ?>
) аналогичен текстовому макроязыку, но это гораздо более мощные и полнофункциональные языки.
Макросы на языке PL/I написаны на подмножестве самого PL/I: компилятор выполняет « операторы препроцессора » во время компиляции, и результат этого выполнения образует часть компилируемого кода. Возможность использовать знакомый процедурный язык в качестве языка макросов дает гораздо большую мощность, чем у макросов замены текста, за счет более крупного и медленного компилятора. Макросы в PL/I, как и во многих ассемблерах, могут иметь побочные эффекты , например, устанавливать переменные, к которым могут получить доступ другие макросы.
Макросы кадров технологии Frame имеют собственный синтаксис команд, но также могут содержать текст на любом языке. Каждый кадр является одновременно общим компонентом в иерархии вложенных подсборок и процедурой интеграции с его кадрами подсборки (рекурсивный процесс, который разрешает конфликты интеграции в пользу подсборок более высокого уровня). Выходные данные представляют собой специальные документы, обычно компилируемые исходные модули. Технология фреймов позволяет избежать распространения похожих, но слегка различающихся компонентов — проблемы, которая преследовала разработку программного обеспечения со времени изобретения макросов и подпрограмм .
Большинство языков ассемблера имеют менее мощные процедурные макросы, например, позволяющие повторять блок кода N раз для развертывания цикла ; но они имеют совершенно другой синтаксис, чем настоящий язык ассемблера.
Макросистемы, такие как препроцессор C, описанный ранее, которые работают на уровне лексических токенов, не могут надежно сохранять лексическую структуру. Вместо этого синтаксические макросистемы работают на уровне абстрактных синтаксических деревьев и сохраняют лексическую структуру исходной программы. Наиболее широко используемые реализации синтаксических макросистем встречаются в Lisp -подобных языках. Эти языки особенно подходят для макросов такого типа благодаря единообразному синтаксису в скобках (известному как S-выражения ). В частности, единый синтаксис упрощает определение вызовов макросов. Макросы Lisp преобразуют саму структуру программы, используя полный язык для выражения таких преобразований. Хотя синтаксические макросы часто встречаются в Lisp-подобных языках, они также доступны и в других языках, таких как Prolog , [6] Erlang , [7] Dylan , [8] Scala , [9] Nemerle , [10] Rust , [11] ] Эликсир , [12] Ним , [13] Хаксе , [14] и Джулия . [15] Они также доступны как сторонние расширения для JavaScript [16] и C# . [17]
До того, как в Лиспе появились макросы, в нем были так называемые FEXPR , операторы, подобные функциям, входные данные которых представляли собой не значения, вычисленные аргументами, а скорее синтаксические формы аргументов, а выходные данные были значениями, которые использовались в вычислениях. Другими словами, FEXPR были реализованы на том же уровне, что и EVAL, и предоставили окно на уровень метаоценки. В целом выяснилось, что эту модель сложно эффективно рассуждать. [18]
В 1963 году Тимоти Харт предложил добавить макросы в Lisp 1.5 в AI Memo 57: Определения макросов для LISP. [19]
Анафорический макрос — это тип программного макроса, который намеренно фиксирует некоторую форму, предоставленную макросу, на которую можно ссылаться с помощью анафоры (выражения, ссылающегося на другое). Анафорические макросы впервые появились в книге Пола Грэма «О Лиспе», и их название является отсылкой к лингвистической анафоре — использованию слов вместо предыдущих слов.
В середине восьмидесятых годов в ряде статей [20] [21] было введено понятие гигиенического расширения макросов ( syntax-rules
), системы, основанной на шаблонах, в которой синтаксическая среда определения макроса и использования макроса различна, что позволяет определяющим макросы и пользователям не беспокоиться о непреднамеренном захвате переменных (см. ссылочную прозрачность ). Гигиенические макросы стандартизированы для Scheme в стандартах R5RS , R6RS и R7RS . Существует ряд конкурирующих реализаций гигиенических макросов, таких как syntax-rules
, syntax-case
, явное переименование и синтаксические замыкания. Оба syntax-rules
стандартизированы syntax-case
в стандартах Схемы.
Недавно Рэкет объединил понятия гигиенических макросов с «башней оценщиков», так что время синтаксического расширения одной макросистемы является обычным временем выполнения другого блока кода [22] и показал, как применять чередующееся расширение и синтаксический анализ. на языке без скобок. [23]
Ряд языков, кроме Scheme, либо реализуют гигиенические макросы, либо реализуют частично гигиенические системы. Примеры включают Scala , Rust , Elixir , Julia , Dylan , Nim и Nemerle .
cond
но отсутствует if
, можно определить последнее в терминах первого с помощью макросов. Например, в Scheme есть как продолжения , так и гигиенические макросы, что позволяет программисту разрабатывать свои собственные абстракции управления, такие как циклы и конструкции раннего выхода, без необходимости встраивать их в язык.let
в применение функции к набору аргументов.Феллизен предполагает [25] , что эти три категории составляют основные законные способы использования макросов в такой системе. Другие предложили альтернативное использование макросов, например, анафорические макросы в макросистемах, которые негигиеничны или допускают выборочную негигиеническую трансформацию.
Взаимодействие макросов и других особенностей языка было продуктивной областью исследований. Например, компоненты и модули полезны для крупномасштабного программирования, но для их совместного использования необходимо определить взаимодействие макросов и других конструкций. Для Scheme и других языков с макросами были предложены модули и системы компонентов, которые могут взаимодействовать с макросами. Например, язык Racket расширяет понятие макросистемы до синтаксической башни, где макросы могут быть написаны на языках, включая макросы, используя гигиену, чтобы гарантировать, что синтаксические уровни различимы, и позволяя модулям экспортировать макросы в другие модули.
Макросы обычно используются для сопоставления короткой строки (вызова макроса) с более длинной последовательностью инструкций. Другой, менее распространенный вариант использования макросов — обратное: сопоставление последовательности инструкций со строкой макроса. Именно такой подход был использован в системе мобильного программирования STAGE2 , которая использовала элементарный компилятор макросов (называемый SIMCMP) для отображения конкретного набора команд данного компьютера в машинно-независимые макросы. Приложения (особенно компиляторы), написанные с использованием этих машинно-независимых макросов, затем можно запускать без изменений на любом компьютере, оснащенном элементарным компилятором макросов. Первое приложение, запускаемое в таком контексте, представляет собой более сложный и мощный компилятор макросов, написанный на машинно-независимом языке макросов. Этот макрокомпилятор применяется к самому себе в режиме начальной загрузки для создания скомпилированной и гораздо более эффективной версии самого себя. Преимущество этого подхода состоит в том, что сложные приложения можно переносить с одного компьютера на другой компьютер с минимальными усилиями (для каждой целевой архитектуры достаточно просто написать элементарный макрокомпилятор). [26] [27] Появление современных языков программирования, особенно C , для которого компиляторы доступны практически на всех компьютерах, сделало такой подход излишним. Однако это был один из первых (если не первый) случаев начальной загрузки компилятора .
Хотя макрокоманды могут быть определены программистом для любого набора собственных программных инструкций ассемблера, обычно макросы связаны с библиотеками макросов, поставляемыми с операционной системой, обеспечивающими доступ к функциям операционной системы, таким как
В старых операционных системах, таких как те, которые использовались на мэйнфреймах IBM, полная функциональность операционной системы была доступна только для программ на языке ассемблера, но не для программ на языке высокого уровня (если, конечно, не использовались подпрограммы языка ассемблера), поскольку стандартные макрокоманды не всегда выполнялись. иметь аналоги в процедурах, доступных в языках высокого уровня.
В середине 1950-х годов, когда программирование на языке ассемблера широко использовалось для написания программ для цифровых компьютеров , использование макроинструкций было инициировано для двух основных целей: уменьшить объем программного кода, который необходимо было написать, путем создания нескольких операторов языка ассемблера. из одной макрокоманды и для обеспечения соблюдения стандартов написания программ, например, стандартного определения команд ввода/вывода. [30] Макроинструкции фактически были промежуточным этапом между программированием на языке ассемблера и последующими языками программирования высокого уровня , такими как FORTRAN и COBOL . Две из первых программных установок для разработки «макроязыков» для компьютера IBM 705 находились в Dow Chemical Corp. в Делавэре и в Управлении авиационных материалов Управления логистики баллистических ракет в Калифорнии. Макроинструкция, написанная в формате целевого языка ассемблера, обрабатывалась макрокомпилятором, который был препроцессором ассемблера, для генерации одной или нескольких инструкций ассемблера, которые затем обрабатывались программой ассемблера, которая транслировала бы инструкции языка ассемблера в инструкции машинного языка . [31]
К концу 1950-х годов за макроязыком последовали макроассемблеры . Это была комбинация того и другого, где одна программа выполняла обе функции: макропрепроцессора и ассемблера в одном пакете. [31] [ не удалось проверить ]
В 1959 году Дуглас Э. Иствуд и Дуглас Макилрой из Bell Labs ввели условные и рекурсивные макросы в популярный ассемблер SAP [32] , создав так называемый Macro SAP. [33] Статья Макилроя 1960 года была плодотворной в области расширения любых языков программирования (включая языки высокого уровня ) с помощью макропроцессоров . [34] [32]
Макросемблеры позволяли программистам на языке ассемблера реализовывать свои собственные макроязыки и обеспечивали ограниченную переносимость кода между двумя машинами с одним и тем же процессором, но с разными операционными системами, например, ранними версиями MS-DOS и CP/M-86 . Библиотека макросов должна быть написана для каждой целевой машины, а не для всей программы на языке ассемблера. Обратите внимание, что более мощные ассемблеры макросов позволяли использовать конструкции условной сборки в макроинструкциях, которые могли генерировать разный код на разных машинах или в разных операционных системах, что уменьшало потребность в нескольких библиотеках. [ нужна цитата ]
В 1980-х и начале 1990-х годов настольные ПК работали на частоте всего несколько МГц, а программы на языке ассемблера обычно использовались для ускорения программ, написанных на C, Fortran, Pascal и других языках. В то время в этих языках использовались разные соглашения о вызовах. Макросы можно использовать для взаимодействия подпрограмм, написанных на языке ассемблера, с интерфейсом приложений, написанных практически на любом языке. Опять же, базовый код ассемблера остался прежним, только нужно было написать библиотеки макросов для каждого целевого языка. [ нужна цитата ]
В современных операционных системах, таких как Unix и ее производных, доступ к операционной системе осуществляется через подпрограммы, обычно предоставляемые динамическими библиотеками. Языки высокого уровня, такие как C, предлагают полный доступ к функциям операционной системы, устраняя необходимость в программах на языке ассемблера для реализации такой функциональности. [ нужна цитата ]
Одним из важных применений макросов программатора является экономия времени и ошибок канцелярского типа при написании последовательности инструкций, которые часто повторяются в ходе выполнения программы.