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.

232 lines
4.3KB

  1. ; *** Requirements ***
  2. ; findchar
  3. ; multDEBC
  4. ; callIXI
  5. ;
  6. ; *** Defines ***
  7. ;
  8. ; EXPR_PARSE: routine to call to parse literals or symbols that are part of
  9. ; the expression. Routine's signature:
  10. ; String in (HL), returns its parsed value to IX. Z for success.
  11. ;
  12. ; *** Code ***
  13. ;
  14. ; Parse expression in string at (HL) and returns the result in IX.
  15. ; **This routine mutates (HL).**
  16. ; We expect (HL) to be disposable: we mutate it to avoid having to make a copy.
  17. ; Sets Z on success, unset on error.
  18. ; TODO: the IX output register is a bit awkward. Nearly everywhere, I need
  19. ; to push \ pop that thing. See if we could return the result in DE
  20. ; instead.
  21. parseExpr:
  22. push de
  23. push hl
  24. call _parseExpr
  25. pop hl
  26. pop de
  27. ret
  28. _parseExpr:
  29. ld de, exprTbl
  30. .loop:
  31. ld a, (de)
  32. or a
  33. jp z, EXPR_PARSE ; no operator, just parse the literal
  34. push de ; --> lvl 1. save operator row
  35. call _findAndSplit
  36. jr z, .found
  37. pop de ; <-- lvl 1
  38. inc de \ inc de \ inc de
  39. jr .loop
  40. .found:
  41. ; Operator found, string splitted. Left in (HL), right in (DE)
  42. call _resolveLeftAndRight
  43. ; Whether _resolveLeftAndRight was a success, we pop our lvl 1 stack
  44. ; out, which contains our operator row. We pop it in IX.
  45. ; L-R numbers are parsed in HL (left) and DE (right).
  46. pop ix ; <-- lvl 1
  47. ret nz
  48. ; Resolving left and right succeeded, proceed!
  49. inc ix ; point to routine pointer
  50. call callIXI
  51. push de \ pop ix
  52. cp a ; ensure Z
  53. ret
  54. ; Given a string in (HL) and a separator char in A, return a splitted string,
  55. ; that is, the same (HL) string but with the found A char replaced by a null
  56. ; char. DE points to the second part of the split.
  57. ; Sets Z if found, unset if not found.
  58. _findAndSplit:
  59. push hl
  60. call .skipCharLiteral
  61. call findchar
  62. jr nz, .end ; nothing found
  63. ; Alright, we have our char and we're pointing at it. Let's replace it
  64. ; with a null char.
  65. xor a
  66. ld (hl), a ; + changed to \0
  67. inc hl
  68. ex de, hl ; DE now points to the second part of the split
  69. cp a ; ensure Z
  70. .end:
  71. pop hl ; HL is back to the start
  72. ret
  73. .skipCharLiteral:
  74. ; special case: if our first char is ', skip the first 3 characters
  75. ; so that we don't mistake a literal for an iterator
  76. push af
  77. ld a, (hl)
  78. cp 0x27 ; '
  79. jr nz, .skipCharLiteralEnd ; not a '
  80. xor a ; check for null char during skipping
  81. ; skip 3
  82. inc hl
  83. cp (hl)
  84. jr z, .skipCharLiteralEnd
  85. inc hl
  86. cp (hl)
  87. jr z, .skipCharLiteralEnd
  88. inc hl
  89. .skipCharLiteralEnd:
  90. pop af
  91. ret
  92. .find:
  93. ; parse expression on the left (HL) and the right (DE) and put the results in
  94. ; HL (left) and DE (right)
  95. _resolveLeftAndRight:
  96. ; special case: is (HL) zero? If yes, it means that our left operand
  97. ; is empty. consider it as 0
  98. ld ix, 0 ; pre-set to 0
  99. ld a, (hl)
  100. or a
  101. jr z, .skip
  102. ; Parse left operand in (HL)
  103. call parseExpr
  104. ret nz ; return immediately if error
  105. .skip:
  106. ; Now we have parsed everything to the left and we have its result in
  107. ; IX. What we need to do now is the same thing on (DE) and then apply
  108. ; the + operator. Let's save IX somewhere and parse this.
  109. ex de, hl ; right expr now in HL
  110. push ix ; --> lvl 1
  111. call parseExpr
  112. pop hl ; <-- lvl 1. left
  113. push ix \ pop de ; right
  114. ret ; Z is parseExpr's result
  115. ; Routines in here all have the same signature: they take two numbers, DE (left)
  116. ; and IX (right), apply the operator and put the resulting number in DE.
  117. ; The table has 3 bytes per row: 1 byte for operator and 2 bytes for routine
  118. ; pointer.
  119. exprTbl:
  120. .db '+'
  121. .dw .plus
  122. .db '-'
  123. .dw .minus
  124. .db '*'
  125. .dw .mult
  126. .db '/'
  127. .dw .div
  128. .db '%'
  129. .dw .mod
  130. .db '&'
  131. .dw .and
  132. .db 0x7c ; '|'
  133. .dw .or
  134. .db '^'
  135. .dw .xor
  136. .db '}'
  137. .dw .rshift
  138. .db '{'
  139. .dw .lshift
  140. .db 0 ; end of table
  141. .plus:
  142. add hl, de
  143. ex de, hl
  144. ret
  145. .minus:
  146. or a ; clear carry
  147. sbc hl, de
  148. ex de, hl
  149. ret
  150. .mult:
  151. ld b, h
  152. ld c, l
  153. call multDEBC ; --> HL
  154. ex de, hl
  155. ret
  156. .div:
  157. ; divide takes HL/DE
  158. push bc
  159. call divide
  160. ld e, c
  161. ld d, b
  162. pop bc
  163. ret
  164. .mod:
  165. call .div
  166. ex de, hl
  167. ret
  168. .and:
  169. ld a, h
  170. and d
  171. ld d, a
  172. ld a, l
  173. and e
  174. ld e, a
  175. ret
  176. .or:
  177. ld a, h
  178. or d
  179. ld d, a
  180. ld a, l
  181. or e
  182. ld e, a
  183. ret
  184. .xor:
  185. ld a, h
  186. xor d
  187. ld d, a
  188. ld a, l
  189. xor e
  190. ld e, a
  191. ret
  192. .rshift:
  193. ld a, e
  194. and 0xf
  195. ret z
  196. push bc
  197. ld b, a
  198. .rshiftLoop:
  199. srl h
  200. rr l
  201. djnz .rshiftLoop
  202. ex de, hl
  203. pop bc
  204. ret
  205. .lshift:
  206. ld a, e
  207. and 0xf
  208. ret z
  209. push bc
  210. ld b, a
  211. .lshiftLoop:
  212. sla l
  213. rl h
  214. djnz .lshiftLoop
  215. ex de, hl
  216. pop bc
  217. ret