M0-macro-compact.s 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. ; Copyright (C) 2020 Jeremiah Orians
  2. ; This file is part of stage0.
  3. ;
  4. ; stage0 is free software: you can redistribute it and/or modify
  5. ; it under the terms of the GNU General Public License as published by
  6. ; the Free Software Foundation, either version 3 of the License, or
  7. ; (at your option) any later version.
  8. ;
  9. ; stage0 is distributed in the hope that it will be useful,
  10. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ; GNU General Public License for more details.
  13. ;
  14. ; You should have received a copy of the GNU General Public License
  15. ; along with stage0. If not, see <http://www.gnu.org/licenses/>.
  16. :start
  17. ;; We will be using R12 for scratch
  18. ;; We will be using R13 for storage of tokens
  19. LOADUI R14 0x800 ; Our malloc pointer (Initialized)
  20. LOADUI R15 $stack ; Put stack at end of program
  21. ;; Prep TAPE_01
  22. LOADUI R0 0x1100
  23. FOPEN_READ
  24. ;; Prep TAPE_02
  25. LOADUI R0 0x1101
  26. FOPEN_WRITE
  27. ;; Setup offset table
  28. READSCID R0 ; Get process capabilities
  29. ANDI R1 R0 0xF ; We only care about size nybble
  30. LOADUI R0 1 ; Assume we are 8bit
  31. SL0 R0 R0 R1 ; Let size nybble correct answer
  32. STORER16 R0 @offset_Text ; Set ->TEXT offset
  33. ADDU R1 R0 R0 ; twice the size is the offset of the expression
  34. STORER16 R1 @offset_Expression ; Set ->EXPRESSION offset
  35. ADDU R0 R1 R0 ; 3 times the size of the register is the size of the struct
  36. STORER16 R0 @offset_struct ; Set offset_struct
  37. ;; Main program
  38. ;; Reads contents of Tape_01 and applies all Definitions
  39. ;; Writes results to Tape_02
  40. ;; Accepts no arguments and HALTS when done
  41. :main
  42. COPY R12 R14 ; calloc scratch
  43. CALLI R15 @collect_defines ; Get all the defines
  44. ;; We need to rewind tape_01 to perform our second pass
  45. LOADUI R0 0x1100
  46. REWIND
  47. FALSE R0 ; Make sure not EOF
  48. CALLI R15 @generate_output ; Write the results to Tape_02
  49. LOADUI R0 0x1100 ; Close TAPE_01
  50. FCLOSE
  51. LOADUI R0 0x1101 ; Close TAPE_02
  52. FCLOSE
  53. HALT ; We are Done
  54. ;; match function
  55. ;; Receives a CHAR* in R0, CHAR* in R1
  56. ;; Returns Bool in R0 indicating if strings match
  57. :match
  58. PUSHR R1 R15 ; Protect R1
  59. PUSHR R2 R15 ; Protect R2
  60. PUSHR R3 R15 ; Protect R3
  61. PUSHR R4 R15 ; Protect R4
  62. MOVE R2 R0 ; Put First string in place
  63. MOVE R3 R1 ; Put Second string in place
  64. LOADUI R4 0 ; Set initial index of 0
  65. :match_cmpbyte
  66. LOADXU8 R0 R2 R4 ; Get a byte of our first string
  67. LOADXU8 R1 R3 R4 ; Get a byte of our second string
  68. ADDUI R4 R4 1 ; Prep for next loop
  69. CMPSKIP.NE R1 R0 ; Compare the bytes
  70. JUMP.NZ R1 @match_cmpbyte ; Loop if bytes are equal
  71. ;; Done
  72. FALSE R2 ; Default answer
  73. CMPSKIP.NE R0 R1 ; If ended loop with everything matching
  74. TRUE R2 ; Set as TRUE
  75. MOVE R0 R2 ; Prepare for return
  76. POPR R4 R15 ; Restore R4
  77. POPR R3 R15 ; Restore R3
  78. POPR R2 R15 ; Restore R2
  79. POPR R1 R15 ; Restore R1
  80. RET R15
  81. ;; in_set function
  82. ;; Receives a Char in R0, char* in R1
  83. ;; Return result in R0
  84. :in_set
  85. PUSHR R1 R15 ; Protect R1
  86. PUSHR R2 R15 ; Protect R2 from changes
  87. :in_set_reset
  88. LOADU8 R2 R1 0 ; Get char from list
  89. JUMP.Z R2 @in_set_fail ; Stop when 0 == s[0]
  90. CMPJUMPI.E R0 R2 @in_set_done ; We found a match
  91. ADDUI R1 R1 1 ; Increment to next char
  92. JUMP.NZ R2 @in_set_reset ; Iterate if not NULL
  93. :in_set_fail
  94. ;; Looks like not found
  95. FALSE R1 ; Return FALSE
  96. :in_set_done
  97. CMPSKIPI.E R1 0 ; Provided not FALSE
  98. TRUE R2 ; The result is true
  99. MOVE R0 R2 ; Put result in correct place
  100. POPR R2 R15 ; Restore R2
  101. POPR R1 R15 ; Restore R1
  102. RET R15
  103. ;; file_print function
  104. ;; Receives pointer to string in R0 and FILE* in R1
  105. ;; Returns nothing
  106. :file_print
  107. PUSHR R2 R15 ; Protect R2 from Overwrite
  108. MOVE R2 R0 ; Put string pointer into place
  109. :file_print_read
  110. LOAD8 R0 R2 0 ; Get a char
  111. JUMP.Z R0 @file_print_done ; If NULL be done
  112. FPUTC ; Write the Char
  113. ADDUI R2 R2 1 ; Point at next CHAR
  114. JUMP @file_print_read ; Loop again
  115. :file_print_done
  116. POPR R2 R15 ; Restore R2
  117. RET R15
  118. ;; numerate_string function
  119. ;; Receives pointer To string in R0
  120. ;; Returns number in R0 equal to value of string
  121. ;; Or Zero in the event of invalid string
  122. :numerate_string
  123. ;; Preserve Registers
  124. PUSHR R1 R15
  125. PUSHR R2 R15
  126. PUSHR R3 R15
  127. PUSHR R4 R15
  128. ;; Initialize
  129. MOVE R1 R0 ; Get Text pointer out of the way
  130. FALSE R2 ; Set Negative flag to false
  131. FALSE R3 ; Set current count to Zero
  132. LOAD8 R0 R1 1 ; Get second byte
  133. CMPSKIPI.NE R0 120 ; If the second byte is x
  134. JUMP @numerate_string_hex ; treat string like hex
  135. ;; Deal with Decimal input
  136. LOADUI R4 10 ; Multiply by 10
  137. LOAD8 R0 R1 0 ; Get a byte
  138. CMPSKIPI.NE R0 45 ; If - toggle flag
  139. TRUE R2 ; So that we know to negate
  140. CMPSKIPI.E R2 0 ; If toggled
  141. ADDUI R1 R1 1 ; Move to next
  142. :numerate_string_dec
  143. LOAD8 R0 R1 0 ; Get a byte
  144. CMPSKIPI.NE R0 0 ; If NULL
  145. JUMP @numerate_string_done ; Be done
  146. MUL R3 R3 R4 ; Shift counter by 10
  147. SUBI R0 R0 48 ; Convert ascii to number
  148. CMPSKIPI.GE R0 0 ; If less than a number
  149. JUMP @numerate_string_done ; Terminate NOW
  150. CMPSKIPI.L R0 10 ; If more than a number
  151. JUMP @numerate_string_done ; Terminate NOW
  152. ADDU R3 R3 R0 ; Don't add to the count
  153. ADDUI R1 R1 1 ; Move onto next byte
  154. JUMP @numerate_string_dec
  155. ;; Deal with Hex input
  156. :numerate_string_hex
  157. LOAD8 R0 R1 0 ; Get a byte
  158. CMPSKIPI.E R0 48 ; All hex strings start with 0x
  159. JUMP @numerate_string_done ; Be done if not a match
  160. ADDUI R1 R1 2 ; Move to after leading 0x
  161. :numerate_string_hex_0
  162. LOAD8 R0 R1 0 ; Get a byte
  163. JUMP.Z R0 @numerate_string_done ; If NULL Be done
  164. SL0I R3 4 ; Shift counter by 16
  165. SUBI R0 R0 48 ; Convert ascii number to number
  166. CMPSKIPI.L R0 10 ; If A-F
  167. SUBI R0 R0 7 ; Shove into Range
  168. CMPSKIPI.L R0 16 ; If a-f
  169. SUBI R0 R0 32 ; Shove into Range
  170. ADDU R3 R3 R0 ; Add to the count
  171. ADDUI R1 R1 1 ; Get next Hex
  172. JUMP @numerate_string_hex_0
  173. ;; Clean up
  174. :numerate_string_done
  175. CMPSKIPI.E R2 0 ; If Negate flag has been set
  176. NEG R3 R3 ; Make the number negative
  177. MOVE R0 R3 ; Put number in R0
  178. ;; Restore Registers
  179. POPR R4 R15
  180. POPR R3 R15
  181. POPR R2 R15
  182. POPR R1 R15
  183. RET R15
  184. ;; collect_defines function
  185. ;; Returns nothing
  186. ;; Recieves nothing
  187. ;; Simply reads one token at a time
  188. ;; Collecting the DEFINEs
  189. ;; Uses R0, R1 and R2 as temps
  190. ;; Updates R12 scratch, R13 tokens and R14 HEAP
  191. :collect_defines
  192. PUSHR R0 R15 ; Protect R0
  193. PUSHR R1 R15 ; Protect R1
  194. PUSHR R2 R15 ; Protect R2
  195. :collect_defines_loop
  196. CALLI R15 @read_token ; c = read_token();
  197. PUSHR R0 R15 ; Protect C
  198. COPY R0 R12 ; Using scratch
  199. LOADUI R1 $DEFINE_STRING ; Using "DEFINE"
  200. CALLI R15 @match ; See if they match
  201. JUMP.NZ R0 @collect_defines_valid ; Looks like we have a match
  202. CALLI R15 @clear_scratch ; Clear out the scratch buffer
  203. POPR R0 R15 ; Restore C
  204. JUMP.NP R0 @collect_defines_done ; Hit EOF
  205. JUMP @collect_defines_loop ; Otherwise keep looping
  206. :collect_defines_valid
  207. POPR R0 R15 ; Restore C
  208. CALLI R15 @clear_scratch ; Clear out the scratch buffer
  209. LOADR16 R0 @offset_struct ; Get the size of the struct
  210. ADDU R14 R14 R0 ; Allocate struct
  211. STORE R13 R12 0 ; N->NEXT = tokens
  212. COPY R13 R12 ; tokens = N
  213. COPY R12 R14 ; SCRATCH = CALLOC(max_string, sizeof(char));
  214. CALLI R15 @read_token ; get the text of the define
  215. LOADR16 R0 @offset_Text ; Get ->TEXT offset
  216. STOREX R12 R13 R0 ; N->TEXT = scratch
  217. ADDUI R14 R14 1 ; Add some NULL padding
  218. COPY R12 R14 ; SCRATCH = CALLOC(max_string, sizeof(char)); length = 0;
  219. CALLI R15 @read_token ; Get the expression of the define
  220. PUSHR R0 R15 ; Protect C
  221. LOADR16 R0 @offset_Expression ; Get ->EXPRESSION offset
  222. STOREX R12 R13 R0 ; N->EXPRESSION = scratch
  223. ADDUI R14 R14 1 ; Add some NULL padding
  224. COPY R12 R14 ; SCRATCH = CALLOC(max_string, sizeof(char)); length = 0;
  225. POPR R0 R15 ; Restore C
  226. JUMP.P R0 @collect_defines_loop ; Keep looping if not NULL
  227. :collect_defines_done
  228. POPR R2 R15 ; Restore R2
  229. POPR R1 R15 ; Restore R1
  230. POPR R0 R15 ; Restore R0
  231. RET R15
  232. ;; read_token function
  233. ;; Returns int C in R0
  234. ;; Updates the contents of (R12) scratch and (R12-R14)length (via updating HEAP (R14))
  235. ;; Uses R0, R1 and R2 as temps
  236. :read_token
  237. PUSHR R1 R15 ; Protect R1
  238. PUSHR R2 R15 ; Protect R2
  239. LOADUI R1 0x1100 ; Using TAPE_01
  240. FGETC ; Read a byte
  241. JUMP.NP R0 @read_token_done ; if EOF, just return EOF
  242. CMPSKIPI.NE R0 10 ; IF '\n' just return '\n'
  243. JUMP @read_token_done ; Be done
  244. CMPSKIPI.NE R0 9 ; IF '\t' just return '\t'
  245. JUMP @read_token_done ; Be done
  246. CMPSKIPI.NE R0 32 ; IF ' ' just return ' '
  247. JUMP @read_token_done ; Be done
  248. COPY R2 R0 ; Protect C
  249. LOADUI R1 $read_token_comments ; Using "#;"
  250. CALLI R15 @in_set ; Check if in set
  251. LOADUI R1 0x1100 ; Using TAPE_01
  252. JUMP.NZ R0 @delete_line_comment ; Then it is a line comment and needs to be purged
  253. COPY R0 R2 ; Put C into place for write
  254. CMPSKIPI.NE R0 34 ; IF '"'
  255. JUMP @read_string ; Collect that string
  256. CMPSKIPI.NE R0 39 ; IF "'"
  257. JUMP @read_string ; Collect that string
  258. ;; Deal with the fallthrough case of a single token
  259. :read_token_loop
  260. PUSH8 R2 R14 ; scratch[length] = c; length = length + 1;
  261. LOADUI R1 0x1100 ; Using TAPE_01
  262. FGETC ; Read a byte
  263. COPY R2 R0 ; Protect C
  264. LOADUI R1 $read_token_whitespace ; Using " \t\n"
  265. CALLI R15 @in_set ; IF in set
  266. JUMP.Z R0 @read_token_loop ; Otherwise keep looping
  267. MOVE R0 R2 ; Return our C
  268. JUMP @read_token_done ; else be done
  269. ;; Deal with line comment case
  270. :delete_line_comment
  271. FGETC ; Read a byte
  272. CMPSKIPI.NE R0 10 ; IF '\n'
  273. JUMP @read_token_done ; Be done
  274. JUMP @delete_line_comment ; Otherwise keep looping
  275. ;; Deal with "RAW STRINGS" and 'HEX LITERALS'
  276. ;; R1 is already TAPE_01 and R2 is the terminator
  277. :read_string
  278. PUSH8 R0 R14 ; scratch[length] = c; length = length + 1;
  279. FGETC ; Read a byte
  280. CMPJUMPI.NE R0 R2 @read_string ; Keep looping if not terminator
  281. :read_token_done
  282. POPR R2 R15 ; Restore R2
  283. POPR R1 R15 ; Restore R1
  284. RET R15
  285. :read_token_comments
  286. "#;"
  287. :read_token_whitespace
  288. "
  289. "
  290. ;; clear_scratch function
  291. ;; Recieves nothing
  292. ;; Returns nothing
  293. ;; Clears SCRATCH (R12) and LENGTH (R14-R12) by POPing off the HEAP (R14)
  294. :clear_scratch
  295. PUSHR R0 R15 ; Protect R0
  296. :clear_scratch_loop
  297. CMPJUMPI.E R12 R14 @clear_scratch_done ; When LENGTH == 0 and SCRATCH is cleared
  298. POP8 R0 R14 ; Clear the last byte of SCRATCH and decrement LENGTH
  299. JUMP @clear_scratch_loop ; Keep looping
  300. :clear_scratch_done
  301. POPR R0 R15 ; Restore R0
  302. RET R15
  303. ;; generate_output function
  304. ;; Returns nothing
  305. ;; Recieves nothing
  306. ;; Simply reads one token at a time
  307. ;; Outputting if possible
  308. ;; Uses R0, R1 and R2 as temps
  309. ;; Manipulates SCRATCH (R12) and LENGTH (R14-R12) but should reset HEAP (R14) each loop
  310. :generate_output
  311. JUMP.NP R0 @generate_output_done ; Stop if we hit EOF
  312. CALLI R15 @clear_scratch ; Clear the scratch
  313. CALLI R15 @read_token ; Get a token
  314. CMPJUMPI.E R12 R14 @generate_output ; Go again if we read nothing
  315. COPY R2 R0 ; Protect C
  316. LOAD8 R0 R12 0 ; SCRATCH[0]
  317. LOADUI R1 $generate_output_hex ; Using ":!@$%&"
  318. CALLI R15 @in_set ; See if worth keeping
  319. JUMP.Z R0 @generate_output_define
  320. ;; Deal with the case of labels and pointers
  321. COPY R0 R12 ; Using scratch
  322. LOADUI R1 0x1101 ; And TAPE_02
  323. CALLI R15 @file_print ; Print it
  324. LOADUI R0 10 ; Using '\n'
  325. FPUTC ; fputc('\n', TAPE_02);
  326. MOVE R0 R2 ; Put C in correct spot for catching EOF
  327. JUMP @generate_output ; Loop it
  328. :generate_output_define
  329. COPY R0 R12 ; Using SCRATCH
  330. LOADUI R1 $DEFINE_STRING ; Using "DEFINE"
  331. CALLI R15 @match ; See if we have a match
  332. JUMP.Z R0 @generate_output_string ; If not try a string
  333. ;; Deal with the case of DEFINE statement
  334. CALLI R15 @clear_scratch ; Clear out the scratch
  335. CALLI R15 @read_token ; Get a token
  336. CALLI R15 @clear_scratch ; Clear out the scratch
  337. CALLI R15 @read_token ; Get a token
  338. JUMP @generate_output ; Loop it
  339. :generate_output_string
  340. LOAD8 R0 R12 0 ; SCRATCH[0]
  341. CMPSKIPI.E R0 34 ; If SCRATCH[0] == '"'
  342. JUMP @generate_output_literal ; Otherwise try next
  343. ;; Deal with the case of "RAW STRING"
  344. LOADUI R1 0x1101 ; And TAPE_02
  345. CALLI R15 @hexify_string ; Write it
  346. LOADUI R0 10 ; Using '\n'
  347. FPUTC ; Write it
  348. MOVE R0 R2 ; Return C
  349. JUMP @generate_output ; Loop it
  350. :generate_output_literal
  351. CMPSKIPI.E R0 39 ; If SCRATCH[0] == '\''
  352. JUMP @generate_output_defined ; Otherwise try next
  353. ;; Deal with the case of 'HEX LITERAL'
  354. ADDUI R0 R12 1 ; Using SCRATCH + 1
  355. LOADUI R1 0x1101 ; And TAPE_02
  356. CALLI R15 @file_print ; Print it
  357. LOADUI R0 10 ; Using '\n'
  358. FPUTC ; Write it
  359. MOVE R0 R2 ; Return C
  360. JUMP @generate_output ; Loop it
  361. :generate_output_defined
  362. CALLI R15 @find_match ; Lets see if SCRATCH has a match
  363. JUMP.Z R0 @generate_output_number ; Nope, try a NUMBER
  364. ;; Deal with case of a DEFINED token
  365. LOADUI R1 0x1101 ; And TAPE_02
  366. CALLI R15 @file_print ; Print it
  367. LOADUI R0 10 ; Using '\n'
  368. FPUTC ; Write it
  369. MOVE R0 R2 ; Return C
  370. JUMP @generate_output ; Loop it
  371. :generate_output_number
  372. COPY R0 R12 ; Using SCRATCH
  373. LOAD8 R1 R12 0 ; Get SCRATCH[0]
  374. CALLI R15 @numerate_string ; See if it is a number
  375. CMPSKIPI.E R1 48 ; IF '0' == SCRATCH[0]
  376. JUMP.Z R0 @generate_output_fail ; We failed
  377. ;; Deal with the case of numbers
  378. LOADUI R1 0x1101 ; And TAPE_02
  379. CALLI R15 @hex16 ; Write it
  380. LOADUI R0 10 ; Using '\n'
  381. FPUTC ; Write it
  382. MOVE R0 R2 ; Return C
  383. JUMP @generate_output ; Loop it
  384. :generate_output_fail
  385. FALSE R1 ; Write to STDOUT
  386. LOADUI R0 $generate_output_message1 ; Put our header
  387. CALLI R15 @file_print ; Print it
  388. MOVE R0 R12 ; Using SCRATCH
  389. CALLI R15 @file_print ; Print it
  390. LOADUI R0 $generate_output_message2 ; Put our header
  391. CALLI R15 @file_print ; Print it
  392. HALT ; FUCK
  393. :generate_output_done
  394. RET R15
  395. :generate_output_hex
  396. ":!@$%&"
  397. :generate_output_message1
  398. "
  399. Unknown other: "
  400. :generate_output_message2
  401. "
  402. Aborting to prevent problems
  403. "
  404. ;; hexify_string function
  405. ;; Recieves FILE* in R1
  406. ;; Writes SCRATCH (R12)
  407. ;; Uses R2 to check for hitting NULL and R3 for I
  408. :hexify_string
  409. PUSHR R2 R15 ; Protect R2
  410. PUSHR R3 R15 ; Protect R3
  411. PUSHR R12 R15 ; Protect R12
  412. ADDUI R12 R12 1 ; Skip past the '"'
  413. FALSE R3 ; I = 0
  414. :hexify_string_loop
  415. LOADXU16 R0 R12 R3 ; Grab 2 bytes
  416. ANDI R2 R0 0xFF ; Preserve byte to check for NULL
  417. CALLI R15 @hex16 ; Convert to hex and print
  418. ADDUI R3 R3 2 ; I = I + 2
  419. JUMP.NZ R2 @hexify_string_loop
  420. ;; Deal with extra padding
  421. :hexify_string_padding
  422. FALSE R0 ; Writing ZERO
  423. ANDI R3 R3 0x3 ; (I & 0x3)
  424. JUMP.Z R3 @hexify_string_done ; IF (0 == (I & 0x3)) be done
  425. CALLI R15 @hex8 ; Write another NULL byte
  426. ADDUI R3 R3 1 ; I = I + 1
  427. JUMP @hexify_string_padding ; Keep padding
  428. :hexify_string_done
  429. POPR R12 R15 ; Restore R12
  430. POPR R3 R15 ; Restore R3
  431. POPR R2 R15 ; Restore R2
  432. RET R15
  433. ;; hex16 functionality
  434. ;; Accepts 16bit value in R0
  435. ;; And FILE* output in R1
  436. ;; Returns to whatever called it
  437. :hex16
  438. PUSHR R0 R15
  439. SR0I R0 8 ; Do high byte first
  440. CALLI R15 @hex8
  441. POPR R0 R15
  442. :hex8
  443. PUSHR R0 R15
  444. SR0I R0 4 ; Do high nybble first
  445. CALLI R15 @hex4
  446. POPR R0 R15
  447. :hex4
  448. ANDI R0 R0 0xF ; isolate nybble
  449. ADDUI R0 R0 48 ; convert to ascii
  450. CMPSKIPI.LE R0 57 ; If nybble was greater than '9'
  451. ADDUI R0 R0 7 ; Shift it into 'A' range of ascii
  452. FPUTC ; Write HEX
  453. RET R15 ; Get next nybble or return if done
  454. ;; find_match function
  455. ;; Recieves SCRATCH in R12
  456. ;; And tokens in R13
  457. ;; Returns NULL or EXPRESSION if match found
  458. :find_match
  459. PUSHR R1 R15 ; Protect R1
  460. PUSHR R2 R15 ; Protect R2
  461. COPY R2 R13 ; P = tokens
  462. :find_match_loop
  463. JUMP.Z R2 @find_match_done ; Be done if not found
  464. LOADR16 R1 @offset_Text ; Get ->TEXT offset
  465. LOADX R0 R2 R1 ; Using P->TEXT
  466. COPY R1 R12 ; Using SCRATCH
  467. CALLI R15 @match ; See if they match
  468. JUMP.NZ R0 @find_match_success ; Found it
  469. LOAD R2 R2 0 ; P = P->NEXT
  470. JUMP @find_match_loop ; Keep looping
  471. ;; Deal with match
  472. :find_match_success
  473. LOADR16 R1 @offset_Expression ; Using ->EXPRESSION offset
  474. LOADX R2 R2 R1 ; Using P->EXPRESSION
  475. :find_match_done
  476. MOVE R0 R2 ; Put result in R0
  477. POPR R2 R15 ; Restore R2
  478. POPR R1 R15 ; Restore R1
  479. RET R15
  480. ;; offset table
  481. ;; Values will be updated to reflect
  482. ;; register sizes greater than 8bits
  483. ;; if registers are larger than 8 bits
  484. ;; Padded with 2 extra NULLs to help the Disassembler
  485. ;; As 4byte alignment is generally assumed to simply
  486. ;; Work required to figure out strings
  487. :offset_Text
  488. 1
  489. :offset_Expression
  490. 2
  491. :offset_struct
  492. 3
  493. '00 00'
  494. :DEFINE_STRING
  495. "DEFINE"
  496. ; Where our stack will start
  497. :stack