;asc-bin.asm
;converts a string of numbers to a signed 16 bit number
STACK SEGMENT PARA STACK 'STACK'
       DB 64 DUP('STACK ')
STACK ENDS

CODE SEGMENT PARA 'CODE'

ASCII_BIN PROC FAR
          ASSUME CS:CODE,SS:STACK
          PUBLIC ASCII_BIN

       PUSH BX          ;SAVE BX AND CX
       PUSH CX
       SUB  AX,AX       ;TO START, RESULT = 0
       SUB  DX,DX       ;  DECIMAL COUNT = 0
       MOV  DI,0FFH     ;  ASSUME NO BAD CHARACTERS
       CMP  CX,7        ;STRING TOO LONG?
       JA   NO_GOOD     ;IF SO, GO SET CF AND EXIT
       
BLANKS:
       CMP  BYTE PTR [BX],' '   ;SCAN PAST LEADING BLANKS
       JNE  CHK_NEG
       INC  BX
       LOOP BLANKS

CHK_NEG:
       CMP  BYTE PTR [BX],'-'   ;NEGATIVE NUMBER?
       JNE  CHK_POS
       INC  BX                  ;IF SO INCREMENT POINTER
       DEC  CX                  ;   DECREMENT THE COUNT
       CALL CONV_AB             ;   AND CONVERT THE STRING

       JC   THRU
       CMP  AX,32768            ;IS THE NUMBER TOO SMALL?
       JA   NO_GOOD
       NEG  AX                  ;NO. COMPLEMENT THE RESULT
       JS   GOOD

CHK_POS:
       CMP  BYTE PTR [BX],'+'   ;POSITIVE NUMBER?
       JNE  GO_CONV
       INC  BX                  ;IF SO, INCREMENT POINTER
       DEC  CX                  ;   DECREMENT THE COUNT
GO_CONV:
       CALL CONV_AB             ;   AND CONVERT THE STRING

       JC   THRU
       CMP  AX,32767            ;IS THE NUMBER TOO BIG?
       JA   NO_GOOD
GOOD:
       CLC
       JNC  THRU
NO_GOOD:
       STC                      ;IF SO, SET CARRY FLAG
THRU:
       POP  CX                  ;RESTORE REGISTERS
       POP  BX
       RET                      ;EXIT

ASCII_BIN ENDP
;
;   THIS PROCEDURE PERFORMS THE ACTUAL CONVERSION.
;
CONV_AB PROC
       PUSH BP          ;SAVE SCRATCH REGISTERS
       PUSH BX
       PUSH SI

       MOV  BP,BX       ;IS THIS NECESSARY     ******NOT IN BOOK

CHK_PT:
       CMP  DX,0        ;DICIMAL POINT ALREADY FOUND?
       JNZ  RANGE       ;  IF SO, SKIP FOLLOWING CHECK
       CMP  BYTE PTR DS:[BP],'.'   ;DECIMAL POINT
       JNE  RANGE
       DEC  CX          ;IF SO DECREMENT COUNT
       MOV  DX,CX       ;  AND RECOR IT IN DX
       JZ   END_CONV    ;  EXIT IF CX=0
       INC  BP          ;  INCREMENT POINTER

RANGE:
       CMP  BYTE PTR DS:[BP],'0'  ;IF THE CHARACTER IS
       JB   NON_DIG               ;  NOT A DIGIT
       CMP  BYTE PTR DS:[BP],'9'
       JBE  DIGIT

NON_DIG:
       MOV  DI,BP        ;PUT ITS ADDRESS IN DI
       STC               ;SET THE CARRY FLAG,
       JC   END_CONV     ;AND EXIT

DIGIT:
       MOV  SI,10        ;THE CHARACTER IS A DIGIT
       PUSH DX
       MUL  SI           ;  SO MULTIPLY AX BY 10
                         ;NOTE-FIRST TIME THROUGH AX=0
       JC   END_CONV1    ;EXIT IF RESULT IS TOO BIG  ******NOT IN BOOK
       POP  DX
       MOV  BL,DS:[BP]   ;FETCH ASCII CODE,  
       AND  BX,0FH       ; SAVE ONLY HIGH BITS, 
       ADD  AX,BX        ; AND UPDATE PARTIAL RESULTS
       JC   END_CONV     ;EXIT IF RESULT IS TOO BIG
       INC  BP           ;OTHERWISE, INCREMENT
       LOOP CHK_PT       ; BP AND CONTINUE
       CLC               ;WHEN DONE, CLEAR CARRY FLAG

       JMP END_CONV      ;                            ******NOT IN BOOK

END_CONV1:               ;                             *****NOT IN BOOK
       POP  DX           ;TO KEEP STACK RIGHT          *****NOT IN BOOK
END_CONV:
       POP  SI           ;RESTORE REGISTERS
       POP  BX
       POP  BP
       RET               ;RETURN TO CALLER
CONV_AB ENDP

CODE ENDS
      END
   pop     di
        mov     ah,func         ;put in