汇编语言定使用WHILE、REPEAT、FOR 和 FORC伪指令定义重复语句块
- WHILE 伪指令根据一个布尔表达式来重复语句块。
- REPEAT 伪指令根据计数器的值来重复语句块。
- FOR 伪指令通过遍历符号列表来重复语句块。
- FORC 伪指令通过遍历字符串来重复语句块。
WHILE 伪指令
WHILE 伪指令重复一个语句块,直到特定的常量表达式为真。其语法如下:
	WHILE constExpression
	    statements
	ENDM
.data
val1 = 1
val2 = 1
DWORD val1                   ;前两个值
DWORD val2
val3 = val1 + val2
WHILE val3 LT 0F0000000h
    DWORD val3
    val1 = val2
    val2 = val3
    val3 = val1 + val2
ENDM
REEPEAT 伪指令
在汇编时,REPEAT 伪指令将一个语句块重复固定次数。其语法如下:
	REPEAT constExpression
	    statements
	ENDM
在创建数组时,REPEAT 的用法与 DUP 类似。在下面的例子中,WeatherReadings 结构含有一个地点字符串和一个包含了降雨量与湿度读数的数组:
WEEKS_PER_YEAR = 52
    WeatherReadings STRUCT
    location BYTE 50 DUP(0)
    REPEAT WEEKS_PER_YEAR
        LOCAL rainfall, humidity
        rainfall DWORD ?
        humidity DWORD ?
    ENDM
WeatherReadings ENDS
由于汇编时循环会对降雨量和湿度重定义,使用 LOCAL 伪指令可以避免因其导致的错误。FOR 伪指令
FOR 伪指令通过迭代用逗号分隔的符号列表来重复一个语句块。列表中的每个符号都会引发循环的一次迭代过程。其语法如下:
	FOR parameter,<arg1,arg2,arg3,...>
	    statements
	ENDM
【示例】现在创建一个学生注册的场景,其中,COURSE 结构含有课程编号和学分值;SEMESTER 结构包含一个有 6 门课程的数组和一个计数器 NumCourses:
COURSE STRUCT
    Number BYTE 9 DUP(?)
    Credits BYTE ?
COURSE ENDS
;semester 含有一个课程数组。
SEMESTER STRUCT
    Courses COURSE 6 DUP(<>)
    NumCourses WORD ?
SEMESTER ENDS
使用 FOR 循环可以定义 4 个 SEMESTER 对象,每一个对象都从由尖括号括起的符号列表中选择一个不同的名称:
	.data
	    FOR semName,<Fall2013, Spring2014, Summer2014, Fall2014>
	    semName SEMESTER <>
	ENDM
	.data
	Fall2013 SEMESTER <>
	Spring2014 SEMESTER <>
	Summer2014 SEMESTER <>
	Fall2014 SEMESTER <>
FORC 伪指令
FORC 伪指令通过迭代字符串来重复一个语句块。字符串中的每个字符都会引发循环的一次迭代过程。其语法如下:
	FORC parameter, <string>
	    statements
	ENDM
下面的例子创建了一个字符查找表,其中包含了一些非字母字符。注意,< 和 > 的前面必须有文字字符(!)运算符,以防它们违反FORC伪指令的语法:
	Delimiters LABEL BYTE
	FORC code, <@#$%^&*!<!>>
	    BYTE "&code"
	ENDM
	00000000  40  1  BYTE  "@"
	00000001  23  1  BYTE  "#"
	00000002  24  1  BYTE  "$"
	00000003  25  1  BYTE  "%"
	00000004  5E  1  BYTE  "^"
	00000005  26  1  BYTE  "&"
	00000006  2A  1  BYTE  "*"
	00000007  3C  1  BYTE  "<"
	00000008  3E  1  BYTE  ">"
示例:链表
结合结构声明与 REPEAT 伪指令以指示汇编器创建一个链表的数据结构是相当简单的。链表中的每个节点都含有一个数据域和一个链接域:
在数据域中,一个或多个变量可以保存每个节点所特有的数据。在链接域中,一个指针包含了链表下一个节点的地址。最后一个节点的链接域通常是一个空指针。现在编写程序创建并显示一个简单链表。首先,程序定义一个节点,其中含有一个整数(数据)和一个指向下一个节点的指针:
	ListNode STRUCT
	    NodeData DWORD ?    ;节点的数据
	    NextPtr DWORD ?        ;指向下一个节点的指针
	ListNode ENDS
TotalNodeCount = 15
NULL = 0
Counter = 0
.data
LinkedList LABEL PTR ListNode
REPEAT TotalNodeCount
    Counter = Counter + 1
    ListNode <Counter, ($ + Counter * SIZEOF ListNode)>
ENDM
表达式 ($+Counter*SIZEOF ListNode) 告诉汇编器把计数值与 ListNode 的大小相乘,并将乘积与当前地址计数器相加。结果值插入结构内的 NextPtr 域。[注意一个有趣的现象:位置计数器的值 ($) 固定在表的第一节点上。]该表用尾节点 (tail node) 来标记末尾,其 NextPtr 域为空 (0):ListNode <0,0>
当程序遍历该表时,它用下面的语句检索 NextPtr 域,并将其与 NULL 比较,以检查是否为表的末尾:
	mov eax,(ListNode PTR [esi]).NextPtr
	cmp eax,NULL
程序清单
完整的程序清单如下所示。在 main 中,一个循环遍历链表并显示全部的节点值。与使用固定计数值控制循环相比,程序检查是否为尾节点的空指针,若是则停止循环:
; 创建一个链表            (List.asm)
INCLUDE Irvine32.inc
ListNode STRUCT
  NodeData DWORD ?
  NextPtr  DWORD ?
ListNode ENDS
TotalNodeCount = 15
NULL = 0
Counter = 0
.data
LinkedList LABEL PTR ListNode
REPT TotalNodeCount
    Counter = Counter + 1
    ListNode <Counter, ($ + Counter * SIZEOF ListNode)>
ENDM
ListNode <0,0>    ; tail node
.code
main PROC
    mov  esi,OFFSET LinkedList
; 显示 NodeData 域的值
NextNode:
    ; 检查是否为尾节点
    mov  eax,(ListNode PTR [esi]).NextPtr
    cmp  eax,NULL
    je   quit
    ; 显示节点数据
    mov  eax,(ListNode PTR [esi]).NodeData
    call WriteDec
    call Crlf
    ; 获取下一个节点的指针
    mov  esi,(ListNode PTR [esi]).NextPtr
    jmp  NextNode
quit:
    exit
main ENDP
END main
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算
