asmg.asm 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. ;; This file is part of asmc, a bootstrapping OS with minimal seed
  2. ;; Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
  3. ;; https://gitlab.com/giomasce/asmc
  4. ;; This program 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. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;; You should have received a copy of the GNU General Public License
  13. ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. WRITE_LABEL_BUF_LEN equ 128
  15. STACK_VARS_LEN equ 1024
  16. section .data
  17. temp_var:
  18. db '_'
  19. db 0
  20. section .bss
  21. label_num:
  22. resd 1
  23. stack_vars_ptr:
  24. resd 1
  25. block_depth:
  26. resd 1
  27. stack_depth:
  28. resd 1
  29. temp_depth:
  30. resd 1
  31. token_given_back:
  32. resd 1
  33. token_len:
  34. resd 1
  35. token_buf_ptr:
  36. resd 1
  37. buf2_ptr:
  38. resd 1
  39. write_label_buf_ptr:
  40. resd 1
  41. read_ptr:
  42. resd 1
  43. read_ptr_begin:
  44. resd 1
  45. read_ptr_end:
  46. resd 1
  47. section .text
  48. ;; Return: EAX
  49. gen_label:
  50. ;; Increment by 1 gen_label and return its original value
  51. mov eax, [label_num]
  52. inc DWORD [label_num]
  53. ret
  54. ;; Input in EDX
  55. ;; Destroys: ECX, EDX
  56. ;; Return: EAX
  57. write_label:
  58. ;; Write the initial dot
  59. mov ecx, [write_label_buf_ptr]
  60. mov BYTE [ecx], DOT
  61. ;; Move to the end of the string
  62. add ecx, 8
  63. ;; Loop over the hexadecimal digits and write them in the buffer
  64. write_label_loop:
  65. mov al, dl
  66. call num2alphahex
  67. mov [ecx], al
  68. shr edx, 4
  69. dec ecx
  70. cmp ecx, [write_label_buf_ptr]
  71. jne write_label_loop
  72. ;; Return the buffer's address
  73. mov eax, [write_label_buf_ptr]
  74. ret
  75. ;; Input in EDX (variable name)
  76. ;; Destroys: EAX
  77. push_var:
  78. push esi
  79. push edi
  80. ;; Check input length
  81. mov esi, edx
  82. call check_symbol_length
  83. ;; Check we are not overflowing the stack
  84. mov edi, [stack_depth]
  85. cmp edi, STACK_VARS_LEN
  86. jnb platform_panic
  87. ;; Copy the variable name in the stack
  88. shl edi, MAX_SYMBOL_NAME_LEN_LOG
  89. add edi, [stack_vars_ptr]
  90. mov esi, edx
  91. call strcpy2
  92. ;; Increment the stack depth
  93. inc DWORD [stack_depth]
  94. pop edi
  95. pop esi
  96. ;; If this is a temp var, increment also temp_depth
  97. cmp edx, temp_var
  98. jne push_var_non_temp
  99. inc DWORD [temp_depth]
  100. ret
  101. ;; If this is not a temp var, check temp_depth is zero
  102. push_var_non_temp:
  103. cmp DWORD [temp_depth], 0
  104. jne platform_panic
  105. ret
  106. ;; Input in EAX (is temporary)
  107. pop_var:
  108. ;; Check stack depth is positive and decrement it
  109. cmp DWORD [stack_depth], 0
  110. jna platform_panic
  111. dec DWORD [stack_depth]
  112. ;; If this is a temp var...
  113. cmp eax, 0
  114. jne pop_var_temp
  115. ret
  116. ;; ...check and decrement temp_depth
  117. pop_var_temp:
  118. cmp DWORD [temp_depth], 0
  119. jna platform_panic
  120. dec DWORD [temp_depth]
  121. ret
  122. ;; No input
  123. ;; Destroys: EAX
  124. pop_temps:
  125. ;; Check for termination
  126. cmp DWORD [temp_depth], 0
  127. jna pop_temps_ret
  128. ;; Call pop_var
  129. mov eax, 1
  130. call pop_var
  131. jmp pop_temps
  132. pop_temps_ret:
  133. ret
  134. ;; Input in EDX
  135. ;; Destroys: ECX
  136. ;; Returns: EAX
  137. find_in_stack:
  138. push esi
  139. push edi
  140. xor ecx, ecx
  141. find_in_stack_loop:
  142. ;; Check for termination
  143. cmp ecx, [stack_depth]
  144. je find_in_stack_not_found
  145. ;; Compute the pointer to be checked
  146. mov esi, [stack_depth]
  147. dec esi
  148. sub esi, ecx
  149. shl esi, MAX_SYMBOL_NAME_LEN_LOG
  150. add esi, [stack_vars_ptr]
  151. ;; Call strcmp and return if it matches
  152. mov edi, edx
  153. call strcmp2
  154. cmp eax, 0
  155. je find_in_stack_found
  156. ;; Increment index and restart
  157. inc ecx
  158. jmp find_in_stack_loop
  159. find_in_stack_not_found:
  160. mov eax, -1
  161. jmp find_in_stack_end
  162. find_in_stack_found:
  163. mov eax, ecx
  164. jmp find_in_stack_end
  165. find_in_stack_end:
  166. pop edi
  167. pop esi
  168. ret
  169. ;; Returns: EAX (either char in AL or -1 in EAX)
  170. get_char:
  171. mov eax, [read_ptr]
  172. cmp eax, [read_ptr_end]
  173. je get_char_end
  174. mov al, [eax]
  175. inc DWORD [read_ptr]
  176. ret
  177. get_char_end:
  178. mov eax, -1
  179. ret
  180. ;; Input in AL
  181. ;; Returns: DL
  182. is_whitespace:
  183. mov dl, 1
  184. cmp al, SPACE
  185. je ret_simple
  186. cmp al, TAB
  187. je ret_simple
  188. cmp al, NEWLINE
  189. je ret_simple
  190. mov dl, 0
  191. ret
  192. ;; Destroys: ECX, EDX
  193. ;; Returns: EAX (token, which is empty at EOF)
  194. get_token:
  195. ;; If the token was given back, just return it
  196. cmp DWORD [token_given_back], 0
  197. je get_token_not_gb
  198. mov DWORD [token_given_back], 0
  199. jmp get_token_ret_no_term
  200. get_token_not_gb:
  201. ;; Use ECX for the buffer pointer
  202. mov ecx, [token_buf_ptr]
  203. get_token_skip:
  204. ;; Get a char and check EOF
  205. call get_char
  206. cmp eax, -1
  207. je get_token_ret
  208. ;; Skip whitespace
  209. call is_whitespace
  210. cmp dl, 0
  211. jne get_token_skip
  212. ;; Skip comments
  213. cmp al, POUND
  214. jne get_token_skipped
  215. get_token_skip_comment:
  216. call get_char
  217. cmp eax, -1
  218. je get_token_ret
  219. cmp al, NEWLINE
  220. je get_token_skip
  221. jmp get_token_skip_comment
  222. get_token_skipped:
  223. ;; Now we have a real token; let us see what is the type
  224. mov dl, 0
  225. cmp al, QUOTE
  226. je get_token_string
  227. cmp al, APEX
  228. je get_token_string
  229. ;; Plain token, just put in chars until whitespace
  230. get_token_plain:
  231. mov [ecx], al
  232. inc ecx
  233. call get_char
  234. cmp eax, -1
  235. je get_token_ret
  236. call is_whitespace
  237. cmp dl, 0
  238. je get_token_plain
  239. jmp get_token_ret
  240. ;; String token (DL stores whether current char is escaped)
  241. get_token_string:
  242. mov [ecx], al
  243. inc ecx
  244. call get_char
  245. cmp eax, -1
  246. je platform_panic
  247. ;; If escaped, restart loop immediately
  248. cmp dl, 0
  249. mov dl, 0
  250. jne get_token_string
  251. ;; Last char was not a backslash and we have quote or apex: finish
  252. cmp al, QUOTE
  253. je get_token_string_end
  254. cmp al, APEX
  255. je get_token_string_end
  256. cmp al, BACKSLASH
  257. jne get_token_string
  258. mov dl, 1
  259. jmp get_token_string
  260. get_token_string_end:
  261. ;; Put the closing apex or quote and return
  262. mov [ecx], al
  263. inc ecx
  264. get_token_ret:
  265. ;; Put the terminator and return the buffer's address
  266. mov BYTE [ecx], 0
  267. get_token_ret_no_term:
  268. mov eax, [token_buf_ptr]
  269. ret
  270. give_back_token:
  271. ;; Check another token was not already given back
  272. cmp DWORD [token_given_back], 0
  273. jne platform_panic
  274. ;; Mark the current one as given back
  275. mov DWORD [token_given_back], 1
  276. ret
  277. ;; Input in DL
  278. ;; Returns: AL
  279. escaped:
  280. xor eax, eax
  281. mov al, NEWLINE
  282. cmp dl, LITTLEN
  283. je escaped_ret
  284. mov al, TAB
  285. cmp dl, LITTLET
  286. je escaped_ret
  287. mov al, FEED
  288. cmp dl, LITTLEF
  289. je escaped_ret
  290. mov al, RETURN
  291. cmp dl, LITTLER
  292. je escaped_ret
  293. mov al, VERTTAB
  294. cmp dl, LITTLEV
  295. je escaped_ret
  296. mov al, 0
  297. cmp dl, ZERO
  298. je escaped_ret
  299. mov al, BACKSLASH
  300. cmp dl, BACKSLASH
  301. je escaped_ret
  302. mov al, APEX
  303. cmp dl, APEX
  304. je escaped_ret
  305. mov al, QUOTE
  306. cmp dl, QUOTE
  307. je escaped_ret
  308. jmp platform_panic
  309. escaped_ret:
  310. ret
  311. ;; Input in ECX
  312. emit_escaped_string:
  313. ;; Check the string beings with a quote
  314. cmp BYTE [ecx], QUOTE
  315. jne platform_panic
  316. inc ecx
  317. emit_escaped_string_loop:
  318. ;; Check we did not find the terminator (without a closing quote)
  319. mov dl, [ecx]
  320. cmp dl, 0
  321. je platform_panic
  322. ;; If we found a quote, jump to end
  323. cmp dl, QUOTE
  324. je emit_escaped_string_end
  325. ;; If we found a backslash, jump to the following character and
  326. ;; escape it
  327. cmp dl, BACKSLASH
  328. jne emit_escaped_string_emit
  329. inc ecx
  330. mov dl, [ecx]
  331. call escaped
  332. mov dl, al
  333. emit_escaped_string_emit:
  334. ;; Call emit and increment pointer
  335. push ecx
  336. mov ecx, edx
  337. call emit
  338. pop ecx
  339. inc ecx
  340. jmp emit_escaped_string_loop
  341. emit_escaped_string_end:
  342. ;; Check a terminator follows and then return
  343. cmp BYTE [ecx+1], 0
  344. jne platform_panic
  345. ret
  346. ;; Input in EAX
  347. ;; Destroys: ECX
  348. ;; Returns: EAX (valid), EDX (number value)
  349. decode_number_or_char:
  350. ;; The first argument does not begin with an apex, call
  351. ;; decode_number
  352. cmp BYTE [eax], APEX
  353. je decode_number_or_char_char
  354. call decode_number
  355. ret
  356. decode_number_or_char_char:
  357. ;; Clean higher bits in EDX
  358. xor edx, edx
  359. ;; If second char is not a backslash, just return it
  360. cmp BYTE [eax+1], BACKSLASH
  361. je decode_number_or_char_backslash
  362. mov dl, [eax+1]
  363. ;; Check that the input string finishes here
  364. cmp BYTE [eax+2], APEX
  365. jne platform_panic
  366. cmp BYTE [eax+3], 0
  367. jne platform_panic
  368. mov eax, 1
  369. ret
  370. decode_number_or_char_backslash:
  371. ;; Check that the input string finishes here
  372. cmp BYTE [eax+3], APEX
  373. jne platform_panic
  374. cmp BYTE [eax+4], 0
  375. jne platform_panic
  376. ;; Call escaped and return the result
  377. mov dl, [eax+2]
  378. call escaped
  379. mov dl, al
  380. mov eax, 1
  381. ret
  382. ;; Input in EAX
  383. ;; Returns: EAX
  384. compute_rel:
  385. ;; Subtract current_loc and than 4
  386. sub eax, [current_loc]
  387. sub eax, 4
  388. ret
  389. ;; Input in EDX (label number)
  390. ;; Destroys: EAX, ECX, EDX
  391. add_symbol_label:
  392. call write_label
  393. mov edx, -1
  394. mov ecx, [current_loc]
  395. call add_symbol_wrapper
  396. ret
  397. ;; Input in [ESP+4] (name) and [ESP+8] (want_address)
  398. ;; Destroys: EAX, ECX, EDX
  399. push_expr:
  400. push ebp
  401. mov ebp, esp
  402. push ebx
  403. push esi
  404. ;; Try to interpret argument as number
  405. mov eax, [ebp+8]
  406. call decode_number_or_char
  407. cmp eax, 0
  408. je push_expr_stack
  409. ;; It is a number, check that we do not want the address
  410. cmp DWORD [ebp+12], 0
  411. jne platform_panic
  412. ;; Emit the code
  413. mov ebx, edx
  414. mov cl, 0x68 ; push ??
  415. call emit
  416. mov ecx, ebx
  417. call emit32
  418. jmp push_expr_ret
  419. push_expr_stack:
  420. ;; Call find_in_stack
  421. mov edx, [ebp+8]
  422. call find_in_stack
  423. cmp eax, -1
  424. je push_expr_symbol
  425. ;; Multiply the position by 4
  426. mov ebx, eax
  427. shl ebx, 2
  428. ;; It is on the stack: check if we want the address or not
  429. cmp DWORD [ebp+12], 0
  430. jne push_expr_stack_addr
  431. ;; We want the value, emit the code
  432. mov ecx, 0x24b4ff ; push [esp+??]
  433. call emit24
  434. mov ecx, ebx
  435. call emit32
  436. jmp push_expr_ret
  437. push_expr_stack_addr:
  438. ;; We want the address, emit the code
  439. mov ecx, 0x24848d ; lea eax, [esp+??]
  440. call emit24
  441. mov ecx, ebx
  442. call emit32
  443. mov cl, 0x50 ; push eax
  444. call emit
  445. jmp push_expr_ret
  446. push_expr_symbol:
  447. ;; Get symbol data
  448. mov edx, [ebp+8]
  449. call find_symbol_or_panic
  450. mov ebx, eax
  451. ;; Handle (in this order) global constants, cases when we want the
  452. ;; address and global variables
  453. cmp edx, -2
  454. je push_expr_symbol_const
  455. cmp DWORD [ebp+12], 0
  456. jne push_expr_symbol_addr
  457. cmp edx, -1
  458. je push_expr_symbol_var
  459. ;; This is a real function call, save arity and emit the call
  460. mov esi, edx
  461. mov cl, 0xe8 ; call ??
  462. call emit
  463. mov eax, ebx
  464. call compute_rel
  465. mov ecx, eax
  466. call emit32
  467. ;; Multiply the arity by 4 and emit stack unwinding
  468. mov ecx, 0xc481 ; add esp, ??
  469. call emit16
  470. mov ecx, esi
  471. shl ecx, 2
  472. call emit32
  473. mov cl, 0x50 ; push eax
  474. call emit
  475. ;; Update stack variables
  476. push_expr_symbol_call_loop:
  477. ;; Check for termination
  478. cmp esi, 0
  479. je push_expr_ret
  480. ;; Call pop_var
  481. mov eax, 1
  482. call pop_var
  483. ;; Decrement arity and reloop
  484. dec esi
  485. jmp push_expr_symbol_call_loop
  486. push_expr_symbol_const:
  487. ;; Check we do not want the address
  488. cmp DWORD [ebp+12], 0
  489. jne platform_panic
  490. ;; But we actually emit the address, because there is where the
  491. ;; constant value is stored
  492. push_expr_symbol_addr:
  493. ;; We want the address, emit the code
  494. mov cl, 0x68 ; push ??
  495. call emit
  496. mov ecx, ebx
  497. call emit32
  498. jmp push_expr_ret
  499. push_expr_symbol_var:
  500. ;; We want the value, emit the code
  501. mov ecx, 0x35ff ; push [??]
  502. call emit16
  503. mov ecx, ebx
  504. call emit32
  505. jmp push_expr_ret
  506. push_expr_ret:
  507. ;; Keep note of the new temporary
  508. mov edx, temp_var
  509. call push_var
  510. pop esi
  511. pop ebx
  512. pop ebp
  513. ret
  514. ;; Input in EAX
  515. ;; Destroys: EAX, ECX, EDX
  516. push_token:
  517. ;; Check if it is a string
  518. cmp BYTE [eax], QUOTE
  519. je push_token_str
  520. ;; Check if we want the address
  521. xor edx, edx
  522. cmp BYTE [eax], AT_SIGN
  523. jne push_token_value
  524. inc eax
  525. inc edx
  526. push_token_value:
  527. ;; Call push_expr
  528. push edx
  529. push eax
  530. call push_expr
  531. add esp, 8
  532. ret
  533. push_token_str:
  534. push esi
  535. push edi
  536. push ebx
  537. mov ebx, eax
  538. ;; Generate a jump (in esi) and a string (in edi) label
  539. call gen_label
  540. mov esi, eax
  541. call gen_label
  542. mov edi, eax
  543. ;; Emit code to jump to the jump label
  544. mov cl, 0xe9 ; jmp ??
  545. call emit
  546. mov edx, esi
  547. call write_label
  548. mov edx, eax
  549. call find_symbol_or_zero
  550. call compute_rel
  551. mov ecx, eax
  552. call emit32
  553. ;; Add a symbol for the string label
  554. mov edx, edi
  555. call add_symbol_label
  556. ;; Emit escaped string and a terminator
  557. mov ecx, ebx
  558. call emit_escaped_string
  559. mov cl, 0
  560. call emit
  561. ;; Add a symbol for the jump label
  562. mov edx, esi
  563. call add_symbol_label
  564. ;; Emit code to push the string label
  565. mov cl, 0x68 ; push ??
  566. call emit
  567. mov edx, edi
  568. call write_label
  569. mov edx, eax
  570. call find_symbol_or_zero
  571. mov ecx, eax
  572. call emit32
  573. ;; Keep note of the new variable
  574. mov edx, temp_var
  575. call push_var
  576. pop ebx
  577. pop edi
  578. pop esi
  579. ret
  580. ;; Destroys: EAX, ECX, EDX
  581. push_token_until_brace:
  582. ;; Get a token
  583. call get_token
  584. ;; If it is an open brace, exit loop
  585. mov ecx, [eax]
  586. and ecx, 0xffff
  587. cmp ecx, '{'
  588. je push_token_until_brace_end
  589. call push_token
  590. jmp push_token_until_brace
  591. push_token_until_brace_end:
  592. ;; Given the token back
  593. call give_back_token
  594. ;; Check that temp depth is positive
  595. cmp DWORD [temp_depth], 0
  596. jna platform_panic
  597. ret
  598. ;; Destroys: EAX, ECX, EDX
  599. parse_block:
  600. push ebx
  601. push esi
  602. push edi
  603. ;; Increment block depth
  604. inc DWORD [block_depth]
  605. ;; Save stack depth
  606. push DWORD [stack_depth]
  607. ;; Expect and discard an open curly brace token
  608. call get_token
  609. mov ecx, [eax]
  610. and ecx, 0xffff
  611. cmp ecx, '{'
  612. jne platform_panic
  613. ;; Main parsing loop
  614. parse_block_loop:
  615. ;; Receive a token and save it in ebx
  616. call get_token
  617. mov ebx, eax
  618. ;; Ensure it is not empty (meaning EOF)
  619. cmp BYTE [ebx], 0
  620. je platform_panic
  621. ;; If it is a closed curly brace, then break
  622. mov ecx, [ebx]
  623. and ecx, 0xffff
  624. cmp ecx, '}'
  625. je parse_block_end
  626. ;; Jump to the appropriate handler
  627. ;; semicolon
  628. cmp ecx, ';'
  629. je parse_block_semicolon
  630. ;; ret
  631. cmp DWORD [ebx], 'ret'
  632. je parse_block_ret
  633. ;; if
  634. mov eax, [ebx]
  635. and eax, 0xffffff
  636. sub eax, 'if'
  637. je parse_block_if
  638. ;; while
  639. mov eax, [ebx]
  640. sub eax, 'whil'
  641. mov ecx, [ebx+4]
  642. and ecx, 0xffff
  643. sub ecx, 'e'
  644. or eax, ecx
  645. je parse_block_while
  646. ;; dollar
  647. cmp BYTE [ebx], DOLLAR
  648. je parse_block_alloc
  649. ;; backslash
  650. cmp BYTE [ebx], BACKSLASH
  651. je parse_block_call
  652. ;; Usual token push
  653. mov eax, ebx
  654. call push_token
  655. jmp parse_block_loop
  656. parse_block_semicolon:
  657. ;; Emit code to rewind temp stack
  658. mov ecx, 0xc481 ; add esp, ??
  659. call emit16
  660. mov ecx, [temp_depth]
  661. shl ecx, 2
  662. call emit32
  663. call pop_temps
  664. jmp parse_block_loop
  665. parse_block_ret:
  666. ;; If there are temp vars, emit code to pop one
  667. cmp DWORD [temp_depth], 0
  668. jna parse_block_ret_emit
  669. mov cl, 0x58 ; pop eax
  670. call emit
  671. mov eax, 1
  672. call pop_var
  673. parse_block_ret_emit:
  674. ;; Emit code to unwind stack and return
  675. mov ecx, 0xc35dec89 ; mov esp, ebp; pop ebp; ret
  676. call emit32
  677. jmp parse_block_loop
  678. parse_block_if:
  679. ;; Call push_token_until_brace
  680. call push_token_until_brace
  681. ;; Generate the else label
  682. call gen_label
  683. mov ebx, eax
  684. ;; Emit code to pop and possibly jump to else label
  685. mov eax, 1
  686. call pop_var
  687. mov ecx, 0x00f88358 ; pop eax; cmp eax, 0
  688. call emit32
  689. mov ecx, 0x840f ; je ??
  690. call emit16
  691. mov edx, ebx
  692. call write_label
  693. mov edx, eax
  694. call find_symbol_or_zero
  695. call compute_rel
  696. mov ecx, eax
  697. call emit32
  698. ;; Recursively parse the inner block
  699. call parse_block
  700. ;; Get another token and check if it is an else
  701. call get_token
  702. mov ecx, [eax]
  703. sub ecx, 'else'
  704. or cl, [eax+4]
  705. test ecx, ecx
  706. je parse_block_else
  707. ;; Not an else: add a symbol for the else label
  708. mov edx, ebx
  709. call add_symbol_label
  710. ;; Give the token back
  711. call give_back_token
  712. jmp parse_block_loop
  713. parse_block_else:
  714. ;; There is an else: generate the fi label (load in edi)
  715. call gen_label
  716. mov edi, eax
  717. ;; Emit code to jump to fi
  718. mov cl, 0xe9 ; jmp ??
  719. call emit
  720. mov edx, edi
  721. call write_label
  722. mov edx, eax
  723. call find_symbol_or_zero
  724. call compute_rel
  725. mov ecx, eax
  726. call emit32
  727. ;; Add the symbol for the else label
  728. mov edx, ebx
  729. call add_symbol_label
  730. ;; Recursively parse the inner block
  731. call parse_block
  732. ;; Add the symbol for the fi label
  733. mov edx, edi
  734. call add_symbol_label
  735. jmp parse_block_loop
  736. parse_block_while:
  737. ;; Generate the restart label (in esi) and the end label (in edi)
  738. call gen_label
  739. mov esi, eax
  740. call gen_label
  741. mov edi, eax
  742. ;; Add a symbol for the restart label
  743. mov edx, esi
  744. call add_symbol_label
  745. ;; Call push_token_until_brace
  746. call push_token_until_brace
  747. ;; Emit code to pop and possibly jump to end label
  748. mov eax, 1
  749. call pop_var
  750. mov ecx, 0x00f88358 ; pop eax; cmp eax, 0
  751. call emit32
  752. mov ecx, 0x840f ; je ??
  753. call emit16
  754. mov edx, edi
  755. call write_label
  756. mov edx, eax
  757. call find_symbol_or_zero
  758. call compute_rel
  759. mov ecx, eax
  760. call emit32
  761. ;; Recursively parse the inner block
  762. call parse_block
  763. ;; Emit code to restart the loop
  764. mov cl, 0xe9 ; jmp ??
  765. call emit
  766. mov edx, esi
  767. call write_label
  768. mov edx, eax
  769. call find_symbol_or_zero
  770. call compute_rel
  771. mov ecx, eax
  772. call emit32
  773. ;; Add a symbol for the end label
  774. mov edx, edi
  775. call add_symbol_label
  776. jmp parse_block_loop
  777. parse_block_alloc:
  778. ;; Call push_var
  779. inc ebx
  780. mov edx, ebx
  781. call push_var
  782. ;; Emit code
  783. mov ecx, 0x04ec83 ; sub esp, 4
  784. call emit24
  785. jmp parse_block_loop
  786. parse_block_call:
  787. ;; Skip to following char and check it is not a terminator
  788. inc ebx
  789. cmp BYTE [ebx], 0
  790. je platform_panic
  791. ;; Call decode_number_or_symbol
  792. mov eax, ebx
  793. call decode_number_or_symbol
  794. mov ebx, eax
  795. ;; Call pop_var
  796. mov eax, 1
  797. call pop_var
  798. ;; Emit code to do the indirect call
  799. mov ecx, 0xd0ff58 ; pop eax; call eax
  800. call emit24
  801. ;; Emit code for stack cleanup
  802. mov ecx, 0xc481 ; add esp, ??
  803. call emit16
  804. mov ecx, ebx
  805. shl ecx, 2
  806. call emit32
  807. ;; Pop an appropriate number of temp vars
  808. parse_block_call_loop:
  809. ;; Check for termination
  810. cmp ebx, 0
  811. je parse_block_call_end
  812. ;; Pop a var
  813. mov eax, 1
  814. call pop_var
  815. ;; Decrement counter and reloop
  816. dec ebx
  817. jmp parse_block_call_loop
  818. parse_block_call_end:
  819. ;; Emit code to push the return value
  820. mov edx, temp_var
  821. call push_var
  822. mov cl, 0x50 ; push eax
  823. call emit
  824. jmp parse_block_loop
  825. parse_block_end:
  826. ;; Emit stack unwinding code
  827. mov ecx, 0xc481 ; add esp, ??
  828. call emit16
  829. ;; Sanity check: stack depth must not have decreased
  830. mov eax, [stack_depth]
  831. pop ecx
  832. sub eax, ecx
  833. jnge platform_panic
  834. ;; Reset stack depth to saved value and decrease block depth
  835. mov [stack_depth], ecx
  836. dec DWORD [block_depth]
  837. ;; Emit stack depth difference, multiplied by 4
  838. mov ecx, eax
  839. shl ecx, 2
  840. call emit32
  841. pop edi
  842. pop esi
  843. pop ebx
  844. ret
  845. ;; Input in EAX
  846. ;; Destroys: EBX, ECX, EDX
  847. ;; Returns: EAX
  848. decode_number_or_symbol:
  849. ;; Try to decode as number
  850. mov ebx, eax
  851. call decode_number_or_char
  852. ;; If it returned true, return
  853. cmp eax, 0
  854. je decode_number_or_symbol_symbol
  855. mov eax, edx
  856. ret
  857. decode_number_or_symbol_symbol:
  858. ;; Get symbol address
  859. mov edx, ebx
  860. call find_symbol_or_panic
  861. ret
  862. ;; Destroys: EAX, ECX, EDX
  863. parse:
  864. push ebx
  865. ;; Main loop
  866. parse_loop:
  867. ;; Get a token and break if it is empty
  868. call get_token
  869. mov ebx, eax
  870. cmp BYTE [ebx], 0
  871. je parse_ret
  872. ;; Jump to the appropriate handler
  873. ;; fun
  874. cmp DWORD [ebx], 'fun'
  875. je parse_fun
  876. ;; ifun
  877. mov eax, [ebx]
  878. sub eax, 'ifun'
  879. or al, [ebx+4]
  880. test eax, eax
  881. je parse_ifun
  882. ;; const
  883. mov eax, [ebx]
  884. sub eax, 'cons'
  885. mov ecx, [ebx+4]
  886. and ecx, 0xffff
  887. sub ecx, 't'
  888. or eax, ecx
  889. je parse_const
  890. ;; global declaration
  891. cmp BYTE [ebx], DOLLAR
  892. je parse_var
  893. call platform_panic
  894. parse_fun:
  895. ;; Get a token and copy it in buf2 (pointed by ebx)
  896. mov ebx, [buf2_ptr]
  897. call get_token
  898. push eax
  899. push ebx
  900. call strcpy
  901. add esp, 8
  902. ;; Get another token and convert it to an integer
  903. call get_token
  904. call atoi
  905. ;; Add a symbol for the function
  906. mov edx, eax
  907. mov ecx, [current_loc]
  908. mov eax, ebx
  909. call fix_symbol_placeholder
  910. ;; Emit the prologue
  911. mov ecx, 0xe58955 ; push ebp; mov ebp, esp
  912. call emit24
  913. ;; Parse the block
  914. call parse_block
  915. ;; Emit the epilogue
  916. mov ecx, 0xc35d ; pop ebp; ret
  917. call emit16
  918. jmp parse_loop
  919. parse_ifun:
  920. ;; Get a token and copy it in buf2 (pointed by ebx)
  921. mov ebx, [buf2_ptr]
  922. call get_token
  923. push eax
  924. push ebx
  925. call strcpy
  926. add esp, 8
  927. ;; Get another token and convert it to an integer
  928. call get_token
  929. call atoi
  930. ;; Add a symbol placeholder for the function
  931. mov edx, eax
  932. mov eax, ebx
  933. call add_symbol_placeholder
  934. jmp parse_loop
  935. parse_const:
  936. ;; Get a token and copy it in buf2 (pointed by ebx)
  937. mov ebx, [buf2_ptr]
  938. call get_token
  939. push eax
  940. push ebx
  941. call strcpy
  942. add esp, 8
  943. ;; Get another token and interpret it as a number or symbol
  944. call get_token
  945. call decode_number_or_symbol
  946. ;; Add a symbol
  947. mov edx, -2
  948. mov ecx, eax
  949. mov eax, [buf2_ptr]
  950. call add_symbol_wrapper
  951. jmp parse_loop
  952. parse_var:
  953. ;; Increment the pointer and check the string continues
  954. inc ebx
  955. cmp BYTE [ebx], 0
  956. je platform_panic
  957. ;; Add a symbol
  958. mov edx, -1
  959. mov ecx, [current_loc]
  960. mov eax, ebx
  961. call add_symbol_wrapper
  962. ;; Emit a zero to allocate space for the variable
  963. xor ecx, ecx
  964. call emit32
  965. jmp parse_loop
  966. parse_ret:
  967. pop ebx
  968. ret
  969. ;; Destroys: EAX, ECX
  970. init_g_compiler:
  971. ;; Allocate stack variables list
  972. mov eax, STACK_VARS_LEN * MAX_SYMBOL_NAME_LEN
  973. call allocate
  974. mov [stack_vars_ptr], eax
  975. ;; Allocate the token buffer
  976. mov eax, MAX_SYMBOL_NAME_LEN
  977. call allocate
  978. mov [token_buf_ptr], eax
  979. ;; Allocate buf2
  980. mov eax, MAX_SYMBOL_NAME_LEN
  981. call allocate
  982. mov [buf2_ptr], eax
  983. ;; Allocate write_label_buf
  984. mov eax, WRITE_LABEL_BUF_LEN
  985. call allocate
  986. mov [write_label_buf_ptr], eax
  987. ;; Set token_given_back to false
  988. mov DWORD [token_given_back], 0
  989. ret
  990. ;; Destroys: EAX, ECX, EDX
  991. compile:
  992. ;; Reset depths and stage
  993. mov DWORD [block_depth], 0
  994. mov DWORD [stack_depth], 0
  995. mov DWORD [temp_depth], 0
  996. mov DWORD [stage], 0
  997. compile_stage_loop:
  998. ;; Check for termination
  999. cmp DWORD [stage], 2
  1000. je ret_simple
  1001. ;; Reset file to the beginning
  1002. mov eax, [read_ptr_begin]
  1003. mov [read_ptr], eax
  1004. ;; Reset label_num and current_loc
  1005. mov DWORD [label_num], 0
  1006. mov ecx, [initial_loc]
  1007. mov [current_loc], ecx
  1008. ;; Call parse
  1009. call parse
  1010. ;; Check that depths were reset to zero
  1011. cmp DWORD [block_depth], 0
  1012. jne platform_panic
  1013. cmp DWORD [stack_depth], 0
  1014. jne platform_panic
  1015. cmp DWORD [temp_depth], 0
  1016. jne platform_panic
  1017. ;; Increment stage
  1018. add DWORD [stage], 1
  1019. jmp compile_stage_loop