Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
5.4KB

  1. ; *** Requirements ***
  2. ; lib/util
  3. ; *** Code ***
  4. ; Parse the hex char at A and extract it's 0-15 numerical value. Put the result
  5. ; in A.
  6. ;
  7. ; On success, the carry flag is reset. On error, it is set.
  8. parseHex:
  9. ; First, let's see if we have an easy 0-9 case
  10. add a, 0xc6 ; maps '0'-'9' onto 0xf6-0xff
  11. sub 0xf6 ; maps to 0-9 and carries if not a digit
  12. ret nc
  13. and 0xdf ; converts lowercase to uppercase
  14. add a, 0xe9 ; map 0x11-x017 onto 0xFA - 0xFF
  15. sub 0xfa ; map onto 0-6
  16. ret c
  17. ; we have an A-F digit
  18. add a, 10 ; C is clear, map back to 0xA-0xF
  19. ret
  20. ; Parse the decimal char at A and extract it's 0-9 numerical value. Put the
  21. ; result in A.
  22. ;
  23. ; On success, the carry flag is reset. On error, it is set.
  24. ; Also, zero flag set if '0'
  25. ; parseDecimalDigit has been replaced with the following code inline:
  26. ; add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
  27. ; sub 0xff-9 ; maps to 0-9 and carries if not a digit
  28. ; Parse string at (HL) as a decimal value and return value in DE under the
  29. ; same conditions as parseLiteral.
  30. ; Sets Z on success, unset on error.
  31. ; To parse successfully, all characters following HL must be digits and those
  32. ; digits must form a number that fits in 16 bits. To end the number, both \0
  33. ; and whitespaces (0x20 and 0x09) are accepted. There must be at least one
  34. ; digit in the string.
  35. parseDecimal:
  36. push hl ; --> lvl 1
  37. ld a, (hl)
  38. add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
  39. sub 0xff-9 ; maps to 0-9 and carries if not a digit
  40. jr c, .error ; not a digit on first char? error
  41. exx ; preserve bc, hl, de
  42. ld h, 0
  43. ld l, a ; load first digit in without multiplying
  44. ld b, 3 ; Carries can only occur for decimals >=5 in length
  45. .loop:
  46. exx
  47. inc hl
  48. ld a, (hl)
  49. exx
  50. ; inline parseDecimalDigit
  51. add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff
  52. sub 0xff-9 ; maps to 0-9 and carries if not a digit
  53. jr c, .end
  54. add hl, hl ; x2
  55. ld d, h
  56. ld e, l ; de is x2
  57. add hl, hl ; x4
  58. add hl, hl ; x8
  59. add hl, de ; x10
  60. ld d, 0
  61. ld e, a
  62. add hl, de
  63. jr c, .end ; if hl was 0x1999, it may carry here
  64. djnz .loop
  65. inc b ; so loop only executes once more
  66. ; only numbers >0x1999 can carry when multiplied by 10.
  67. ld de, 0xE666
  68. ex de, hl
  69. add hl, de
  70. ex de, hl
  71. jr nc, .loop ; if it doesn't carry, it's small enough
  72. exx
  73. inc hl
  74. ld a, (hl)
  75. exx
  76. add a, 0xd0 ; the next line expects a null to be mapped to 0xd0
  77. .end:
  78. ; Because of the add and sub in parseDecimalDigit, null is mapped
  79. ; to 0x00+(0xff-'9')-(0xff-9)=-0x30=0xd0
  80. sub 0xd0 ; if a is null, set Z
  81. ; a is checked for null before any errors
  82. push hl ; --> lvl 2, result
  83. exx ; restore original bc
  84. pop de ; <-- lvl 2, result
  85. pop hl ; <-- lvl 1, orig
  86. ret z
  87. ; A is not 0? Ok, but if it's a space, we're happy too.
  88. jp isWS
  89. .error:
  90. pop hl ; <-- lvl 1, orig
  91. jp unsetZ
  92. ; Parse string at (HL) as a hexadecimal value without the "0x" prefix and
  93. ; return value in DE.
  94. ; HL is advanced to the character following the last successfully read char.
  95. ; Sets Z on success.
  96. parseHexadecimal:
  97. ld a, (hl)
  98. call parseHex
  99. jp c, unsetZ ; we need at least one char
  100. push bc
  101. ld de, 0
  102. ld b, 0
  103. .loop:
  104. ; we push to B to verify overflow
  105. rl e \ rl d \ rl b
  106. rl e \ rl d \ rl b
  107. rl e \ rl d \ rl b
  108. rl e \ rl d \ rl b
  109. or e
  110. ld e, a
  111. ; did we overflow?
  112. ld a, b
  113. or a
  114. jr nz, .end ; overflow, NZ already set
  115. ; next char
  116. inc hl
  117. ld a, (hl)
  118. call parseHex
  119. jr nc, .loop
  120. cp a ; ensure Z
  121. .end:
  122. pop bc
  123. ret
  124. ; Parse string at (HL) as a binary value (010101) without the "0b" prefix and
  125. ; return value in E. D is always zero.
  126. ; Sets Z on success.
  127. parseBinaryLiteral:
  128. push bc
  129. push hl
  130. call strlen
  131. or a
  132. jr z, .error ; empty, error
  133. cp 9
  134. jr nc, .error ; >= 9, too long
  135. ; We have a string of 8 or less chars. What we'll do is that for each
  136. ; char, we rotate left and set the LSB according to whether we have '0'
  137. ; or '1'. Error out on anything else. C is our stored result.
  138. ld b, a ; we loop for "strlen" times
  139. ld c, 0 ; our stored result
  140. .loop:
  141. rlc c
  142. ld a, (hl)
  143. inc hl
  144. cp '0'
  145. jr z, .nobit ; no bit to set
  146. cp '1'
  147. jr nz, .error ; not 0 or 1
  148. ; We have a bit to set
  149. inc c
  150. .nobit:
  151. djnz .loop
  152. ld e, c
  153. cp a ; ensure Z
  154. jr .end
  155. .error:
  156. call unsetZ
  157. .end:
  158. pop hl
  159. pop bc
  160. ret
  161. ; Parses the string at (HL) and returns the 16-bit value in DE. The string
  162. ; can be a decimal literal (1234), a hexadecimal literal (0x1234) or a char
  163. ; literal ('X').
  164. ;
  165. ; As soon as the number doesn't fit 16-bit any more, parsing stops and the
  166. ; number is invalid. If the number is valid, Z is set, otherwise, unset.
  167. parseLiteral:
  168. ld de, 0 ; pre-fill
  169. ld a, (hl)
  170. cp 0x27 ; apostrophe
  171. jr z, .char
  172. cp '0'
  173. jr z, .hexOrBin
  174. jp parseDecimal
  175. ; Parse string at (HL) and, if it is a char literal, sets Z and return
  176. ; corresponding value in E. D is always zero.
  177. ;
  178. ; A valid char literal starts with ', ends with ' and has one character in the
  179. ; middle. No escape sequence are accepted, but ''' will return the apostrophe
  180. ; character.
  181. .char:
  182. push hl
  183. inc hl
  184. inc hl
  185. cp (hl)
  186. jr nz, .charEnd ; not ending with an apostrophe
  187. inc hl
  188. ld a, (hl)
  189. or a ; cp 0
  190. jr nz, .charEnd ; string has to end there
  191. ; Valid char, good
  192. dec hl
  193. dec hl
  194. ld e, (hl)
  195. cp a ; ensure Z
  196. .charEnd:
  197. pop hl
  198. ret
  199. .hexOrBin:
  200. inc hl
  201. ld a, (hl)
  202. inc hl ; already place it for hex or bin
  203. cp 'x'
  204. jr z, .hex
  205. cp 'b'
  206. jr z, .bin
  207. ; special case: single '0'. set Z if we hit have null terminating.
  208. or a
  209. .hexOrBinEnd:
  210. dec hl \ dec hl ; replace HL
  211. ret ; Z already set
  212. .hex:
  213. push hl
  214. call parseHexadecimal
  215. pop hl
  216. jr .hexOrBinEnd
  217. .bin:
  218. call parseBinaryLiteral
  219. jr .hexOrBinEnd