DATA  SEGMENT
 MSG_NEWLINE  DB        0AH,0DH,"$"
      BUFFER  DB        100H   DUP(?)           ;BUFFER   用于保存表达式。
 NUMBER_FLAG  DB        00H         ;NUMBER_FLAG   用于标记操作数是否为负数。
       MINUS  EQU       2DH
        DATA  ENDS
        CODE  SEGMENT
              ASSUME    CS:CODE,DS:DATA
      START:                        ;初始化。
              MOV       AX,DATA
              MOV       DS,AX
              LEA       BX,BUFFER
              MOV       CX,00H

              MOV       DX,OFFSET   MSG_NEWLINE
              MOV       AH,09H
              INT       21H

         GET_EXPRESSION:                        ;获取用户输入的需要计算的表达式字符串。
              MOV       AH,01H
              INT       21H
              CMP       AL,2EH      ;输入小数点程序结束。
              JE        QUIT
              CMP       AL,3DH      ;输入表达式以等号结束。
              JE        INPUT_FINISH
              MOV       [BX],AL
              INC       BX
              INC       CX
              JMP       GET_EXPRESSION
       QUIT:
              MOV       AH,4CH
              INT       21H


           INPUT_FINISH:
              SUB       BX,CX
              MOV       CX,00H
              CMP       BYTE PTR [BX],MINUS
              JNE       GET_NUMBER_1            ;如果表达式的第一个字符为负号,第一个操作数为负数。
              INC       BX
              INC       NUMBER_FLAG
              JMP       GET_NUMBER_1


           GET_NUMBER_1:                        ;获得第一个操作数。
              MOV       DX,[BX]
              SUB       DX,30H
              ADC       CX,DX
              INC       BX
              MOV       DL,[BX]
              CMP       DL,30H
              JL        GET_NEXT_NUMBER         ;如果下一个字符是加减乘除四则运算符之一,则跳转。
              MOV       AX,CX
              MOV       DL,10D
              IMUL      DL
              MOV       CX,AX
              JMP       GET_NUMBER_1


        GET_NEXT_NUMBER:
  ;先获得第二个操作数,并保存运算符在SI寄存器。   
    ;   如果NUMBER_FLAG标志为1,则操作数一为负数,高字保存在DX,低字保存在AX。   
              CMP       NUMBER_FLAG,0
              JE        SAVE_NUMBER1
              DEC       NUMBER_FLAG ; NUMBER_FLAG标志消零。
              MOV       AX,CX
              MOV       DL,-1H
              IMUL      DL
              MOV       CX,AX
              JMP       SAVE_NUMBER1


           SAVE_NUMBER1:                        ;保存第一个操作数至SI寄存器。
              MOV       DL,CL
              MOV       DH,00H
              MOV       SI,DX
              MOV       DH,[BX]     ;保存运算符至DH寄存器。
              INC       BX
              MOV       CX,00H
              CMP       BYTE PTR [BX],MINUS
              JNE       GET_NUMBER_2            ;如果表达式中运算符后面的字符为负号,第二个操作数为负数。
              INC       BX
              INC       NUMBER_FLAG
              JMP       GET_NUMBER_2


           GET_NUMBER_2:                        ;获得第二个操作数。
              MOV       DX,[BX]
              SUB       DX,30H
              ADC       CX,DX
              CMP       BYTE PTR [BX+1],'='     ;如果下一个字符是"等于"符号,则跳转至计算。
              JE        PRE_ACCOUNT
              INC       BX

              MOV       AX,CX
              MOV       DL,10D
              IMUL      DL
              MOV       CX,AX
              JMP       GET_NUMBER_2

            PRE_ACCOUNT:                        ;如果NUMBER_FLAG标志为1,则操作数二为负数。
              CMP       NUMBER_FLAG,0
              JE        ACCOUNT

              MOV       AX,CX
              MOV       DL,-1H
              IMUL      DL
              MOV       CX,AX
              JMP       ACCOUNT

    ACCOUNT:
              MOV       BH,DH
              CMP       BH,'+'
              JE        OPTR_ADD
              CMP       BH,'-'
              JE        OPTR_SUB
              CMP       BH,'*'
              JE        OPTR_MUL
              CMP       BH,'/'
              JE        OPTR_DIV

   OPTR_ADD:
              MOV       BX,SI
              ADD       BX,CX
              MOV       DX,BX
              AND       DX,8000H
              CMP       DX,8000H
              JE        SIGN
              ;MOV       SI,BX
              JMP       SHOW_RESULT
   OPTR_SUB:
              MOV       BX,SI
              SUB       BX,CX
              MOV       DX,BX
              AND       DX,8000H
              CMP       DX,8000H
              JE        SIGN
              JMP       SHOW_RESULT
   OPTR_MUL:
              MOV       AX,CX
              IMUL      SI
              MOV       BX,AX
              MOV       DX,BX
              AND       DX,8000H
              CMP       DX,8000H
              JE        SIGN
              JMP       SHOW_RESULT
   OPTR_DIV:
              MOV       AX,SI
              CWD
              MOV       BX,CX
              IDIV      BX
              MOV       BX,AX
              MOV       DX,BX
              AND       DX,8000H
              CMP       DX,8000H
              JE        SIGN
              JMP       SHOW_RESULT
       SIGN:                        ;结果的正负的处理
              MOV       DL,'-'
              MOV       AH,2
              INT       21H
              MOV       AX,BX
              MOV       CX,-1H
              IMUL      CX
              MOV       BX,AX
              JMP       SHOW_RESULT
            SHOW_RESULT:
              CALL      BINIDEC
              CALL      START


     BINIDEC  PROC      NEAR        ;将计算结果转化为十进制数字并显示在屏幕上。
              MOV       CX,10000D
              CALL      DEC_DIV
              MOV       CX,1000D
              CALL      DEC_DIV
              MOV       CX,100D
              CALL      DEC_DIV
              MOV       CX,10D
              CALL      DEC_DIV
              MOV       CX,1D
              CALL      DEC_DIV
              RET

     DEC_DIV  PROC      NEAR
              MOV       AX,BX
              MOV       DX,0
              DIV       CX


              ;CMP       AX,0
             ; JZ        STOP
              MOV       BX,DX
              MOV       DL,AL
              ADD       DL,30H
              MOV       AH,2H
              INT       21H
       ;STOP:
              RET
     DEC_DIV  ENDP
     BINIDEC  ENDP
        CODE  ENDS
              END       START