From 3d110a3494e6304b9188cf1dcda106d8008d602d Mon Sep 17 00:00:00 2001 From: Steve Sprang Date: Sat, 24 Feb 2018 14:49:31 -0800 Subject: [PATCH] Initial commit. --- .gitignore | 1 + Cargo.lock | 4 + Cargo.toml | 5 + LICENSE | 21 +++ README.md | 20 +++ programs/99bottles.mb | 246 ++++++++++++++++++++++++++++ programs/cat-wikipedia.mb | 5 + programs/copy.mb | 1 + programs/empty.mb | 0 programs/hello-world-wikipedia.mb | 1 + programs/hello-world.mb | 1 + programs/invalid-char.mb | 2 + programs/too-short.mb | 1 + reference/malbolge.c | 162 +++++++++++++++++++ src/main.rs | 257 ++++++++++++++++++++++++++++++ 15 files changed, 727 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 programs/99bottles.mb create mode 100644 programs/cat-wikipedia.mb create mode 100644 programs/copy.mb create mode 100644 programs/empty.mb create mode 100644 programs/hello-world-wikipedia.mb create mode 100644 programs/hello-world.mb create mode 100644 programs/invalid-char.mb create mode 100644 programs/too-short.mb create mode 100644 reference/malbolge.c create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..688bf0e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4 @@ +[[package]] +name = "malbolge" +version = "0.0.1" + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..859791c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,5 @@ +[package] + +name = "malbolge" +version = "0.0.1" +authors = ["Steve Sprang "] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..360c73b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Steve Sprang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..99cb027 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +Malbolge +======== + +This is an implementation of the +[Malbolge](http://en.wikipedia.org/wiki/Malbolge) interpreter in Rust. + +Running +------- + +Run the binary against the sample Malbolge programs in the `programs` directory: + +`cargo run --release programs/99bottles.mb` + +Malbolge Programs +----------------- +hello-world.mb by [Andrew Cooke](http://www.acooke.org/malbolge.html) + +99bottles.mb by [Hisashi Iizawa](http://www.99-bottles-of-beer.net/language-malbolge-995.html) + +copy.mb by [Lou Scheffer](http://www.lscheffer.com/malbolge.shtml) diff --git a/programs/99bottles.mb b/programs/99bottles.mb new file mode 100644 index 0000000..4c873c8 --- /dev/null +++ b/programs/99bottles.mb @@ -0,0 +1,246 @@ +b'`;$9!=IlXFiVwwvtPO0)pon%IHGFDV|dd@Q=+^:('&Y$#m!1S|.QOO=v('98$65aCB}0i.Tw+QPU'7qK#I20jiDVgG +S(bt<%@#!7~|4{y1xv.us+rp(om%lj"ig}fd"cx``uz]rwvYnslkTonPfOjiKgJeG]\EC_X]@[Z7~;:9y16w43s10)p-,l*#(i&%e#d!~``{tyxZpuXsrTTongOkdMhg`Hd]ba`_^W@[ZYXW9UNSRQPOHMLK +J-++FE''=<;:387xw43s10/(-&m*)('&}${d!~}|^zyxwvutmVqpiRQlkjiKafedc\E`_^@\[ZYX;V9NMRQ42NG +LK.IH*F?DCBA$#>7~;{{8xx5uu2rr/oo,ll)ii&f|e"!aw`{z\r[vXnmVTpongPkNihgJ_dcFa`B^]\UZ=RWV8TSLQ4O +N0LE.IHA)E>'BA:?!7~5|38y6/v321q).-&m*)i'&%|{d!~}_{zs\wvutsUqTonPlOjiKgJedFbE`_A]@[Z7~;:987w5v32r0)p-,+k)('~g$#"b~w|uz]xwvutsrqTinQlOjLhgfeH]bE`CB]\>ZSXWVUTS +RQPON1LE.I,+*((&&$$""~~||zzxxv4u210/(-n+l)(i&g$ddy~}`u^]\ZvutVlUjSQQOOdMKgfeG]F[DBB@@>><<:VU +T6L5JO200EJ-HG*E>'B%$9>=<|4{2y05v321r).o,mlj(igg|#d!~}`uz]x[ZotWUUjoRmlkNibKJIGGEEZ_B]\?Z=XW +PU876442NM/KD-B+))''%%##!!}}{{yyw5v32s0q.-&+l)j'hff{"caav{^yxwZutslUpSnQOOdiLgfHHcba`Y^A\?Z= +;;PU8SRQ4ONMLEJ-,+))''%%##!=<;{3z1xvvttrrppnnll#j!&g$#d!b}|{zyr[vYtsrTjShQfkNihgJedcba`Y^A\? +Z=;WV9TSRQPOHM0K.-++)ED&B;$9"~<;:z2y0wuussqqoom+ljj!&%$dzcx}`{zy\wvutsrqjSnQPNNLhgIedG\EZCA] +\[=SY<;P9775533H1/KJ,HA*?(&&$$">=<|4{2ywwu321q)p'nl*k('gg${"c~a`^z]xwvYtmrUpSRPlOMMbK`IGGEE +Z_^]?U>S<::8866442200.JIH*@)>C&A@?"=<5|{8y65vtt10/(-n+lk"'&%e{dyb``^^\\ZvutVlUjSQmlkMcLaJHHF +bECCX]\[=S>>YXWP9T76K42200.JI+G@)>'%A@?!7~5|zzx654t,s*qo-n+*jj!h%fec!b}|{^s\[vYWWlqTonQlO +jchKfIHFFDDB^]\>T=R;P9NS6QPO2MLE.-,*FED&<%:#!!}}{{yyw543s+r)pnnl*kii~%f#"caa|{zsx[ZutVrkTinQ +lkNiLgfe^cFEDYBW\[=YR;P977553O200EJIH*@)>C&$$9>!<;|9z7654-tsrppnnll#('&f|ezca}|{]s\qZXtsrTjS +hQOOMihgI_H]FDDB^A\[><=<5:{zy0wuussqqoomm$ki'hff{"c~}`{t]\wvuWmVk +pSnmPNNcLKfIGG\aD_^A\?T=<;99775QPO1G0E.,HG)E>'<%#?"~~5:98x0w.ussq/pnn%*k('hff#z!ba|{z\r[puXs +rUpSnglONihgI_H]FDDYBW\[Z=}5|3zxxv4u21r/p-,+*#(i&g$# +c!~av_t][[YutsUkTiRPPNNLLJJHHFFDDB^A\[Z=XWVUTM6Q43HM0..CH+FE''BA@?>=6;|9z765u-t+0q.-,m*)('&% +|#dcb``uzy[wpYnWUUSonmOeNcLJJHHFFDDBB@\?ZY=}5|3zxxvvttrrppn,m*)ii +&%$#"!~}v{^y\wvuWmVkpSnmlOjihgfedc\aD_BAV[ZC&%$""7~|:9y70w.us10/o' +n%ljjhhffddb~a|{^\\wvutmVUTRnQlkNiLgfed]FE`_A]V?TY=<;:927x5vuss +qqo-,+k#j!hffddbb``^^s\qZXXVVTpSQQfkNihg`IHcbaCYBW\?==RW:UT755J321FK.IH+F)>'B%$9"~~||zzxxvvt +210p(o&mkki'&%e{dyb``^z]xwvYtmrUTSQmlkMcLaJHdcbDZCXA?[><T=R;99775Q4ON00KJIBG*E('%A$?>=~;:927 +xwvttr0/.n,m$)('g}f{"c~}`{^yxwvoXsVUSShQOkjLhaJ_HFba`BXAV?=YX:VO8M644220L/JI++FEDCB;@#>!<;:z +2y05v321r/.-,+$)j'hgeeccaa__]][wZXXmVkTiRPPNjMhgfIdcba`_XA@?==;;9977L5J31MLK-C,A*((&BA@"8!6} +{{y765u-t+rppn,m*)j'h%$#"!~}v{^y\[YutsUkTiRPPNNLhgfH^G\ECCAA??==;;9UTS5K4IN1LKJC,G*)''%%#?>= +}5|3zxxvvttrrppnnl*k('gg|e"c~a__ty\wvuXmVUTinmlNdMbKIedFb[DYB@\?==RWVU7M6K42N1LK.,,G@E('&$@# +>=~;|927xw4uss*/.n,%l#(i&%f#d!~w`{^][[YYWWlUjonmOeNcLJJHHFFDDB^A\[==XWVOT7R542N1LKJ-HGF?D'&% +:?"=<}:3z7xwuussqqo-,+k#j!h}fddb~}_{t]r[YYWWUqpoQgPeNLLJJHHFFDDBB@@>Z=XWV9N7R54I2GLKJ,B+@)'' +%%#?>=}5|3zx654t,s*qoommkkiig%f#"bb}v{^y\wvuWmVkpSnmlOjchKJIGGEaD_^A\?ZYR;V986RQP2H1F/--++)) +''%%##!=~;:zz765.3t1rq(-,+k#j!&g$#"c~}|uz]x[ZXtsrTjShQOOMMKKIIGGEECCAA?[><=6}|9zxx/432r*q(o&mk)j'&g$e"!~}|{zsx[vYXVVTponPfOdMbKIIGG\ECCAA??=YXW9O8MR5PONG0K +.I,**?D'BA@9"=~}4{yywwuussqqoommkki'h%$ddyb}`_ty\ZZotsrTjShmPkjiLaJIHFba`BXAV?==;;9977553311 +//-IHG)?(=B%@?"=~;49z7x543s+r)pnnl*)(h~g|ec!b``uzyxZpYnWUqpoQgPeNLLJJHHFFD`C^]??ZYR;V986R5PO +N1LKD-,+))''%%##!=<;{3z1xvvttrrppn,mkk"'&f${dy~a|{^\\wvunsVUpSQQfkNihKfIdcb[`C^A\[ZZS7~;|{y76v4-t+rp.-,l$k"iggeecca}`{z\\wvunsVqTonPleNchKfedGba`Y^A@?==;W +VU7M6K42N1//DIHG)?(=&$$""~~||zzxxv4u21rpp-,+*#ji&geez!b}|_z]xwvunWrUpSQQfkjiKaJ_HFbE`_AA\[ZY +XQV9T764P3NML/JIHGF?D'&%##!=<;{3z1x/v-2s0/p-n+*)('&}f#d!b``uz][[pYnsrqSiRgPNNLLJfedF\EZCA]\[ +=S!<}:{yy05v321r/.-,+*)"'hg$e"!b``{zyxwvutmVqToRPlkNihgfedcb[DCBW +@>><<::8TSR4J3H1//--++))''%A@?!7~5:{87x5.u2s0/o-&m$)j'&ff{"c~a|_]]rwZutsVkpSnQPeNchgfH^G\ECC +AA??==;;997S6QPO2MF/J-,A*((&&$$""~~||zzxx/4u210q.-&+l)jig%$d"ybw|_zyx[vunsVUTRnmlNdMbKIIGGEa +`B^W@U><<::88664PON0F/DI,GF)D'BA@9"=~}4{yy0wuus10/o'n%ljjh&%$dzcxa__]][wvXtmVkTRRPPNjMhgIIdc +baZ_B]@[ZY;Q:OT7RQP3NMLKDI,+FED&<%:#!=<|:3z1xvvttrrppnnlljjh&g$#d!b}|{zyr[vYXVrqpRhQfOMMKKII +GGEECCAA??=Y'=~;:9876/4utsq/pnn%*)i'~g|ec!b}|_z]xwvutsrkToRQOkjiKa +J_HFFDDBB@\?==RWV8TM6K42NML.D-B+))'C&A@""=<;:9876/4u2s0/o-&m$)j'&%f#"!~}|{zsx[vuXsVqSShmlOdM +hKJ_HFFDDBB@\[ZT=RW:UT7R5J32M0KJ-++F?D'&A@">7~5:{87xvv32+rq.omm$)j'&g$e"!xa|_^\xwYunWlUSonm +OeNcLJJHHFFDDBB@@>Z=XW99TSRKP3N10.J-HGF)DCB;@#"!6}{{y765u-t+rppn,+*j"i~geeccaa__]][wZutWUUpo +nmfONihgI_H]bE`_B]@[ZYXQ:9T755JO200E.CHGF(>'!<}:9876/4utsq/.-m%l#jhhf$#c!xav_]][[YuXsrU +pSnmlkjchKJIGGEa`_AW@U><<::8TS5QJ3H1/KJI+A*?(&&$@#>=~||9876543,1rq.-m+$k"'h%$e"c~}|{zyxqvYXs +VTTinmlNdMbgJedGbE`_^]\[ZYR;:9775QPO1M0EJ-HG*E>'B%$9"~~||zzxxvvttrrppn,m*)ii~%f#d!b``uz]xwvY +nsVqTSQQOkjiKaJ_HFFDDBB@@>><<::886R5PON1LE.-H+))>'Y<;P977553311//--++)EDC%;$9"7~5:{876w432+rqpnn%lj('g%|ezcaa__]y +\wvYtWrqpohmPkNMKKIIGGEECCAA??==;W:88MR5PON1LKJIHA*)(=&$$">!<;|zz765432+0qpo&+*)i!h}fd"!~`v_ +t][[YutsUkTiRPPNNLLJJHdGbaD_B]\[ZYXQV9T76KP3NM//JIHGFED=&A$#8=~||3876v.u,1r/.-n+*)('&%|edcx} +|^zs\qZXXVrqSohQfkNihKf_HGF[`_^@V?TY<::OT7RQ4OH10K.IH+F)>'B%@#!=<}4{z765u-t+r).o,+l)j'~%fedb +~a__ty\wvYtWrkpSRQfkNLLafIdcFaD_^W@?Z=;;PU8SR533NMLEJ-,G*((=B%@?"=~;:927xw43s10q(-,+k#j!hffd +db~}_{t]r[YYWWUUSSQQOkNihKfIdcbaZCBA?[><><<:V9TSR5PONMLKD-,+@)>C&$$9>!<;|92yx543s+r)p'n%lj(i +&%f#zc~a`u^\\ZZXXVVTTRRPPNNLLafIdcbEZ_B]@?=Y<::OT7RQP3HM0K.-BG*((=B%@?>!<5|{z1xvvt2sqq(-,+k# +j!hffddbb``^^\\ZvuWslUjoRmlOMMhg`eHGbECCX]@[Z=X;VUNS6Q4O200EJ-++@E(CBA$?>=6}:{8yww.3t10pp-,+ +*#(i&g$eccx}`{zy\wvutmrUpSnQOOdiLJJ_dGba`C^]\[ZSC&A$?"~~5:{876w43210/(- +n+l)jhh}$eccx}`{zy\wvutsrqjSnQlOMMbgJedFFa`_^]\[ZSX;V9T755JO2MLK.IHGFEDCB;@#"!6}{{y765u3t+0q +.-n+$k(i&geez!b``uz]xwvYnWrUpSQQfkNihJJe^cFaD_B@@UZ=XWV9TMR5P3200..,,**((&&$$""~<;:z2y0w.3t1 +0/p-,%l)jiggeecca}|{]s\qZXXVVTponPfOdMKgfeG]F[DBB@@>><<:V9TS55PONGL/J-H+))>C&A@?"=<;49zy6w43 +tr*qp-n+*kii~g$e"ca}|_t]x[vuWslUjoRmlNNibgJeHcFDDY^A\[Z=XQV9T76K4INML.D-B+))''%%##!!}}{9z765 +v32+rqp'nllj('&f|ezca}|{]s\qZXtsrTjShmPkjMKKfed]bEDCA]@[Z=X;VUTMR5P320LKJ,B+@)''%%##!!}}{{yy +wwu321q)p',m*)(i&%$#zc~a|{]yr[pYWsVqpohQlOjMKK`I^cbD`YBW\?ZYX;PU8S653311//--+GFE'=&;$""~~|:9 +y70w.ussqqo-n+*)j!&g$e"!~`v{zyx[voXWrUpoRmPkdMhKJHdGEEZ_^]?U>S<:VUT6L5J311//--++))''%A$?>~~; +:38y6wvt2s0/.o,+$)j'hgeeccaa_{zy[qZoXmVTTRRPPeNLLJJHdGba`C^]\U>=X;VU86L5P32GLKJ,B+@)''%%##!= +~||3876v.u,sqqo-,+k#j!&g$#ccx}`{^y\ZZotWrqpShmPkNMKK`edFb[DYB@@>><<::88664PON0F/D-BG*EDC&A:# +"!}}{{yyw543s+r)p'n%*k('h%f#"y~a|_^\\ZZXXmrqpRhQfOMiLJJ_dcEaZCXA?[ZY;Q:O8664PO1MF/DI,GFE(CBA +:#"=~||38y65v3,srq(-n+*k(i~%f#dcaav_t][wvuWmVkTRRPPNNLLJJHHFFD`CAAV[>YXW:UN7R542N1//D-BG*((= +B%@?>!<;49z7x5vtt+r).-,l$k"'h%$#d!~w|_z]\ZZoXVrqSohQfOMMKgfeG]F[DBB@@>ZYX:P9N75QPO1G0E.,,**( +(&B%@?!!<;:3z7xwu3t10/p-,+$kj'h%$ecc~}|{ty\wZutVrkTinQlkMMhgfed]FaD_B@@UZ=XWV9TSRQPI21LKJ,B+ +@)''%%##!!}}{{yyw5v32sqq.-,+*)"'hg$#"bxav{^yx[vYtsrqpohmPONchKII^cFa`C^W@?Z=;;PU8SR5PI2M0/D- +++)EDC%;$9"~~||z876v.u,sqqoommk)j'&ff{d!ba_{^yxwZoXWVkTinmlNdMbgJedGbE`Y^A@?=YXW9O8M6442NM/K +D-B+))''%A$?>!<}:38y6wv-21q/(o&mk)(h&}f{dbb``^^\\ZZXXVVTpSnmOOjihafIdGFD`C^]\?ZYXQV9T7R533HM +LK-C,AF)DCB%@?>=6}|{2ywwuuss*q(om+*)i!h}fddbb``^^\\ZvYtsVTTonmlkdiLKJHdGbaD_B]\[ZYRW:U87L5J3 +H1/KJI+A*?D'BA@9"!<}{{2765u-t+0q.-n+l#jih}f{dy~a|{^y\qZuXWlUjonmOeNcLJfIdcbE`Y^A\?><<::88664 +PON0F/D-++))'CB$@9"7~||zzx6w432s0).onmk)(h&}f{db~}|^t]r[YYWWUUSSQQOOMMKgJHH]bE`_B]@[ZS!<;:38y6w432r*/.-,m*)('~gf#d!~a|_zyxwpYXWUqpoQgPeNLLJJHHFFDDBB@@UZ=XW:U +8SRQPOHM0/.,HG)E>'<%#?"~~5:98x0w.ussq/p-,m*k('&%${"c~a`u^\\qZotWrqSSnmlkjibKfIdcbDZCX]@[ZYT= +RW:UT7R5JO21L/JI,G*E>'&A$?>!<}:3z7xwu321q)p'nlljjhhffddbb``^zyxZpYnsVqpRRmlejMhKfIGG\aD_^]@[ +ZSX;:977553311//--++)E(&&;@?>~6}49z76w4u210)po,mkk"'h%$ecc~}|{ty\[vuWslUjoRmlOjMhgfe^cFaDCXA +?[><YXWVOT7R542200..,HGF(>'<%:#8!}}{987w/v-2sqq(-n+*)j'&%$#zcb}`{z]x[vutsrqjoRQlOjiLgJe +dcba`Y^A@?=YXW9O8M6K4I20L/--BGFE'=&;@#>=~;|9876543,s0qpnnlljjhhffddbb`|_]]rwZutVVqponmlkjchK +fIdcbDZCX]@[ZY'<%:#!!}}{{2ywwuussq/pnn%*k('&}f#d!b``uz]xwvoXsVUjonPlkNc +LafedF\EZCAA??==;;997SRQ3I2G0..,H+FED'<%$#!!};:9y1x/vttrrppnnlljjh&g$#dbb}v{^]\ZvYtsVqTohmPO +NchgIe^G\EC_^]?U>SX;VU8S6QPI210..,,*FED&<%:#!!}}{{yywwu3t10qoo,+*#(ihge#d!~a|_zyxqvYtWVTTinm +OkdMbKIedFbaDY^]\>T=R;997SR4PI2G0..,HG)E>'~~;:981x5vus1r/.-n+*)(!hg$e"!b``{zyxwpuXsVqTR +nmPkjihg`eHcFa`B^W@UZ=XW99TSRQPOH1L/J-++@E(CBA$?>=<;:3zy654t,s*/p-,m*#jih}$#"b~av{^yx[voXWVT +TRRPPNNLhgfH^G\ECCA]\[=S!~;|98y6w4-ts0q.-n+l)"i&gfd"!~`v_t]r[pYWs +VqpoRmlejMLKIIGGEECCAA??==;W:88MRQP2H1FK.IH+F)DCB;$?"!6;|zz16w43ss0/.-&+l)j'hff{"c~}|_zyxwpu +XWVTpSQQfOdMbgfeG]F[DBB@@>><<::88664P311FKJI+A*?D'BA$?"=<;:92yx54t2+r).o,+l)"i&gfd"!~`|_ty\w +vuXmrUTShQOOMMKKIIGGEECCAA?[ZY;Q:OT7RQ4O2MF/.-B+@EDC%;$9>!<;|9z76/4uts*qoommkki'&f${dyb`|{]y +r[pYWsVqpSnQlkdiLKJ_dcbDZCXA??==;;99775QPO1G0E.,,*F)''=<;49zyxvvttrrp.-,l$k"iggeeccaa +__]][wvuWmVkpSnmPkNihgfe^GbEDYBW\[ZZ=XW:U8SRQPOHM0/.,,**((&&$@?>~6}4{yyw5vtt+0/.n&m +$kiig%$#cybw|_]]rwZutWrUponmlkdMhgJeHcEEZ_^AV?Z=XW9UN7LQ422GL/JIHA*E('%%##!!}}{987w/v-trrppn +nlljjh&g$#ccx}`{^yxZvoXmrUponQfkNMLaJHHFba`BXAV?==;WVU7M6K4220L/--BGFE'=&;@#>=~;|92y6wvttrrp +.-,l*k"'h%$#d!~w|_^yxZvoXmrUSShmPkjMhKfed]FaD_^]?U>S<::8866442200..,H+FE''BA@?8=~;|{y7x543t1 +0/.',m*kjh&geez!b}|{t]\wZXXmrqpRhQfOdMKgfeG]F[DBB@\[Z=<;:3 +z7x5vtt+0q.-,m*)('&%|e"!b}`{]]rwvYnWVUSSQQOOMihJf_H]bE`_B]V?Z='%%##!= +<|:3z1xvvttr0q.-mm*)(!h%f#"!aw`uz]xwvYtsrkTSRPPNNLhgfH^G\ECCAA??==;;997S6QP311LKJIBG*)DCB$:# +8=~;:{8y6543,1rqp'nl*)i'~g|ec!~}_u^s\ZZXXVVTTRRPPNNLhKfeHcFa`_^]V?>YYXW9O8M6442200.JIH*@) +>'%A$?>!}}:98705vutr0q.-n+l)('&}$e"cbw`^zyxZpYnWUUSonmOeNcLJJHdcEaZCXA??==;W:UT66QPONMF/J-HG +F(>'=~;:9870w4ut+0/o-&m$kiiggeeccaa__]yxwYoXmrUponQlkjihg`eHcFECCX]@>>SX;VUT7RQPONMFK.I +,+@E(&&;@?>~6}49zxx/4u210)p-n+ljj!&g$#"yb}`_t][wvuWmVkTRRPPNNLLJJHHFFDDB^A\[Z=R;:97SRQ3I2G0. +.,,**((&&;$">=};4{2yw5v32s0q.',m*k('g%|ezcaa__]][[YYWWUUSSQmPNNchKfeGGbaZC^A\[Z'%%:?>=}5|3zx654t,s*qo-n+*k(i&%${"cb}|{]s\qZXXmrqSohQfkNihKfIdcb[`CBAV?=YXW9O8MR5PO +200KJIHA*)(=B%@?"=~;:981xwvt210p(o&+l)(i&}f#dcaa__]][[pYWWUqpRngPeNLLJfedF\EZCAA??==R;9U8SRQ +4IN10/--++)E(CB%##>7~}|3876v.u,sqqoommkkiig%$#cybw|_zy\wZunWVUSoRPPejiKg`I^GEECCAA??=YXW9O8M +64P3NM0..IHAF)('%A$?>!<}:927x5vussqqoom+*j(!h}fddb~}|^t]r[pYnWUqTonPPkjibKfIdcbDZCX]@[ZY7<}|{yywwu321q)p'nlljjhhf$#"bxav_]][wZXXmrqpRhQfOMMKgJedGbE`_^]\U>=X; +VU86L5P32GL/JIHA*E('<%:#8=~;:9z16wvus10p.-n%*)i'~g|ecca}`^^sxwYunWlUSoRmlOjMhaJIHFba`BXAV?== +;WV8TM6K4220LKJ,B+@)''%%##!!};|98yww43,1rq.omm$)j'&g$e"!x}`{^yxwYoXmVTTRRPlkjLbK`IGcbaCYBW@> +><<::88664P3NM//JIHA*E(C&$$9>!<;:{876/vutrrppn,m*)jhh%$#"y~a`_tyxwYoXmVTTRnmlNdMbKIIGGEECCA] +@[Z=X;VUTSLQ4O21//-IHG)?(=&$@?>~6}4{yywwuussqqo-n+*jj'&%$#zc~a`^z]xwvYtsrqpiRmPkjiKaJ_HFF[DY +B@\[=YR;PU8SRQJ321/K.,,AFED&<%:#!!}}{{yywwuussq/p-,mkk"'hgfd"c~}`{^sx[ZYWsrqSiRgPNNLLJJHHFFD +`_^@V?T=;;9U8SR5P3NMLKJC,+*((&&$$""~~5:9y70w.3t10q.o,+*)('~%fe"caav_ty\ZZotWrqToRmlkjihafIdG +F[DBB@@U>!<;:{8765432+rqpnnl*)(h~g|eccaa__]][[YutsUkTinQlkNibKJe +HFF[`C^]@[T=X;:88M64PON0F/D-++))''%%##!!};|98xx/4u2s0qoo&+l)('h}$edcx}|^zy\qvYtsVqTohQlOjMKK +`eHcbDD_^W\?Z=X;99NS6QPO2MLEJ-,G*((=BA#?8!6;|98y6w432+r/p-nll#(i&%ee"!~}v{^y\wZXXmrUponQlkji +bgJIdGbaD_B]\[ZYR;VU8S6Q332MLKJIB+F)D'%%:?"=<||987654-2s0q.omm$)j'&%f#"!~}|uz]x[vYWWlqpoQgPe +NLLJJHHFFDDBB@@>>=};4{2ywwuussqqoommk)('g}f{"c~}`{^s\wZYWsrTpiRg +lOjiKKf_dGbE`CAAV[>YXW:UNS65P311FKJ,HA*?D'BA$?"=<5|9z7xvv-2s0/oo,+*#(i&g$eccx}`{zy\wvunsVUpS +QQfkjiKaJ_dGbaD_B]\[ZSY<<<::8866442200.JIH*@)>C&A@?"=<;:3z7xwuussqqoommkk"iggeec!b``uzy +xZpYnsVqpoRmlkjibgJIH]FDDY^]\>T=R;9977553311//--++)EDC%;$9>!<;|9z765432+rq.o,+l)j'&%$#"!x}`_ +^s\ZZXXVVkTRRPlkMibK`IGGEECCAA??=Y<::OT7RQ4O2MLKJIHGF?(CB%@#>~~5:9z1x5vussqqoommk)('g}f{dbb` +`^^\\ZvYWWlqTonmfONiLgfIdG\aDC^A\[>Y7<}|{yywwuussqqoom+ljj!h}$e +"!b}`{zyxwpYtWrUSShmPNNchKfedGba`_^]V[>=<:VUT6L5J311//-IHG)?(=&$$""~~||z8yww.321q)p',m*)j'h% +$#"!~}v_z]x[YYnsVTTinQlkjMhgfedcbaZ_BA@U>S'%%:?>=}5|3zxxv4uss*/.n,%l#jh +hffddbb``^^\x[YYnsVqpoRgPONLLJfedF\EZCAA?[ZC&%@#!!6;|98y6w4-2sr/.-m%l# +jhhffddbb``^^\\ZZXXmrUSShmlkMcLafIdcFaD_^W@?><<::88664422G0..,,*F)''!}}49z76w4-ts0q +oo&+l)(i&g|#d!ba__]][[YYWWUUSSQQOkNLLafedF\EZ_B]\[>YR;:U8SR5P3NMFK.I,+@)''%%:?>=}5|3zxxvvttr +rppnnllj('&f|ez!b}|{^yxwpYtWVkTinQlkjcLKfIGG\aDBBW\?ZY'%%##!!}}{{yywwu3 +21q)p',m*)(i&}fe"caav{^\\qvYtsVqTonglOjMLJJHHFFDDB^]?[T=R;997755331MLK-C,A*(D'BA@#>=<5|{8yww +.3trr).o,+l)j'&%${"cba__]yxwYoXmVTponPfOdMKKIIGGEECCA]@[Z=;;VUTSRQJO210.J-HG*E(CBA@?>7<}:{zx +xv43s1*q(om+*)i!h}fddbb``^^\\ZZXXVrUponQlkjihgf_HGFD`_A]V?T=;;9UTS5K4I200..,,**((&&$@#>=~;4{ +z7xvv-2s0/p-&m*kjhhffddbb``^^s\ZZXXVrUSShmlkMcLafIdcbEZ_BA\[Z><<:V9TS6Q4ONMF/J-H+))>C&$$9>! +<;:{8765.3tsr)pnn%*)(h~g|#dbbw|_zy\wZutsrqjSnQlOMMbgJHH]bE`_^A\[ZYXWPU87644220LKJ,B+@)''<%## +!!}}{{yy05v32s0)p-nmkki'&f${dyb`|{]yx[putVrkTiRPlkMibK`IGGEECCAA??=Y=XWV8N7L53ONM/K.CHGF( +>'!<}:98765.u2s0qoo&+ljj!&g$#"c~}|{zyxqvYtWrqpRhQfkNihg`IdGF[DBBW\[=YR;P977553311//--+G +FE'=&;@#>=<}4{8yxvvttrrppn,+*j"i~ge#"!aw`u^s\qZXtWrqpSnglONMKKIIGGEECCAA??==;WV8TM6KP311FK.I +H+F)DC<%$?"=<}:{876/4ut10/o'n%ljjhhffddbb``^^sx[vuXsVqpongPkNiLJJ_dGEEZ_B]\[>YXWVUNS65P311FK +.,,AF)DC&A$?>=<;:3z7x5vtt+0qoo&+l)('h%$#"!~}v{^y\[YYnWUUSonPleNcLJJHdGba`YB]@[ZY;Q:O866K4IN1 +LKJC,+F)''<YX; +V9TSL5P3N1//DI,**?D'BA@#>=<5:{8yxvv-trrp.-m+$k"igge#d!~``{zyxwpuXsVqpoQgPejMhgfIdcba`Y^A@[ZY +;Q:O86R533HML.JC,A*((&&$$""~~||zzx654t,s*/p-,m*k('&%$#zc~a`^^\\ZvuWslUjSQQOOMMKKIIGGEaDBBW\? +ZYX;VUTSRQPIN10/D-++))>C&A@#>!<;:98765.u2srp.-,l$k"iggeeccaa__]][[YutsUkTinQlkjcLgJI^cbD`YBW +@>Z=XWV9NS6Q4311F/--+GF(D=&;$">=<|4{2ywwuussqqo-n+*)j'~g$e"!a}v_t][[YutsUkTiRPPNNLLJJHH]FDDB +B@\?ZYX;VUNS6Q4311FKJI+A*?(&&$$""~~||zzxxvvt2sqq(-n+*)j'&%|ed!b}|_z]xwvunsVqTSQQOOMMKgJHH]ba +C_^AV[Z7~}:{87x5v3210/.',ml)('g}f{dbb``^^\\ZZXXVVTponPfOdiLgfIdG +ba`_^]\U>Y7<}:9z7x5uu,10q(onm$ki'&%e{dyb``^^\\ZvutVlUjSQQOOMMKKIe +HFF[`C^]@[T=X;VUT6L5J31M0..C,AFED&<%:?"~~5:{876w.utsqq(ommkkii~%$#cybw`^^\\ZZXXVVTpSnmPkNibg +JeHGEECCAA?[Z'=~;:3zy6wuu,1rpp',m*)j'h%$#z!b}`{zy[qZoXVrqpRhQfOMM +KKIIGGEECCAA??=Y><<::O866442N1//DIHG)?(=B%@?>!6;|9zyww.3trr).-,l$k"ig%$#cybw`^^\\ZZXXVVTTR +RPlOMMbgJedcFaZCBAV?TY!<;:{87654-ts0qoo&+ljj!&g$#d!b}|{zyxq +vYtWVkTRRPPNNcLafedF\EZCAA??==;;997755331M0KJIB+*EDC%;$9"~<}{{2y0543s+r).omm$)j'&g$ezc~a`^^\ +\ZZXtsrTjShQOOMMKKIIGGEaD_^]@[TY<;:8866442NM/KD-B+))''%%##!!};:z81x/4u21r/p-,%l)j'hff{"caav{ +^yxwZutslqToRQOOdihgI_H]FDDBB@@>><<::88664P311FK.IHG*EDCB;$#>!<;|9z76543,1rq.o,+lj"i&g$#"b~a +v{^yxwpYXWUqpoQgPeNLLJJHHFFDDBB@@>>~<5|3zxxvvttrrp.-,l$k"'h%$e"c +~w|_^][[putsUkTiRPlkjLbK`IGcbD`YBW@>><<::8866442N1//DI,GF)D'BA:#"!}}{{yy0wu32r0)p'nlljjhhffd +"!~`v_ty\wvYtWrqpinQPkjiKaJ_HFbECCXAV[ZY;Q:OT755JO2ML/J-HGFE>'&%##!!}}{{yyww.ussqqo-nll#('&f +|ez!b}|_z]xwvutmrUTSQQOkjLhaJ_HFbaC_^AV[Z!<}:98765.ut10p.'n%*kii +~g|#d!~a|_zyxwvutmrUpoRmPkMMbgfI^GFEC_^]?U>S<::8866442200..,H+FE(C<%@#"7~5:98x0w.us10/o'n%lj +jh&%e#zcxa__]][[YYWWUqpoQgPejMhgfI^GFEC_B@@UZ=XW:U8SLQ4O21F/--BG*((=BA@"8!6;|987x54-ts0qoo&+ +ljj!&g$#d!b}|{ty\wZYWWUUSSQQOOMMKKIIGcbD`YBW\?==RW:UTS6QPONG0/J-HG*E(CBA@?8=~;|987w5v-2s0/.' +nmljj!&%$dzcxa_{zy[qZoXVrqSohQfOMMKKIIGGEECCA]\[=S~6}4{yyw543s+r) +pnnlljjhhffd"c~}|_zsx[ZuXVVkpSQQfOdMbgJedGbE`_XA\?Z=;;PU866KP3NML/JIHAF)D'&$$">=<|4{2ywwu321 +q)p'nlljjhhff{"c~}|_zyxwpYtWVTTRRPPNNLLJJ_dcbDZCXA??==;;99775Q4ONM0KJIHG@E('BA@"8!6}{987w/v- +trrppnnlljjhhffddb~a|{^y\wvutsrkToRQOkNLLaJ_H]ba`BXAV?==;;9977553311//-I,GFE>'B%$""~~||z876v +.u,sqqoommkkiig%f#"!bw|_z]\ZZoXVrqpRhQfOMMKKIIGGEECCAA?[><=<| +4{2yw543s+r)pnnlljjhhf$e"!~w`_z][[puXVVkTinQlkNLLafIHcbD`YBW\?ZY7 +~;|{yywwuussqq(-,+k#j!hffddbb``^^\x[vutWrqjoRmPOMihgI_H]FDDB^]\>T=R;9977553311//--BG*EDC&A@? +8!~}4{2ywwuus10p.'n%ljjhhffddbb``^zyxZpYnsVqpSnQlkjibgJIdcbDZCXA?[><=6}|{yywwuussqqoo&mkkiig%fddy~}|^t]rwZutWrUponmlkdiLgJedFb[DYB@\[Z!}}49z76w4u21*/ponlljjh&geez!~}_u^s\ZvutVlUjSQQOOMMKKIeHcbECC^]\[TY<;:8T7RQ4O2MLK +JCH+FE(C&A##8=<}4{8y65u3,10/.'nml#jhhff{"!~`v_t][[YutsUkTiRPPNNLLJJHHFFD`C^]@[>S<;V977LQ4ON1 +//JCHGF)D&&;@#>=~;|92765vussq/.-m%l#jhhf$#"bxav_]y\ZZoXW2qjiR.-e=)KgJ%^]F!~C}W@[ZY;WPbTSqK#m +2k}ih,gTF)bPO%:"K7I54zW7gvv-sr*N.'JI[6FE&fUeAR>P+u:9[[pYW3lkS/.QyON*bKJ%dcF!m_^W@>-<;W:sN6%4 +]n[MjEWz,GFd'&s`#L]~6;|WW7UBeuc1qNpLJIk6FEgD1{zyQ=|*:([775WVrUSoAQ,Od*KJJ%HFF!!}}|?.Z=;QPtTq +%4o31kj/WIyfSRbC<`MLo\<|k{2V0fv-Qb=q.o&JH#G4~V$Bdy>P_;](x8vH5"3UpSh.fe=ib(J%7cF!`2B{i.Z+{]]88Y6XslT0B.zl,=<;(J%d]F!`}BW@yyY+d +tO8Mq5PINkjih-BTecQCa`qp>J~5XzW165eR,bO/L^m8[6j'D%UBdc>}`N^9x&vonF2qCSRmf>M*;J&8^]\n~}}@?[xY ++:Pt8S6o]3l~Y..,,*@RQ diff --git a/programs/cat-wikipedia.mb b/programs/cat-wikipedia.mb new file mode 100644 index 0000000..d662275 --- /dev/null +++ b/programs/cat-wikipedia.mb @@ -0,0 +1,5 @@ +(=BA#9"=<;:3y7x54-21q/p-,+*)"!h%B0/. +~P< +<:(8& +66#"!~}|{zyxwvu +gJ% diff --git a/programs/copy.mb b/programs/copy.mb new file mode 100644 index 0000000..fcb60f3 --- /dev/null +++ b/programs/copy.mb @@ -0,0 +1 @@ +D'BA@?>=<;:9876543210/.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDC&_十十十十十十十十十十十十十十十十十十篏十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十篏十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十十 diff --git a/programs/empty.mb b/programs/empty.mb new file mode 100644 index 0000000..e69de29 diff --git a/programs/hello-world-wikipedia.mb b/programs/hello-world-wikipedia.mb new file mode 100644 index 0000000..f7ce5a9 --- /dev/null +++ b/programs/hello-world-wikipedia.mb @@ -0,0 +1 @@ +(=<`#9]~6ZY32Vx/4Rs+0No-&Jk)"Fh}|Bcy?`=*z]Kw%oG4UUS0/@-ejc(:'8dc \ No newline at end of file diff --git a/programs/hello-world.mb b/programs/hello-world.mb new file mode 100644 index 0000000..9b0e52b --- /dev/null +++ b/programs/hello-world.mb @@ -0,0 +1 @@ +(=<`$9]7<5YXz7wT.3,+O/o'K%$H"'~D|#z@b=`{^Lx8%$Xmrkpohm-kNi;gsedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543s+O64K data arrays; this means using the HUGE memory model on most */ +/* compilers, but MS C, as of 8.00, possibly earlier as well, allows */ +/* you to specify a custom memory-model; the best model to choose in */ +/* this case is /Ashd (near code, huge data), I think. */ + +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +static inline +#endif +void exec( unsigned short *mem ); + +#ifdef __GNUC__ +static inline +#endif +unsigned short op( unsigned short x, unsigned short y ); + +const char xlat1[] = + "+b(29e*j1VMEKLyC})8&m#~W>qxdRp0wkrUo[D7,XTcA\"lI" + ".v%{gJh4G\\-=O@5`_3iU!pJS72FhOA1C" + "B6v^=I_0/8|jsb9m<.TVac`uY*MK'X~xDl}REokN:#?G\"i@"; + +int main( int argc, char **argv ) +{ + FILE *f; + unsigned short i = 0, j; + int x; + unsigned short *mem; + if ( argc != 2 ) + { + fputs( "invalid command line\n", stderr ); + return ( 1 ); + } + if ( ( f = fopen( argv[1], "r" ) ) == NULL ) + { + fputs( "can't open file\n", stderr ); + return ( 1 ); + } +#ifdef _MSC_VER + mem = (unsigned short *)_halloc( 59049, sizeof(unsigned short) ); +#else + mem = (unsigned short *)malloc( sizeof(unsigned short) * 59049 ); +#endif + if ( mem == NULL ) + { + fclose( f ); + fputs( "can't allocate memory\n", stderr ); + return ( 1 ); + } + while ( ( x = getc( f ) ) != EOF ) + { + if ( isspace( x ) ) continue; + if ( x < 127 && x > 32 ) + { + if ( strchr( "ji*p 126 ) continue; + switch ( xlat1[( mem[c] - 33 + c ) % 94] ) + { + case 'j': d = mem[d]; break; + case 'i': c = mem[d]; break; + case '*': a = mem[d] = mem[d] / 3 + mem[d] % 3 * 19683; break; + case 'p': a = mem[d] = op( a, mem[d] ); break; + case '<': +#if '\n' != 10 + if ( x == 10 ) putc( '\n', stdout ); else +#endif + putc( a, stdout ); + break; + case '/': + x = getc( stdin ); +#if '\n' != 10 + if ( x == '\n' ) a = 10; else +#endif + if ( x == EOF ) a = 59048; else a = x; + break; + case 'v': return; + } + mem[c] = xlat2[mem[c] - 33]; + if ( c == 59048 ) c = 0; else c++; + if ( d == 59048 ) d = 0; else d++; + } +} + +#ifdef __GNUC__ +static inline +#endif +unsigned short op( unsigned short x, unsigned short y ) +{ + unsigned short i = 0, j; + static const unsigned short p9[5] = + { 1, 9, 81, 729, 6561 }; + static const unsigned short o[9][9] = + { + { 4, 3, 3, 1, 0, 0, 1, 0, 0 }, + { 4, 3, 5, 1, 0, 2, 1, 0, 2 }, + { 5, 5, 4, 2, 2, 1, 2, 2, 1 }, + { 4, 3, 3, 1, 0, 0, 7, 6, 6 }, + { 4, 3, 5, 1, 0, 2, 7, 6, 8 }, + { 5, 5, 4, 2, 2, 1, 8, 8, 7 }, + { 7, 6, 6, 7, 6, 6, 4, 3, 3 }, + { 7, 6, 8, 7, 6, 8, 4, 3, 5 }, + { 8, 8, 7, 8, 8, 7, 5, 5, 4 }, + }; + for ( j = 0; j < 5; j++ ) + i += o[y / p9[j] % 9][x / p9[j] % 9] * p9[j]; + return ( i ); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..f423392 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,257 @@ +// MIT License +// +// Copyright (C) 2015-2018 Steve Sprang +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +/// This is an implementation of the Malbolge interpreter in Rust. +/// It's basically a translation of the original C version found here: +/// http://www.lscheffer.com/malbolge_interp.html +/// +/// For more information about Malbolge: +/// http://en.wikipedia.org/wiki/Malbolge +/// http://www.lscheffer.com/malbolge_spec.html +/// + +use std::fmt; +use std::fs::File; +use std::io::Read; +use std::path::Path; + +static XLAT1: &[u8] = b"+b(29e*j1VMEKLyC})8&m#~W>qxdRp0wkrUo[D7,XTcA\"lI\ + .v%{gJh4G\\-=O@5`_3iU!pJS72FhOA1C\ + B6v^=I_0/8|jsb9m<.TVac`uY*MK'X~xDl}REokN:#?G\"i@"; + +const MAX_MEMORY: usize = 59049; // == 3^10 + +// u16 would work here, but this saves a bunch of casting +type Memory = [usize; MAX_MEMORY]; + +//////////////////////////////////////////////////////////////////////////////// +// InitError +//////////////////////////////////////////////////////////////////////////////// + +#[derive(Debug)] +enum InitError { + InvalidChar(char, usize), + SourceTooShort, + SourceTooLong, +} + +use InitError::*; + +impl fmt::Display for InitError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + InvalidChar(c, loc) => + write!(f, "Invalid character in source program: '{}' \ + at location: {:#X}", c, loc), + SourceTooShort => write!(f, "Source program is too short."), + SourceTooLong => write!(f, "Source program is too long."), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// main +//////////////////////////////////////////////////////////////////////////////// + +fn main() { + let args: Vec = std::env::args().collect(); + + if args.len() != 2 { + println!("Usage: {} FILE", args[0]); + return; + } + + match load(&args[1]) { + Ok(contents) => run(contents), + Err(e) => println!("{}", e), + } +} + +//////////////////////////////////////////////////////////////////////////////// +// File Handling +//////////////////////////////////////////////////////////////////////////////// + +fn load(filename: &str) -> std::io::Result> { + let path = Path::new(filename); + let mut file = File::open(path)?; + + let mut contents = Vec::new(); + file.read_to_end(&mut contents)?; + + Ok(contents) +} + +//////////////////////////////////////////////////////////////////////////////// +// Interpreter Core +//////////////////////////////////////////////////////////////////////////////// + +fn run(contents: Vec) { + let mut mem = [0; MAX_MEMORY]; + + match init(contents, &mut mem) { + Ok(_) => execute(&mut mem), + Err(why) => println!("Could not initialize memory.\n{}", why), + } +} + +fn init(input: Vec, mem: &mut Memory) -> Result { + let mut i = 0; + let valid = "ji*p= MAX_MEMORY { + return Err(SourceTooLong); + } + + mem[i] = b as usize; + i += 1; + } + + if i < 2 { + // the C version does not check for this case + return Err(SourceTooShort); + } + + // fill in the rest of memory + for n in i..MAX_MEMORY { + mem[n] = crazy_op(mem[n - 1], mem[n - 2]); + } + + Ok(MAX_MEMORY) +} + +fn execute(mem: &mut Memory) { + let mut r_a = 0; + let mut r_c = 0; + let mut r_d = 0; + let mut input = std::io::stdin(); + + while is_printable(mem[r_c]) { + let index = (mem[r_c] - 33 + r_c) % 94; + let op = XLAT1[index] as char; + + match op { + 'j' => r_d = mem[r_d], + 'i' => r_c = mem[r_d], + '*' => { + r_a = tri_rotate(mem[r_d]); + mem[r_d] = r_a; + } + 'p' => { + r_a = crazy_op(r_a, mem[r_d]); + mem[r_d] = r_a; + } + '<' => print!("{}", r_a as u8 as char), + '/' => { + let mut buf = [0u8]; + let result = input.read(&mut buf); + + match result { + Ok(cnt) => { + if cnt == 1 { + // read a byte + r_a = buf[0] as usize; + } else if cnt == 0 { + // EOF + r_a = MAX_MEMORY - 1; + } + } + Err(e) => println!("{}", e), + } + } + 'v' => return, + _ => { /* no op */ } + } + + let index = mem[r_c] - 33; + mem[r_c] = XLAT2[index] as usize; + r_c = (r_c + 1) % MAX_MEMORY; + r_d = (r_d + 1) % MAX_MEMORY; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Interpreter Functions +//////////////////////////////////////////////////////////////////////////////// + +#[inline] +fn is_printable(c: usize) -> bool { + 32 < c && c < 127 +} + +#[inline] +fn tri_rotate(x: usize) -> usize { + // shift right and move the rightmost trit to the front + let (q, r) = (x / 3, x % 3); + q + r * 19683 // 3^9 == 19683 +} + +#[inline] +fn crazy_op(x: usize, y: usize) -> usize { + static P9: [usize; 5] = [1, 9, 81, 729, 6561]; + static O: [[usize; 9]; 9] = [ + [4, 3, 3, 1, 0, 0, 1, 0, 0], + [4, 3, 5, 1, 0, 2, 1, 0, 2], + [5, 5, 4, 2, 2, 1, 2, 2, 1], + [4, 3, 3, 1, 0, 0, 7, 6, 6], + [4, 3, 5, 1, 0, 2, 7, 6, 8], + [5, 5, 4, 2, 2, 1, 8, 8, 7], + [7, 6, 6, 7, 6, 6, 4, 3, 3], + [7, 6, 8, 7, 6, 8, 4, 3, 5], + [8, 8, 7, 8, 8, 7, 5, 5, 4], + ]; + + (0..5).fold(0, |sum, i| sum + O[y / P9[i] % 9][x / P9[i] % 9] * P9[i]) +} + +//////////////////////////////////////////////////////////////////////////////// +// Tests +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(test)] +mod tests { + use super::tri_rotate; + + #[test] + fn rotate_test() { + let input = 17; + let rotated = (0..10).fold(input, |prev, _| tri_rotate(prev)); + assert_eq!(input, rotated); + } +}