Irvine chapter 10 Structures and macros. A simple point struct used in next program COORD STRUCT X...

47
Irvine chapter 10 Structures and macros
  • date post

    19-Dec-2015
  • Category

    Documents

  • view

    233
  • download

    0

Transcript of Irvine chapter 10 Structures and macros. A simple point struct used in next program COORD STRUCT X...

Irvine chapter 10

Structures and macros

A simple point struct used in next program

COORD STRUCT

X WORD ?

Y WORD ?

COORD ENDS;; struct requires end-struct

3 points initialized to (1,1), (2,2), (3,3)TITLE Loop Through Array (AllPoints.asm); Loop through the array of points and set their; X and Y values.; Last update: 11/26/01INCLUDE Irvine32.inc;coor is already defined in smallwin referenced by irvine32.inc.data;;;I added a message up here; Create instances of the COORD structure,; assigning values to both X and Y:point1 COORD <5,10>point2 COORD <10,20>NumPoints = 3AllPoints COORD NumPoints DUP(<0,0>);;3 sets of int points.codemain PROC

mov edi,0 ; array indexmov ecx,NumPoints ; loop countermov ax,1 ; starting X, Y values

L1:mov (COORD PTR AllPoints[edi]).X,axmov (COORD PTR AllPoints[edi]).Y,axadd edi,TYPE COORDinc axLoop L1exit

main ENDPEND main• C:\Masm615>allpoints• just made point #1just made point #2just made point #3

An “employee”

typEmployee STRUCT

Idnum BYTE 9 DUP(0)

Lastname BYTE 30 DUP(0)

Years WORD 0

SalaryHistory DWORD 10 DUP(0)

typEmployee ENDS

Employee slide 1TITLE Intro to STRUCT (Struct1.asm)

INCLUDE Irvine32.inc

typEmployee STRUCTIdnum BYTE 9 DUP(0)Lastname BYTE 30 DUP(0)Years WORD 0SalaryHistory DWORD 10 DUP(0)

typEmployee ENDS

.data

worker typEmployee <>

; override all fields. Either angle brackets; or curly braces can be used:person1 typEmployee {"555223333"}person2 typEmployee <"555223333">

; override only the second field:person3 typEmployee <,"Jones">

; skip the first three fields, and; use DUP to initialize the last field:person4 typEmployee <,,,3 DUP(20000)>

Employee slide 2.codemain PROC; Get the offset of a field within a structure:

mov edx,OFFSET typEmployee.SalaryHistory

; The following generates an "undefined identifier" error:;mov edx,OFFSET Salary

; The TYPE, LENGTH, and SIZE operators can be applied; to the structure and its fields:

mov eax,TYPE typEmployee ; 82mov eax,SIZE typEmployeemov eax,SIZE workermov eax,SIZEOF workermov eax,TYPE typEmployee.SalaryHistory ; 4mov eax,LENGTH typEmployee.SalaryHistory ; 10mov eax,SIZE typEmployee.SalaryHistory ; 40

; The TYPE, LENGTH and SIZE operators can be applied; to instances of the structure:

mov eax,TYPE worker ; 82mov eax,TYPE worker.Years ; 2

; Indirect operands require the PTR operator:mov esi,offset workermov ax,(typEmployee PTR [esi]).Years

exitmain ENDPEND main

There is no output from the program but it is a model for building say an array of employees.

Structs can be nested…a rectangle consists of upper left/lower right coords

TITLE Nested Structures (Struct2.asm)

; This program shows how to declare nested; structures, and how to access the members.; Last update: 8/14/01.INCLUDE Irvine32.incRectangle STRUCT

UpperLeft COORD <>LowerRight COORD <>

Rectangle ENDS.datarect1 Rectangle <>rect2 Rectangle { }rect3 Rectangle { {10,20}, {5,15} }rect4 Rectangle < <10,20>, <5,15> >

.codemain PROC; Direct reference to a nested member.

mov rect1.UpperLeft.X,30; Using an indirect operand, access a; nested member.

mov esi,OFFSET rect1mov (Rectangle PTR [esi]).UpperLeft.Y, 40

; Get the offsets of individual members.mov edi,OFFSET rect2.LowerRightmov edi,OFFSET rect2.LowerRight.X

exitmain ENDPEND main

Showtime system time struct & output (I added clrscr)

SYSTEMTIME STRUCT wYear WORD ? wMonth WORD ? wDayOfWeek WORD ? wDay WORD ? wHour WORD ? wMinute WORD ? wSecond WORD ? wMilliseconds WORD ?SYSTEMTIME ENDS

• I added a bunch of output to the original

The rest of showtime.datasysTime SYSTEMTIME <>XYPos COORD <10,5>consoleHandle DWORD ?colonStr BYTE ":",0TheTimeIs BYTE "The time is ",0.codemain PROCcall clrscr; Get the standard output handle for the Win32 Console.

INVOKE GetStdHandle, STD_OUTPUT_HANDLEmov consoleHandle,eax

; Set the cursor position and get the local time zone.INVOKE SetConsoleCursorPosition, consoleHandle, XYPosINVOKE GetLocalTime,ADDR sysTimemov edx,offset yearcall writestringmovzx eax,sysTime.wYear ; yearcall WriteDeccall crlfmov edx,offset month ; call WriteStringmovzx eax,sysTime.wMonth ; monthcall crlfcall WriteDecmov edx,offset day ; ":"call WriteStringmovzx eax,sysTime.wdayofweek ; daycall WriteDec

call Crlfcall Crlfmov edx,OFFSET TheTimeIs ; "The time is "call WriteStringmovzx eax,sysTime.wHour ; hours

call WriteDecmov edx,offset colonStr ; ":"call WriteStringmovzx eax,sysTime.wMinute ; minutescall WriteDecmov edx,offset colonStr ; ":"call WriteStringmovzx eax,sysTime.wSecond ; seconds

call WriteDecexit

main ENDP

A drunkard’s walkC:\Masm615>walk25,2524,2523,2524,2524,2425,2425,2524,2524,2624,2523,2523,2623,2523,2623,2723,2623,2523,2422,2421,2422,2423,2423,2322,2322,2421,2421,2521,2420,2419,24

Main proc for drunkard’s walkINCLUDE Irvine32.incWalkMax = 30StartX = 25StartY = 25DrunkardWalk STRUCT

path COORD WalkMax DUP(<0,0>)pathsUsed WORD 0

DrunkardWalk ENDSDisplayPosition PROTO currX:WORD, currY:WORD.dataaWalk DrunkardWalk <>.codemain PROC

mov esi,offset aWalkcall TakeDrunkenWalkexit

main ENDP

The take-a-walk procTakeDrunkenWalk PROCLOCAL currX:WORD, currY:WORD;; Take a walk in random directions (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,esiadd edi,OFFSET DrunkardWalk.pathmov ecx,WalkMax ; loop countermov currX,StartX ; current X-locationmov currY,StartY ; current Y-location

Again:; Insert current location in array.mov ax,currXmov (COORD PTR [edi]).X,axmov ax,currYmov (COORD PTR [edi]).Y,axINVOKE DisplayPosition, currX, currY;;;this generates output….not shownmov 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

next:add edi,TYPE COORD ; point to next COORDloop Again

finish:mov ax,WalkMax ; count the steps takensub ax,cxmov (DrunkardWalk PTR [esi]).pathsUsed, axpopadret

TakeDrunkenWalk ENDP

A bunch of useful macros• TITLE Useful Macros (Macro2.ASM)

• ; This program demonstrates several useful macros:• ; mGotoxy, mWrite, mWriteLn, mWriteStr, mReadStr,• ; and mDumpMem.• ; Last update: 8/17/01.

• INCLUDE Irvine32.inc

• ;-----------------------------------------------------• mWriteStr MACRO buffer• ;• ; Improved version of mWriteStr that checks for• ; a blank argument.• ;-----------------------------------------------------• IFB <buffer>• ECHO -----------------------------------------• ECHO * Error: parameter missing in mWriteStr• ECHO * (no code generated)• ECHO -----------------------------------------• EXITM• ENDIF• push edx• mov edx,OFFSET buffer• call WriteString• pop edx• ENDM

useful macros continued• ;-----------------------------------------------------• mWrite MACRO text• ;• ; No changes to this macro.• ;-----------------------------------------------------• LOCAL string• .data ;; local data• string BYTE text,0 ;; define the string• .code• push edx• mov edx,OFFSET string• call Writestring• pop edx• ENDM

• ;-----------------------------------------------------• ; This version supplies a default argument.

• mWriteLn MACRO text := < " " >• ;-----------------------------------------------------• mWrite text• call Crlf• ENDM

useful macros continued• ;-----------------------------------------------------• mGotoxyConst MACRO X:REQ, Y:REQ• ;• ; Set the cursor position• ; This version checks the ranges of X and Y.• ; are not used.• ;------------------------------------------------------• LOCAL ERRS ;; local constant• ERRS = 0• IF (X LT 0) OR (X GT 79)• ECHO Warning: First argument to mGotoxy (X) is out of range.• ECHO ********************************************************• ERRS = 1• ENDIF• IF (Y LT 0) OR (Y GT 24)• ECHO Warning: Second argument to mGotoxy (Y) is out of range.• ECHO ********************************************************• ERRS = ERRS + 1• ENDIF• IF ERRS GT 0 ;; if errors found,• EXITM ;; exit the macro• ENDIF• push edx• mov dh,Y• mov dl,X• call Gotoxy• pop edx• ENDM

useful macros continued• ;------------------------------------------------------• mReadStr MACRO bufferPtr, maxChars• ;• ; Read from standard input into a buffer.• ; EDX cannot be the second argument.• ;------------------------------------------------------• IFIDNI <maxChars> , <EDX>• ECHO Warning: EDX cannot be second argument to mReadStr.• ECHO ***************************************************• EXITM• ENDIF• push ecx• push edx• mov edx,bufferPtr• mov ecx,maxChars• call ReadString• pop edx• pop ecx• ENDM

useful macros continued• ;---------------------------------------------------• ShowRegister MACRO regName• LOCAL tempStr• ;• ; Display a register's name and contents.• ;---------------------------------------------------• .data• tempStr BYTE " &regName=",0• .code• push eax

• ; Display the register name• push edx• mov edx,offset tempStr• call WriteString• pop edx

• ; Display the register contents• mov eax,regName• call WriteHex• pop eax• ENDM

• .data• message BYTE "Hello there",0• buffer BYTE 50 DUP(?)

• BadYValue TEXTEQU <Warning: Y-coordinate is !> 24>

• ShowWarning MACRO message• mWrite "&message"• ENDM

useful macros …a main drivercount = 4sumVal TEXTEQU %5 + count ; sumVal = 9

.codemain PROC

mGotoxyConst %5 * 10, %3 + 4

;ShowWarning %BadYValue

call Crlfcall Crlf

ShowRegister ECX

mReadStr OFFSET buffer,50 ; ok

mov edx,50;mReadStr buffer,edx ; generates warning

mGotoxyConst 10,20

mWrite "Line one"mWriteLn ; missing argumentmWriteLn "Line two"

mWrite <"Line three",0dh,0ah>

mWriteStr ; missing argument

exitmain ENDPEND main

Run of macro2 (I added clrscr)

• ECX=0012FFB0

• Line one• Line two• Line three

• C:\Masm615>

Macro redefinition

• Macros can be redefined. For example, if you define a macro using – Somemac macro– ---– Endm

• All invocations to the macro use the current definition. But if, later, you use the same name again to (re)define the macro, the macro has been redefined and all subsequent invocations will use the new definition.

Another redefinition exampleINCLUDE Irvine16.inc.codecls macro

local skipjmp short skip

cls_sub proc nearpushaxor cx,cxmov dh,24mov dl,79mov bh, 7xor al,almov ah,6int 10hpoparet

cls_sub endpcls macro call cls_sub endmskip: cls

endmmain PROC

mov ax,@datamov ds,axclsexit

main ENDPEND main

16 bit exit to DOS macro

Exittodos MACRO

mov ax,4C00h

int 21h

ENDM

 

Toupper macro

to_upper MACRO ch

LOCAL done

cmp ch,'a’

jb done

cmp ch,'z' ;;2 semicolons suppresses this comment in expansion

ja done ;but this comment would be displayed

sub ch,32

done:

ENDM

Generic operation macro

doanything MACRO op_code, dest,src

op_code dest,src

ENDM

SWAP word macro

SWAP MACRO operand1, operand2

xchg AX,operand1

xchg AX,operand2

xchg AX,operand1

ENDM

 

16 bit GOTOXY Macro

GOTOXY MACRO Row, ColumnPUSH AXPUSH BXPUSH DXMOV AH, 02H;;rom bios codeMOV DH, RowMOV DL, ColumnMOV BH, 0;;video pageINT 10H ;;bios intPOP DXPOP BXPOP AXENDM

Recursive macro

 

pushall MACRO reg1, reg2, reg3, reg4, reg5, reg6

IFNB <reg1> ;; If parameter not blank

push reg1

;; push one register and

;; repeat

pushall reg2, reg3, reg4, reg5, reg6

ENDIF

ENDM

;;example call

pushall ax, bx, si, ds

pushall cs, es

 

Substitute operator (&)

Substitutes a parameter with the actual argument

sort2 MACRO cond, num1, num2

LOCAL done

push AX

mov AX,num1

cmp AX,num2

j&cond done

xchg AX,num2

mov num1,AX

done:

pop AX

ENDM

Literal-text string operator (< >)

* Treats the enclosed text as a single string literal rather

than separate arguments

* Syntax: <text>

range_error1 MACRO number,variable,range

err_msg&number DB '&variable: out of range',0

range_msg&number DB 'Correct range is &range',0

ENDM

• Invoking with

range_error1 1,<Assignment mark>,<0 to 25>

produces

err_msg1 DB 'Assignment mark: out of range',0

range_msg1 DB 'Correct range is 0 to 25',0

 

 

Literal-character operator (!)

* Treats the character literally without its default meaning

* Syntax: !character

range_error2 MACRO number,variable,range

err_msg&number DB '&variable: out of range - &range',0

ENDM

• Invoking with

range_error2 3,mark,<can!'!'t be !> 100>

produces

err_msg3 DB 'mark: out of range - can''t be > 100',0

* Without the ! operator, two single quotes will produce a single quote

in the output

Expression Evaluate operator (%)

* Expression is evaluated and its value is used to replace

the expression itself

* Syntax: %expression

init_arry MACRO element_size,name,size,init_value

name &element_size size DUP (init_value)

ENDM

• Assuming NUM_STUDENTS EQU 47

NUM_TESTS EQU 7

Invoking with

init_array Word,marks,%NUM_STUDENTS*NUM_TESTS,-1

produces

marks Word 329 DUP (-1)

Literal-character operator (!)

* Treats the character literally without its default meaning

* Syntax: !character

range_error2 MACRO number,variable,range

err_msg&number DB '&variable: out of range - &range',0

ENDM

• Invoking with

range_error2 3,mark,<can!'!'t be !> 100>

produces

err_msg3 DB 'mark: out of range - can''t be > 100',0

* Without the ! operator, two single quotes will produce a single quote

in the output

Generating data for dictionary program using repeat macro, & and %

;will generate data like:

;wd0 byte 20 dup(0)

;wd1 byte 20 dup(0)

;wd2 byte 20 dup(0)

include irvine32.inc

gen macro val

wd&val byte 20 dup(0)

endm

.data

value=0

wct=20

repeat wct

gen %value

value=value+1

endm

.code

start proc

exit

start endp

end start

Similar but using for include irvine16.inc

.data

wordval label dword

for ctr,<0,1,2,3,4,5,6,7,8,9>

wordval&ctr dword ctr

endm

;;generates

;;wordval0 dword 0

;;etc

.code

main proc

mov ax,@data

mov ds,ax

mov ecx, 9

mov di,0

up:

mov eax,wordval[di]

call writeint

add di,4

call crlf

loop up

exit

main endp

end main

 

And using this with % to add numbers up

include irvine16.inc ;;32 bit ok too

.data

wordval label dword

for ctr,<0,1,2,3,4,5,6,7,8,9>

wordval&ctr dword ctr

endm

sum macro c

add eax,wordval&c

endm

addup macro

count=0

while count LT 10

sum %count

count=count+1

endm

endm

continued

.code

main proc

mov ax,@data

mov ds,ax

xor eax,eax

addup

call writedec

exit

main endp

end main

 

A program with I/0 similar to wordsort:

 include irvine16.inc

 .data

words label byte

for ctr,<0,1,2,3,4,5,6,7,8,9>

words&ctr byte 10 dup(0)

endm

prompt byte 0ah,0dh,"enter",0ah,0dh,'$'

getstart & fill macros

getstart macro x,c

mov x,offset words&c

endm

 fill macro

count=0

while count LT 5

print prompt

getstart edx,%count

call readstring

count=count+1

endm

endm

 

print

print macro x

pusha

mov ah,9;;DOS print…requires ‘$’ terminator

mov dx,offset x

int 21h

popa

endm

Show macro

show macro

count=0

while count LT 5

getstart edx,%count

call writestring

call crlf

count=count+1

endm

endm

driver

.code

main proc

mov ax,@data; or could be 32 bit

mov ds,ax

fill

show

exit

main endp

end main

Linklist output• C:\Masm615>list• 1• 2• 3• 4• 5• 6• 7• 8• 9• 10• 11• 12• 13• 14• 15

Linked list part1TITLE Creating a Linked List (List.asm)

; This program shows how the STRUC directive; and the REPT directive can be combined to; create a linked list at assembly time.; Last update: 11/8/02

INCLUDE Irvine32.inc

ListNode STRUCT NodeData DWORD ? NextPtr DWORD ?ListNode ENDS

TotalNodeCount = 15NULL = 0Counter = 0

.dataLinkedList LABEL PTR ListNodeREPT TotalNodeCount

Counter = Counter + 1ListNode <Counter, ($ + Counter * SIZEOF ListNode)>

ENDMListNode <0,0> ; tail node

Linked list part2.codemain PROC

mov esi,OFFSET LinkedList

; Display the integers in the NodeData members.NextNode:

; Check for the tail node.mov eax,(ListNode PTR [esi]).NextPtrcmp eax,NULLje quit

; Display the node data.mov eax,(ListNode PTR [esi]).NodeDatacall WriteDeccall Crlf

; Get pointer to next node.mov esi,(ListNode PTR [esi]).NextPtrjmp NextNode

quit:exit

main ENDPEND main

Linklist2 a linklist on the stackC:\Masm615>linklist2enter numbers... 999 to quit34enter numbers... 999 to quit56enter numbers... 999 to quit333enter numbers... 999 to quit12enter numbers... 999 to quit90enter numbers... 999 to quit609enter numbers... 999 to quit45enter numbers... 999 to quit32enter numbers... 999 to quit665enter numbers... 999 to quit435enter numbers... 999 to quit354enter numbers... 999 to quit09enter numbers... 999 to quit54enter numbers... 999 to quit999549354435665324560990123335634

C:\Masm615>

Linklist2…build arbitrary size list (up to stack allocation)

ListNode STRUCT NodeData DWORD ? NextPtr DWORD ?ListNode ENDS

TotalNodeCount = 15;;;not usedNULL = 0Counter = 0

.datanullval dword 0prompt byte "enter numbers... 999 to quit",0;;;;LinkedList LABEL PTR ListNode

ListNode <0,0> ; tail node…not used

.code

Linklist2 mainmain PROCpush nullvalpush nullval;;;this is the tail ptrmov esi,esp;;;current node addressmore:

mov edx,offset promptcall writestringcall crlfcall readint;;;;;;here is where we get datacmp eax,999je doneInputmov ebp,esipush ebp ;;;this is the next node ptrpush eax;;;this is the datamov esi,esp;;;now this is the address of current node

jmp moredoneInput: NextNode:

; Check for the tail node.mov eax,(ListNode PTR [esi]).NextPtrcmp eax,NULLje quit; Display the node data.mov eax,(ListNode PTR [esi]).NodeDatacall WriteDeccall Crlf

; Get pointer to next node.mov esi,(ListNode PTR [esi]).NextPtrjmp NextNode

quit:exit

main ENDPEND main