9.6.宏的扩充

MASM 6.11编程系统对宏定义及其相关语句进行了一定程度的扩充。虽然这些扩充给编程带来了一些方便,但它们不一定能被其它的汇编语言编程系统所接受,所以,程序员在使用这些方便的扩充功能时,要注意到可能带来的限制。

下面介绍MASM 6.11编程系统对宏及其相关语句的扩充。

9.6.1 宏定义形式

在MASM 6.11编程系统中,其宏定义的一般形式如下:

宏名 MACRO  [参数1[:tag]] [,参数2[:tag]…]

[LOCAL varlist] ;宏定义体内的局部变量和标号

… ;宏的定义体

[EXITM [value]]

ENDM

对上述宏定义的说明与9.1.1节中的说明完全一致,其需要增加的说明如下:

tag——其值可以是REQ、=<缺省值>或VARARG

REQ指定该参数是不可缺少。在宏引用时,若该参数不对应某个“实参”,那么,汇编程序会报错;

=<缺省值> 在宏引用时,若不指定该参数所对应的“实参”,那么,该参数就取其缺省值;

VARARG该参数对应一个可变长的实参表,各实参之间用逗号分开;若参数的属性指定为VARARG,那么,该参数一定要是最后一个参数。有关该属性的应用,请见随后9.6.7节中的举例。

value——宏功能的返回值,其为可选项。

9.6.2 重复伪指令REPEAT

重复伪指令REPEAT与前面9.4.1节中伪指令REPT在功能和使用方式方面完全一致,设置该伪指令的主要原因是保证与先前版本的兼容性。

伪指令REPEAT的使用方式如下:

REPEAT数值表达式

语句序列 ;被重复的汇编语言语句

ENDM

 

 

 

 

 

 

 

 

 

 

9.6.3 循环伪指令WHILE

循环伪指令WHILE的使用方式如下:

WHILE Exp

语句序列 ;被重复的汇编语言语句

ENDM

 

 

 

 

 

 

 

 

 

 

其功能是先判断表达式Exp是否为假(或为0),若是,则终止该伪指令的功能,否则,循环汇编下面的指令块。表达式Exp是能在汇编时计算出其值的数值表达式。

例9.16:编写一个带有参数result和k的宏,其功能是把1+2+…+k的累加和存入result之中,其中:result是不可缺省的,k的缺省值为1。

解:

SUM MACRO result:REQ, k:=<1>

LOCAL n

n = k

mov result, 0

WHILE n

 add    result, n

n = n – 1

ENDM

ENDM

有了上面的宏定义,就可书写下面的宏引用来实现其相应的功能:

SUM ax, 10 ;寄存器ax=1+2+3+…+10

SUM bh ;寄存器bh=1,因为第二个形参取其缺省值

SUM ecx, 100 ;寄存器ecx=1+2+3+…+100

SUM data, 20 ;存储单元data=1+2+3+…+20

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

9.6.4 循环伪指令FOR

循环伪指令FOR与9.4.2节中伪指令IRP在功能上完全一致,设置该伪指令的原因也是为了保证与先前版本的兼容性。

伪指令FOR的使用方式如下:

FOR  parameter[:REQ|:=<default>], <argument [, argument]…>

语句序列 ;被重复的汇编语言语句

ENDM

其中各参数的说明如下:

Parameter一个合法的标识符,它依次取后面参数表中的值。在指令序列中,该变量的每次出现都用其值所替换;

:REQ说明该变量的取值不能为空;

:=<default>指定该变量的缺省值,若后面的参数表缺省某个参数(用连续的逗号),这时,该循环变量将取其缺省值;

Argument参数表中可含有文本、符号、字符串或数值常量,每个参数之间要用逗号分割。

例如:

FOR data:=<?>, <“123”, , 21, 0>

DB  data

ENDM

……

FOR reg:REQ, <ax, bx, dx>

push  reg

ENDM

该语句在宏展开时,将得到下列语句:

DB ”123″

DB  ?

DB  21

DB  0

……

push  ax

push  bx

push  dx

9.6.5 循环伪指令FORC

循环伪指令FOR与9.4.3节中伪指令IRPC在功能上完全一致,它也是为保证与先前版本的兼容性而设置的。

伪指令FORC的使用方式如下:

FORC parameter, <string>

语句序列 ;被重复的汇编语言语句

ENDM

 

 

 

 

 

 

 

 

 

 

其中各参数的说明如下:

parameter:一个合法的标识符,它依次取字符串中的每个字符。在语句序列中,该变量的每次出现都用其值所替换;

String:一个字符串或被定义为字符串的符号名,字符串中的空格也被算为一个字符。括号”<“、”>”是必不可少的。

例如:

FORC data, <1?3>

DB data

ENDM

……

FORC reg, <abd>

  push reg&x

ENDM

该语句在宏展开时,将得到下列语句:

DB 1

DB ?

DB 3

……

push ax

push bx

push dx

9.6.6 转移伪指令GOTO

转移伪指令GOTO用于实现宏定义体内的转移功能,其使用方式如下:

GOTO 标号

:标号     ;标号后不能写指令,但可写注释

该伪指令的功能是使汇编程序转移到“标号”处汇编,它只能在宏定义MACRO、REPEAT、WHILE、FOR和FORC等语句块内使用,该标号也只在该语句块内有效。

9.6.7 宏扩充的举例

例9.17:编写一个给任意寄存器或存储单元清零的宏定义。

解:

Clear list : VARARG

FOR data:REQ, <list>

mov data, 0

ENDM

ENDM

有了上面的宏定义,下面的二个宏引用都是正确的,尽管宏引用时所带的参数个数是不同的。这正是参数属性VARARG的作用所在。

Clear   ax, bx

……

Clear   si, cl, MemVar, edx      ;MemVar是内存变量,任意类型都可以

这二个宏引用展开时所得到的指令如下:

mov ax, 0

mov bx, 0

……

mov si, 0

mov cl, 0

mov MemVar, 0

mov edx, 0

9.6.8 系统定义的宏

MASM 6.11系统定义了大量的标准宏,程序员能很方便地使用它们。在使用这些系统宏之前,要象C语言那样用伪指令INCLUDE把有关“宏库”文件包含在用户的源程序中。主要的系统宏库文件有:DOS.INC和BIOS.INC,它们存放在系统的include子目录中。

例9.18:使用系统宏定义,编写从键盘上读取一个字符。

解:

include dos.inc     ;把系统宏定义文件包含在源程序之中

……

@getchar 1, 1     ;引用系统宏定义

……

下面是系统宏@getchar的使用参数描述和定义,其它系统宏的有关信息请参阅相关的宏定义文件。

1、系统宏@GetChar的使用说明

宏的功能:从键盘读字符

使用语法:@GetChar  [echo] [,[break] [,clearbuf]]

参数说明:

<echo> ;常量,非零表示“回显”,缺省值为“回显”

<break>;常量,非零表示接受“^C”,缺省值为“接受”

<clearbuf>;常量,非零表示清键盘缓冲区,缺省值为“不清”

返回参数:AL=ASCII码

内容破坏:AX,DL(若回显,且不接受^C)

参见内容:INT 21h — 01h、07h、08h和0Ch,@GetStr

2、系统宏@GetChar的定义

该宏定义在宏库文件dos.inc中,其具体宏定义如下:

@GetChar

MACRO  ech:=<1>, cc:=<1>, clear:=<0>

LOCAL funct, disp

disp = 1

IF ech

IF cc

funct = 01h    ;使用功能1

ELSE

funct = 07h    ;使用功能7

disp = 02h     ;设置需要回显标志

ENDIF

ELSE

 IF cc

funct = 08h    ;使用功能8

ELSE

funct = 07h    ;使用功能7

ENDIF

ENDIF

IFE clear

mov ah, funct   ;置功能号

 ELSE

  mov ah, 0Ch    ;先清输入缓冲区,再接受键盘输入

mov al, funct

 ENDIF

  Int 21h         ;调用DOS功能中断

  IF disp EQ 02h     ;检查是否需要回显

  mov dl, al

  mov ah, 02h

int 21h

ENDIF

ENDM

对于上面的宏定义,程序员完全可以把它修改成其它形式的宏定义。

 

© 版权声明

相关文章

暂无评论

none
暂无评论...