`
qdujunjie
  • 浏览: 108711 次
  • 性别: Icon_minigender_1
  • 来自: Mars
社区版块
存档分类
最新评论

汇编语言醉汉走路代码分析(15)

 
阅读更多

来自于《Intel汇编语言程序设计》(第四版)第10章----结构和宏。

所谓醉汉走路,即在一个XY坐标的二维地图中,模拟一个醉汉走路的轨迹(原书中说的是一个喝醉了酒还未清醒的教授)。此处仍然用到了结构和宏,来看一下原书代码:

 

 

TITLE Drunkard's Walk                   (Walk.asm)

INCLUDE Irvine32.inc

WalkMax = 50

StartX = 25

StartY = 25

DrunkardWalk STRUCT

         path COORD WalkMax DUP(<0,0>)

         pathsUsed WORD 0

DrunkardWalk ENDS

DisplayPosition PROTO currX:WORD,currY:WORD

.data

aWalk DrunkardWalk <>

.code

main PROC

        mov esi,offset aWalk

        call TakeDrunkenWalk

        exit

main ENDP

;------------------------------------------------------------------------------

TakeDrunkenWalk PROC

LOCAL currX:WORD,currY:WORD

;

; Take a walk in random direction (north ,south,east,west).

; Receives : ESI points to a DrunkardWalk structure

; Returns : the structure is initialized with random values

;------------------------------------------------------------------------------

          pushad

; Point EDI to the array of  COORD objects.

          mov edi,esi

          add edi,OFFSET DrunkardWalk.path

          mov ecx,WalkMax                 ; loop count

          mov currX,StartX                   ; current X-location

          mov currY,StartY                    ; current Y-location

Again:

          ; insert current location in array

          mov ax,currX

          mov (COORD PTR [edi]).X , ax

          mov ax,currY

          mov (COORD PTR [edi]).Y , ax

          INVOKE DisplayPosition , currX , currY

          mov eax,4            ; choose a direction (0-3)

          call RandomRange

         

          .IF eax==0                    ; north

          inc currY

          .ELSEIF eax==1            ; south

          dec currY

          .ELSEIF eax==2            ; west

          dec currX

          .ELSE                            ; east (eax = 3)

           inc currX

          .ENDIF

          add edi,TYPE COORD    ; point to next COORD

          loop Again

Finish:

          mov (DrunkardWalk PTR [esi]).pathsUsed,WalkMax

          popad

          ret

TakeDrunkenWalk ENDP

;------------------------------------------------------------------------------

DisplayPosition PROC currX:WORD,currY:WORD

; Display the current X and Y position.

;------------------------------------------------------------------------------

.data

commaStr BYTE ",",0

.code

           pushad

           movzx eax,currX                          ; current X postion

           call WriteDec

           mov edx, OFFSET commaStr        ; "," string

           call WriteString

           movzx eax,currY                          ; current Y position

           call WriteDec

           call Crlf

           popad

           ret

DisplayPosition ENDP

END main

 

 

让我们用代码注释来具体分析:

 

 

TITLE Drunkard's Walk                   (Walk.asm)

INCLUDE Irvine32.inc                              ; 包含了作者的库,许多函数就来自于这个库,比如WriteString,WriteDec,RandomRange函数等等

WalkMax = 50                                         ; 最多能行走的步数

StartX = 25                                             ; 开始X坐标

StartY = 25                                             ; 开始Y坐标

DrunkardWalk STRUCT                              ; 一个醉汉的结构

         path COORD WalkMax DUP(<0,0>)  ; 一个存储行走过得坐标位置的COORD类型的结构数组

         pathsUsed WORD 0                         ; 存储行走过的步数

DrunkardWalk ENDS                                 ; 结构结束

DisplayPosition PROTO currX:WORD,currY:WORD        ;  DisplayPosition 函数的原型声明

.data

aWalk DrunkardWalk <>                            ; 声明了一个DrunkardWalk 结构变量aWalk

.code

main PROC                                                 ; 开始主程序

        mov esi,offset aWalk                          ; 将aWalk 的偏移地址赋值到esi中

        call TakeDrunkenWalk                        ; 调用本逻辑的主要函数TakeDrunkenWalk,让“醉汉”走起来

        exit

main ENDP

;------------------------------------------------------------------------------

TakeDrunkenWalk PROC

LOCAL currX:WORD,currY:WORD

;

; Take a walk in random direction (north ,south,east,west).        

; Receives : ESI points to a DrunkardWalk structure                  ;记得调用之前把aWalk赋给了ESI吗?本函数接收esi为参数

; Returns : the structure is initialized with random values

;------------------------------------------------------------------------------

          pushad                                                                                ; 以防万一,将所有寄存器压入堆栈

; Point EDI to the array of  COORD objects.

          mov edi,esi                                                                          ; 将ESI赋到edi中

          add edi,OFFSET DrunkardWalk.path                                    ; 计算出了aWalk结构中的path成员地址

          mov ecx,WalkMax                 ; loop count                            ; 最多能走的步数赋到ecx中

          mov currX,StartX                   ; current X-location                 ; 开始X坐标赋到currX中

          mov currY,StartY                    ; current Y-location                ; 开始Y坐标赋到currY中

Again:

          ; insert current location in array

          mov ax,currX                                       ; 将currX保存到ax中

          mov (COORD PTR [edi]).X , ax             ; 将ax赋到aWalk结构中的path成员的X成员,因为是间接引用,所以这里使用了PTR

          mov ax,currY

          mov (COORD PTR [edi]).Y , ax

          INVOKE DisplayPosition , currX , currY              ; 调用DisplayPosition 打印目前的XY坐标

          mov eax,4            ; choose a direction (0-3)    ; 将4赋值到eax中,用来生成随机数,范围为0-3

          call RandomRange                                            ; 生成随机数,仍然保存在eax中

          

          .IF eax==0                    ; north                         ; 判断生成的随机数到底是哪个方向,然后分情况进行相应计算

          inc currY

          .ELSEIF eax==1            ; south

          dec currY

          .ELSEIF eax==2            ; west

          dec currX

          .ELSE                            ; east (eax = 3)

           inc currX

          .ENDIF

          add edi,TYPE COORD    ; 指向path成员的下一个坐标地址

          loop Again                    ; 接着走醉步

Finish:

          mov (DrunkardWalk PTR [esi]).pathsUsed,WalkMax    ; 不知道这里要为什么要赋回去

          popad

          ret

TakeDrunkenWalk ENDP

;------------------------------------------------------------------------------

DisplayPosition PROC currX:WORD,currY:WORD                           

; 用来将X,Y坐标输出的函数,接收X,Y坐标作为参数

;------------------------------------------------------------------------------

.data

commaStr BYTE ",",0

.code

           pushad

           movzx eax,currX                          ; current X postion

           call WriteDec

           mov edx, OFFSET commaStr        ; "," string

           call WriteString

           movzx eax,currY                          ; current Y position

           call WriteDec

           call Crlf

           popad

           ret

DisplayPosition ENDP

END main

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics