asmg.asm 23 KB

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