/examples/compiler/bfcl.bf

https://github.com/FabianM/brainfuck · Brainfuck · 586 lines · 543 code · 43 blank · 0 comment · 485 complexity · 1e1374f2f58233bf6d651ff735c71dd6 MD5 · raw file

  1. This is version 0_1 of bfcl
  2. bfcl is a BrainFuck compiler for Linux written itself in BrainFuck
  3. It reads the input from stdin and outputs a Linux ELF binary on stdout
  4. Currently no optimization at all is done (which is another reason why
  5. this thing is so sloooooooow on my system :) but that is planned for
  6. version 0_2
  7. Conventions assumed in this program:
  8. fields are one byte long and decreasing zero is possible
  9. Conventions in the binaries compiled with bfcl:
  10. a) fields are one byte long
  11. b) there are 30 000 fields
  12. c) moving the pointer outside this area will lead to your computer
  13. catching fire;
  14. nothing is done to prevent you from doing that however
  15. d) when end of file is encountered the program stores whatever
  16. the Linux syscall returns (I believe it's zero but I'm too lazy to
  17. check)
  18. e) No checks are made on matching parentheses; maybe for version 0_3 :)
  19. And yes; I know the code is far from pretty; far from optimized; and not
  20. very well documented; but I'm sending it out anyway because the longer I
  21. stare at it the more my head hurts
  22. Final word of thanks: many ideas are shamelessly stolen from Brian
  23. Raiter's 171 byte BF compiler available from www_muppetlabs_com/~breadbox/
  24. For questions and comments you can reach me at
  25. vissers@theochem dot kun dot nl
  26. You will forgive me for not typing the dots :)
  27. Ge Vissers
  28. 17 april 2003
  29. **************************************************************************
  30. >>>>>>> reserve some extra space
  31. so we can shift the program later
  32. Read the program
  33. Reading a character is a bit of a nuisance since different compilers
  34. use different strategies:
  35. a) leave byte unchanged
  36. b) set byte to zero
  37. c) set byte to 0xff
  38. I *believe* the following code snippets catches all three possibilities above
  39. so that the program ends on either a null or a 0xff byte
  40. >- set character to 0xff
  41. , read a character
  42. [<+>->+<] copy byte to previous and next field
  43. >[+<]> if byte is not zero
  44. add one to it
  45. [ if it is still not zero
  46. [-]< clear the copy
  47. +++++[<-------->-]<--- subtract plus from input
  48. [ if char is not plus
  49. - subtract 1 from char
  50. [ if char is not comma
  51. - subtract 1 from char
  52. [ if char is not minus
  53. - subtract 1 from char
  54. [ if char is not dot
  55. -------------- subtract 14 from char
  56. [ if char is not left angle
  57. -- subtract 2 from char
  58. [ if char is not right angle
  59. >+++[<---------->-]<+ subtract 29 from char
  60. [ if char is not left bracket
  61. -- subtract 2 from char
  62. [ if char is not right bracket
  63. <--------> set opcode to minus 8
  64. [-] clear character
  65. ]
  66. <+> increase opcode
  67. ] end if (char is not left bracket)
  68. <+> increase opcode
  69. ] end if (char is not right angle)
  70. <+> increase opcode
  71. ] end if (char is not left angle)
  72. <+> increase opcode
  73. ] end if (char is not dot)
  74. <+> increase opcode
  75. ] end if (char is not minus)
  76. <+> increase opcode
  77. ] end if (char is not comma)
  78. <+> increase opcode
  79. ] end if (char is not plus)
  80. <+ increase opcode
  81. [ if opcode is not zero
  82. > move to next field
  83. ] end if (opcode is not zero)
  84. >>-, read in a new character
  85. [<+>->+<] copy to previous and next field
  86. >[+<]> if not null check if it's 0xff
  87. ] end while not EOF
  88. <<[+] clear possible 0xff
  89. >>++++++++[<++++++++++>-]<++++< 84 bytes for ELF header
  90. >++++++++++++< 12 bytes to initialize program
  91. >++++++< 6 bytes to end program
  92. Calculate file size
  93. <<[<]> move to first opcode
  94. [ while opcode exists
  95. [<<+<+>>>-]<< copy to two previous fields
  96. - decrease
  97. [ if opcode is not plus
  98. - decrease opcode
  99. [ if opcode is not comma
  100. - decrease opcode
  101. [ if opcode is not minus
  102. - decrease opcode
  103. [ if opcode is not dot
  104. - decrease opcode
  105. [ if opcode is not left angle
  106. - decrease opcode
  107. [ if opcode is not right angle
  108. - decrease opcode
  109. [ if opcode is not left bracket
  110. >>>[>]>+++++ indicate 5 bytes should be added
  111. <<[<]-<< set indicator to minus one
  112. -
  113. ] end if (opcode is not left bracket)
  114. >>[<-<->>+]<[>-<+]<+ copy indicator and increase
  115. [ else (opcode is left bracket)
  116. >>>[>]>++++++++ indicate 8 bytes should be added
  117. <<[<]-<< set indicator to minus one
  118. -
  119. ] end else (opcode is left bracket)
  120. ] end if (opcode is not right angle)
  121. >>[<-<->>+]<[>-<+]<+ copy indicator and increase
  122. [ else (opcode is right angle)
  123. >>>[>]>+ indicate 1 byte should be added
  124. <<[<]-<< set indicator to minus 1
  125. -
  126. ] end else (opcode is right angle)
  127. ] end if (opcode is not left angle)
  128. >>[<-<->>+]<[>-<+]<+ copy indicator and increase
  129. [ else (opcode is left angle)
  130. >>>[>]>+ indicate 1 byte should be added
  131. <<[<]-<< set indicator to minus 1
  132. -
  133. ] end else (opcode is left angle)
  134. ] end if (opcode is not dot)
  135. >>[<-<->>+]<[>-<+]<+ copy indicator and increase
  136. [ else (opcode is dot)
  137. >>>[>]>++++++ indicate 6 bytes should be added
  138. <<[<]-<< set indicator to minus 1
  139. -
  140. ] end else (opcode is dot)
  141. ] end if (opcode is not minus)
  142. >>[<-<->>+]<[>-<+]<+ copy indicator and increase
  143. [ else (opcode is minus)
  144. >>>[>]>++ indicate 2 bytes should be added
  145. <<[<]-<< set indicator to minus 1
  146. -
  147. ] end else (opcode is minus)
  148. ] end if (opcode is not comma)
  149. >>[<-<->>+]<[>-<+]<+ copy indicator and increase
  150. [ else (opcode is comma)
  151. >>>[>]>++++++ indicate 6 bytes should be added
  152. <<[<]-<< set indicator to minus 1
  153. -
  154. ] end else (opcode is comma)
  155. ] end if (opcode is not plus)
  156. >>[<-<->>+]<[>-<+]<+ copy indicator and increase
  157. [ else (opcode is plus)
  158. >>>[>]>++ indicate 2 bytes should be added
  159. <<[<]-<< set indicator to minus 1
  160. -
  161. ] end else (opcode is plus)
  162. >>+>[>]> move to increment
  163. [>+ increase byte 1
  164. [>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] copy byte 1
  165. <[>-<[-]] if no overflow set field to minus 1
  166. >+[- if overflow
  167. <<<<+ increase byte 2
  168. [>>>+>+<<<<-]>>>>[<<<<+>>>>-] copy byte 2
  169. <[>-<[-]] if no overflow set field to minus 1
  170. >+[- if overflow
  171. <<<+ increase byte 3
  172. [>>+>+<<<-]>>>[<<<+>>>-] copy byte 3
  173. <[>-<[-]] if no overflow set field to minus 1
  174. >+[- if overflow
  175. <<+ increase byte 4
  176. >>
  177. ] end if
  178. ] end if
  179. ] end if
  180. <<<<<<- decrease increment
  181. ]
  182. <<[<]> move to next opcode
  183. ]
  184. >>>>>> move behind file size
  185. >++++++++[<++++++++++++++++>-]<-. output ELF magic bytes
  186. >+++++++[<-------->-]<--.
  187. +++++++.------.
  188. [-]+...-.........++.--.+++.---.+.-... print rest of ELF header
  189. >++++++++[<++++++++++>-]<++++.
  190. >++++++[<+++++++>-]<++.[-]++++.++++.
  191. >++++++[<+++++++>-]<++.[-]...........
  192. >+++++++[<+++++++>-]<+++.>.++++
  193. [<----->-]<.>.+.-.<++++++++.[-].....
  194. +.-........>
  195. ++++++++[<++++++++++++++++>-]<.>++++.
  196. ++++.>.<<.>----.++++.
  197. <<<<<.>.>.>. this is file size
  198. Copy the file size since we need it to initialize ecx
  199. >[-]>[-]<< clear the fields
  200. <<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] copy the bytes
  201. <<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]
  202. <<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]
  203. <<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]
  204. We have to add 30 000 = 0x75 30 to the file size
  205. Start with 0x30
  206. >>>++++++[<++++++++>-]< set to 0x30
  207. [ while increment is not 0
  208. <<<<<<+ increase byte 1
  209. [>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] copy byte 1
  210. <[>-<[-]] if no overflow set field to minus 1
  211. >+[-
  212. <<<<+ if overflow increase byte 2
  213. [>>>+>+<<<<-]>>>>[<<<<+>>>>-] copy byte 2
  214. <[>-<[-]] if no overflow set field to minus 1
  215. >+[-
  216. <<<+ if overflow increase byte 3
  217. [>>+>+<<<-]>>>[<<<+>>>-] copy byte 3
  218. <[>-<[-]] if no overflow set field to minus 1
  219. >+[<<+>>-] if overflow increase byte 4
  220. ]
  221. ]
  222. >- decrease increment
  223. ]
  224. <<<<<<. print first byte
  225. Now do 0x75 00
  226. >>>>>>>
  227. +++++++[<++++++++++++++++>-]<+++++ set increment
  228. [ while increment is not 0
  229. <<<<<+ increase byte 2
  230. [>>>+>+<<<<-]>>>>[<<<<+>>>>-] copy byte 2
  231. <[>-<[-]] if no overflow set field to minus 1
  232. >+[-
  233. <<<+ if overflow increase byte 3
  234. [>>+>+<<<-]>>>[<<<+>>>-] copy byte 3
  235. <[>-<[-]] if no overflow set field to minus 1
  236. >+[<<+>>-] if overflow increase byte 4
  237. ]
  238. >- decrease increment
  239. ]
  240. <<<<<.>.>. print other 3 bytes
  241. [-]<[-]<[-]<[-] clear up
  242. ++++++.------....++++++++++++++++. print rest of header
  243. [-]..
  244. add 0x80 00 to file size
  245. >++++++++[<++++++++++++++++>-]< set counter to 0x80
  246. [<<<+ increase byte 2
  247. [>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] copy byte 2
  248. <[>-<[-]] if no overflow set indicator to minus 1
  249. >+[- if overflow
  250. <<<<+ increase byte 3
  251. [>>>+>+<<<<]>>>>[<<<<+>>>>-] copy byte 3
  252. <[>-<[-]] if no overflow set indicator to minus 1
  253. >+[<<<+>>>-] if overflow increase byte 4
  254. ]
  255. <<- decrease counter
  256. ] loop until counter is zero
  257. add 0x04 00 00 to file size
  258. ++++ set counter to 0x04
  259. [<<+ increase byte 3
  260. [>>>+>+<<<<-]>>>>[<<<<+>>>>-] copy byte 3
  261. <[>-<[-]] if no overflow set indicator to minus 1
  262. >+[<<<+>>>-] if overflow increase byte 4
  263. <<- decrease counter
  264. ] loop until counter is zero
  265. add 0x08 00 00 00 to file size
  266. <++++++++>
  267. Initialize registers
  268. >>+++++++[<+++++++>-]<. xor eax eax
  269. >>++++++++++++[<++++++++++++++++>-]<.
  270. <.>>+++[<+++++++++>-]<. xor ebx ebx
  271. >++++[<-------->-]<--.<<<<<<.>.>.>. mov ecx filesize
  272. >>.>>+++++[<+++++>-]<. xor edx edx
  273. >++++[<<++++>>-]<<+. inc edx
  274. Now start compiling
  275. >[-]<[-]<[-]<[-]<[-]<[-]<[-] clean up
  276. <<<<<<[<]> move to first instruction
  277. [ while opcode exists
  278. - decrease opcode
  279. [ if opcode is not plus
  280. - decrease opcode
  281. [ if opcode is not comma
  282. - decrease opcode
  283. [ if opcode is not minus
  284. - decrease opcode
  285. [ if opcode is not dot
  286. - decrease opcode
  287. [ if opcode is not left angle
  288. - decrease opcode
  289. [ if opcode is not right angle
  290. - decrease opcode
  291. [ if opcode is not left bracket
  292. <++++[>------<-]>. output e9
  293. [-] clear this field
  294. >[>]>>>>>>>>[>>>>>>] move to end of loop size stack
  295. -------->->->-<<< initialize increment
  296. <<<<< move to byte 1 of size
  297. [ while byte 1 is not zero
  298. >>>>>- decrease byte 1
  299. [>>>>+>+<<<<<-] copy byte 1
  300. >>>>>[<<<<<+>>>>>-]
  301. <[>-<[-]] if no underflow set field to minus 1
  302. >+[- if underflow
  303. <<<<- decrease byte 2
  304. [>>>+>+<<<<-] copy byte 2
  305. >>>>[<<<<+>>>>-]
  306. <[>-<[-]] if no underflow set field to minus 1
  307. >+[- if underflow
  308. <<<- decrease byte 3
  309. [>>+>+<<<-] copy byte 3
  310. >>>[<<<+>>>-]
  311. <[>-<[-]] if no underflow set field to minus 1
  312. >+[-<<->>] if underflow decrease byte 4
  313. ] end if
  314. ] end if
  315. <<<<<<<<<<- decrease byte 1 of size
  316. ] end while
  317. > move to byte 2 of size
  318. [ while byte 2 is not zero
  319. >>>>>- decrease byte 2
  320. [>>>+>+<<<<-] copy byte two
  321. >>>>[<<<<+>>>>-]
  322. <[>-<[-]] if no underflow set field to minus 1
  323. >+[- if underflow
  324. <<<- decrease byte 3
  325. [>>+>+<<<-] copy byte 3
  326. >>>[<<<+>>>-]
  327. <[>-<[-]] if no underflow set field to minus 1
  328. >+[-<<->>] if underflow decrease byte 4
  329. ] end if
  330. <<<<<<<<<- decrease byte 2 of size
  331. ] end while
  332. > move to byte 3 of size
  333. [ while byte 3 is not zero
  334. >>>>>- decrease byte 3
  335. [>>+>+<<<-] copy byte 3
  336. >>>[<<<+>>>-]
  337. <[>-<[-]] if no underflow set field to minus 1
  338. >+[-<<->>] if underflow decrease byte 4
  339. <<<<<<<<- decrease byte 3 of size
  340. ]
  341. > move to byte 4 of size
  342. [ while byte 4 is not zero
  343. >>>>>-<<<<<- decrease byte 4
  344. ]
  345. >->.>.>.>. print increment
  346. [+]<[+]<[+]<[+] clear increment
  347. <<<<<<- remove size from stack
  348. <[<<<<<<]<<<<<<<<[<] move back to opcode
  349. <-> set indicator to minus 1
  350. ] end if (opcode is not left bracket)
  351. <+ increase indicator
  352. [ else (opcode is left bracket)
  353. ++++++[>++++++++<-] set to 38
  354. >++.---------. output 3a 31
  355. <+++++++++++++++. output 0f
  356. +[>+++++<-]>+++. output 84
  357. [-] clear this byte
  358. clear the byte counter
  359. + set nesting level to one
  360. [ while nesting greater than 0
  361. >[<<<+<+>>>>-] copy opcode before nesting level
  362. <<<------- subtract 7 from opcode
  363. [ if opcode is not left bracket
  364. - decrease opcode
  365. [ if opcode is not right bracket
  366. [+] clear field
  367. >-< set indicator to minus 1
  368. ] end if opcode is not right braket
  369. >+ increase indicator
  370. [ else (opcode is right bracket)
  371. >-<- decrease nesting level
  372. ] end else (opcode is right bracket)
  373. -< set indicator to minus 1
  374. ] end if (opcode is not left bracket)
  375. >+ increase indicator
  376. [ else (opcode is left bracket)
  377. >+<- increase nesting level
  378. ] end else (opcode is left bracket)
  379. >[>+<-]> copy nesting to next field
  380. ] end while (nesting greater than 0)
  381. <<<< move to last opcode in loop
  382. [ while there are opcodes
  383. [>>>+>+<<<<-] copy the opcode twice
  384. >>> move to first copy
  385. - decrease opcode
  386. [ if opcode is not plus
  387. - decrease opcode
  388. [ if opcode is not comma
  389. - decrease opcode
  390. [ if opcode is not minus
  391. - decrease opcode
  392. [ if opcode is not dot
  393. - decrease opcode
  394. [ if opcode is not left angle
  395. - decrease opcode
  396. [ if opcode is not right angle
  397. - decrease opcode
  398. [ if opcode is not left bracket
  399. - then it must be right bracket
  400. set increment to five bytes
  401. <<+++++>->
  402. ] end if (opcode is not left bracket)
  403. <+ increase indicator
  404. [ else (opcode is left bracket)
  405. set increment to 8 bytes
  406. <++++++++>-
  407. ] end else (opcode is left bracket)
  408. -> set indicator to minus 1
  409. ] end if (opcode is not right angle)
  410. <+ increase indicator
  411. [ else (opcode is right angle)
  412. <+>- set increment to 1 byte
  413. ] end else (opcode is right angle)
  414. -> set indicator to minus 1
  415. ] end if (opcode is not left angle)
  416. <+ increase indicator
  417. [ else (opcode is left angle)
  418. <+>- set increment to 1 byte
  419. ] end else (opcode is left angle)
  420. -> set indicator to minus 1
  421. ] end else (opcode is not dot)
  422. <+ increase indicator
  423. [ else (opcode is dot)
  424. <++++++>- set increment to 6 bytes
  425. ] end else (opcode is dot)
  426. -> set indicator to minus 1
  427. ] end if (opcode is not minus)
  428. <+ increase indicator
  429. [ else (opcode is minus)
  430. <++>- set increment to two bytes
  431. ] end else (opcode is minus)
  432. -> set indicator to minus 1
  433. ] end if (opcode is not comma)
  434. <+ increase indicator
  435. [ else (opcode is comma)
  436. <++++++>- set increment to 6 bytes
  437. ] end else (opcode is comma)
  438. -> set indicator to minus 1
  439. ] end if (opcode is not plus)
  440. <+ increase indicator
  441. [ else (opcode is plus)
  442. <++>- set increment to 2 bytes
  443. ] end else (opcode is plus)
  444. <[>>>[>]>+<<[<]<<-] copy increment behind program
  445. >>>[>]> move to increment
  446. [ while increment is not zero
  447. >+ increase byte 1
  448. [>>>>+>+<<<<<-] copy byte 1
  449. >>>>>[<<<<<+>>>>>-]
  450. <[>-<[-]] if no overflow set field to minus 1
  451. >+[- if overflow
  452. <<<<+ increase byte 2
  453. [>>>+>+<<<<-] copy byte 2
  454. >>>>[<<<<+>>>>-]
  455. <[>-<[-]] if no overflow set field to minus 1
  456. >+[- if overflow
  457. <<<+ increase byte 3
  458. [>>+>+<<<-] copy byte 3
  459. >>>[<<<+>>>-]
  460. <[>-<[-]] if no overflow set field to minus 1
  461. >+[- if overflow
  462. <<+>> increase byte 4
  463. ]
  464. ] end if
  465. ] end if
  466. <<<<<<- decrease increment
  467. ] end while
  468. <<[<]<<<< move to next opcode
  469. ] end while opcode exists
  470. >>>>>[>]>>.>.>.>. output the loop increment
  471. <<< move to byte 1
  472. copy byte 1 on stack
  473. [>>>>>>[>>>>>>]>+<<[<<<<<<]<<<<<-]
  474. > move to byte 2
  475. copy byte 2 on stack
  476. [>>>>>[>>>>>>]>>+<<<[<<<<<<]<<<<-]
  477. > move to byte 3
  478. copy byte 3 on stack
  479. [>>>>[>>>>>>]>>>+<<<<[<<<<<<]<<<-]
  480. > move to byte 4
  481. copy byte 4 on stack
  482. [>>>[>>>>>>]>>>>+<<<<<[<<<<<<]<<-]
  483. set surrounding 1 bytes
  484. >>>[>>>>>>]+>>>>>+<<<<<<[<<<<<<]<<
  485. <<<<<<[<] move back to start of loop
  486. < move to indicator field
  487. ] end else (opcode is left bracket)
  488. -> set indicator to minus 1
  489. ] end if (opcode is not right angle)
  490. <+ increase indicator
  491. [ else (opcode is right angle)
  492. +++++++[>++++++++<-]>+ set to 41
  493. .[-]< output 41 and clear up
  494. ] end else (opcode is right angle)
  495. -> set indicator to minus 1
  496. ] end if (opcode is not left angle)
  497. <+ increase indicator
  498. [ else (opcode is left angle)
  499. +++++++[>+++++++++<-]>+. output 49
  500. [-]< clear up
  501. ] end else (opcode is left angle)
  502. -> set indicator to minus 1
  503. ] end if (opcode is not dot)
  504. <+ increase indicator
  505. [ else (opcode is dot)
  506. ++++++++++ set to b0
  507. [>++++++++++++++++<-]>. output b0
  508. <++++.>+++.<---. output 04 b3 01
  509. +[>+++++++++++++<-]>. output cd
  510. <+++++++[>-----------<-]>. output 80
  511. [-]< clear up
  512. ] end else (opcode is dot)
  513. -> set indicator to minus 1
  514. ] end if (opcode is not minus)
  515. <+ increase indicator
  516. [ else (opcode is minus)
  517. >--.++<++++++++.--------- output fe 09
  518. ] end else (opcode is minus)
  519. -> set indicator to minus 1
  520. ] end if (opcode is not comma)
  521. <+ increase indicator
  522. [ else (opcode is comma)
  523. ++++++++++[>++++++++++++++++<-] set to b0
  524. >.<+++.>+++.<---. output b0 03 b3 00
  525. ++[>+++++++++++++<-]>.< output cd
  526. +++++++[>-----------<-]>. output 80
  527. [-]< clear up
  528. ] end else (opcode is comma)
  529. -> set indicator to minus one
  530. ] end if (opcode is not plus)
  531. <+ increase indicator
  532. [ else (opcode is plus)
  533. ---.+++.- output fe 01
  534. ] end else (opcode is plus)
  535. >> move to next opcode
  536. ]
  537. [>]>
  538. Clean up
  539. >+++++++++++[<++++++++++++++++>-]<. mov al 1
  540. >+.
  541. <+++.>-. mov bl 0
  542. ++++[<++++++>-]<++. int 0x80
  543. >>++++++++[<++++++++++++++++>-]<.