.code ; =============================== ; sort (short * arr, short count) ; =============================== ; An implementation of bubble sort. Sort proc near ;void sort (short * arr, short count) { pusha pushf mov bp, sp mov bx, [bp+22] ; bx = count dec bx ; bx-- shl bx, 1 ; bx *= 2 mov cx, [bp+20] ; cx = arr mov dx, cx ; dx = cx add dx, bx ; dx += bx ; begin outer loop (left ptr) sortloop0: cmp cx, dx ; while (cx < dx) { jae sortloop0_end mov bx, dx ; bx = dx ; begin inner loop (right ptr) sortloop1: cmp cx, bx ; while (cx < bx) { jae sortloop1_end sortif0: mov ax, [bx] ; ax = *bx cmp ax, [bx-2] ; if (ax < *(bx - 2)) { jge sortif0_end xchg ax, [bx-2] ; swap(ax, *(bx - 2)) xchg [bx], ax ; swap(*bx, ax) sortif0_end: ; } sub bx, 2 ; bx -= 2 jmp sortloop1 ; } sortloop1_end: add cx, 2 ; cx += 2 jmp sortloop0 ; } sortloop0_end: popf popa ret 4 ; return 0 Sort endp ;} ; ===================== ; WriteStr (char * ptr) ; ===================== ; writes a null-terminated string to the console. WriteStr proc near ;void writestr(char * ptr) { pusha pushf ; Read the argument in mov bp, sp mov bx, [bp+20] ; bx = ptr ; Start at the pointer passed, print the byte pointed to, ; then increment the counter, until we get 0x00 (NULL) printloop0_start: ; while (*bx != 0) { mov ah, 0 cmp ah, [bx] je printloop0_end mov ah, 2 ; putchar(*bx) mov dl, [bx] int 21h inc bx ; bx++ jmp printloop0_start ; } printloop0_end: popf popa ret 2 ; return WriteStr endp ;} ; ===================================== ; ReadStr (char * PTR, short SIZE) ; ===================================== ; Reads a string of SIZE length from the console, stores it beginning at ; *PTR. When (SIZE - 1) characters have been read, or 0x0D (CR) is read, ; reading stops and a null terminator is inserted in the next position. If ; the string entered is greater than (SIZE - 1) characters, all subsequent ; characters leading up to 0x1D (CR) are discarded. ReadStr proc near ;void ReadStr(char * PTR, short SIZE) { pusha pushf mov bp, sp ; Read the arguments in mov bx, [bp+20] ; bx = PTR mov dx, [bp+22] ; dx = SIZE dec dx ; dx-- mov cx, 0 ; cx = 0 ; While we don't get 0x0D (CR), read characters into ; the pointer that was passed in, incrementing the pointer ; with each character mov ah, 1 ; ah = 1 readloop0_start: ; while ((al = getchar()) != 13) { int 21h cmp al, 13 je readloop0_end cmp cx, dx ; if (cx >= dx) jae readloop0_overflow ; goto overflow mov [bx], al ; *bx = al inc bx ; bx++ inc cx ; cx++ jmp readloop0_start ; } readloop0_end: ; If we got too many characters (more than SIZE-1), read them ; and immediately discard them until we get 0x0D (CR) jmp readloop0_overflow_end ; goto notoverflow readloop0_overflow: ; overflow: int 21h ; while ((al = getchar()) != 13) {} cmp al, 13 jne readloop0_overflow readloop0_overflow_end: ; notoverflow: ; Put a null terminator at the end of the string mov byte ptr [bx], 0 ; *bx = 0 popf popa ret 4 ; return ReadStr endp ;} ; ==================== ; WriteInt(short VAL) ; ==================== ; Writes an integer to the console. .data WriteIntField db 7 DUP (0) WriteIntBase dw 10 .code WriteInt proc near ;void WriteInt(short VAL) { pusha pushf ; clear out the field string, and put the pointer at the last byte mov bx, offset WriteIntField ; bx = WriteIntField mov cx, 5 ; cx = 5 WriteIntLoop0_start: ; while (cx > 0) { mov [bx], byte ptr ' ' ; *bx = ' ' inc bx ; bx++ loop WriteIntLoop0_start ; dec cx } ; grab the argument mov bp, sp mov ax, [bp+20] ; ax = VAL ; if the argument is negative, invert it cmp [bp+20], word ptr 0 ; if (VAL >= 0) { jge WriteIntIf0_end neg ax ; ax = -ax WriteIntIf0_end: ; } ; repeatedly divide the argument by 10, printing the quotient WriteIntLoop1_start: ; do { mov dx, word ptr 0 ; dx = 0 div WriteIntBase ; ax /= WriteIntBase add dl, '0' ; *bx = (ax % WriteIntBase) + '0' mov [bx], dl dec bx ; bx-- cmp ax, 0 ; } while (ax > 0) jg WriteIntLoop1_start ; if the argument was negative, now insert the - sign cmp [bp+20], word ptr 0 ; if (VAL < 0) { jge WriteIntIf1_end mov [bx], byte ptr '-' ; *bx = '-' WriteIntIf1_end: ; } ; call WriteStr to print the string that was generated push offset WriteIntField ; WriteStr(WriteIntField) call WriteStr popf popa ret 2 ; return WriteInt endp ;} ; ===================== ; ReadInt (short * VAL) ; ===================== .data ReadIntNeg db 0 ReadIntField db 7 DUP (0) ReadIntInvalid db 'Invalid entry. Please try again: ',0 .code Proc ReadInt near ;void ReadInt(short * VAL) { pusha pushf ; Call ReadStr to get a string. ReadInt_start: push word ptr 7 ; ReadStr(ReadIntField, 7) push offset ReadIntField ; call ReadStr ; Unset negative flag, set ax to 0 mov ax, 0 ; ax = 0 mov ReadIntNeg, 0 ; ReadIntNeg = 0 ; Point bx to our string. mov bx, offset ReadIntField ; bx = ReadIntField ; Go through the string that was returned from right to left ReadIntLoop0_start: cmp [bx], byte ptr 0 ; while (*bx != 0) { je ReadIntLoop0_end ; If this character is a dash cmp [bx], byte ptr '-' ; if (*bx = '-') { jne ReadIntIf0_end ; if this isn't the first character, it's invalid cmp bx, offset ReadIntField ; if (bx != &ReadIntField) jne ReadInt_invalid ; goto invalid ; otherwise it is, the number is negative, so set the negative flag mov ReadIntNeg, 1 ; ReadIntNeg = 1 ; and jump to continue jmp ReadIntLoop0_continue ; continue ReadIntIf0_end: ; } ; If this character is a plus cmp [bx], byte ptr '+' ; if (*bx = '+') { jne ReadIntIf1_end ; if this isn't the first character, it's invalid cmp bx, offset ReadIntField ; if (bx != &ReadIntField) jne ReadInt_invalid ; goto invalid ; otherwise ignore it jmp ReadIntLoop0_continue ; continue ReadIntIf1_end: ; } ; if this character is < '0', it's not a digit and is invalid cmp [bx], byte ptr '0' ; if (*bx < '0') jb ReadInt_invalid ; goto invalid ; if this character is > '9', it's not a digit and is invalid cmp [bx], byte ptr '9' ; if (*bx > '9') ja ReadInt_invalid ; goto invalid ; we need to multiply by 10, but mul sucks. what do we do? ; copy ax into dx. shift dx right by 3, which multiplies by 8. ; shift ax right 1, which multiplies by 2. ; add dx to ax, because x*2 + x*8 = x*10 mov dx, ax ; dx = ax shl dx, 3 ; dx *= 8 shl ax, 1 ; ax *= 2 add ax, dx ; ax += dx ; now clear dx and copy the digit into dl mov dx, 0 ; dx = *bx - '0' mov dl, [bx] sub dl, '0' ; and add dx to dl add ax, dx ; ax += dx ; increment the pointer, and take it from the top ReadIntLoop0_continue: inc bx ; bx++ jmp ReadIntLoop0_start ; } ReadIntLoop0_end: ; If the negative flag is set, invert ax test ReadIntNeg, 1 ; if (ReadIntNeg & 1) { jz ReadInt_noneg neg ax ; ax = -ax ReadInt_noneg: ; } ; this section has no sane analog in C++, as far as I know. ; if any invalid conditions were caught above, we jumped to here ; now we inform the user that they entered an invalid value ; and jump back to the start jmp ReadInt_notinvalid ; goto notinvalid ReadInt_invalid: ; invalid: push offset ReadIntInvalid ; cout << ReadIntInvalid call WriteStr jmp ReadInt_start ; goto start ReadInt_notinvalid: ; notinvalid: ; now grab the pointer argument and copy the value we read into it. mov bp, sp mov bx, [bp+20] ; bx = VAL mov [bx], ax ; *bx = ax popf popa ret 2 ; return ReadInt endp ;} ; ======================= ; writebin (short a) ; ======================= ; writes the value of a in binary. WriteBin PROC near pusha pushf mov bp, sp mov bx, [bp+20] mov ah, 2 mov cx, 1000000000000000b loop0_start: test cx, 1111111111111111b jz loop0_end mov dx, cx and dx, bx test dx, cx jz loop0_test0_zero mov dl, '1' jmp loop0_test0_end loop0_test0_zero: mov dl, '0' loop0_test0_end: int 21h shr cx, 1 jmp loop0_start loop0_end: popf popa ret 2 WriteBin ENDP