home *** CD-ROM | disk | FTP | other *** search
/ ticalc.org / ticalc_org_rev_b.iso / archives / 86 / asm / source / routines / strtonum.asm < prev    next >
Encoding:
Assembly Source File  |  2001-07-01  |  9.7 KB  |  428 lines

  1. ; ***************************************************************************
  2. ; CSpread StringToNumeric Routine
  3. ;
  4. ; Version 1.2
  5. ;
  6. ; Written By David Hart (davey3000) 1998-1999
  7. ; ***************************************************************************
  8. ;
  9. ; Notes: Remember to include the standard TI include files in your main
  10. ;        program before including this file.
  11. ;
  12. ; How To Use: Just call CheckStrNumeric to check that a string is a valid
  13. ;             number, and then call StringToNumeric if it is to convert
  14. ;             the string to a real number in OP1.  Note that this
  15. ;             DESTROYS THE ORIGINAL STRING.
  16. ;
  17. ; LEGAL DISCLAIMER
  18. ;
  19. ; This SOFTWARE (that is, all software programs included with this text file)
  20. ; is free-ware, and therefore is provided "as-is" without any kind of warranty.
  21. ; I provide no guarantee as to the functionality, usefulness, fitness for a
  22. ; particular purpose or merchantability of the SOFTWARE.  I may not be held
  23. ; liable for any damages whatsoever arising from the use of or inability to
  24. ; use the SOFTWARE.
  25. ;
  26. ;
  27. ; Please feel free to use this code however you see fit.  I would appreciate
  28. ; a small credit in the documentation of any program that you produce
  29. ; which uses this code.
  30. ;
  31.  
  32.  
  33. ; ***** Required variables - these can point to any spare place in memory
  34. ;
  35. decimal_point_pos    equ    _textShadow+0    ; Position of decimal point
  36.                         ; in a number (2 BYTES)
  37. exponent_len        equ    _textShadow+2    ; Length of the exponent
  38.                         ; string, or zero if none -
  39.                         ; valid when converting a str
  40.                         ; to a number (1 BYTE)
  41.  
  42.  
  43. ; ***** Check the string pointed to by HL, of length B, to see if it is
  44. ;    numeric.  CF set if non-numeric, otherwise cleared - Destroys A
  45. CheckStrNumeric:
  46.     push    bc
  47.     push    de
  48.     push    hl
  49.  
  50.     ld    c,0            ; C is the status register, and its
  51.                     ; bits mean as follows:
  52.                     ; 0 - Set when decimal point found
  53.                     ; 1 - Set when first non-space char
  54.                     ;     found
  55.                     ; 2 - Set when exponent char found
  56.                     ; 3 - Set when first numeric digit
  57.                     ;     found
  58.                     ; 4 - Set when exponent char first
  59.                     ;     found, reset when next char is
  60.                     ;     checked - used to allow a neg
  61.                     ;     sign after exponent char
  62.  
  63.     ld    d,0            ; D holds the index of the current
  64.                     ; digit, relative to the start of the
  65.                     ; number
  66.  
  67. check_byte_numeric:
  68.     ld    a,(hl)            ; Get current char
  69.  
  70.     cp    Lspace            ; Spaces are not counted as digits, but
  71.     jr    nz,no_more_spaces    ; are accepted if before any other
  72.     bit    1,c            ; chars
  73.     jr    z,is_numeric_byte_no_count
  74.     jr    not_numeric
  75.  
  76. no_more_spaces:
  77.     set    1,c            ; Non-space char found, so no more
  78.                     ; spaces allowed
  79.  
  80. check_exponent:
  81.     cp    Lexponent        ; Check for exponent (only one allowed)
  82.     jr    nz,check_dec_point
  83.     bit    2,c
  84.     jr    nz,not_numeric
  85.     set    2,c            ; Set exponent just found
  86.     set    4,c
  87.     res    3,c            ; Must be at least one numeric digit
  88.     jr    is_numeric_byte_no_res_exp
  89.  
  90. check_dec_point:
  91.     cp    Lperiod            ; Check for decimal point
  92.     jr    nz,check_neg
  93.     bit    0,c            ; Check there is only one decimal        
  94.     jr    nz,not_numeric        ; point - exit with error if not
  95.     bit    2,c            ; Check no dec. point after exponent
  96.     jr    nz,not_numeric
  97.     set    0,c
  98.     jr    is_numeric_byte
  99.  
  100. check_neg:
  101.     cp    Lneg            ; Check for negative (-) sign
  102.     jr    nz,check_numbers
  103.     xor    a            ; Check - sign is at start of number
  104.     cp    d
  105.     jr    z,is_numeric_byte
  106.     bit    4,c
  107.     jr    nz,is_numeric_byte
  108.     jr    not_numeric
  109.     
  110. check_numbers:
  111.     cp    L0            ; Check for numbers (final filter)
  112.     jr    c,not_numeric
  113.     cp    L9+1
  114.     jr    nc,not_numeric
  115.     set    3,c            ; Numeric char (digit) found, so record
  116.     jr    is_numeric_byte        ; in C that it has been
  117.  
  118. not_numeric:
  119.     scf                ; Non-numeric, so set CF
  120.     jr    check_str_numeric_exit    
  121.  
  122. is_numeric_byte:
  123.     res    4,c            ; Clear negative allowance after
  124.                     ; exponent
  125. is_numeric_byte_no_res_exp:
  126.     inc    d            ; Count digit
  127. is_numeric_byte_no_count:
  128.     inc    hl            ; Point HL to next char, and loop
  129.     djnz    check_byte_numeric
  130.  
  131.     bit    3,c            ; Signal non-numeric string if no
  132.     jr    z,not_numeric        ; numbers found
  133.  
  134.     or    a            ; Clear CF to signal numeric
  135.  
  136. check_str_numeric_exit:
  137.     pop    hl
  138.     pop    de
  139.     pop    bc
  140.     ret
  141.  
  142.  
  143. ; ***** Converts string in HL, length B, to number in OP1 (MUST be checked
  144. ;    to be numeric with CheckStrNumeric first) - Destroys A AND THE STRING
  145. ;    IT CHECKS
  146. StringToNumeric:
  147.     push    bc
  148.     push    de
  149.     push    hl
  150.  
  151.     push    hl
  152.     call    _ZEROOP1        ; Clear OP1
  153.     pop    hl
  154.  
  155. remove_initial_spaces:
  156.     ld    a,(hl)            ; Remove all spaces at start of number
  157.     cp    Lspace
  158.     jr    nz,stop_spaces
  159.     inc    hl
  160.     dec    b
  161.     jr    remove_initial_spaces
  162. stop_spaces:
  163.  
  164.     ld    de,_OP1            ; Store pointer to OP1 in DE
  165.  
  166.     ld    a,(hl)            ; Check whether first char of string
  167.     cp    Lneg            ; is the -ve sign (-), and set A
  168.     ld    a,0            ; accordingly
  169.     jr    nz,not_negative_number
  170.     ld    a,$80
  171.     inc    hl
  172.     dec    b
  173. not_negative_number:
  174.     ld    (de),a            ; Store type of OP1 (real) and sign
  175.     inc    de
  176.  
  177.     inc    de            ; Add 2 to DE to point to mantissa
  178.     inc    de
  179.  
  180.  
  181.     ; ** Remove the exponent and everything after it
  182.  
  183.     xor    a            ; No exponent by default
  184.     ld    (exponent_len),a
  185.  
  186.     ld    a,Lexponent        ; Handle exponent (by altering string
  187.     call    FindByte        ; length to remove it, and by setting
  188.     jr    c,no_exponent        ; the num_has_exponent variable)
  189.  
  190.     ld    c,a            ; Store exponent value length
  191.     ld    a,b
  192.     sub    c
  193.     ld    (exponent_len),a
  194.     
  195.     ld    b,c            ; Set new string length
  196.  
  197.     ld    a,c            ; If exponent is before any numbers,
  198.     or    a            ; then take it as being before 1
  199.     jr    nz,no_exponent
  200.     push    hl
  201.     call    _op1set1
  202.     pop    hl
  203.     jp    check_conv_exponent
  204. no_exponent:
  205.  
  206.  
  207.     push    hl            ; Set default decimal point pos
  208.     ld    h,0
  209.     ld    l,b
  210.     ld    (decimal_point_pos),hl
  211.     pop    hl
  212.  
  213.  
  214.     ; ** Remove the decimal point - makes all future tasks easier
  215.  
  216.     ld    a,Lperiod        ; Find decimal point pos, and store
  217.     call    FindByte
  218.     jr    c,no_dec_point
  219.  
  220.     dec    b            ; Reduce string length to allow for
  221.     push    hl            ; removal of the dec. point, and store
  222.     ld    h,0            ; the position of the dec. point
  223.     ld    l,a
  224.     ld    (decimal_point_pos),hl
  225.     pop    hl
  226.  
  227.     cp    b            ; If decimal point is at end of string,
  228.     jr    z,no_dec_point        ; it has already been removed fully
  229.  
  230.     push    bc
  231.     push    de
  232.     push    hl
  233.  
  234.     ld    h,0            ; Find length of string to move, and
  235.     ld    l,b            ; store in BC
  236.     ld    a,(exponent_len)
  237.     ld    e,a
  238.     ld    d,h
  239.     add    hl,de
  240.     ld    de,(decimal_point_pos)
  241.     or    a
  242.     sbc    hl,de
  243.     ld    b,h
  244.     ld    c,l
  245.  
  246.     ld    de,(decimal_point_pos)
  247.     pop    hl            ; Store pointer to dec. point in HL
  248.     push    hl
  249.     add    hl,de
  250.  
  251.     ld    d,h            ; Get rid of decimal point (by setting
  252.     ld    e,l            ; HL to point to byte after dec. point,
  253.     inc    hl            ; and DE to point to dec. point)
  254.     ldir
  255.  
  256.     pop    hl
  257.     pop    de
  258.     pop    bc
  259. no_dec_point:
  260.  
  261.  
  262. find_first_non_zero_digit:
  263.     ld    a,(hl)            ; Skip past any superfluous zeros
  264.     cp    L0
  265.     jr    nz,non_zero_digit_found
  266.  
  267.     inc    hl            ; Check next character is a number -
  268.     ld    a,(hl)            ; don't remove zero if not
  269.     dec    hl
  270.     cp    L0
  271.     jr    nc,another_digit_after
  272.     cp    L9+1
  273.     jr    c,another_digit_after
  274.  
  275. set_zero_number:
  276.     call    _OP1SET0        ; Main part of number is zero, so just
  277.     jr    no_get_exponent        ; set entire number to zero, and exit
  278.  
  279. another_digit_after:
  280.     ld    a,b            ; Remove zero digit.  Make sure there
  281.     cp    1            ; is always at least one digit
  282.     jr    z,set_zero_number
  283.     dec    b
  284.     inc    hl
  285.  
  286.     push    hl            ; Correct decimal point pos
  287.     ld    hl,(decimal_point_pos)
  288.     dec    hl
  289.     ld    (decimal_point_pos),hl
  290.     pop    hl
  291.     jr    find_first_non_zero_digit
  292. non_zero_digit_found:
  293.  
  294.  
  295. add_digit_to_op1:
  296.     ld    a,(hl)            ; Get first digit as ASCII char
  297.     inc    hl
  298.  
  299.     sub    L0            ; Convert first char to BCD digit,
  300.     rlca                ; and shift to upper nibble of C
  301.     rlca
  302.     rlca
  303.     rlca
  304.     ld    c,a
  305.  
  306.     dec    b            ; If last digit, then write straight
  307.     jr    nz,is_second_digit    ; out to OP1 without a second digit
  308.     ld    (de),a
  309.     jr    fin_conv_number
  310.  
  311. is_second_digit:
  312.     ld    a,(hl)
  313.     inc    hl
  314.  
  315.     sub    L0            ; Store BCD digit in OP1
  316.     or    c
  317.     ld    (de),a
  318.     inc    de
  319.  
  320. digit_conv_loop_end:
  321.     djnz    add_digit_to_op1    ; Check all digits
  322.  
  323.  
  324. fin_conv_number:
  325.     push    hl
  326.     ld    de,(decimal_point_pos)    ; Calculate exponent based on decimal
  327.     ld    hl,$FBFF        ; point pos
  328.     add    hl,de
  329.     ld    (_OP1EXPM),hl
  330.     pop    hl
  331.  
  332. check_conv_exponent:
  333.     ld    a,(exponent_len)    ; Check whether exponent must be
  334.     or    a            ; processed
  335.     jr    z,no_get_exponent
  336.  
  337.     inc    hl            ; Adjust HL to point to value after
  338.                     ; exponent
  339.  
  340.     dec    a            ; Decrement exponent length to allow
  341.     ld    b,a            ; for removed E sign, and limit
  342.     ld    a,(hl)            ; exponent length to 3 digits - allows
  343.     cp    Lneg            ; an extra char for the negation (-)
  344.     ld    a,3            ; sign if needed
  345.     jr    nz,no_neg_sign
  346.     ld    a,4
  347. no_neg_sign:
  348.     call    LimitBToA
  349.  
  350.     push    bc
  351.     push    hl
  352.     rst    08h            ; Store main number in OP2
  353.     pop    hl
  354.     pop    bc
  355.  
  356.     call    StringToNumeric        ; Convert exponent from string to
  357.                     ; value in OP1
  358.  
  359.     call    _CONVOP1        ; Convert exponent from float to binary
  360.                     ; word in DE
  361.  
  362.     ld    a,(_OP1)
  363.     or    a
  364.     jr    z,normal_adjust_exp
  365.     ld    hl,(_OP2EXPM)        ; Adjust exponent of main number
  366.     or    a            ; (negative exponent)
  367.     sbc    hl,de
  368.     ld    (_OP2EXPM),hl
  369.     jr    restore_main_number
  370.  
  371. normal_adjust_exp:
  372.     ld    hl,(_OP2EXPM)        ; Adjust exponent of main number
  373.     add    hl,de            ; (positive exponent)
  374.     ld    (_OP2EXPM),hl
  375.  
  376. restore_main_number:
  377.     call    _OP2TOOP1        ; Restore main number
  378.  
  379. no_get_exponent:
  380.     pop    hl
  381.     pop    de
  382.     pop    bc
  383.     ret
  384.  
  385.  
  386. ; ***** Limits the value in B to the value in A (B will be less than or equal
  387. ;    to A afterwards)
  388. LimitBToA:
  389.     cp    b
  390.     ret    nc
  391.     ld    b,a
  392.     ret
  393.  
  394.  
  395. ; ***** Finds the first byte of value A in the block of memory pointed to
  396. ;    by HL of length B - Returns position of value in A, or index of char
  397. ;    after last char if not found - CF also set if byte not found
  398. FindByte:
  399.     push    bc
  400.     push    de
  401.     push    hl
  402.  
  403.     ld    c,a            ; C holds target value
  404.     ld    d,0            ; D holds current byte index
  405.  
  406. check_for_byte:
  407.     ld    a,(hl)            ; Search for byte value
  408.     cp    c
  409.     jr    z,byte_found
  410.     inc    d
  411.     inc    hl
  412.     djnz    check_for_byte
  413.  
  414.     ld    a,d            ; Indicate byte not found
  415.     scf
  416.     jr    exit_find_byte
  417.  
  418. byte_found:
  419.     ld    a,d            ; Indicate byte found, and store index
  420.     or    a            ; in A
  421.  
  422. exit_find_byte:
  423.     pop    hl
  424.     pop    de
  425.     pop    bc
  426.     ret
  427.  
  428.