asmg.asm 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  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. parse_block:
  599. push ebp
  600. mov ebp, esp
  601. push ebx
  602. push esi
  603. push edi
  604. ;; Increment block depth
  605. inc DWORD [block_depth]
  606. ;; Save stack depth
  607. push DWORD [stack_depth]
  608. ;; Expect and discard an open curly brace token
  609. call get_token
  610. mov ecx, [eax]
  611. and ecx, 0xffff
  612. cmp ecx, '{'
  613. jne platform_panic
  614. ;; Main parsing loop
  615. parse_block_loop:
  616. ;; Receive a token and save it in ebx
  617. call get_token
  618. mov ebx, eax
  619. ;; Ensure it is not empty (meaning EOF)
  620. cmp BYTE [ebx], 0
  621. je platform_panic
  622. ;; If it is a closed curly brace, then break
  623. mov ecx, [ebx]
  624. and ecx, 0xffff
  625. cmp ecx, '}'
  626. je parse_block_end
  627. ;; Jump to the appropriate handler
  628. cmp ecx, ';'
  629. je parse_block_semicolon
  630. cmp DWORD [ebx], 'ret'
  631. je parse_block_ret
  632. mov eax, [ebx]
  633. and eax, 0xffffff
  634. sub eax, 'if'
  635. je parse_block_if
  636. mov eax, [ebx]
  637. sub eax, 'whil'
  638. mov ecx, [ebx+4]
  639. and ecx, 0xffff
  640. sub ecx, 'e'
  641. or eax, ecx
  642. je parse_block_while
  643. cmp BYTE [ebx], DOLLAR
  644. je parse_block_alloc
  645. cmp BYTE [ebx], BACKSLASH
  646. je parse_block_call
  647. mov eax, ebx
  648. call push_token
  649. jmp parse_block_loop
  650. parse_block_semicolon:
  651. ;; Emit code to rewind temp stack
  652. mov ecx, 0xc481 ; add esp, ??
  653. call emit16
  654. mov ecx, [temp_depth]
  655. shl ecx, 2
  656. call emit32
  657. call pop_temps
  658. jmp parse_block_loop
  659. parse_block_ret:
  660. ;; If there are temp vars, emit code to pop one
  661. cmp DWORD [temp_depth], 0
  662. jna parse_block_ret_emit
  663. mov cl, 0x58 ; pop eax
  664. call emit
  665. mov eax, 1
  666. call pop_var
  667. parse_block_ret_emit:
  668. ;; Emit code to unwind stack and return
  669. mov ecx, 0xc35dec89 ; mov esp, ebp; pop ebp; ret
  670. call emit32
  671. jmp parse_block_loop
  672. parse_block_if:
  673. ;; Call push_token_until_brace
  674. call push_token_until_brace
  675. ;; Generate the else label
  676. call gen_label
  677. mov ebx, eax
  678. ;; Emit code to pop and possibly jump to else label
  679. mov eax, 1
  680. call pop_var
  681. mov ecx, 0x00f88358 ; pop eax; cmp eax, 0
  682. call emit32
  683. mov ecx, 0x840f ; je ??
  684. call emit16
  685. mov edx, ebx
  686. call write_label
  687. mov edx, eax
  688. call find_symbol_or_zero
  689. call compute_rel
  690. mov ecx, eax
  691. call emit32
  692. ;; Recursively parse the inner block
  693. call parse_block
  694. ;; Get another token and check if it is an else
  695. call get_token
  696. mov ecx, [eax]
  697. sub ecx, 'else'
  698. or cl, [eax+4]
  699. test ecx, ecx
  700. je parse_block_else
  701. ;; Not an else: add a symbol for the else label
  702. mov edx, ebx
  703. call add_symbol_label
  704. ;; Give the token back
  705. call give_back_token
  706. jmp parse_block_loop
  707. parse_block_else:
  708. ;; There is an else: generate the fi label (load in edi)
  709. call gen_label
  710. mov edi, eax
  711. ;; Emit code to jump to fi
  712. mov cl, 0xe9 ; jmp ??
  713. call emit
  714. mov edx, edi
  715. call write_label
  716. mov edx, eax
  717. call find_symbol_or_zero
  718. call compute_rel
  719. mov ecx, eax
  720. call emit32
  721. ;; Add the symbol for the else label
  722. mov edx, ebx
  723. call add_symbol_label
  724. ;; Recursively parse the inner block
  725. call parse_block
  726. ;; Add the symbol for the fi label
  727. mov edx, edi
  728. call add_symbol_label
  729. jmp parse_block_loop
  730. parse_block_while:
  731. ;; Generate the restart label (in esi) and the end label (in edi)
  732. call gen_label
  733. mov esi, eax
  734. call gen_label
  735. mov edi, eax
  736. ;; Add a symbol for the restart label
  737. mov edx, esi
  738. call add_symbol_label
  739. ;; Call push_token_until_brace
  740. call push_token_until_brace
  741. ;; Emit code to pop and possibly jump to end label
  742. mov eax, 1
  743. call pop_var
  744. mov ecx, 0x00f88358 ; pop eax; cmp eax, 0
  745. call emit32
  746. mov ecx, 0x840f ; je ??
  747. call emit16
  748. mov edx, edi
  749. call write_label
  750. mov edx, eax
  751. call find_symbol_or_zero
  752. call compute_rel
  753. mov ecx, eax
  754. call emit32
  755. ;; Recursively parse the inner block
  756. call parse_block
  757. ;; Emit code to restart the loop
  758. mov cl, 0xe9 ; jmp ??
  759. call emit
  760. mov edx, esi
  761. call write_label
  762. mov edx, eax
  763. call find_symbol_or_zero
  764. call compute_rel
  765. mov ecx, eax
  766. call emit32
  767. ;; Add a symbol for the end label
  768. mov edx, edi
  769. call add_symbol_label
  770. jmp parse_block_loop
  771. parse_block_alloc:
  772. ;; Call push_var
  773. inc ebx
  774. mov edx, ebx
  775. call push_var
  776. ;; Emit code
  777. mov ecx, 0x04ec83 ; sub esp, 4
  778. call emit24
  779. jmp parse_block_loop
  780. parse_block_call:
  781. ;; Skip to following char and check it is not a terminator
  782. inc ebx
  783. cmp BYTE [ebx], 0
  784. je platform_panic
  785. ;; Call decode_number_or_symbol
  786. mov eax, ebx
  787. call decode_number_or_symbol
  788. mov ebx, eax
  789. ;; Call pop_var
  790. mov eax, 1
  791. call pop_var
  792. ;; Emit code to do the indirect call
  793. mov ecx, 0xd0ff58 ; pop eax; call eax
  794. call emit24
  795. ;; Emit code for stack cleanup
  796. mov ecx, 0xc481 ; add esp, ??
  797. call emit16
  798. mov ecx, ebx
  799. shl ecx, 2
  800. call emit32
  801. ;; Pop an appropriate number of temp vars
  802. parse_block_call_loop:
  803. ;; Check for termination
  804. cmp ebx, 0
  805. je parse_block_call_end
  806. ;; Pop a var
  807. mov eax, 1
  808. call pop_var
  809. ;; Decrement counter and reloop
  810. dec ebx
  811. jmp parse_block_call_loop
  812. parse_block_call_end:
  813. ;; Emit code to push the return value
  814. mov edx, temp_var
  815. call push_var
  816. mov cl, 0x50 ; push eax
  817. call emit
  818. jmp parse_block_loop
  819. parse_block_end:
  820. ;; Emit stack unwinding code
  821. mov ecx, 0xc481 ; add esp, ??
  822. call emit16
  823. ;; Sanity check: stack depth must not have decreased
  824. mov eax, [stack_depth]
  825. pop ecx
  826. sub eax, ecx
  827. jnge platform_panic
  828. ;; Reset stack depth to saved value and decrease block depth
  829. mov [stack_depth], ecx
  830. dec DWORD [block_depth]
  831. ;; Emit stack depth difference, multiplied by 4
  832. mov ecx, eax
  833. shl ecx, 2
  834. call emit32
  835. pop edi
  836. pop esi
  837. pop ebx
  838. pop ebp
  839. ret
  840. ;; Input in EAX
  841. ;; Destroys: EBX, ECX, EDX
  842. ;; Returns: EAX
  843. decode_number_or_symbol:
  844. ;; Try to decode as number
  845. mov ebx, eax
  846. call decode_number_or_char
  847. ;; If it returned true, return
  848. cmp eax, 0
  849. je decode_number_or_symbol_symbol
  850. mov eax, edx
  851. ret
  852. decode_number_or_symbol_symbol:
  853. ;; Get symbol address
  854. mov edx, ebx
  855. call find_symbol_or_panic
  856. ret
  857. parse:
  858. push ebp
  859. mov ebp, esp
  860. push ebx
  861. ;; Main loop
  862. parse_loop:
  863. ;; Get a token and break if it is empty
  864. call get_token
  865. mov ebx, eax
  866. cmp BYTE [ebx], 0
  867. je parse_ret
  868. ;; Jump to the appropriate handler
  869. ;; fun
  870. cmp DWORD [ebx], 'fun'
  871. je parse_fun
  872. ;; ifun
  873. mov eax, [ebx]
  874. sub eax, 'ifun'
  875. or al, [ebx+4]
  876. test eax, eax
  877. je parse_ifun
  878. ;; const
  879. mov eax, [ebx]
  880. sub eax, 'cons'
  881. mov ecx, [ebx+4]
  882. and ecx, 0xffff
  883. sub ecx, 't'
  884. or eax, ecx
  885. je parse_const
  886. ;; global declaration
  887. cmp BYTE [ebx], DOLLAR
  888. je parse_var
  889. call platform_panic
  890. parse_fun:
  891. ;; Get a token and copy it in buf2 (pointed by ebx)
  892. mov ebx, [buf2_ptr]
  893. call get_token
  894. push eax
  895. push ebx
  896. call strcpy
  897. add esp, 8
  898. ;; Get another token and convert it to an integer
  899. call get_token
  900. call atoi
  901. ;; Add a symbol for the function
  902. mov edx, eax
  903. mov ecx, [current_loc]
  904. mov eax, ebx
  905. call fix_symbol_placeholder
  906. ;; Emit the prologue
  907. mov ecx, 0xe58955 ; push ebp; mov ebp, esp
  908. call emit24
  909. ;; Parse the block
  910. call parse_block
  911. ;; Emit the epilogue
  912. mov ecx, 0xc35d ; pop ebp; ret
  913. call emit16
  914. jmp parse_loop
  915. parse_ifun:
  916. ;; Get a token and copy it in buf2 (pointed by ebx)
  917. mov ebx, [buf2_ptr]
  918. call get_token
  919. push eax
  920. push ebx
  921. call strcpy
  922. add esp, 8
  923. ;; Get another token and convert it to an integer
  924. call get_token
  925. call atoi
  926. ;; Add a symbol placeholder for the function
  927. mov edx, eax
  928. mov eax, ebx
  929. call add_symbol_placeholder
  930. jmp parse_loop
  931. parse_const:
  932. ;; Get a token and copy it in buf2 (pointed by ebx)
  933. mov ebx, [buf2_ptr]
  934. call get_token
  935. push eax
  936. push ebx
  937. call strcpy
  938. add esp, 8
  939. ;; Get another token and interpret it as a number or symbol
  940. call get_token
  941. call decode_number_or_symbol
  942. ;; Add a symbol
  943. mov edx, -2
  944. mov ecx, eax
  945. mov eax, [buf2_ptr]
  946. call add_symbol_wrapper
  947. jmp parse_loop
  948. parse_var:
  949. ;; Increment the pointer and check the string continues
  950. inc ebx
  951. cmp BYTE [ebx], 0
  952. je platform_panic
  953. ;; Add a symbol
  954. mov edx, -1
  955. mov ecx, [current_loc]
  956. mov eax, ebx
  957. call add_symbol_wrapper
  958. ;; Emit a zero to allocate space for the variable
  959. xor ecx, ecx
  960. call emit32
  961. jmp parse_loop
  962. parse_ret:
  963. pop ebx
  964. pop ebp
  965. ret
  966. init_g_compiler:
  967. ;; Allocate stack variables list
  968. mov eax, STACK_VARS_LEN * MAX_SYMBOL_NAME_LEN
  969. call allocate
  970. mov [stack_vars_ptr], eax
  971. ;; Allocate the token buffer
  972. mov eax, MAX_SYMBOL_NAME_LEN
  973. call allocate
  974. mov [token_buf_ptr], eax
  975. ;; Allocate buf2
  976. mov eax, MAX_SYMBOL_NAME_LEN
  977. call allocate
  978. mov [buf2_ptr], eax
  979. ;; Allocate write_label_buf
  980. mov eax, WRITE_LABEL_BUF_LEN
  981. call allocate
  982. mov [write_label_buf_ptr], eax
  983. ;; Set token_given_back to false
  984. mov DWORD [token_given_back], 0
  985. ret
  986. compile:
  987. ;; Reset depths and stage
  988. mov DWORD [block_depth], 0
  989. mov DWORD [stack_depth], 0
  990. mov DWORD [temp_depth], 0
  991. mov DWORD [stage], 0
  992. compile_stage_loop:
  993. ;; Check for termination
  994. cmp DWORD [stage], 2
  995. je ret_simple
  996. ;; Reset file to the beginning
  997. mov eax, [read_ptr_begin]
  998. mov [read_ptr], eax
  999. ;; Reset label_num and current_loc
  1000. mov DWORD [label_num], 0
  1001. mov ecx, [initial_loc]
  1002. mov [current_loc], ecx
  1003. ;; Call parse
  1004. call parse
  1005. ;; Check that depths were reset to zero
  1006. cmp DWORD [block_depth], 0
  1007. jne platform_panic
  1008. cmp DWORD [stack_depth], 0
  1009. jne platform_panic
  1010. cmp DWORD [temp_depth], 0
  1011. jne platform_panic
  1012. ;; Increment stage
  1013. add DWORD [stage], 1
  1014. jmp compile_stage_loop