宏(计算机科学)
在计算机编程中,一个宏(“宏观指示”的简称;来自希腊语 μακρο- “长,大”)是一种规则或模式,它指定应如何将某个输入映射到替换输出。将宏应用于输入被称为宏扩展。输入和输出可以是一系列词汇令牌或字符,或语法树。在软件应用程序中支持字符宏,以使调用通用命令序列变得容易。某些编程语言支持令牌和树宏,以启用代码重复使用或扩展语言,有时是针对特定域的语言。
宏用于使程序员作为单个程序语句提供一系列计算说明,从而使编程任务越来越乏味且易于错误。 (因此,它们被称为“宏”,因为可以从“小”字符序列扩展一个“大”代码块。)宏通常允许位置或关键字参数,这些参数决定了条件汇编程序生成的内容并已用于使用了什么并已用于使用。根据操作系统,平台或其他因素等变量创建整个程序或程序套件。该术语源自“宏指令”,此类扩展最初用于生成汇编语言代码。
键盘和鼠标宏
键盘宏和鼠标宏可以简短的击键和鼠标动作序列转换为其他耗时的键击和鼠标动作序列。这样,可以自动化的击键和鼠标运动的经常使用或重复的序列。创建这些宏的单独程序称为宏记录器。
在1980年代,宏观程序(最初是SmartKey ,然后是SuperKey,KeyWorks,Prokey)非常受欢迎,首先是自动格式化剧本的一种手段,然后是各种用户输入任务。这些程序基于终止居民的操作模式,并应用于所有键盘输入,无论其发生在哪种情况下。在鼠标驱动的用户界面出现以及应用程序中的键盘和鼠标宏的可用性(例如文字处理器和电子表格)之后,它们在某种程度上陷入了过时,从而可以创建对应用程序敏感的键盘宏。
键盘宏可用于大量多人在线角色扮演游戏(MMORPG),以执行重复但有利可图的任务,从而积累了资源。由于这是在没有人力的情况下完成的,因此它可能会偏向游戏的经济性。因此,使用宏是对大多数MMORPG的TOS或EULA的侵犯,他们的管理员花费大量精力来抑制它们。
应用宏和脚本
使用应用程序内置的宏观功能创建的键盘和鼠标宏有时称为应用程序宏。它们是通过执行序列并让应用程序记录操作的。也可能存在一种基本的宏观编程语言,最常见的是脚本语言,可以直接访问应用程序的功能。
程序员的文本编辑器Emacs (“编辑宏”的缩写)遵循此想法得出的结论。实际上,大多数编辑器都是由宏制成的。 Emacs最初是在编辑语言Teco中设计为一组宏。后来将其移植到LISP的方言。
另一个程序员的文本编辑器VIM ( VI的后代)也具有键盘宏的实现。它可以记录到一个人在键盘上类型的寄存器(宏),并且可以像Microsoft Office的VBA宏一样重播或编辑。 VIM还拥有一种称为Vimscript的脚本语言,可以创建宏。
Visual Basic for Applications (VBA)是Microsoft Office 97到Office 2019中的一种编程语言(尽管在Office 97之前可以在Office的某些组件中使用)。但是,它的功能已从最初包含在其中一些应用中的宏观语言发展并取代。
Xedit在VM的对话监视器系统(CMS)组件上运行,支持在Exec , Exec2和Rexx中编写的宏,并且某些CMS命令实际上是Xedit Macros周围的包装器。 Hessling Editor (The)是Xedit的部分克隆,使用Regina和开放对象REXX (Oorexx)支持REXX宏。许多常见的应用程序,以及PC上的一些应用程序,将REXX用作脚本语言。
宏病毒
打开文档时, VBA可以访问大多数Microsoft Windows系统调用和执行。这使得在VBA(通常称为宏病毒)中编写计算机病毒相对容易。在1990年代中期,这成为计算机病毒的最常见类型之一。但是,在1990年代后期,至今,微软一直在修补和更新其程序。此外,当前的反病毒计划立即抵消了此类攻击。
参数化和无参数宏
参数化的宏是能够将给定对象插入其扩展中的宏。这给了宏一些功能的功能。
作为一个简单的例子,在C编程语言中,这是一个典型的宏,不是参数化的宏,即,无参数宏:
#define PI 3.14159
这导致PI
总是被替换3.14159
无论发生在哪里。另一方面,参数化宏的一个示例是:
#define pred(x) ((x)-1)
该宏扩展的内容取决于传递哪个参数x 。以下是一些可能的扩展:
pred(2) → ((2) -1) pred(y+2) → ((y+2) -1) pred(f(5)) → ((f(5))-1)
参数化宏是执行在线扩展的有用源级别的机制,但是在C等语言中,它们使用简单的文本替代,它们在执行在线扩展的其他机制中具有许多严重的缺点,例如在线扩展。
另一方面,在LISP , PL/I和方案等语言中使用的参数化宏更加强大,能够根据其参数对制作的代码做出决定;因此,它们可以有效地用于执行运行时代码生成。
文本实体宏
诸如C和某些汇编语言之类的语言具有基本的宏观系统,以编译器或汇编器的预处理程序实现。 C预处理器宏通过简单的文本替换在令牌而不是字符级别来工作。但是,无法使用预处理程序实现更复杂的汇编器,例如IBM高级汇编器(HLASM)的宏观设施;组装指令和数据的代码散布在组装宏观调用的代码中。
宏的经典用途是在计算机排版系统TEX及其导数中,其中大多数功能基于宏。
MACROML是一种实验系统,旨在调和静态键入和宏观系统。 Nemerle具有键入语法宏,一种思考这些语法宏的生产方法是一种多阶段计算。
其他示例:
- M4是一个复杂的独立宏处理器。
- trac
- 宏扩展TAL ,随附的模板属性语言
- SMX:用于网页
- ML/1 (宏语言一)
- 通用大量生成器是一种上下文模式匹配宏处理器,可以描述为正则表达式的组合, EBNF和尴尬
- Troff和NROFF :用于排版和格式化UNIX手册。
- CMS Exec :用于命令行宏和应用程序宏
- 对话监视系统(CMS)中的Exec 2 :用于命令行宏和应用程序宏
- Clist在IBM的时间共享选项(TSO)中:用于命令行宏和应用程序宏
- REXX :用于命令行宏和应用宏,例如, Amigaos ,CMS, OS/2 ,TSO
- 脚本:用于格式化文档
- 各种外壳,例如, Linux
一些主要的应用程序已将其他应用程序(例如, Xedit在CMS中)编写为文本宏。
可嵌入的语言
某些语言(例如PHP )可以嵌入自由格式文本或其他语言的源代码中。识别代码片段的机制(例如,由<?php
和?>
)类似于文本宏语言,但是它们更强大,功能齐全的语言。
程序宏
PL/I语言中的宏以PL/I本身的子集写入:编译器在编译时间执行“预处理器语句”,并且此执行的输出构成了编译的代码的一部分。使用熟悉的程序语言作为宏观语言的能力比文本替代宏具有更大的力量,而牺牲了更大且较慢的编译器。
框架技术的框架宏具有自己的命令语法,但也可以包含任何语言的文本。每个帧既是嵌套子组件层次结构中的一个通用组件,又是将自己与其子组件框架集成的过程(解决集成冲突以支持高级子组件的递归过程)。输出是自定义文档,通常是可编译的源模块。框架技术可以避免类似但微妙的组件的扩散,这是自宏和子例程发明以来困扰软件开发的问题。
大多数汇编语言具有功能较小的程序宏设施,例如,允许重复n次n次循环曲线。但是,这些语法与实际的汇编语言完全不同。
句法宏
宏系统(如前所述的C预处理器)在词汇代币级别上工作无法可靠地保留词汇结构。句法宏系统在抽象语法树的层面上起作用,并保留原始程序的词汇结构。句法宏观系统使用最广泛的实现是在类似LISP的语言中发现的。这些语言由于其统一的括号语法(称为s-expressions )而特别适合这种宏观。特别是,统一的语法使确定宏的调用变得更加容易。 LISP宏可以改变程序结构本身,并提供完整的语言来表达这种转换。尽管句法宏经常在类似LISP的语言中找到,但它们也有其他语言,例如Prolog , Erlang , Dylan , Scala , Nemerle , Rust , Elixir ,Nim, Nim , Haxe和Julia 。它们也可以作为JavaScript和C#的第三方扩展名。
早期的LISP宏
在LISP拥有宏之前,它具有所谓的fexprs ,类似函数的运算符,其输入不是由参数计算的值,而是参数的句法形式,其输出是要在计算中使用的值。换句话说,FEXPR在与eval相同的级别上实现,并提供了元评估层的窗口。通常发现这是一个很难有效推理的模型。
1963年,蒂莫西·哈特(Timothy Hart)提出了在AI备忘录中的LISP 1.5中添加宏:LISP的宏定义。
放置宏
放置宏是一种编程宏,故意捕获了提供给宏的某种形式,该形式可以由检查器(一种指代另一个表达式)提及。停电宏首次出现在保罗·格雷厄姆(Paul Graham)的LISP上,其名称是对语言性图谱的提及,即用单词用作先前单词的替代品。
卫生宏
在八十年代中期,许多论文引入了卫生宏扩展的概念(syntax-rules
),一个基于模式的系统,其中宏定义和宏使用的句法环境是不同的,允许宏定义器和用户不必担心无意的变量捕获(参见参考透明度)。 R5RS , R6R和R7RS标准的卫生宏已标准化。存在许多相互竞争的卫生宏实施syntax-rules
,syntax-case
,明确的重命名和句法封闭。两个都syntax-rules
和syntax-case
已在计划标准中标准化。
最近,球拍将卫生宏的概念与“评估塔”相结合,因此,一个宏系统的句法扩展时间是另一个代码块的普通运行时,并展示了如何将交织的扩展和在非非代码中进行解析。 - 父母的语言。
除了方案以外的许多语言要幺实施卫生宏或实施部分卫生系统。例子包括Scala , Rust , Elixir , Julia , Dylan , Nim和Nemerle 。
申请
- 评估顺序
- 宏系统具有一系列用途。能够选择评估顺序(请参阅懒惰的评估和非图片功能),使创建新的句法结构(例如控制结构)与该语言中的内置的结构无法区分。例如,在具有的LISP方言中
cond
但是缺乏if
,可以根据前者使用宏来定义后者。例如,方案既具有连续性和卫生宏,又使程序员能够设计自己的控制抽象,例如循环和早期退出结构,而无需将它们构建到语言中。 - 数据亚语言和域特异性语言
- 接下来,宏使定义立即编译为代码的数据语言成为可能,这意味着可以以自然而有效的方式实现诸如状态机器之类的构造。
- 结合构建体
- 宏也可以用于引入新的结合构建体。最著名的例子是转变
let
将函数应用于一组参数。
费利森(Felleisen)猜想这三个类别构成了这种系统中宏的主要合法用途。其他人则提出了宏的替代用途,例如在不卫生或允许选择性不卫生转换的宏观系统中的放置宏。
宏和其他语言特征的相互作用一直是研究的富有成效领域。例如,组件和模块对于大规模编程很有用,但是宏的相互作用和这些其他构造必须定义为它们的使用。已经为方案和其他语言与宏提出了可以与宏相互作用的模块和组件系统。例如,球拍语言将宏系统的概念扩展到了句法塔,在那里可以使用卫生来用宏(包括宏(包括宏)编写宏来编写宏来确保句法层是不同的,并允许模块将宏导出到其他模块。
无关机器软件的宏
宏通常用于将短字符串(宏调用)映射到更长的指令序列。宏的另一个不常见的用法是进行反面:将指令序列映射到宏字符串。这是Stage2移动编程系统采用的方法,该系统使用基本的宏观编译器(称为SIMCMP)将给定计算机的特定指令集映射到与机器无关的宏中。然后,在配备有基本宏观编译器的任何计算机上,可以运行这些独立于机器的宏的应用程序(尤其是编译器),而无需更改。在这种情况下,第一个应用程序运行是用无独立的宏观语言编写的更复杂和功能强大的宏编译器。该宏编译器以引导程序的方式应用于自身,以生成自身的编译和更有效的版本。这种方法的优点是,复杂的应用程序可以从一台计算机上移植到一台非常不同的计算机(对于每个目标机器架构,只需编写基本宏观编译器)即可。现代编程语言(尤其是C)的出现,几乎所有计算机都可以使用编译器,它使这种方法变得多余。但是,这是编译器引导程序的第一个实例之一(如果不是第一个)之一。
装配语言
虽然宏指令可以由编程器为任何一组本机汇编程序指令定义
- 通过访问方法访问周围访问(包括宏(包括打开,关闭,读写)等宏)
- 操作系统功能,例如附件,等待和发布子任务的创建和同步。通常,此类宏扩展为可执行代码,例如,对于出口大体结构,
- 定义常数指令的列表,例如DCB宏—DTF(定义文件) DOS或代码和常数的组合,并取决于宏指令的参数(例如参考)的详细信息到一个文件和数据区域以进行读取指令);
- 可执行的代码通常在分支和链接寄存器指令中终止,以调用例程,或者主管呼叫指令直接调用操作系统功能。
- 为系统生成生成2阶段的作业流,例如OS/360 。与典型的宏不同,Sysgen阶段1宏不会生成要加载到存储中的数据或代码,而是使用Punch语句输出JCL和相关数据。
在IBM大型机上使用的较旧操作系统中,完整的操作系统功能仅适用于汇编语言程序,而不是高级语言程序(当然,除非使用汇编语言子例程),因为标准宏指令并非总是如此在可用于高级语言的例程中有对应物。
历史
在1950年代中期,当汇编语言编程通常用于为数字计算机编写程序时,启动了宏指令的使用是出于两个主要目的:减少必须通过生成多个汇编语言语句编写的程序编码量从一项宏指令和执行程序编写标准,例如以标准方式指定输入/输出命令。宏说明实际上是汇编语言编程和随后的高级编程语言(例如Fortran和Cobol)之间的中间步骤。为IBM 705计算机开发“宏观语言”的最早的编程装置是在特拉华州的Dow Chemical Corp.和加利福尼亚州的弹道导弹后勤办公室的Air Matery Command。以目标组装语言格式编写的宏指令将由宏观编译器(是汇编程序的预处理器)处理的,以生成一个或多个汇编语言指令,由汇编程序下一步处理,该指令将由汇编程序进行处理汇编语言说明中的机器语言说明。
到1950年代后期,宏观汇编者之后是宏观语言。这是两个程序都符合两个程序的组合,即宏观处理器和同一软件包中的汇编器的功能。
1959年,贝尔实验室的道格拉斯·E·伊斯特伍德(Douglas E. Eastwood)和道格拉斯·麦克罗伊(Douglas McIlroy)将条件和递归宏引入了流行的SAP汇编器,创建了所谓的Macro SAP 。麦克罗伊(McIlroy)的1960年论文在通过宏处理器扩展任何(包括高级)编程语言的领域是开创性的。
宏汇编器允许汇编语言程序员实施自己的宏观语言,并允许在运行相同CPU但不同操作系统的两台机器之间的代码有限的可移植性,例如, MS-DOS和CP/M-86的早期版本。宏库需要为每个目标机器编写,而不是整体组装语言程序。请注意,更强大的宏汇编器允许在宏指令中使用有条件的装配构造,这些构造可以在不同的机器或不同的操作系统上生成不同的代码,从而减少了对多个库的需求。
在1980年代和1990年代初,台式PC仅在几个MHz上运行,并且通常使用汇编语言程序来加快C,Fortran,Pascal等人编写的程序。当时,这些语言使用了不同的呼叫约定。宏可用于将用汇编语言编写的例程与几乎任何语言编写的应用程序的前端进行连接。同样,基本的汇编语言代码保持不变,只需要为每个目标语言编写宏库。
在UNIX及其导数等现代操作系统中,通常由动态库提供的子例程提供操作系统访问。高级语言(例如C)提供了对操作系统功能的全面访问,从而避免了对此类功能的汇编语言程序的需求。