Irvine chapter 10 Structures and macros A simple















































- Slides: 47

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 (All. Points. asm) ; Loop through the array of points and set their ; X and Y values. ; Last update: 11/26/01 INCLUDE Irvine 32. inc ; coor is already defined in smallwin referenced by irvine 32. inc. data; ; ; I added a message up here ; Create instances of the COORD structure, ; assigning values to both X and Y: point 1 COORD <5, 10> point 2 COORD <10, 20> Num. Points = 3 All. Points COORD Num. Points DUP(<0, 0>); ; 3 sets of int points. code main PROC mov edi, 0 ; array index mov ecx, Num. Points ; loop counter mov ax, 1 ; starting X, Y values L 1: mov (COORD PTR All. Points[edi]). X, ax mov (COORD PTR All. Points[edi]). Y, ax add edi, TYPE COORD inc ax Loop L 1 exit main ENDP END main • C: Masm 615>allpoints • just made point #1 just made point #2 just made point #3

An “employee” typ. Employee STRUCT Idnum BYTE 9 DUP(0) Lastname BYTE 30 DUP(0) Years WORD 0 Salary. History DWORD 10 DUP(0) typ. Employee ENDS

Employee slide 1 TITLE Intro to STRUCT (Struct 1. asm) INCLUDE Irvine 32. inc typ. Employee STRUCT Idnum BYTE 9 DUP(0) Lastname BYTE 30 DUP(0) Years WORD 0 Salary. History DWORD 10 DUP(0) typ. Employee ENDS. data worker typ. Employee <> ; override all fields. Either angle brackets ; or curly braces can be used: person 1 typ. Employee {"555223333"} person 2 typ. Employee <"555223333"> ; override only the second field: person 3 typ. Employee <, "Jones"> ; skip the first three fields, and ; use DUP to initialize the last field: person 4 typ. Employee <, , , 3 DUP(20000)>

Employee slide 2. code main PROC ; Get the offset of a field within a structure: mov edx, OFFSET typ. Employee. Salary. History ; 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 typ. Employee mov eax, SIZE worker mov eax, SIZEOF worker mov eax, TYPE typ. Employee. Salary. History; 4 mov eax, LENGTH typ. Employee. Salary. History mov eax, SIZE typ. Employee. Salary. History ; 40 ; The TYPE, LENGTH and SIZE operators can be applied ; to instances of the structure: mov eax, TYPE worker ; 82 mov eax, TYPE worker. Years ; Indirect operands require the PTR operator: mov esi, offset worker mov ax, (typ. Employee PTR [esi]). Years ; 82 ; 10 ; 2 exit main ENDP END 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 (Struct 2. asm) ; This program shows how to declare nested ; structures, and how to access the members. ; Last update: 8/14/01. INCLUDE Irvine 32. inc Rectangle STRUCT Upper. Left COORD <> Lower. Right COORD <> Rectangle ENDS. data rect 1 Rectangle <> rect 2 Rectangle { } rect 3 Rectangle { {10, 20}, {5, 15} } rect 4 Rectangle < <10, 20>, <5, 15> >. code main PROC ; Direct reference to a nested member. mov rect 1. Upper. Left. X, 30 ; Using an indirect operand, access a ; nested member. mov esi, OFFSET rect 1 mov (Rectangle PTR [esi]). Upper. Left. Y, 40 ; Get the offsets of individual members. mov edi, OFFSET rect 2. Lower. Right. X exit main ENDP END main

Showtime system time struct & output (I added clrscr) SYSTEMTIME STRUCT w. Year WORD ? w. Month WORD ? w. Day. Of. Week WORD ? w. Day WORD ? w. Hour WORD ? w. Minute WORD ? w. Second WORD ? w. Milliseconds WORD ? SYSTEMTIME ENDS • I added a bunch of output to the original

The rest of showtime. data sys. Time SYSTEMTIME <> XYPos COORD <10, 5> console. Handle DWORD ? colon. Str BYTE ": ", 0 The. Time. Is BYTE "The time is ", 0. code main PROC call clrscr ; Get the standard output handle for the Win 32 Console. INVOKE Get. Std. Handle, STD_OUTPUT_HANDLE mov console. Handle, eax ; Set the cursor position and get the local time zone. INVOKE Set. Console. Cursor. Position, console. Handle, XYPos INVOKE Get. Local. Time, ADDR sys. Time mov edx, offset year call writestring movzx eax, sys. Time. w. Year ; year call Write. Dec call crlf mov edx, offset month ; call Write. String movzx eax, sys. Time. w. Month ; month call crlf call Write. Dec mov edx, offset day ; ": " call Write. String movzx eax, sys. Time. wdayofweek ; day call Write. Dec call Crlf mov edx, OFFSET The. Time. Is call Write. String movzx eax, sys. Time. w. Hour call Write. Dec mov edx, offset colon. Str call Write. String movzx eax, sys. Time. w. Minute call Write. Dec mov edx, offset colon. Str call Write. String movzx eax, sys. Time. w. Second call Write. Dec exit main ENDP ; "The time is " ; hours ; ": " ; minutes ; ": " ; seconds

A drunkard’s walk C: Masm 615>walk 25, 25 24, 25 23, 25 24, 24 25, 25 24, 26 24, 25 23, 26 23, 27 23, 26 23, 25 23, 24 22, 24 21, 24 22, 24 23, 23 22, 24 21, 25 21, 24 20, 24 19, 24

Main proc for drunkard’s walk INCLUDE Irvine 32. inc Walk. Max = 30 Start. X = 25 Start. Y = 25 Drunkard. Walk STRUCT path COORD Walk. Max DUP(<0, 0>) paths. Used WORD 0 Drunkard. Walk ENDS Display. Position PROTO curr. X: WORD, curr. Y: WORD. data a. Walk Drunkard. Walk <>. code main PROC mov esi, offset a. Walk call Take. Drunken. Walk exit main ENDP

The take-a-walk proc Take. Drunken. Walk PROC LOCAL curr. X: WORD, curr. Y: WORD ; ; Take a walk in random directions (north, south, east, ; west). ; Receives: ESI points to a Drunkard. Walk structure ; Returns: the structure is initialized with random values ; ---------------------------pushad ; Point EDI to the array of COORD objects. mov edi, esi add edi, OFFSET Drunkard. Walk. path mov ecx, Walk. Max ; loop counter mov curr. X, Start. X ; current X-location mov curr. Y, Start. Y ; current Y-location Again: ; Insert current location in array. mov ax, curr. X mov (COORD PTR [edi]). X, ax mov ax, curr. Y mov (COORD PTR [edi]). Y, ax INVOKE Display. Position, curr. X, curr. Y; ; ; this generates output…. not shown mov eax, 4 ; choose a direction (0 -3) call Random. Range. IF eax == 0 ; North inc curr. Y. ELSEIF eax == 1 ; South dec curr. Y. ELSEIF eax == 2 ; West dec curr. X. ELSE ; East (EAX = 3) inc curr. X. ENDIF next: add edi, TYPE COORD loop Again ; point to next COORD finish: mov ax, Walk. Max ; count the steps taken sub ax, cx mov (Drunkard. Walk PTR [esi]). paths. Used, ax popad ret Take. Drunken. Walk ENDP

A bunch of useful macros • TITLE Useful Macros (Macro 2. ASM) • • ; This program demonstrates several useful macros: ; m. Gotoxy, m. Write. Ln, m. Write. Str, m. Read. Str, ; and m. Dump. Mem. ; Last update: 8/17/01. • INCLUDE Irvine 32. inc • • • • • ; --------------------------m. Write. Str MACRO buffer ; ; Improved version of m. Write. Str that checks for ; a blank argument. ; --------------------------IFB <buffer> ECHO -------------------- ECHO * Error: parameter missing in m. Write. Str ECHO * (no code generated) ECHO -------------------- EXITM ENDIF push edx mov edx, OFFSET buffer call Write. String pop edx ENDM

useful macros continued • • • • ; --------------------------m. Write 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. • • • m. Write. Ln MACRO text : = < " " > ; --------------------------m. Write text call Crlf ENDM

useful macros continued • • • • • • • ; --------------------------m. Gotoxy. Const 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 m. Gotoxy (X) is out of range. ECHO **************************** ERRS = 1 ENDIF IF (Y LT 0) OR (Y GT 24) ECHO Warning: Second argument to m. Gotoxy (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 • • • • • ; ---------------------------m. Read. Str MACRO buffer. Ptr, max. Chars ; ; Read from standard input into a buffer. ; EDX cannot be the second argument. ; ---------------------------IFIDNI <max. Chars> , <EDX> ECHO Warning: EDX cannot be second argument to m. Read. Str. ECHO ************************** EXITM ENDIF push ecx push edx mov edx, buffer. Ptr mov ecx, max. Chars call Read. String pop edx pop ecx ENDM

useful macros continued • • • ; -------------------------Show. Register MACRO reg. Name LOCAL temp. Str ; ; Display a register's name and contents. ; -------------------------. data temp. Str BYTE " ®. Name=", 0. code push eax • • • ; Display the register name push edx mov edx, offset temp. Str call Write. String pop edx • • • ; Display the register contents mov eax, reg. Name call Write. Hex pop eax ENDM • • • . data message BYTE "Hello there", 0 buffer BYTE 50 DUP(? ) • Bad. YValue TEXTEQU <Warning: Y-coordinate is !> 24> • • • Show. Warning MACRO message m. Write "&message" ENDM

useful macros …a main driver count = 4 sum. Val TEXTEQU %5 + count ; sum. Val = 9. code main PROC m. Gotoxy. Const %5 * 10, %3 + 4 ; Show. Warning %Bad. YValue call Crlf Show. Register ECX m. Read. Str OFFSET buffer, 50; ok mov edx, 50 ; m. Read. Str buffer, edx ; generates warning m. Gotoxy. Const 10, 20 m. Write "Line one" m. Write. Ln ; missing argument m. Write. Ln "Line two" m. Write <"Line three", 0 dh, 0 ah> m. Write. Str ; missing argument exit main ENDP END main

Run of macro 2 (I added clrscr) • ECX=0012 FFB 0 • • • Line one Line two Line three • C: Masm 615>

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 example INCLUDE Irvine 16. inc. code cls macro local skip jmp short skip cls_sub proc near pusha xor cx, cx mov dh, 24 mov dl, 79 mov bh, 7 xor al, al mov ah, 6 int 10 h popa ret cls_sub endp cls macro call cls_sub endm skip: cls endm main PROC mov ax, @data mov ds, ax cls exit main ENDP END main

16 bit exit to DOS macro Exittodos MACRO mov ax, 4 C 00 h int 21 h 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 operand 1, operand 2 xchg AX, operand 1 xchg AX, operand 2 xchg AX, operand 1 ENDM

16 bit GOTOXY Macro GOTOXY MACRO Row, Column PUSH AX PUSH BX PUSH DX MOV AH, 02 H; ; rom bios code MOV DH, Row MOV DL, Column MOV BH, 0; ; video page INT 10 H ; ; bios int POP DX POP BX POP AX ENDM

Recursive macro pushall MACRO reg 1, reg 2, reg 3, reg 4, reg 5, reg 6 IFNB <reg 1> ; ; If parameter not blank push reg 1 ; ; push one register and ; ; repeat pushall reg 2, reg 3, reg 4, reg 5, reg 6 ENDIF ENDM ; ; example call pushall ax, bx, si, ds pushall cs, es

Substitute operator (&) Substitutes a parameter with the actual argument sort 2 MACRO cond, num 1, num 2 LOCAL done push AX mov AX, num 1 cmp AX, num 2 j&cond done xchg AX, num 2 mov num 1, 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_error 1 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_error 1 1, <Assignment mark>, <0 to 25> produces err_msg 1 DB 'Assignment mark: out of range', 0 range_msg 1 DB 'Correct range is 0 to 25', 0

Literal-character operator (!) * Treats the character literally without its default meaning * Syntax: !character range_error 2 MACRO number, variable, range err_msg&number DB '&variable: out of range - &range', 0 ENDM • Invoking with range_error 2 3, mark, <can!'!'t be !> 100> produces err_msg 3 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 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_error 2 MACRO number, variable, range err_msg&number DB '&variable: out of range - &range', 0 ENDM • Invoking with range_error 2 3, mark, <can!'!'t be !> 100> produces err_msg 3 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: ; wd 0 byte 20 dup(0) ; wd 1 byte 20 dup(0) ; wd 2 byte 20 dup(0) include irvine 32. inc gen macro val wd&val byte 20 dup(0) endm. data value=0 wct=20 repeat wct gen %value=value+1 endm. code start proc exit start endp end start

Similar but using for include irvine 16. inc. data wordval label dword for ctr, <0, 1, 2, 3, 4, 5, 6, 7, 8, 9> wordval&ctr dword ctr endm ; ; generates ; ; wordval 0 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 irvine 16. 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+1 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 irvine 16. 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 0 ah, 0 dh, "enter", 0 ah, 0 dh, '$'

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

print macro x pusha mov ah, 9; ; DOS print…requires ‘$’ terminator mov dx, offset x int 21 h popa endm

Show macro show macro count=0 while count LT 5 getstart edx, %count call writestring call crlf count=count+1 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: Masm 615>list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Linked list part 1 TITLE 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 Irvine 32. inc List. Node STRUCT Node. Data DWORD ? Next. Ptr DWORD ? List. Node ENDS Total. Node. Count = 15 NULL = 0 Counter = 0. data Linked. List LABEL PTR List. Node REPT Total. Node. Counter = Counter + 1 List. Node <Counter, ($ + Counter * SIZEOF List. Node)> ENDM List. Node <0, 0> ; tail node

Linked list part 2. code main PROC mov esi, OFFSET Linked. List ; Display the integers in the Node. Data members. Next. Node: ; Check for the tail node. mov eax, (List. Node PTR [esi]). Next. Ptr cmp eax, NULL je quit ; Display the node data. mov eax, (List. Node PTR [esi]). Node. Data call Write. Dec call Crlf ; Get pointer to next node. mov esi, (List. Node PTR [esi]). Next. Ptr jmp Next. Node quit: exit main ENDP END main

Linklist 2 a linklist on the stack C: Masm 615>linklist 2 enter numbers. . . 999 to quit 34 enter numbers. . . 999 to quit 56 enter numbers. . . 999 to quit 333 enter numbers. . . 999 to quit 12 enter numbers. . . 999 to quit 90 enter numbers. . . 999 to quit 609 enter numbers. . . 999 to quit 45 enter numbers. . . 999 to quit 32 enter numbers. . . 999 to quit 665 enter numbers. . . 999 to quit 435 enter numbers. . . 999 to quit 354 enter numbers. . . 999 to quit 09 enter numbers. . . 999 to quit 54 enter numbers. . . 999 to quit 999 54 9 354 435 665 32 45 609 90 12 333 56 34 C: Masm 615>

Linklist 2…build arbitrary size list (up to stack allocation) List. Node STRUCT Node. Data DWORD ? Next. Ptr DWORD ? List. Node ENDS Total. Node. Count = 15; ; ; not used NULL = 0 Counter = 0. data nullval dword 0 prompt byte "enter numbers. . . 999 to quit", 0 ; ; Linked. List LABEL PTR List. Node <0, 0>. code ; tail node…not used

Linklist 2 main PROC push nullval; ; ; this is the tail ptr mov esi, esp; ; ; current node address more: mov edx, offset prompt call writestring call crlf call readint; ; ; here is where we get data cmp eax, 999 je done. Input mov ebp, esi push ebp ; ; ; this is the next node ptr push eax; ; ; this is the data mov esi, esp; ; ; now this is the address of current node jmp more done. Input: Next. Node: ; Check for the tail node. mov eax, (List. Node PTR [esi]). Next. Ptr cmp eax, NULL je quit ; Display the node data. mov eax, (List. Node PTR [esi]). Node. Data call Write. Dec call Crlf ; Get pointer to next node. mov esi, (List. Node PTR [esi]). Next. Ptr jmp Next. Node quit: exit main ENDP END main